Устранение неполадок, связанных с SELinux

Мэт Маккейб, Джо Уокер, Питер Бой (pboy) Version F36 and newer Last review: 2023-06-18

Если вы планируете включить SELinux в системах, где он ранее был отключён, или если вы запускаете службу в нестандартной конфигурации, вам может потребоваться устранение неполадок в ситуациях, потенциально блокируемых SELinux. Обратите внимание, что в большинстве случаев отказы SELinux являются признаками неправильной настройки.

Выявление отказов SELinux

Выполняйте только необходимые шаги из этой процедуры; в большинстве случаев вам нужно выполнить только шаг 1.

Процедура

  1. Когда ваш сценарий блокируется SELinux, файл /var/log/audit/audit.log — это первое место, где следует искать дополнительную информацию об отказе. Для запроса журналов Audit используйте инструмент ausearch. Поскольку решения SELinux, такие как разрешение или запрет доступа, кэшируются и этот кэш известен как Access Vector Cache (AVC), используйте значения AVC и USER_AVC для параметра типа сообщения, например:

    $ sudo ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent

    Если совпадений нет, проверьте, запущен ли демон Audit. Если нет, повторите сценарий с отказом после запуска auditd и снова проверьте журнал Audit.

  2. Если auditd запущен, но в выводе ausearch нет совпадений, проверьте сообщения, предоставляемые журналом systemd:

    $ sudo journalctl -t setroubleshoot
  3. Если SELinux активен и демон Audit не запущен в вашей системе, найдите определённые сообщения SELinux в выводе команды dmesg:

    $ sudo dmesg | grep -i -e type=1300 -e type=1400
  4. Даже после предыдущих трёх проверок всё ещё возможно, что вы ничего не нашли. В этом случае отказы AVC могут быть заглушены из-за правил dontaudit.

    Чтобы временно отключить правила dontaudit, позволяя регистрировать все отказы:

    $ sudo semodule -DB

    После повторного запуска сценария с отказом и поиска сообщений об отказах с помощью предыдущих шагов следующая команда снова включает правила dontaudit в политике:

    $ sudo semodule -B
  5. Если вы применили все четыре предыдущих шага, а проблема всё ещё остаётся невыявленной, подумайте, действительно ли SELinux блокирует ваш сценарий:

    • Переключитесь в разрешающий режим:

      $ sudo setenforce 0
      $ getenforce
      Permissive
    • Повторите ваш сценарий.

Если проблема всё ещё возникает, ваш сценарий блокирует что-то другое, а не SELinux.

Анализ сообщений об отказах SELinux

После выявления того, что SELinux блокирует ваш сценарий, вам может потребоваться проанализировать первопричину, прежде чем выбрать исправление.

Предварительные требования

  • Пакеты policycoreutils-python-utils и setroubleshoot-server установлены в вашей системе.

Процедура

  1. Выведите более подробную информацию о зарегистрированном отказе с помощью команды sealert, например:

    $ sealert -l "*"
    SELinux is preventing /usr/bin/passwd from write access on the file
    /root/test.
    
    *****  Plugin leaks (86.2 confidence) suggests *****************************
    
    If you want to ignore passwd trying to write access the test file,
    because you believe it should not need this access.
    Then you should report this as a bug.
    You can generate a local policy module to dontaudit this access.
    Do
    # ausearch -x /usr/bin/passwd --raw | audit2allow -D -M my-passwd
    # semodule -X 300 -i my-passwd.pp
    
    *****  Plugin catchall (14.7 confidence) suggests **************************
    
    ...
    
    Raw Audit Messages
    type=AVC msg=audit(1553609555.619:127): avc:  denied  { write } for
    pid=4097 comm="passwd" path="/root/test" dev="dm-0" ino=17142697
    scontext=unconfined_u:unconfined_r:passwd_t:s0-s0:c0.c1023
    tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file permissive=0
    
    ..
    
    Hash: passwd,passwd_t,admin_home_t,file,write
  2. Если вывод, полученный на предыдущем шаге, не содержит чётких рекомендаций:

    • Включите аудит полных путей, чтобы видеть полные пути к объектам, к которым произошёл доступ, и сделать видимыми дополнительные поля событий Linux Audit:

      $ sudo auditctl -w /etc/shadow -p w -k shadow-write
    • Очистите кэш setroubleshoot:

      $ sudo rm -f /var/lib/setroubleshoot/setroubleshoot.xml
    • Воспроизведите проблему.

    • Повторите шаг 1.

      После завершения процесса отключите аудит полных путей:

      $ sudo auditctl -W /etc/shadow -p w -k shadow-write
  3. Если sealert возвращает только предложения catchall или предлагает добавить новое правило с помощью инструмента audit2allow, сопоставьте свою проблему с примерами, перечисленными и объяснёнными в разделе об отказах SELinux в журнале Audit.

