Python Seccomp Разрешить STDIN

Я работаю над проектом, в котором буду запускать потенциально вредоносный код. Его основная организация заключается в том, что есть ведущий и подчиненный процессы. Подчиненный процесс запускает потенциально вредоносный код и включает seccomp.

import prctl

prctl.set_seccomp(True)

Вот как включается seccomp. Я могу нормально общаться ОТ ведомого к ведущему, но не наоборот. Когда я не включаю seccomp, я могу использовать:

import sys

lines = sys.stdin.read()

Или что-то вдоль этих линий. Я нашел это довольно странным, у меня должен быть доступ для чтения и записи, учитывая параметры seccomp по умолчанию, особенно для stdin/out. Я даже пытался открыть стандартный ввод до того, как включу seccomp. Например.

stdinFile = sys.stdin
prctl.set_seccomp(True)
lines = stdinFile.read()

Но все равно безрезультатно. Я также пробовал readlines(), который не работает. Друг предложил мне попробовать сокеты домена Unix, открыв его перед запуском seccomp, а затем просто используя вызов write(). Это тоже не сработало. Если у кого-то есть предложения по борьбе с этой проблемой, пишите! Я видел некоторый код на C для чего-то вроде

seccomp_add_rule(stuff)

Но мне не удалось использовать это в Python с модулем cffi.


