В настоящее время я работаю над проектом, в котором у меня есть родительский процесс, который устанавливает пару сокетов, разветвляется, а затем использует эту пару сокетов для связи. Дочерний, если он хочет открыть файл (или любой другой ресурс, основанный на дескрипторе файла), должен всегда идти к родителю, запрашивать ресурс и получать fd
отправленный через socketpair. Кроме того, я хочу запретить ребенку самостоятельно открывать любой дескриптор файла.
Я наткнулся на то, setrlimit
что успешно мешает дочернему элементу открывать новые файловые дескрипторы, но, похоже, также делает недействительными любые файловые дескрипторы, отправленные через исходное соединение с сокетом. Существует ли какой-либо метод в Linux, который позволяет одному процессу открывать любой файл, отправлять свой дескриптор файла другим процессам и позволяет им использовать их, не позволяя этим другим процессам самостоятельно открывать какой-либо дескриптор файла?
Для моего варианта использования это может быть любая конфигурация ядра, системный вызов и т. Д., Если это применимо после fork и при условии, что оно применяется ко всем файловым дескрипторам (не только файлам, но также сокетам, парам сокетов и т. Д.).
источник
Ответы:
Здесь у вас есть именно тот случай использования seccomp .
Используя seccomp, вы можете фильтровать системные вызовы по-разному. То , что вы хотите сделать в этой ситуации, сразу же после того
fork()
, чтобы установитьseccomp
фильтр , который запрещает использованиеopen(2)
,openat(2)
,socket(2)
(и больше). Для этого вы можете сделать следующее:seccomp_init(3)
с использованием поведения по умолчаниюSCMP_ACT_ALLOW
.seccomp_rule_add(3)
для каждого системного вызова, который вы хотите запретить. Вы можете использовать,SCMP_ACT_KILL
чтобы завершить процесс при попытке системного вызова,SCMP_ACT_ERRNO(val)
чтобы системный вызов не смог вернуть указанноеerrno
значение, или любой другойaction
значение, определенное на странице руководства.seccomp_load(3)
чтобы сделать его эффективным.Прежде чем продолжить, ОБРАТИТЕ ВНИМАНИЕ, что такой черный список, как этот, в целом слабее, чем белый. Это позволяет любой системный вызов, который явно не запрещен, и может привести к обходу фильтра . Если вы считаете, что дочерний процесс, который вы хотите выполнить, мог злонамеренно пытаться избежать фильтра, или если вы уже знаете, какие системные вызовы понадобятся детям, лучше использовать белый список, и вы должны сделать обратное: создать фильтр с действием по умолчанию
SCMP_ACT_KILL
и разрешить необходимые системные вызовы сSCMP_ACT_ALLOW
. С точки зрения кода разница минимальна (белый список, вероятно, длиннее, но шаги одинаковы).Вот пример выше (я делаю
exit(-1)
в случае ошибки просто для простоты):Теперь в вашей программе вы можете вызвать вышеуказанную функцию, чтобы применить фильтр seccomp сразу после
fork()
:Несколько важных замечаний по seccomp:
fork(2)
илиclone(2)
фильтр разрешен разрешен, любые дочерние процессы будут ограничены тем же фильтром.execve(2)
это разрешено, существующий фильтр будет сохранен при вызовеexecve(2)
.prctl(2)
системный вызов разрешен, процесс может применить дополнительные фильтры.источник
socket(2)
также может создатьfd
, так что это тоже должно быть заблокировано. Если вы знаете, что ребенок обрабатывает, лучше использовать белый список.creat()
,dup()
иdup2()
все системы Linux вызовы, возвращающие дескрипторы файлов. Есть много способов обойти черный список ...