Дополнительные ресурсы

  • страница руководства sealert(8)

Исправление проанализированных отказов SELinux

В большинстве случаев рекомендации, предоставляемые инструментом sealert, дают вам правильное руководство о том, как исправить проблемы, связанные с политикой SELinux. Информацию о том, как использовать sealert для анализа отказов SELinux, см. в разделе «Анализ сообщений об отказах SELinux».

Будьте осторожны, когда инструмент предлагает использовать audit2allow для изменений конфигурации. Не следует использовать audit2allow для генерации локального модуля политики в качестве первого варианта, когда вы видите отказ SELinux. Устранение неполадок следует начинать с проверки, нет ли проблемы с маркировкой. Второй по частоте случай — вы изменили конфигурацию процесса и забыли сообщить об этом SELinux.

Проблемы с маркировкой

Распространённой причиной проблем с маркировкой является использование нестандартного каталога для службы. Например, вместо использования /var/www/html/ для веб-сайта администратор может захотеть использовать /srv/myweb/. В Red Hat Enterprise Linux каталог /srv помечен типом var_t. Файлы и каталоги, созданные в /srv, наследуют этот тип. Кроме того, вновь созданные объекты в каталогах верхнего уровня, таких как /myserver, могут быть помечены типом default_t. SELinux запрещает веб-серверу Apache HTTP Server (httpd) доступ к обоим этим типам. Чтобы разрешить доступ, SELinux должен знать, что файлы в /srv/myweb/ должны быть доступны для httpd:

$ sudo semanage fcontext -a -t httpd_sys_content_t "/srv/myweb(/.*)?"

Эта команда semanage добавляет контекст для каталога /srv/myweb/ и всех файлов и каталогов под ним в конфигурацию файловых контекстов SELinux. Утилита semanage не изменяет контекст. От имени root используйте утилиту restorecon, чтобы применить изменения:

$ sudo restorecon -R -v /srv/myweb

Неправильный контекст Утилита matchpathcon проверяет контекст пути к файлу и сравнивает его с меткой по умолчанию для этого пути. Следующий пример демонстрирует использование matchpathcon для каталога, содержащего неправильно помеченные файлы:

