Эта статья входит в число добротных статей

Seccomp

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску

seccomp(сокр. отангл.secure computing mode) — один из механизмов безопасностиядра Linux,который обеспечивает возможность ограничивать набор доступныхсистемных вызововдля приложений, а также с помощью механизма BPF (Berkeley Packet Filter) производить сложную фильтрацию вызовов и их аргументов. Впервые появился в ядре версии 2.6.12 в 2005 году[1][2].

Для работы с недоверенными или непроверенными, а поэтому потенциально опасными программами желательно использовать специально выделенные среды, из которых нельзя нанести вред работоспособности системы в целом. В таких средах (песочницах, контейнерах) для запускаемых программ лимитированы многие системные возможности, такие как доступ к сети, устройствам ввода-вывода, взаимодействие с операционной системой. Механизм seccomp определяет для процесса набор разрешённых системных вызовов и блокирует те, которые не были заранее объявлены. В настоящее время используется в рядебраузеров,Linux подобных ОС и некоторыхсистемах виртуализации.

Механизм seccomp был разработан Андреа Арканджели (итал.Andrea Arcangeli) в рамках коммерческого проекта CPUShare, основной идеей которого было определение возможностей и наработка решений по предоставлению вычислительных ресурсов компьютеров, в частности с ОС Linux, для исполнения стороннего кода. Впервые появился в ядре Linux в марте 2005 года (версия 2.6.12). В первой версии чтобы включить seccomp, процесс был должен записать «1» в файл /proc/PID/seccomp. После этого гостевому коду были доступны только четыре системных вызова:read(),write(),exit()иsigreturn()[3].В 2007 году в версии 2.6.23 была добавлена возможность включения seccomp через системный вызовprctl()с помощью операции PR_SET_SECCOMP, а интерфейс взаимодействия через /proc был исключён[4].

Несмотря на то, что проект CPUShare, для которого seccomp разрабатывался, не получил развития и закрылся, он остался в ядре Linux[3].В феврале 2009 года в коде seccomp обнаружилась уязвимость. Она была связана с тем, что в 32-разрядной и 64-разрядной версиях Linux одним и тем же номерам соответствовали разные системные вызовы. Например, разрешённому вызовуread()из 64-битной версии соответствовал запрещённый вызовrestart_syscall()из 32-битной версии. После этого встал вопрос об исключении seccomp из Linux, аЛинус Торвальдспредположил, что seccomp никем не используется[5].

Поскольку seccomp был достаточно прост для использования, у разработчиковGoogle Chromeвозникла идея реализовать на его основе средство для запуска стороннихплагинов.Однако для реализации этой задачи простого блокирования всех системных вызовов за исключением четырёх разрешённых было недостаточно. В итоге в 2012 году с seccomp был интегрирован механизм BPF (Berkeley Packet Filter) (в версии 3.5 добавлен второй режим работы — SECCOMP_MODE_FILTER), значительно расширивший возможности механизма — после нововведения гостевой процесс мог более гибко выбирать набор разрешённых и запрещённых системных вызовов, присоединяя соответствующую BPF-программу. В 2012 году появилась также библиотека libseccomp, которая предоставляет собой простой и удобныйAPIдля фильтрации системных вызовов[4].

Для упрощения использования seccomp, в 2013 году в версии 3.8 было добавлено поле «Seccomp» в /proc/PID/status, которое позволяет выяснить состояние seccomp (после того, как включение убрали из /proc, узнать, работает ли уже включённый seccomp было невозможно без завершения процесса). В 2014 году в версии 3.17 добавлен специальный системный вызов —seccomp(),который частично повторяет функциональностьprctl()[4].

В ноябре 2017 года с выходомбиблиотекиglibcверсии 2.26 появилась новая проблема: поскольку в программах наязыке Cсистемные вызовы делаются не напрямую, а через обёртки стандартной библиотеки, названия которых могут не совпадать с названиями системных вызовов, запрет какого-либо вызова может неожиданным образом повлиять на программу. Например, функцияopen()из стандартной библиотеки glibc версии 2.26 реализована через системный вызовopenat(),который не совпадает с вызовомopen()и может быть ошибочно заблокирован автором фильтра[6].

