Product SiteDocumentation Site

14.5. Введение в SELinux

14.5.1. Принципы

SELinux (Security Enhanced Linux) - это система Mandatory Access Control, построенная на LSM (Linux Security Modules). На практике ядро запрашивает SELinux перед каждой системой, чтобы узнать, уполномочен ли этот процесс делать данную операцию.
SELinux использует набор правил — коллективно известный как политика —, чтобы санкционировать или запретить операции. Эти правила трудно создать. К счастью, две стандартные политики (targeted и strict) предусмотрены, чтобы избежать основной части работы при конфигурировании.
С SELinux управление правами полностью отличается от традиционных систем Unix. Права процесса зависят от его контекста безопасности . Контекст определяется идентификацией пользователя, который начал процесс, role и домен, который пользователь носил в то время. Права действительно зависят от домена, но переходы между доменами контролируются ролями. Наконец, возможные переходы между ролями зависят от идентичности.
Контексты безопасности и пользователи Unix

Рисунок 14.1. Контексты безопасности и пользователи Unix

На практике во время входа пользователю присваивается контекст безопасности по умолчанию (в зависимости от ролей, которые они должны быть в состоянии одобрить). Это определяет текущую область и, следовательно, область, которую будут нести всё новые детские процессы. Если вы хотите изменить текущую роль и связанный с ней домен, вы должны позвонить newrole -r role_r -t domain_t (обычно существует только один домен, разрешенный для данной роли, параметр -t, таким образом, часто может быть исключен). Эта команда аутентифицирует вас, попросив ввести ваш пароль. Эта функция запрещает программам автоматически переключать роли. Такие изменения могут произойти только в том случае, если они прямо разрешены в политике SELinux.
Очевидно, что права не распространяются на все объекты (файлы, каталоги, сокеты, устройства и т.д.). Они могут варьироваться от объекта к объекту. Для достижения этого каждый объект связан с типом (это известно как маркировка). Таким образом, права доменов выражены наборами (не) разрешенных операций на этих типах (и, косвенно, на всех объектах, которые маркируются данным типом).
По умолчанию программа наследует свой домен от пользователя, который её запустил, но стандартные политики SELinux ожидают, что многие важные программы будут работать в выделенных доменах. Для достижения этой цели эти исполняемые материалы маркируются выделенным типом (например, ssh маркируется ssh_exec_t, и при запуске программы он автоматически переключается на ssh_t. Этот автоматический механизм перехода домена позволяет предоставлять только права, требуемые каждой программой. Это фундаментальный принцип SELinux.
Автоматические переходы между доменами

Рисунок 14.2. Автоматические переходы между доменами

14.5.2. Настройка SELinux

Поддержка SELinux встроена в стандартные ядра, предоставляемые Debian. Основные инструменты Unix поддерживают SELinux без каких-либо изменений. Таким образом включить SELinux относительно легко.
apt install selinux-basics selinux-policy-default auditd автоматически установит пакеты, необходимые для настройки системы SELinux.
Пакет selinux-policy-default содержит набор стандартных правил. По умолчанию эта политика ограничивает доступ только для нескольких широко раскрытых сервисов. Сессии пользователей не ограничены, и поэтому маловероятно, что SELinux блокирует законные пользовательские операции. Однако это повышает безопасность системных сервисов, работающих на машине. Чтобы настроить политику, эквивалентную старым правилам “strict”, вам просто нужно отключить unconfined модуль (управление модулями подробно описано далее в этом разделе).
Как только политика была установлена, вы должны маркировать все доступные файлы (что означает назначение им типа). Эта операция должна быть запущена вручную fixfiles relabel.
Система SELinux уже готова. Чтобы включить её, необходимо добавить параметр selinux=1 security=selinux в ядро Linux. Параметр audit=1 позволяет SELinux регистрировать все запрещаемые операции. Наконец, параметр enforcing=1 приводит правила в действие: без него SELinux работает в режиме по умолчанию permissive, в котором запрещаемые действия регистрируются, но всё же выполняются. Таким образом, вы должны изменить файл конфигурации загрузки GRUB для добавления желаемых параметров. Один из простых способов сделать это - изменить GRUB_CMDLINE_LINUX переменную в /etc/default/grub и запустить update-grub. SELinux будет активен после перезагрузки.
Стоит отметить, что сценарий selinux-activate автоматизирует эти операции и заставляет маркировку на следующем загрузке (который избегает новых немаркированных файлов, созданных в то время когда SELinux ещё не был активизирован, но маркировка ещё продолжалась).

14.5.3. Управление системой SELinux

Политика SELinux - это модульный набор правил, и его установка позволяет автоматически обнаруживать все соответствующие модули на основе уже установленных сервисов. Таким образом, система незамедлительно функционирует. Однако, когда сервис установлен после политики SELinux, вы должны иметь возможность вручную включить соответствующий модуль. Это цель команды semodule. Кроме того, вы должны быть в состоянии определить роли, которые каждый пользователь может одобрить, и это может быть сделано командой semanage.
Таким образом, эти две команды могут быть использованы для изменения текущей конфигурации SELinux, которая хранится в /etc/selinux/default/. В отличие от других файлов конфигурации, которые вы можете найти в /etc/, все эти файлы не должны быть изменены вручную. Вы должны использовать программы, предназначенные для этой цели.

14.5.3.1. Управление модулями SELinux

Доступные модули SELinux хранятся в каталоге /usr/share/selinux/default/. Чтобы включить один из этих модулей в текущую конфигурацию, следует использовать semodule -i module.pp.bz2. Расширение pp.bz2 означает policy package (сжатый bzip2).
Удаление модуля из текущей конфигурации осуществляется командой semodule -r module. Наконец, команда semodule -l перечисляет модули, которые в настоящее время установлены. Она также выводит их номера версий. Модули могут быть выборочно включены с semodule -e и отключены командой semodule -d.
# semodule -i /usr/share/selinux/default/abrt.pp.bz2
libsemanage.semanage_direct_install_info: abrt module will be disabled after install as there is a disabled instance of this module present in the system.
# semodule -l
accountsd
acct
[...]
# semodule -e abrt
# semodule -d accountsd
# semodule -l
abrt
acct
[...]
# semodule -r abrt
libsemanage.semanage_direct_remove_key: abrt module at priority 100 is now active.
semodule сразу загружает новую конфигурацию, если вы не используете её -n. Стоит отметить, что программа действует по умолчанию в текущей конфигурации (на которую указывает переменная SELINUXTYPE в /etc/selinux/config), но вы можете изменить другую, указав её опцией -s.

14.5.3.2. Управление идентификаторами

Каждый раз, когда пользователь входит в систему, ему присваивается SELinux идентификатор. Этот идентификатор определяет роли, которые они смогут одобрить. Эти два соответствия (от пользователя к идентификатору и от этого идентификатора к ролям) настраиваются командой semanage.
Вы обязательно должны прочитать страницу руководства semanage (8). Все управляемые концепции имеют свою собственную страницу руководства; например, semanage-login(8). Даже если синтаксис команды имеет тенденцию быть похожим для всех концепций, которые управляются, рекомендуется прочитать его страницу руководства. Вы найдете общие варианты для большинства подкоманд: -a add - добавить, -d delete - удалить, -m modify - изменить, -l list - список, и -t type - тип, чтобы указать тип (или домен).
semanage login -l перечисляет текущее отображение между идентификаторами пользователя и идентификаторами SELinux. Пользователи, которые не имеют явной записи, получают идентификатор, указанный в записи __default__. Команда semanage login -a -s user_u user свяжет user_u идентификатор с данным пользователем. Наконец, semanage login -d user сбросит запись сопоставления, назначенную этому пользователю.
# semanage login -a -s user_u rhertzog
# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
rhertzog             user_u               s0                   *
root                 unconfined_u         s0-s0:c0.c1023       *
# semanage login -d rhertzog
semanage user -l перечисляет сопоставление между пользовательскими идентификаторами SELinux и допустимыми ролями. Чтобы добавить новый идентификатор требуется определить как соответствующие роли, так и префикс маркировки, который используется для присвоения типа личным файлам (/home/user/*). Префикс должен быть выбран среди user, staff и sysadm. Префикс “staff” приводит в файлы типа “staff_home_dir_t”. Создание нового пользовательского идентификатора SELinux осуществляется с semanage user -a -Rroles -P prefix identity . Наконец, вы можете удалить пользовательский идентификатор SELinux командой semanage user -d identity.
# semanage user -a -R 'staff_r user_r' -P staff test_u
# semanage user -l

                Labeling   MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles

root            sysadm     s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r
staff_u         staff      s0         s0-s0:c0.c1023                 staff_r sysadm_r
sysadm_u        sysadm     s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r
test_u          staff      s0         s0                             staff_r user_r
unconfined_u    unconfined s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
# semanage user -d test_u

14.5.3.3. Управление контекстами файлов, портами и булевыми опциями

Каждый модуль SELinux предоставляет набор правил маркировки файлов, но также можно добавлять пользовательские правила маркировки, чтобы удовлетворить конкретный случай. Например, если вы хотите, чтобы веб-сервер мог читать файлы в иерархии файлов /srv/www/, вы могли бы выполнить semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?", за которым следует restorecon -R/srv/www/. Прежняя команда регистрирует новые правила маркировки, а последняя восстанавливает типы файлов в соответствии с действующими правилами маркировки.
Аналогичным образом, порты TCP/UDP маркируются таким образом, чтобы их могли слушать только соответствующие демоны. Например, если вы хотите, чтобы веб-сервер мог слушать на порту 8080, вы должны запустить semanage port -m -t http_port_t -p tcp 8080.
Некоторые модули SELinux экспортируют опции Boolean, которые вы можете настроить, чтобы изменить поведение правил по умолчанию. getsebool утилита может быть использована для проверки этих опций (getsebool boolean отображает один вариант, и getsebool -a отображает все. setsebool boolean value изменяет текущее значение опции Boolean. -P делает изменение постоянным, это означает, что новое значение становится по умолчанию и будет храниться между перезагрузками. Нижеприведенный пример предоставляет веб-серверам доступ к домашним каталогам (это полезно, когда пользователи имеют личные веб-сайты в ~/public_html/.
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs on
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

14.5.4. Адаптирование правил

Поскольку политика SELinux является модульной, может быть интересно разработать новые модули для (возможно, пользовательских) приложений, которые не имеют их. Эти новые модули затем завершат reference policy.
Для создания новых модулей требуется пакет selinux-policy-dev, а также selinux-policy-doc. Последний содержит документацию стандартных правил (/usr/share/doc/selinux-policy-doc/html/) и выборочных файлов, которые могут быть использованы в качестве шаблонов для создания новых модулей. Установите эти файлы и более внимательно изучите их:
$ cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$ cp /usr/share/doc/selinux-policy-doc/example.fc ./
$ cp /usr/share/doc/selinux-policy-doc/example.if ./
$ cp /usr/share/doc/selinux-policy-doc/example.te ./
.te является самым важным. Он определяет правила. .fc файл определяет “file contexts”, то есть типы, назначенные для файлов, относящихся к этому модулю. Данные в файле .fc используются во время этапа маркировки файла. Наконец, файл .if определяет интерфейс модуля: это набор “public functions”, которые другие модули могут использовать для правильного взаимодействия с модулем, который вы создаёте.

14.5.4.1. Написание .fc файла

Чтение приведенного ниже примера должно быть достаточным для понимания структуры такого файла. Вы можете использовать регулярные выражения для присвоения одного и того же контекста безопасности нескольким файлам или даже всему дереву каталога.

Пример 14.2. example.fc файл

# myapp executable will have:
# label: system_u:object_r:myapp_exec_t
# MLS sensitivity: s0
# MCS categories: <none>

/usr/sbin/myapp         --      gen_context(system_u:object_r:myapp_exec_t,s0)

14.5.4.2. Написание файла .if

В образце ниже первый интерфейс (“myapp_domtrans”) контролирует, кто может выполнить приложение. Второй (“myapp_read_log”) предоставляет права чтения в файлах журнала приложения.
Каждый интерфейс должен генерировать действительный набор правил, которые могут быть встроены в файл .te. Таким образом, вы должны объявить все типы, которые вы используете (с макросом gen_require ), и использовать стандартные директивы для предоставления прав. Обратите внимание, что вы можете использовать интерфейсы, предоставляемые другими модулями. Следующий раздел даст больше объяснений о том, как выразить эти права.

Пример 14.3. example.if File

## <summary>Myapp example policy</summary>
## <desc>
##      <p>
##              More descriptive text about myapp.  The desc
##              tag can also use p, ul, and ol
##              html tags for formatting.
##      </p>
##      <p>
##              This policy supports the following myapp features:
##              <ul>
##              <li>Feature A</li>
##              <li>Feature B</li>
##              <li>Feature C</li>
##              </ul>
##      </p>
## </desc>
#

########################################
## <summary>
##      Execute a domain transition to run myapp.
## </summary>
## <param name="domain">
##      <summary>
##      Domain allowed to transition.
##      </summary>
## </param>
#
interface(`myapp_domtrans',`
        gen_require(`
                type myapp_t, myapp_exec_t;
        ')

        domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
## <summary>
##      Read myapp log files.
## </summary>
## <param name="domain">
##      <summary>
##      Domain allowed to read the log files.
##      </summary>
## </param>
#
interface(`myapp_read_log',`
        gen_require(`
                type myapp_log_t;
        ')

        logging_search_logs($1)
        allow $1 myapp_log_t:file read_file_perms;
')

14.5.4.3. Напишите .te файл

Взгляните на файл example.te:
policy_module(example,1.0.0) 1 # a non-base module name must match the file name

########################################
#
# Declarations
#

type myapp_t; 2
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t) 3

type myapp_log_t;
logging_log_file(myapp_log_t) 4

type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
# Myapp local policy
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; 5

allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)

1

Модуль должен быть идентифицирован по его названию и номеру версии. Эта директива необходима.

2

Если модуль вводит новые типы, он должен объявлять их такими директивами, как эта. Не стесняйтесь создавать столько типов, сколько требуется, а не предоставлять слишком много бесполезных прав.

3

Эти интерфейсы определяют тип myapp_t как технологический домен, который должен использоваться любым исполняемым маркированным myapp_exec_t. Подразумевается, что это добавляет атрибут exec_type на эти объекты, что, в свою очередь, позволяет другим модулям предоставлять права на выполнение этих программ: например, userdomain модуль user_t, staff_t, и sysadm_t для их выполнения. Домены других ограниченных приложений не будут иметь права на их выполнение, если только правила не предоставляют им аналогичные права (это случай, например, dpkg с его доменом dpkg_t.

4

logging_log_file - это интерфейс, предоставляемый ссылочной политикой. Это указывает на то, что файлы, отмеченные данным типом, являются лог-файлами, которые должны извлечь выгоду из связанных правил (например, предоставление прав на logrotate, чтобы мочь ими манипулировать).

5

Директива allow является базовой директивой, используемой для разрешения операции. Первым параметром является домен процесса, который позволяет выполнять операцию. Второй определяет объект, которым может манипулировать процесс прежнего домена. Этот параметр имеет форму “type:class“, где type является его типом SELinux и class описывает природу объекта (файл, каталог, сокет, fifo и т.д.). Наконец, последний параметр описывает разрешения (разрешённые операции).
Разрешения определяются как набор разрешенных операций и следуют этому шаблону: { operation1 operation2 }. Тем не менее, вы также можете использовать макросы, представляющие самые полезные разрешения. /usr/share/selinux/devel/include/support/obj_perm_sets.spt перечисляет их.
Следующая веб-страница предоставляет относительно исчерпывающий список классов объектов и разрешений, которые могут быть предоставлены.
Теперь вам просто нужно найти минимальный набор правил, необходимых для обеспечения того, чтобы целевое приложение или сервис работали должным образом. Чтобы достичь этого, вы должны иметь хорошее знание о том, как работает приложение и какими данными оно управляет и / или генерирует.
Однако эмпирический подход возможен. Как только соответствующие объекты будут правильно маркированы, вы можете использовать приложение в разрешительном режиме: операции, которые будут запрещены, записываются, но все же успешны. Анализируя журналы, вы можете теперь идентифицировать операции, чтобы позволить. Вот пример такой записи журнала:
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
Чтобы лучше понять это сообщение, давайте изучим его часть за частью.

Таблица 14.1. Анализ трассировки SELinux

СообщениеОписание
avc: deniedОперация была отклонена.
{ read write }Эта операция требовала read и write разрешения.
pid=1876Процесс с PID 1876 выполнил операцию (или попытался её выполнить).
comm="syslogd"Процесс был экземпляром программы syslogd.
name="xconsole" Целевой объект был назван xconsole. Иногда вы также можете иметь переменную “path” с полным путём вместо этого.
dev=tmpfsУстройство, в котором размещён целевой объект, это tmpfs (файловая система в памяти). На реальном диске можно увидеть раздел, хостящий объект (например, “sda3”).
ino=5510Объект идентифицируется номером inode 5510.
scontext=system_u:system_r:syslogd_t:s0Это контекст безопасности процесса, который выполнил операцию.
tcontext=system_u:object_r:device_t:s0Это контекст безопасности целевого объекта.
tclass=fifo_fileЦелевой объект - это файл FIFO.
Наблюдая за этой записью журнала, можно построить правило, которое позволило бы эту операцию. Например, allow syslogd_t device_t:fifo_file { read write }. Этот процесс может быть автоматизирован, и это именно то, что предлагает команда audit2allow в пакете (policycoreutils). Этот подход полезен только в том случае, если различные объекты уже правильно обозначены в соответствии с тем, что должно быть ограничено. В любом случае, вам придется тщательно пересмотреть сгенерированные правила и проверить их в соответствии с вашими знаниями о приложении. Фактически, такой подход имеет тенденцию предоставлять больше прав, чем это действительно необходимо. Надлежащее решение часто заключается в создании новых типов и предоставлении прав только на эти типы. Также случается, что отказ в операции не является фатальным для приложения, в этом случае может быть лучше просто добавить правило “dontaudit”, чтобы избежать записи в журнал, несмотря на эффективный отказ.

14.5.4.4. Компиляция файлов

Как только 3 файла (example.if, example.fc, и example.te) будут соответствовать вашим ожиданиям по новым правилам, переименуйте их в myapp.extension и запустите make NAME=devel для создания модуля в файле myapp.pp вы можете сразу же загрузить его semodule -i myapp.pp). Если несколько модулей определены, make создаст все соответствующие файлы .pp.