Python Seccomp Разрешаване на STDIN

Работя върху проект, в който ще изпълнявам потенциално зловреден код. Основната организация е, че има главен и подчинен процес. Подчиненият процес изпълнява потенциално злонамерения код и има активиран seccomp.

import prctl

prctl.set_seccomp(True)

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

import sys

lines = sys.stdin.read()

Или нещо в тази насока. Намерих това за доста странно, трябва да имам достъп за четене и запис, като се имат предвид параметрите по подразбиране на seccomp, особено за stdin/out. Дори се опитах да отворя stdin, преди да включа seccomp. Например.

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

Но пак без резултат. Опитах също readlines(), който не работи. Един приятел ми предложи да опитам Unix Domain Sockets, като го отворя преди 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 не отваря stdin, той просто прави stdinFile друга препратка към същия stdin, който вече е отворен. Използването на readlines вместо read няма да помогне с нищо. (Освен това е повече от малко подвеждащо read() цялото нещо в един гигантски низ, но наречете този низ lines.)   -  person abarnert    schedule 11.08.2014
comment
Хей, благодаря за бързите отговори. @abarnert за първия ви въпрос, процесът е убит с мисля, че SIGKILL. Съжалявам за част от объркването с израза ми. Не мога да извикам read() преди seccomp, защото потенциално злонамереният код се нуждае от резултати от заявка за база данни (би трябвало), която изпълнявам в главния, след което искам да препратя резултатите към подчинения процес. За третото ти парче беше нещо, което бях виждал онлайн, но беше само изстрел в тъмното. Както и като цяло подчиненият код, който всъщност е само exec(code) парче, иска данни от главния (с което съм добре).   -  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 Мисля, че това ще реши първоначалния ми проблем. Някакви идеи за това как мога да използвам нещо подобно, за да препратя stdin по средата на изчислителния потребителски код (seccomp on)? Наистина съм доста объркан, защото seccomp трябва да позволява read(), write(), _exit() и sigreturn(), но изобщо не мога да използвам командата read().   -  person KosherBacon    schedule 11.08.2014
comment
Да, и аз не го разбирам. Ако можете да прочетете различна тръба, просто не stdin по някаква причина, очевидно можете да използвате това за заобиколно решение. Или ако можете да прочетете обикновен файл, който сте отворили преди да стартирате 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 от детето ви, но… можете ли да опитате да инсталирате subprocess32 да изключите PyPI и да го използвате вместо това, за да видите дали има значение?   -  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 Чудех се дали е възможно вместо да пиша в stdin с помощта на модула на подпроцеса, а по-скоро на /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...   -  person KosherBacon    schedule 15.08.2014


Отговори (1)


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

person totaam    schedule 25.08.2014