person KosherBacon    schedule 11.08.2014    source источник
comment
Что значит безрезультатно? Вызывает ли это исключение? Вернуть EOF (пустую строку)? Повесить навсегда? Прервать вашу программу сигналом? …?   -  person abarnert    schedule 11.08.2014
comment
Кроме того, если вы просто пытаетесь сделать один большой sys.stdin.read(), почему бы просто не сделать это перед вызовом set_seccomp(True)?   -  person abarnert    schedule 11.08.2014
comment
В качестве примечания: ничто из того, что вы пытаетесь сделать, не имеет смысла. stdinFile = sys.stdin не открывает стандартный ввод, он просто делает stdinFile еще одну ссылку на тот же самый стандартный ввод, который уже открыт. Использование readlines вместо read ничему не поможет. (Кроме того, read() все это в одну гигантскую строку может ввести в заблуждение, но назовите эту строку lines.)   -  person abarnert    schedule 11.08.2014
comment
Эй, спасибо за быстрые ответы. @abarnert для вашего первого вопроса, я думаю, что процесс убит с помощью SIGKILL. Прошу прощения за некоторую путаницу с моей формулировкой. Я не могу вызвать read() перед seccomp, потому что потенциально вредоносному коду нужны результаты запроса к базе данных (предположительно), который я запускаю в главном, а затем я хочу передать результаты подчиненному процессу. Что касается вашей третьей статьи, я видел ее в Интернете, но это был всего лишь выстрел в темноту. Как и в целом, ведомый код, который на самом деле является частью исполняемого кода, требует данные от ведущего (с чем я согласен).   -  person KosherBacon    schedule 11.08.2014
comment
Зачем вам вообще нужно запускать подчиненное устройство перед чтением запроса к базе данных? Есть ли дополнительная работа, которую раб должен сделать перед этим?   -  person abarnert    schedule 11.08.2014
comment
@abarnert нет. Это может решить часть проблемы, глупый я. Но ведомое устройство по-прежнему может сделать запрос и ожидать ответа. Это было бы во время части exec(code), у которой должен быть включен seccomp. Таким образом, пользователь отправляет код, я передаю его подчиненному процессу, он запускается с включенным seccomp, но пользователь может решить в середине своего кода, что он / она хочет отправить запрос и узнать, не удалось ли это.   -  person KosherBacon    schedule 11.08.2014
comment
Я понимаю, что это обходной путь, а не фактическое решение (отчасти поэтому я опубликовал его как комментарий, а не как ответ). Но вы могли бы расширить решение, запустив новые подчиненные процессы (каждый из которых читал stdin перед set_setcomp); Я не знаю, работает ли это для вашего варианта использования или нет, но может.   -  person abarnert    schedule 11.08.2014
comment
@abarnert Я думаю, это решит мою первоначальную проблему. Любые идеи о том, как я мог бы использовать что-то подобное для передачи стандартного ввода на полпути через вычисление пользовательского кода (seccomp on)? Я действительно очень сбит с толку, потому что предполагается, что seccomp разрешает чтение(), запись(), _exit() и sigreturn(), но я вообще не могу использовать команду read().   -  person KosherBacon    schedule 11.08.2014
comment
Да я тоже не понимаю. Если вы можете читать из другого канала, просто по какой-то причине не из стандартного ввода, вы, очевидно, можете использовать это для обходного пути. Или если вы можете прочитать обычный файл, который вы открыли перед запуском seccomp. Или если вы можете получить доступ к общей памяти. Я понятия не имею, сработает ли что-нибудь из этого, но попробовать не помешает, верно? Надеюсь, у кого-то будет реальное решение, но пока это не так, лучше иметь запасной обходной путь, чем нет…   -  person abarnert    schedule 12.08.2014
comment
@abarnert большое спасибо за всю помощь, которую вы оказали. Есть одна вещь, которую я, возможно, нашел. Я копался в документации по seccomp на C и привёл хороший пример. Кажется, что перевод stdin в неблокирующий режим и чтение из него однажды что-то делает с fstat() (я понятия не имею, что он делает), но, по-видимому, это может открыть канал для использования после включения seccomp. Я посмотрю, смогу ли я реализовать это и будет ли это работать.   -  person KosherBacon    schedule 12.08.2014
comment
Это мне кое-что напоминает: если вы используете Python 2.x, sys.stdin.read может делать больше, чем просто read на системном уровне, либо на уровне Python, либо на уровне stdio; может быть, получить fd с sys.stdin.fileno(), а затем использовать os.read для этого сработает? (Если вы используете 3.x, вы можете попробовать получить sys.stdin.buffer.raw и вызвать read вместо самого stdin, но это вряд ли будет проблемой.)   -  person abarnert    schedule 12.08.2014
comment
@abarnert Мне все еще не повезло. Что действительно меня зацепило, так это то, что если я запускаю что-то вроде cat file.txt | ./script.py, мой скрипт может читать из этого stdin и печатать эти сообщения. Но это невозможно, когда я открываю его в подпроцессе. self.p = Popen([sys.executable, "script.py"], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=False) вот как я его открываю.   -  person KosherBacon    schedule 13.08.2014
comment
Я почти уверен, что cat использует обычный буферизованный stdio, точно так же, как объекты Python 2.7 file, так что это исключает множество возможностей, когда родительская сторона делает что-то неправильно при написании. Поэтому лучше всего предположить, что разница между тем, что делает subprocess, и тем, что делает оболочка. Вы можете проверить это, изменив свой скрипт Python, чтобы он просто печатал материал, а затем передал его в другой скрипт; если это все еще работает, это, вероятно, subprocess трубопровод…   -  person abarnert    schedule 13.08.2014
comment
Это напомнило мне: все версии subprocess до Python 3.2 имеют некоторые ошибки, которые могут привести к блокировке в некоторых странных обстоятельствах. Я не знаю, может ли то же самое привести к тому, что ваш ребенок нарушит правила seccomp, но… не могли бы вы попробовать установить   -  person abarnert    schedule 13.08.2014
comment
Просто напомню, что я использую Python 3.4.1.   -  person KosherBacon    schedule 13.08.2014
comment
О, это исключает множество возможных проблем. Ваш subprocess в порядке, а ваши файловые объекты вообще не используют stdio; любая буферизация в чистом Python. Что оставляет нам еще меньше возможностей. Я думаю, мы устранили невозможное, но ничего невероятного не осталось, а это значит… что я не такой умный, как Шерлок Холмс, наверное…   -  person abarnert    schedule 13.08.2014
comment
@abarnert Мне было интересно, можно ли вместо записи в стандартный ввод использовать модуль подпроцесса, а скорее в /proc/pid/fd/0 (где pid - это pid подпроцесса) или в любом другом месте файла. Мне также нужно найти номер файлового дескриптора для sys.stdin. Если бы я мог писать в этот файл с мастера, может быть, это сработало бы?   -  person KosherBacon    schedule 13.08.2014
comment
Это может сработать. Теоретически это должна быть просто символическая ссылка на тот же канал, но кто знает, влияет ли на это seccomp, по крайней мере, не читая больше? Кроме того, если вы запускаете процесс, я думаю, вы можете просто убедиться, что его stdin равен fd 0 (это означает, что не нужно делать ничего странного, чтобы сломать то, что делает subprocess), вместо того, чтобы пытаться понять это. Если нет, вы упомянули, что можете писать в другом направлении, так что ребенок всегда может начать с sys.stdout.write('{}\n'.format(sys.stdin.fileno())), я полагаю.   -  person abarnert    schedule 13.08.2014
comment
@abarnert Мне все еще было очень трудно заставить это работать. Я подтвердил, что мой fd равен 0, и пишу в правильное место. Однако я получаю проблемы с незаконным поиском. Я думаю о попытке запустить песочницу PyPy (что-то, что я пробовал ранее для другой проблемы, но не вернулся). Может быть, я смогу заставить это правильно делать stdin и stdin out...   -  person KosherBacon    schedule 15.08.2014


Ответы (1)


sys.stdin не является дескриптором файла, вам нужно открыть его и получить дескриптор файла перед вызовом set_seccomp. Вы можете использовать os.fdopen для этого. Дескриптор файла для stdin/stdout доступен как sys.stdin.fileno().

person totaam    schedule 25.08.2014