$ matchpathcon -V /var/www/html/*
/var/www/html/index.html has context unconfined_u:object_r:user_home_t:s0, should be system_u:object_r:httpd_sys_content_t:s0
/var/www/html/page1.html has context unconfined_u:object_r:user_home_t:s0, should be system_u:object_r:httpd_sys_content_t:s0

В этом примере файлы index.html и page1.html помечены типом user_home_t. Этот тип используется для файлов в домашних каталогах пользователей. Использование команды mv для перемещения файлов из вашего домашнего каталога может привести к тому, что файлы будут помечены типом user_home_t. Этот тип не должен существовать вне домашних каталогов. Используйте утилиту restorecon, чтобы восстановить такие файлы до их правильного типа:

$ sudo restorecon -v /var/www/html/index.html
restorecon reset /var/www/html/index.html context unconfined_u:object_r:user_home_t:s0->system_u:object_r:httpd_sys_content_t:s0

Чтобы восстановить контекст для всех файлов в каталоге, используйте параметр -R:

$ sudo restorecon -R -v /var/www/html/
restorecon reset /var/www/html/page1.html context unconfined_u:object_r:samba_share_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /var/www/html/index.html context unconfined_u:object_r:samba_share_t:s0->system_u:object_r:httpd_sys_content_t:s0

Изолированные приложения, настроенные нестандартными способами

Службы можно запускать различными способами. Чтобы учесть это, вам нужно указать, как вы запускаете свои службы. Это можно сделать с помощью логических переменных SELinux (booleans), которые позволяют изменять части политики SELinux во время выполнения. Это позволяет вносить изменения, например, разрешать службам доступ к томам NFS, без перезагрузки или перекомпиляции политики SELinux. Кроме того, запуск служб на портах, отличных от портов по умолчанию, требует обновления конфигурации политики с помощью команды semanage.

Например, чтобы разрешить Apache HTTP Server взаимодействовать с MariaDB, включите логическую переменную httpd_can_network_connect_db:

$ sudo setsebool -P httpd_can_network_connect_db on

Обратите внимание, что параметр -P делает настройку постоянной между перезагрузками системы.

Если доступ запрещён для конкретной службы, используйте утилиты getsebool и grep, чтобы узнать, доступны ли какие-либо логические переменные для разрешения доступа. Например, используйте команду getsebool -a | grep ftp для поиска логических переменных, связанных с FTP:

$ getsebool -a | grep ftp
ftpd_anon_write --> off
ftpd_full_access --> off
ftpd_use_cifs --> off
ftpd_use_nfs --> off

ftpd_connect_db --> off
httpd_enable_ftp_server --> off
tftp_anon_write --> off

Чтобы получить список логических переменных и узнать, включены они или отключены, используйте команду getsebool -a. Чтобы получить список логических переменных с их значениями и узнать, включены они или отключены, установите пакет selinux-policy-devel и используйте команду semanage boolean -l от имени root.

*Номера портов

В зависимости от конфигурации политики, службам может быть разрешено работать только на определённых номерах портов. Попытка изменить порт, на котором работает служба, без изменения политики может привести к тому, что служба не запустится. Например, выполните команду semanage port -l | grep http от имени root, чтобы вывести список портов, связанных с http:

$ sudo semanage port -l | grep http
http_cache_port_t              tcp      3128, 8080, 8118
http_cache_port_t              udp      3130
http_port_t                    tcp      80, 443, 488, 8008, 8009, 8443
pegasus_http_port_t            tcp      5988
pegasus_https_port_t           tcp      5989

Тип порта http_port_t определяет порты, которые может прослушивать Apache HTTP Server, в данном случае это TCP-порты 80, 443, 488, 8008, 8009 и 8443. Если администратор настроит httpd.conf так, чтобы httpd прослушивал порт 9876 (Listen 9876), но политика не будет обновлена, чтобы отразить это, следующая команда завершится с ошибкой:

$ sudo systemctl start httpd.service
Job for httpd.service failed. See 'systemctl status httpd.service' and 'journalctl -xn' for details.

$ sudo systemctl status httpd.service
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
   Active: failed (Result: exit-code) since Thu 2013-08-15 09:57:05 CEST; 59s ago
  Process: 16874 ExecStop=/usr/sbin/httpd $OPTIONS -k graceful-stop (code=exited, status=0/SUCCESS)
  Process: 16870 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE)

Сообщение об отказе SELinux, подобное следующему, записывается в /var/log/audit/audit.log:

type=AVC msg=audit(1225948455.061:294): avc:  denied  { name_bind } for  pid=4997 comm="httpd" src=9876 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

Чтобы разрешить httpd прослушивать порт, который не указан для типа порта http_port_t, используйте команду semanage port, чтобы назначить порту другую метку:

$ sudo semanage port -a -t http_port_t -p tcp 9876

Параметр -a добавляет новую запись; параметр -t определяет тип; параметр -p определяет протокол. Последний аргумент — номер порта, который нужно добавить.

Особые случаи, развивающиеся или сломанные приложения и скомпрометированные системы

Приложения могут содержать ошибки, из-за которых SELinux запрещает доступ. Кроме того, правила SELinux развиваются — SELinux может не встречать приложение, работающее определённым образом, что может привести к запрету доступа, даже если приложение работает как ожидалось. Например, если выпущена новая версия PostgreSQL, она может выполнять действия, которые текущая политика не учитывает, что приводит к запрету доступа, даже если доступ должен быть разрешён.

В таких ситуациях после запрета доступа используйте утилиту audit2allow, чтобы создать пользовательский модуль политики для разрешения доступа. Вы можете сообщить об отсутствующих правилах в политике SELinux в Red Hat Bugzilla. Для Red Hat Enterprise Linux 8 создавайте ошибки для продукта Red Hat Enterprise Linux 8 и выбирайте компонент selinux-policy. Включайте в такие отчёты об ошибках вывод команд audit2allow -w -a и audit2allow -a.

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

Solution Engine на портале Red Hat Customer Portal также может предоставить руководство в виде статьи, содержащей возможное решение той же или очень похожей проблемы, с которой вы столкнулись. Выберите соответствующий продукт и версию и используйте ключевые слова, связанные с SELinux, такие как selinux или avc, вместе с именем заблокированной службы или приложения, например: selinux samba.

Отказы SELinux в журнале audit

Система Linux Audit по умолчанию сохраняет записи журнала в файле /var/log/audit/audit.log.

Чтобы вывести только записи, связанные с SELinux, используйте команду ausearch с параметром типа сообщения, установленным как минимум в AVC и AVC_USER, например:

$ sudo ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR

Запись об отказе SELinux в файле журнала Audit может выглядеть так:

type=AVC msg=audit(1395177286.929:1638): avc:  denied  { read } for  pid=6591 comm="httpd" name="webpages" dev="0:37" ino=2112 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:nfs_t:s0 tclass=dir

Наиболее важные части этой записи:

  • avc: denied — действие, выполненное SELinux и записанное в Access Vector Cache (AVC)

  • { read } — запрещённое действие

  • pid=6591 — идентификатор процесса субъекта, который пытался выполнить запрещённое действие

  • comm="httpd" — имя команды, которая использовалась для запуска анализируемого процесса

  • httpd_t — тип SELinux процесса

  • nfs_t — тип SELinux объекта, затронутого действием процесса

  • tclass=dir — класс целевого объекта

Предыдущую запись журнала можно перевести так:

SELinux запретил процессу httpd с PID 6591 и типом httpd_t читать из каталога с типом nfs_t.

Следующее сообщение об отказе SELinux возникает, когда Apache HTTP Server пытается получить доступ к каталогу, помеченному типом для набора Samba:

type=AVC msg=audit(1226874073.147:96): avc:  denied  { getattr } for  pid=2465 comm="httpd" path="/var/www/html/file1" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file
  • { getattr } — запись getattr указывает, что исходный процесс пытался прочитать информацию о состоянии целевого файла. Это происходит перед чтением файлов. SELinux запрещает это действие, потому что процесс обращается к файлу, а тот не имеет подходящей метки. Часто встречающиеся разрешения включают getattr, read и write.

  • path="/var/www/html/file1" — путь к объекту (цели), к которому пытался получить доступ процесс.

  • scontext="unconfined_u:system_r:httpd_t:s0" — контекст SELinux процесса (источника), который пытался выполнить запрещённое действие. В этом случае это контекст SELinux Apache HTTP Server, работающего с типом httpd_t.

  • tcontext="unconfined_u:object_r:samba_share_t:s0" — контекст SELinux объекта (цели), к которому пытался получить доступ процесс. В этом случае это контекст SELinux файла file1.

Этот отказ SELinux можно перевести так:

SELinux запретил процессу httpd с PID 2465 доступ к файлу /var/www/html/file1 с типом samba_share_t, который недоступен процессам, работающим в домене httpd_t, если не настроено иное.

Дополнительные ресурсы

  • страницы руководства auditd(8) и ausearch(8)