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]
Примечания
[править|править код]- ↑123Imamjafar Borate, Chavan R. K., 2016.
- ↑12Kroah-Hartman, 2007.
- ↑123Kurt Dietrich, Johannes Winter, 2011.
- ↑12345678Jake Edge, Michael Kerrisk, 2015.
- ↑Jonathan Corbet.Seccomp and sandboxing// LWN.net. — 2009. — 13 мая.Архивировано12 ноября 2017 года.
- ↑Jonathan Corbet.The inherent fragility of seccomp()// LWN.net. — 2017. — 1 ноября.Архивировано9 декабря 2017 года.
- ↑123Lingguang Lei, Jianhua Sun, Kun Sun, Chris Shenefiel, Rui Ma, Yuewu Wang, Qi Li, 2017.
- ↑12Taesoo Kim, Nickolai Zeldovich, 2013.
- ↑Steven McCanne, Van Jacobson, 1993.
- ↑SECure COMPuting with filters .The Linux Kernel Archives.Linux Kernel Organization. Дата обращения: 3 марта 2018.Архивировано13 октября 2017 года.
- ↑Anto.Y, 2012.
- ↑Adrian Mouat, 2015.
- ↑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 июля.
Ссылки
[править|править код]- Michael Kerrisk.seccomp/seccomp_perf.c .Michael Kerrisk.— пример использования seccomp из The Linux Programming Interface.(англ.)
- SECure COMPuting with filters .The Linux Kernel Archives.Linux Kernel Organization. Дата обращения: 3 марта 2018.часть документации ядраLinux kernel(англ.)
- Julien Tinnes, Chris Evans.Security In-Depth for Linux Software Preventing and Mitigating Security Bugs// HITB Malaysia. — 2009. — Октябрь.(англ.)
- Jake Edge.A seccomp overview .Eklektix, Inc. (2 сентября 2015).(англ.)
- Jonathan Corbet.Seccomp and sandboxing .Eklektix, Inc. (13 мая 2009).(англ.)
Эта статья входит в числодобротных статейрусскоязычного раздела Википедии. |