Чтобы включить в программе seccomp, можно воспользоваться системным вызовомseccomp()илиprctl().На данный момент существуют два режима работы seccomp: SECCOMP_MODE_STRICT и SECCOMP_MODE_FILTER. Узнать, включён ли seccomp и в каком режиме, можно из поля «Seccomp» в файла /proc/[pid]/status. Поле принимает значения 0, 1 или 2: 0 — seccomp для процесса не включён, 1 — seccomp в режиме SECCOMP_MODE_STRICT, 2 — в режиме SECCOMP_MODE_FILTER[4].Включить seccomp для других процессов нельзя[7].

Режим SECCOMP_MODE_STRICT

[править|править код]

Был единственным режимом работы до Linux 3.5. Чтобы его можно было использовать, ядро должно быть сконфигурировано с ключом CONFIG_SECCOMP=y[2].

Чтобы войти в этот режим, необходимо сделать вызовprctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT)или, что то же самое,seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL).Теперь процесс может использовать только четыре системных вызова:read(),write(),_exit()иsigreturn()[3].Результатом использования других системных вызовов будет прерывание процесса сигналом SIGKILL. Поскольку системный вызовopen()запрещён, если потребуется проверка включения seccomp, файл status из procfs необходимо открыть с правами на чтение до включения seccomp в процессе[4].

Режим SECCOMP_MODE_FILTER

[править|править код]

Режим работы, который появился в ядре Linux версии 3.5[8].Доступен, если при сборке ядра был установлен флаг CONFIG_SECCOMP_FILTER=y.

Перед тем, как переходить в этот режим, нужно выполнить вызовprctl(PR_SET_NO_NEW_PRIVS, 1)и, таким образом, установить для процесса бит no_new_privs. Это обязательное требование объясняется тем, что иначе непривилегированный процесс может выполнить привилегированную программу с помощьюexecve().Если этого не сделать, то переход в режим SECCOMP_MODE_FILTER не удастся[4].

После установки бита no_new_privs чтобы присоединить к процессу фильтр нужно выполнить вызовprctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, args)илиseccomp(SECCOMP_SET_MODE_FILTER, 0, args),где args — указатель на структуруsock_fprog,которая из состоит массива BPF-инструкций и его длины. Фильтр запускается каждый раз, когда процесс совершает системный вызов. При запуске фильтр получает на вход структуру с данными о номере системного вызова, архитектуре, текущем состояниисчётчика команди аргументах вызова[7][8].Фильтр обязательно должен возвратить 32-битное значение, в котором верхние 16 бит содержат код действия, которое будет произведено, а нижние 16 бит содержат данные. Если в алгоритме фильтра по ошибке не предусмотрен возврат значения, то он не пройдет статический анализ и такой фильтр присоединён не будет[9].

Если к процессу присоединено несколько фильтров, из них будет сформирован односвязный список и они будут запущены в порядке, обратном порядку их добавления, даже если один из фильтров должен убить процесс[7].В таком случае, возвращаемое значение системного вызова будет определяться первым (по порядку запуска фильтров) возвращаемым значением с наивысшим приоритетом, в соответствии с таблицей (в порядке уменьшения приоритета)[10]:

Действие Результат
SECCOMP_RET_KILL Системный вызов не выполняется, процесс будет убит с помощью сигнала SIGSYS[4]
SECCOMP_RET_TRAP Системный вызов не выполняется, процесс получает сигнал SIGSYS, обработчику сигнала доступна информация о системном вызове, который привёл к этому результату
SECCOMP_RET_ERRNO Системный вызов не выполняется, в переменнойerrnoнаходится возвращаемое значение фильтра
SECCOMP_RET_TRACE Если с помощьюptrace()для процесса указан трассировщик, то он будет уве́домлен о вызове. Если не указан, то системный вызов не выполняется
SECCOMP_RET_ALLOW Системный вызов выполняется

Примеры использования

[править|править код]

Включение режима SECCOMP_MODE_STRICT[4]

#include<stdio.h>
#include<unistd.h>
#include<linux/seccomp.h>
#include<sys/prctl.h>
#include<fcntl.h>

intmain(){
intfd;

prctl(PR_SET_SECCOMP,SECCOMP_MODE_STRICT);

fprintf(stderr,"try open\n");
fd=open("test_file",O_CREAT);
fprintf(stderr,"fd = %d",fd);

return0;
}

Результат работы:

$gcctest_seccomp.c-otest_seccomp
$./test_seccomp
tryopen
Killed

