19.3. 故障排除与 SELinux 相关的问题
如果您计划在之前禁用 SELinux 的系统中启用 SELinux,或者您以非标准配置运行服务,您可能需要排除 SELinux 可能会阻断的问题。请注意,在多数情况下,SELinux 拒绝通常代表存在错误的配置。
19.3.1. 识别 SELinux 拒绝 复制链接链接已复制到粘贴板!
只执行此流程中的必要步骤 ; 在大多数情况下,您只需要执行第 1 步。
步骤
当您的情况被 SELinux 阻止时,
/var/log/audit/audit.log
文件是第一个检查有关拒绝的更多信息。要查询审计日志,请使用ausearch
工具。因为 SELinux 决策(如允许或禁止访问)已被缓存,且这个缓存被称为 Access Vector Cache(AVC),所以对消息类型参数使用AVC
和USER_AVC
值,例如:ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent
# ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果没有匹配项,请检查 audit 守护进程是否正在运行。如果没有,请在启动
auditd
后重复拒绝的场景,然后再次检查审计日志。如果
auditd
正在运行,但ausearch
的输出中没有匹配项,请检查systemd
Journal 提供的消息:journalctl -t setroubleshoot
# journalctl -t setroubleshoot
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果 SELinux 处于活跃状态,且 Audit 守护进程没有在您的系统中运行,在
dmesg
命令的输出中搜索特定的 SELinux 信息:dmesg | grep -i -e type=1300 -e type=1400
# dmesg | grep -i -e type=1300 -e type=1400
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 即使进行了前面的三个检查后,您仍可能找不到任何结果。在这种情况下,因为
dontaudit
规则,可以静默 AVC 拒绝。要临时禁用
dontaudit
规则,请记录所有拒绝:semodule -DB
# semodule -DB
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 在重新运行拒绝的场景并使用前面的步骤查找拒绝信息后,以下命令会在策略中再次启用
dontaudit
规则:semodule -B
# semodule -B
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果您应用了前面所有四个步骤,这个问题仍然无法识别,请考虑 SELinux 是否真正阻止了您的场景:
切换到 permissive 模式:
setenforce 0 getenforce
# setenforce 0 $ getenforce Permissive
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - 重复您的场景。
如果问题仍然存在,则代表 SELinux 以外的系统阻断了您的场景。
19.3.2. 分析 SELinux 拒绝信息 复制链接链接已复制到粘贴板!
在确认 SELinux 会阻止您的场景后,可能需要在进行修复前分析根本原因。
先决条件
-
policycoreutils-python-utils
和setroubleshoot-server
软件包已安装在您的系统中。
步骤
使用
sealert
命令列出有关日志拒绝的详情,例如:sealert -l "*" ausearch -x /usr/bin/passwd --raw | audit2allow -D -M my-passwd semodule -X 300 -i my-passwd.pp
$ 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
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果上一步中的输出没有包含清晰的建议:
启用全路径审核查看访问对象的完整路径,并让其他 Linux Audit 事件字段可见:
auditctl -w /etc/shadow -p w -k shadow-write
# auditctl -w /etc/shadow -p w -k shadow-write
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 清除
setroubleshoot
缓存:rm -f /var/lib/setroubleshoot/setroubleshoot.xml
# rm -f /var/lib/setroubleshoot/setroubleshoot.xml
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - 重现问题。
重复步骤 1。
完成这个过程后,禁用全路径审核:
auditctl -W /etc/shadow -p w -k shadow-write
# auditctl -W /etc/shadow -p w -k shadow-write
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
-
如果
sealert
只返回catchall
建议,或者建议使用audit2allow
工具添加新规则,请将您的问题与 审计日志中 SELinux 拒绝中列出的 示例匹配。
19.3.3. 修复分析的 SELinux 拒绝问题 复制链接链接已复制到粘贴板!
在大多数情况下,sealert
工具提供的建议为您提供有关如何修复与 SELinux 策略相关的问题的正确指导。有关如何使用 sealert
分析 SELinux 拒绝信息的信息,请参阅分析 SELinux 拒绝信息。
当工具建议使用 audit2allow
工具进行配置更改时,请小心。当您看到 SELinux 拒绝时,您不应该使用 audit2allow
生成本地策略模块作为您的第一个选项。故障排除应该先检查是否有标记问题。第二个最常见的情况是您更改了进程配置,并且忘记了要让 SELinux 了解它。
标记问题
标记问题的常见原因是,当服务使用非标准目录时。例如,管理员可能希望使用 /
在 Red Hat Enterprise Linux 中,srv/myweb/,而不是将 /var/www/html
/ 用于网站。/srv
目录标有 var_t
类型。在 /srv
中创建的文件和目录继承此类型。此外,顶级目录中新创建的对象(如 /myserver
)可以使用 default_t
类型进行标记。SELinux 会阻止 Apache HTTP 服务器(httpd)
访问这两种类型。要允许访问,SELinux 必须知道 /srv/myweb/
中的文件可以被 httpd
访问:
semanage fcontext -a -t httpd_sys_content_t "/srv/myweb(/.*)?"
# semanage fcontext -a -t httpd_sys_content_t "/srv/myweb(/.*)?"
此 semanage
命令将 /srv/myweb/
目录的上下文以及该目录下的所有文件和目录添加到 SELinux 文件上下文配置中。semanage
实用程序不会更改上下文。以 root 用户身份,使用 restorecon
工具应用更改:
restorecon -R -v /srv/myweb
# restorecon -R -v /srv/myweb
不正确的上下文
matchpathcon
实用程序检查文件路径的上下文,并将其与该路径的默认标签进行比较。以下示例演示了在包含错误标记文件的目录中使用 matchpathcon
:
matchpathcon -V /var/www/html/*
$ 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
类型进行标记。这种类型用于用户主目录中的文件。使用 st v 命令
从您的主目录中移动文件可能会导致文件使用 user_home_t
类型进行标记。这个类型不应存在于主目录之外。使用 restorecon
实用程序将这些文件恢复到其正确类型:
restorecon -v /var/www/html/index.html
# 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
选项:
restorecon -R -v /var/www/html/
# 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 布尔值达到此目的,允许在运行时更改 SELinux 策略的部分。这启用了更改,比如允许服务访问 NFS 卷而无需重新载入或者重新编译 SELinux 策略。另外,在非默认端口号中运行服务需要使用 semanage
命令来更新策略配置。
例如,要允许 Apache HTTP 服务器与 MariaDB 通信,请启用 httpd_can_network_connect_db
布尔值:
setsebool -P httpd_can_network_connect_db on
# setsebool -P httpd_can_network_connect_db on
请注意,-P
选项可使系统重启后设置具有持久性。
如果特定服务无法访问,请使用 getsebool
和 grep
实用程序查看是否有布尔值是否可用于访问。例如,使用 getsebool -a | grep ftp
命令搜索 FTP 相关布尔值:
getsebool -a | grep 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
软件包并以 root 用户身份使用 semanage boolean -l
命令。
端口号
根据策略配置,服务只能在某些端口号中运行。尝试更改服务在没有更改策略的情况下运行的端口可能会导致服务无法启动。例如,以 root 用户身份运行 semanage port -l | grep http
命令,以列出 http
相关端口:
semanage port -l | grep http
# 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 服务器可以侦听的端口,本例中为 TCP 端口 80、443、488、8008、8009 和 8443。如果管理员配置了 httpd.conf
,以便 httpd
侦听端口 9876(Listen 9876
),但没有更新策略来反应这一点,以下命令会失败:
systemctl start httpd.service systemctl status httpd.service
# systemctl start httpd.service
Job for httpd.service failed. See 'systemctl status httpd.service' and 'journalctl -xn' for details.
# 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
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
命令为端口分配不同的标签:
semanage port -a -t http_port_t -p tcp 9876
# semanage port -a -t http_port_t -p tcp 9876
a
选项添加新的记录; -t
选项定义类型; -p
选项定义协议。最后的参数是要添加的端口号。
个别情况、演变或损坏的应用程序以及被破坏的系统
应用程序可能会包含程序漏洞,从而导致 SELinux 拒绝访问。另外,SELinux 规则会演变 - SELinux 可能还没有以某种某种方式运行某个应用程序,从而导致它拒绝访问,即使应用程序按预期工作。例如,当一个 PostgreSQL 的新版本发布后,它可能会执行一些当前策略无法处理的操作,从而导致访问被拒绝,即使应该允许访问。
对于这种情况,在访问被拒绝后,使用 audit2allow
实用程序创建自定义策略模块以允许访问。您可以通过 在红帽客户门户网站中 插入支持问题单来报告 SELinux 策略中缺少规则。提到 selinux-policy
组件,并在案例中包含 audit2allow -w -a
和 audit2allow -a
命令的输出。
如果应用程序请求主要的安全特权,这可能代表,应用程序可能已被破坏。使用入侵检测工具检查此类行为。
红帽客户门户网站中的 Solution Engine 也以文章的形式提供了相关的指导信息。它包括了您遇到的相同或非常类似的问题的解决方案。选择相关的产品和版本,并使用与 SELinux 相关的关键字,如 selinux 或 avc,以及您被阻断的服务或应用程序的名称,例如: selinux samba
。
19.3.4. 创建本地 SELinux 策略模块 复制链接链接已复制到粘贴板!
在活跃的 SELinux 策略中添加特定的 SELinux 策略模块可以修复 SELinux 策略的某些问题。您可以使用此流程修复 红帽发行注记 中介绍的特定已知问题,或实施特定的 红帽解决方案。
只用红帽提供的规则。红帽不支持使用自定义规则创建 SELinux 策略模块,因为这不会超出 产品支持覆盖范围。如果您并不是相关系统的专家,请联系红帽销售代表并请求咨询服务。
先决条件
-
setools-console
和audit
软件包进行验证。
流程
使用文本编辑器打开新的
.cil
文件,例如:vim <local_module>.cil
# vim <local_module>.cil
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要让您的本地模块更好地组织,请在本地 SELinux 策略模块的名称中使用
local_
前缀。从已知问题或红帽解决方案中插入自定义规则。
重要不要自己编写规则。仅使用特定已知问题或红帽解决方案中提供的规则。
例如,要实现 SELinux 拒绝 cups-lpd 对 RHEL 解决方案中的 cups.sock 的读访问权限,请插入以下规则:
(allow cupsd_lpd_t cupsd_var_run_t (sock_file (read)))
(allow cupsd_lpd_t cupsd_var_run_t (sock_file (read)))
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 在 RHBA-2021:4420 中为 RHEL 永久修复了示例解决方案。因此,特定于本解决方案的部分对更新的 RHEL 8 和 9 个系统没有影响,且只作为语法示例包括。
您可以使用两个 SELinux 规则语法之一: Common Intermediate Language (CIL)和 m4。例如,CIL 中的
(allow cupsd_lpd_t cupsd_var_run_t (sock_file (read)))
等同于 m4 中的以下内容:module local_cupslpd-read-cupssock 1.0; require { type cupsd_var_run_t; type cupsd_lpd_t; class sock_file read; } #============= cupsd_lpd_t ============== allow cupsd_lpd_t cupsd_var_run_t:sock_file read;
module local_cupslpd-read-cupssock 1.0; require { type cupsd_var_run_t; type cupsd_lpd_t; class sock_file read; } #============= cupsd_lpd_t ============== allow cupsd_lpd_t cupsd_var_run_t:sock_file read;
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
- 保存并关闭该文件。
安装策略模块:
semodule -i <local_module>.cil
# semodule -i <local_module>.cil
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果要删除使用
semodule -i
创建的本地策略模块,请参考不带.cil
后缀的模块名称。要删除本地策略模块,请使用semodule -r <local_module>
。重启与规则相关的任何服务:
systemctl restart <service-name>
# systemctl restart <service-name>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
验证
列出 SELinux 策略中安装的本地模块:
semodule -lfull | grep "local_"
# semodule -lfull | grep "local_" 400 local_module cil
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 由于本地模块具有优先级
400
,所以您也可以通过使用该值来从列表中过滤它们,例如使用semodule -lfull | grep -v ^100
命令。在 SELinux 策略中搜索相关的允许规则:
sesearch -A --source=<SOURCENAME> --target=<TARGETNAME> --class=<CLASSNAME> --perm=<P1>,<P2>
# sesearch -A --source=<SOURCENAME> --target=<TARGETNAME> --class=<CLASSNAME> --perm=<P1>,<P2>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 其中
<SOURCENAME>
是源 SELinux 类型,<TARGETNAME>
是目标 SELinux 类型,<CLASSNAME>
是安全类或对象类名称,<P1>
和<P2>
规则的特定权限。例如,要简化 SELinux 拒绝 cups-lpd 读取对 RHEL Red Hat Knowledgbase 解决方案中的 cups.sock 的读访问权限:
sesearch -A --source=cupsd_lpd_t --target=cupsd_var_run_t --class=sock_file --perm=read
# sesearch -A --source=cupsd_lpd_t --target=cupsd_var_run_t --class=sock_file --perm=read allow cupsd_lpd_t cupsd_var_run_t:sock_file { append getattr open read write };
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 最后一行现在应包含
read
操作。验证相关服务受 SELinux 限制:
确定与相关服务相关的进程:
systemctl status <service-name>
$ systemctl status <service-name>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 检查上一命令输出中列出的进程的 SELinux 上下文:
ps -efZ | grep <process-name>
$ ps -efZ | grep <process-name>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
验证该服务是否不会导致任何 SELinux 拒绝:
ausearch -m AVC -i -ts recent
# ausearch -m AVC -i -ts recent <no matches>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow i
选项将数字值解译为人类可读的文本。
19.3.5. 审计日志中的 SELinux 拒绝 复制链接链接已复制到粘贴板!
Linux Audit 系统默认将日志条目存储在 /var/log/audit/audit.log
文件中。
要仅列出与 SELinux 相关的记录,请使用 ausearch
命令,并将 message type 参数设置为 AVC
和 AVC_USER
,例如:
ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR
# ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR
审计日志文件中的 SELinux 拒绝条目类似如下:
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
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 执行的操作,并在 AVC 中记录 -
{ read }
- 被拒绝的操作 -
pid=6591
- 试图执行被拒绝操作的主体的进程识别符 -
comm="httpd"
- 用于调用分析进程的命令名称 -
httpd_t
- 进程的 SELinux 类型 -
nfs_t
- 受进程操作影响的对象的 SELinux 类型 -
tclass=dir
- 目标对象类
以前的日志条目可转换为:
SELinux 拒绝 PID 为 6591、以及从带有 nfs_t
类型的目录进行读取的 httpd_t
类型的 httpd
进程
当 Apache HTTP 服务器试图访问使用 Samba 套件类型标记的目录时,会出现以下 SELinux 拒绝信息:
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
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 上下文。在这种情况下,它是 Apache HTTP 服务器的 SELinux 上下文,它使用httpd_t
类型运行。 -
tcontext="unconfined_u:object_r:samba_share_t:s0"
- 试图访问的对象(目标)的 SELinux 上下文。在这种情况下,它是file1
的 SELinux 上下文。
这个 SELinux 拒绝信息可以被解释为:
SELinux 拒绝了 PID 为 2465 的 httpd
进程访问带有 samba_share_t
类型的 /var/www/html/file1
文件。除非有其他配置,在 httpd_t
域中运行的进程无法访问该文件。