SECCOMP: Как эмулировать malloc, realloc и free?

Я хочу запускать произвольные (потенциально опасные) двоичные файлы на своем сервере. Поэтому я использовал objcopy, чтобы переименовать «главный» символ в «other_main», чтобы я мог связать свою небольшую основную функцию, которая устанавливает соответствующее значение для RLIMIT_CPU и переключает _ 3_ перед вызовом other_main. Пока я вполне доволен этим решением.

Теперь проблема в том, что код сторонней программы может содержать некоторые вызовы malloc, которые могут мгновенно убить программу (sbrk не разрешен). Поэтому я хотел бы предварительно выделить массив разумного размера (например, 20 МБ) перед установкой SECCOMP, который должен использоваться malloc / realloc / calloc / free. К сожалению, я не знаю, как заархивировать последний шаг. Должен ли я выполнять все эти 4 функции самостоятельно? Как я могу внедрить свои собственные функции в stdlib (например, что происходит, когда printf вызывает внутри себя malloc?).


person tux21b    schedule 13.07.2012    source источник
comment
Действительно ли работает переименование символов? Мне действительно интересно, что ОС делает с урезанными двоичными файлами.   -  person Dmitry Poroh    schedule 14.07.2012
comment
Переименование символов здесь отлично работает. objcopy кажется действительно мощным. Очевидно, вам не разрешено удалять двоичные файлы, но для меня это не проблема, потому что я компилирую двоичные файлы самостоятельно. Просто код C ненадежен.   -  person tux21b    schedule 14.07.2012
comment
Можете ли вы предоставить своим пользователям другую библиотеку C (например, Newlib), отличную от библиотеки вашей ОС? Если это так, было бы очень легко написать свой собственный sbrk (который не может выйти из вашей песочницы), а затем malloc / realloc / calloc / free и друзья будут работать.   -  person Kevin Vermeer    schedule 14.07.2012
comment
Прости. Я скучаю по тому, что вы переключаетесь и создаете новую программу.   -  person Dmitry Poroh    schedule 14.07.2012
comment
@KevinVermeer Предоставление другой исправленной библиотеки C действительно может быть вариантом, но я должен признать, что я надеялся на более простое решение, которое также могло бы работать с C ++.   -  person tux21b    schedule 14.07.2012
comment
Обратите внимание, что простого переименования main может быть недостаточно - двоичный файл может содержать инициализаторы, которые выполняются до main.   -  person    schedule 14.07.2012
comment
О, это действительно проблема. Спасибо что подметил это. Будет ли безопаснее, если я сделаю ссылку в моем собственном _start и сообщу компоновщику мою новую точку входа соответственно?   -  person tux21b    schedule 14.07.2012


Ответы (3)


Не все реализации malloc основаны на sbrk (), например, GNU mmalloc . Этот документ также может быть полезен, если требуется индивидуальная реализация.

+ две простые реализации malloc здесь

person pmod    schedule 13.07.2012
comment
Разрешены только системные вызовы: чтение, запись, возврат и выход. Таким образом, я также не могу использовать mmap, если я не выделю достаточно памяти в начале программы (статический массив разумного размера, кажется, подходит для моего варианта использования). Однако ссылка выглядит полезной, если предположить, что мне действительно нужно реализовать свой собственный malloc. Но я все еще не знаю, как мне заменить внутренние вызовы malloc, используемые в printf и других местах в stdlib. - person tux21b; 14.07.2012
comment
Я исправил ответ: dlmalloc действительно использует sbrk (). Однако там я нашел GNU mmaloc, основанный на mmap (). В вашем случае вы можете рассмотреть возможность использования статического пула [] вместо кучи + простая функциональность обработки на его основе. Например, вы можете хранить N ссылок также в статическом массиве. Конечно, это была бы псевдодинамическая память. - person pmod; 14.07.2012

Для malloc и free вашей программе просто нужно определить свои собственные версии. Большинство реализаций libc, которые я видел (включая glibc, klibc и dietlibc), с радостью будут использовать ваши процедуры распределения памяти. Итак, перед входом в режим seccomp выделите большой кусок памяти с помощью mmap или sbrk, а затем выделите malloc / free из этого фрагмента. memmgr - это простой распределитель кучи. который может быть легко адаптирован для выделения из фиксированного буфера.

Настоящая проблема seccomp состоит в том, что набор разрешенных системных вызовов (чтение, запись, выход и sigreturn) просто недостаточен для запуска программ, связанных с более или менее любой libc. Например:

  • в glibc exit и _exit вызывают exit_group
  • в glibc printf может вызывать mmap
  • в dietlibc scanf может вызывать ioctl
  • и т. д. и т. д.

Обычно существуют веские причины, по которым эти звонки необходимы. Например, dietlibc использует ioctl, чтобы проверить, является ли stdin терминалом, когда ввод читается из stdin, чтобы очистить stdout. Это стандартное поведение, обеспечивающее отображение подсказок перед чтением интерактивного ввода, если вывод буферизирован по строке.

Итак, я пришел к выводу, что исходный режим seccomp более-менее бесполезен. Однако режим 2 (также известный как «режим фильтрации») гораздо более полезен, поскольку он позволяет вам заносить в белый список определенные системные вызовы. У меня есть доказательство концепции на моей странице github, которая запускает программы в режиме seccomp 2, но позволяет им использовать printf и scanf, а также выделить память с помощью malloc / free.

person David Hovemeyer    schedule 26.07.2012

seccompsandbox:

  • включает seccomp в одном потоке, который выполняет RPC (через _1 _ / _ 2_ через предварительно выделенный socketpair) другому (не seccomp) потоку в том же процессе, который может выполнять привилегированные операции, такие как mmap
  • функции исправления, такие как malloc (в памяти, во время выполнения), для перенаправления на их безопасные для seccomp-обертки

В песочнице seccomp от Chromium есть дополнительные сведения о том, как она работает.

person ephemient    schedule 13.07.2012