В приведённом примере после вызоваprctl()процесс работает ровно до момента, когда попытается сделать вызовopen().

Примеры использования в ПО

[править|править код]
  • Операционная системаChrome OS[11]
  • Операционная системаAndroid Oreo
  • БраузерFirefox
  • FTP-серверvsftpd[1]
  • Flatpak — инструмент для распространения и установки приложений внутри контейнеров
  • Система виртуализацииDocker[12]
  • Браузер с открытым исходным кодомChromium[1]
  • Система контейнерной виртуализацииLXC[13]
  1. 123Imamjafar Borate, Chavan R. K., 2016.
  2. 12Kroah-Hartman, 2007.
  3. 123Kurt Dietrich, Johannes Winter, 2011.
  4. 12345678Jake Edge, Michael Kerrisk, 2015.
  5. Jonathan Corbet.Seccomp and sandboxing// LWN.net. — 2009. — 13 мая.Архивировано12 ноября 2017 года.
  6. Jonathan Corbet.The inherent fragility of seccomp()// LWN.net. — 2017. — 1 ноября.Архивировано9 декабря 2017 года.
  7. 123Lingguang Lei, Jianhua Sun, Kun Sun, Chris Shenefiel, Rui Ma, Yuewu Wang, Qi Li, 2017.
  8. 12Taesoo Kim, Nickolai Zeldovich, 2013.
  9. Steven McCanne, Van Jacobson, 1993.
  10. SECure COMPuting with filters.The Linux Kernel Archives.Linux Kernel Organization. Дата обращения: 3 марта 2018.Архивировано13 октября 2017 года.
  11. Anto.Y, 2012.
  12. Adrian Mouat, 2015.
  13. Senthil Kumaran S., 2017.
  • Steven McCanne, Van Jacobson.The BSD Packet Filter: A New Architecture for User-level Packet Capture// 1993 Winter USENIX. — San Diego, CA, 1993. — 2 января.
  • Greg Kroah-Hartman.Linux Kernel in a Nutshell.— 1005 Gravenstein Highway North, Sebastopol, CA 95472: O'Reilly Media, 2007. — 208 с. —ISBN 978-0596100797.
  • Michael Kerrisk.The Linux Programming Interface.— San Francisco: No Starch Press, 2010. — 1556 с. —ISBN 978-1-59327-220-3.
  • Jake Edge, Michael Kerrisk.A seccomp overview// LWN.net: Linux Plumbers Conference. — Seattle, Washington, USA, 2015. — 1 сентября.
  • Taesoo Kim, Nickolai Zeldovich.Practical and effective sandboxing for non-root users// 2013 USENIX Annual Technical Conference. — 2013.
  • Ma Bo, Mu Dejun, Fan Wei, Hu Wei.Improvements the Seccomp sandbox based on PBE theory(англ.)// IEEE. — 2013. — 01 Июль. —doi:10.1109/WAINA.2013.81.
  • Imamjafar Borate, Chavan R. K.Sandboxing in Linux: From Smartphone to Cloud(англ.)// International Journal of Computer Applications. — 2016. — Август (т. 148,№ 8).
  • Senthil Kumaran S.Practical LXC and LXD: Linux Containers for Virtualization and Orchestration. — Apress, 2017. — С. 147. — 159 с. —ISBN 978-1-4842-3024-4.
  • Adrian Mouat.Using Docker: Developing and Deploying Software with Containers.— 1005 Gravenstein Highway North, Sebastopol, CA 95472: O'Reilly Media, 2015. — С. 320. — 354 с.
  • Kurt Dietrich, Johannes Winter.Towards a Trustworthy, Lightweight Cloud Computing Framework for Embedded Systems// Trust and Trustworthy Computing: 4th International Conference. — Pittsburgh, PA, USA: Springer, 2011. — Июнь.
  • Anto.Y.Chrome OS and Secret of Google. — Lambert Academic Publishing, 2012. — С. 41. — 228 с. —ISBN 978-3-659-17127-7.
  • Lingguang Lei, Jianhua Sun, Kun Sun, Chris Shenefiel, Rui Ma, Yuewu Wang, Qi Li.SPEAKER: Split-Phase Execution of Application Containers// Detection of Intrusions and Malware, and Vulnerability Assessment: 14th International Conference, DIMVA 2017. — Bonn, Germany: Springer, 2017. — 1 июля.