
Secure code execution
CodeJail управляет выполнением недоверенного кода в безопасных песочницах. Он предназначен в первую очередь для выполнения Python, но может использоваться и для других языков.
Безопасность обеспечивается с помощью AppArmor. Если ваша операционная система не поддерживает AppArmor или профиль AppArmor не определён и не настроен правильно, то CodeJail не обеспечит защиту выполнения.
CodeJail спроектирован как настраиваемый и автоматически сконфигурирует себя для выполнения Python, если вы установите его правильно.
Песочница CodeJail состоит из нескольких частей:
#) Среда песочницы. В случае Python это будет Python и связанные основные пакеты в виде virtualenv. Далее в этом документе она обозначается как . Эта среда доступна только для чтения и используется совместно всеми экземплярами песочниц.
Код в песочнице также имеет доступ к системным библиотекам в той степени, в которой это разрешает профиль AppArmor.
#) Рабочий каталог песочницы. Это эфемерный каталог, доступный только для чтения,
с именем вида /tmp/codejail-XXXXXXXX, содержащий представленный код
(./jailed_code), необязательные дополнительные файлы и доступный для записи
временный каталог (./tmp), который представленный код может использовать как
рабочую область.
Представленный код — это, как правило, код, отправленный студентом для проверки
на сервере, а дополнительные файлы — обычно python_lib.zip, содержащий
библиотеки для оценивания или служебные библиотеки.
Для работы CodeJail требуются две учётные записи. Одна учётная запись — основная,
под которой выполняется код и которая имеет доступ к созданию песочниц. Далее она
будет называться <SANDBOX_CALLER>. Вторая учётная запись — это учётная запись,
под которой работает песочница. Обычно это учётная запись sandbox.
В настоящее время библиотека протестирована на работу со следующими версиями
Python:
Ubuntu:
(Обратите внимание, что версия Python, используемая внутри песочницы, может отличаться от версии, используемой для самой библиотеки.)
Эти инструкции описывают, как настроить вашу операционную систему, чтобы
CodeJail мог безопасно выполнять код Python. Однако также можно установить
codejail.safe_exec.ALWAYS_BE_UNSAFE = True и выполнять представленный Python
напрямую на машине, без какой-либо безопасности. Это может быть приемлемо для
машин разработчиков, которых не беспокоит безопасность, и позволяет тестировать
интеграцию с API CodeJail. Однако его нельзя использовать, если любые входные
данные поступают из недоверенных источников. Не используйте этот вариант в
производственных системах.
Чтобы обеспечить безопасное выполнение Python, вам потребуется создать новый virtualenv. Это означает, что у вас будет два: основной virtualenv для вашего проекта и новый — для Python-кода в песочнице.
Выберите место для нового virtualenv и назовите его . Он будет
автоматически обнаружен и использован, если вы разместите его рядом с
существующим virtualenv, но с добавленным -sandbox. Так, если ваш
существующий virtualenv находится в /home/chris/ve/myproj, сделайте
равным /home/chris/ve/myproj-sandbox.
Пользователь, запускающий LMS, — это <SANDBOX_CALLER>, например, вы на своей
машине для разработки или www-data на сервере.
Прочие детали, зависящие от вашей конфигурации:
Создайте новый virtualenv, используя --copies, чтобы получить отдельный
исполняемый файл Python для ограничения::
$ sudo python3.12 -m venv --copies
По умолчанию virtualenv просто создаёт симлинк на системный Python, и конфигурация AppArmor по умолчанию в некоторых операционных системах может помешать применению ограничений к этому Python.
(Необязательно) Если у вас есть особые пакеты, которые должны быть доступны вашему коду в песочнице, установите их, активировав виртуальное окружение песочницы и используя pip для их установки::
$ /bin/pip install -r requirements/sandbox.txt
Добавьте пользователя песочницы::
$ sudo addgroup sandbox $ sudo adduser --disabled-login sandbox --ingroup sandbox
Разрешите веб-серверу запускать Python в песочнице от имени пользователя
sandbox. Создайте файл /etc/sudoers.d/01-sandbox::
$ sudo visudo -f /etc/sudoers.d/01-sandbox
<SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/bin/python <SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find <SANDBOX_CALLER> ALL=(ALL) NOPASSWD:/usr/bin/pkill
(Обратите внимание, что бинарный файл find может выполнять произвольный
код, поэтому это небезопасный файл sudoers для целей, не связанных с CodeJail.)
Отредактируйте профиль AppArmor. Это текстовый файл, задающий ограничения для
исполняемого файла Python в песочнице. Файл должен находиться в
/etc/apparmor.d и должен быть назван по имени исполняемого файла, где
слэши заменены точками. Например, если ваш Python в песочнице находится в
/home/chris/ve/myproj-sandbox/bin/python, то ваш профиль AppArmor должен
быть /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python.
Если ваш CodeJail правильно настроен для использования safe_exec, попробуйте выполнить эти команды в терминале Python::
import codejail.jail_code
codejail.jail_code.configure('python', '<SANDENV>/bin/python', user='sandbox')
import codejail.safe_exec
jailed_globals = {}
codejail.safe_exec.safe_exec("output=open('/etc/passwd').read()", jailed_globals)
print(jailed_globals) # should be unreachable if codejail is working properly
Это должно завершиться ошибкой с исключением.
Если вам нужно изменить пакеты, установленные в virtualenv вашей песочницы, вам потребуется отключить AppArmor, поскольку ваш Python в песочнице не имеет прав на изменение файлов в своём каталоге site-packages.
Отключите AppArmor для вашей песочницы::
$ sudo apt-get install apparmor-utils # if you haven't already $ sudo aa-complain /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Установите или иным образом измените установленные пакеты::
$ pip install -r requirements/sandbox.txt
Повторно включите AppArmor для вашей песочницы::
$ sudo aa-enforce /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Для запуска тестов необходимо выполнить стандартные шаги установки. Затем необходимо задать следующие переменные окружения::
$ export CODEJAIL_TEST_USER=<owner of sandbox (usually 'sandbox')>
$ export CODEJAIL_TEST_VENV=<SANDENV>
Запустите тесты с помощью Makefile::
$ make tests
Некоторые прокси-тесты пропускаются, если не настроен прокси-режим.
CodeJail достаточно универсален, чтобы его можно было использовать в различных проектах для выполнения недоверенного кода. Он предоставляет два уровня:
jail_code.py обеспечивает безопасное выполнение подпроцессов. Это
достигается запуском программы в подпроцессе, управляемом AppArmor.
safe_exec.py обеспечивает специализированную обработку выполнения Python,
используя jail_code для предоставления семантики оператора exec в Python.
CodeJail запускает программы под управлением AppArmor. AppArmor — это предоставляемая операционной системой функция для ограничения ресурсов, к которым программы могут получить доступ. Чтобы запускать код Python с ограниченным доступом к ресурсам, мы создаём новый virtualenv, затем указываем этот исполняемый файл Python в профиле AppArmor и ограничиваем ресурсы в этом профиле. CodeJail выполнит предоставленную программу Python с помощью этого исполняемого файла, а AppArmor автоматически ограничит ресурсы, к которым она может получить доступ. CodeJail также использует setrlimit для ограничения объёма процессорного времени и/или памяти, доступных процессу.
codejail.jail_code принимает программу для запуска, файлы для копирования в
её окружение, аргументы командной строки и поток stdin. Он создаёт временный
каталог, создаёт или копирует необходимые файлы, запускает подпроцесс для
выполнения кода и возвращает вывод и код завершения процесса.
codejail.safe_exec эмулирует оператор exec в Python. Он принимает фрагмент
кода Python и выполняет его с помощью jail_code, изменяя словарь globals в
качестве побочного эффекта. safe_exec делает это, сериализуя globals в JSON при
передаче в подпроцесс и обратно.
Если codejail или AppArmor настроены неправильно, codejail может по умолчанию выполнять код небезопасно (без песочницы). Он не является безопасным по умолчанию. Проектам, интегрирующим codejail, следует рассмотреть возможность включения набора тестов времени выполнения, который проверяет правильность изоляции при запуске, прежде чем принимать недоверенные входные данные.
Изоляция песочницы достигается за счёт ограничений AppArmor. Codejail способствует этому, но не может изолировать выполнение без использования AppArmor.
Ограничения ресурсов могут быть установлены только с помощью механизмов, предоставляемых rlimit в Linux. Некоторые существенные недостатки:
Хотя FSIZE из rlimit может ограничить размер любого отдельного файла,
который может создать процесс, и может ограничить количество открытых им
файлов в любой момент времени, он не может ограничить общее количество
записанных файлов и, следовательно, не может ограничить общее количество
байт, записанных во все файлы. Частичным смягчением является ограничение
максимального времени выполнения. (Все файлы, записанные в песочнице, в любом
случае будут удалены по завершении выполнения.)
Ограничение NPROC ограничивает возможность текущего процесса создавать
новые потоки и процессы, но счётчик использования (сколько процессов уже
существует) равен сумме по всем процессам с тем же UID, даже в других
контейнерах на том же хосте, где этот UID может быть сопоставлен с другим
именем пользователя. Это ограничение также распространяется на пользователя
приложения из-за того, как применяются rlimits. Даже если UID выбраны так,
чтобы они не использовались другим программным обеспечением на хосте,
несколько процессов песочниц codejail на одном хосте будут совместно
использовать этот пул использования и могут снижать способность друг друга
создавать процессы. В такой ситуации NPROC необходимо будет установить
выше, чем для одного экземпляра codejail, обрабатывающего один запрос за раз.
Песочницы не имеют сильной изоляции друг от друга. При правильной настройке недоверенный код не должен иметь возможности обнаружить другие активные выполнения кода, но если это предположение нарушается, одна песочница теоретически может помешать другой.
Пожалуйста, не сообщайте о проблемах безопасности публично. Пожалуйста, отправьте электронное письмо на [email protected].
Пример профиля см. в apparmor-profiles/. Профиль необходимо настроить
в соответствии с расположением вашей песочницы.
Загрузите профили::
$ sudo apparmor_parser --replace --warn=all --warn=no-debug-cache --Werror <APPARMOR_FILE>
Снова активируйте основной virtualenv вашего проекта.
Отключите использование PAM для установки rlimits::
sed -i '/pam_limits.so/d' /etc/pam.d/sudo