आपके पास यहां जो भी है वह वास्तव में seccomp का उपयोग मामला है ।
Seccomp का उपयोग करके, आप विभिन्न तरीकों से syscalls को फ़िल्टर कर सकते हैं। इस स्थिति में आप क्या करना चाहते हैं, ठीक है, fork()
एक seccomp
फिल्टर स्थापित करने के लिए open(2)
, जो openat(2)
, socket(2)
(और अधिक) के उपयोग को रोक देता है । इसे पूरा करने के लिए, आप निम्नलिखित कार्य कर सकते हैं:
- पहले,
seccomp_init(3)
डिफ़ॉल्ट व्यवहार के साथ प्रयोग करके एक seccomp संदर्भ बनाएं SCMP_ACT_ALLOW
।
- फिर
seccomp_rule_add(3)
प्रत्येक syscall का उपयोग करके उस संदर्भ में एक नियम जोड़ें जिसे आप अस्वीकार करना चाहते हैं। आप SCMP_ACT_KILL
प्रक्रिया को मारने के लिए उपयोग कर सकते हैं यदि syscall का प्रयास किया जाता है, SCMP_ACT_ERRNO(val)
तो syscall को निर्दिष्ट errno
मान को वापस करने में विफल रहता है , या action
मैनुअल पेज में परिभाषित कोई अन्य मूल्य।
seccomp_load(3)
इसे प्रभावी बनाने के लिए संदर्भ को लोड करें ।
जारी रखने से पहले, ध्यान दें कि इस तरह एक ब्लैकलिस्ट दृष्टिकोण एक श्वेतसूची दृष्टिकोण से सामान्य रूप से कमजोर है। यह किसी भी syscall की अनुमति देता है जो स्पष्ट रूप से अस्वीकृत नहीं है, और इसके परिणामस्वरूप फ़िल्टर का बायपास हो सकता है । यदि आप मानते हैं कि जिस बच्चे की प्रक्रिया को आप निष्पादित करना चाहते हैं, वह फ़िल्टर से बचने के लिए दुर्भावनापूर्ण रूप से कोशिश कर सकता है, या यदि आप पहले से ही जानते हैं कि बच्चों को कौन से सिस्कोल्स की आवश्यकता होगी, तो एक श्वेतसूची दृष्टिकोण बेहतर है, और आपको इसके विपरीत करना चाहिए। की डिफ़ॉल्ट कार्रवाई के साथ फ़िल्टर बनाएं SCMP_ACT_KILL
और आवश्यक syscalls के साथ अनुमति दें SCMP_ACT_ALLOW
। कोड के संदर्भ में अंतर न्यूनतम है (श्वेतसूची संभवतः लंबी है, लेकिन चरण समान हैं)।
यहाँ ऊपर का एक उदाहरण है (मैं exit(-1)
सिर्फ सादगी के लिए त्रुटि के मामले में कर रहा हूँ ):
#include <stdlib.h>
#include <seccomp.h>
static void secure(void) {
int err;
scmp_filter_ctx ctx;
int blacklist[] = {
SCMP_SYS(open),
SCMP_SYS(openat),
SCMP_SYS(creat),
SCMP_SYS(socket),
SCMP_SYS(open_by_handle_at),
// ... possibly more ...
};
// Create a new seccomp context, allowing every syscall by default.
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL)
exit(-1);
/* Now add a filter for each syscall that you want to disallow.
In this case, we'll use SCMP_ACT_KILL to kill the process if it
attempts to execute the specified syscall. */
for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
if (err)
exit(-1);
}
// Load the context making it effective.
err = seccomp_load(ctx);
if (err)
exit(-1);
}
अब, अपने कार्यक्रम में, आप fork()
इस तरह से seccomp फ़िल्टर लागू करने के लिए उपरोक्त फ़ंक्शन को कॉल कर सकते हैं :
child_pid = fork();
if (child_pid == -1)
exit(-1);
if (child_pid == 0) {
secure();
// Child code here...
exit(0);
} else {
// Parent code here...
}
Seccomp पर कुछ महत्वपूर्ण नोट्स:
- एक सेकंड फ़िल्टर, एक बार लागू होने पर, प्रक्रिया द्वारा हटाया या परिवर्तित नहीं किया जा सकता है।
- तो
fork(2)
या clone(2)
फिल्टर द्वारा अनुमति दी जाती है, किसी भी बच्चे की प्रक्रिया एक ही फिल्टर से विवश कर दिया जाएगा।
- यदि
execve(2)
अनुमति दी जाती है, तो मौजूदा फ़िल्टर को कॉल करने के लिए संरक्षित किया जाएगा execve(2)
।
- यदि
prctl(2)
syscall की अनुमति है, तो प्रक्रिया आगे फ़िल्टर लागू करने में सक्षम है।