10.3. 故障排除与 SELinux 相关的问题
如果您计划在之前禁用 SELinux 的系统中启用 SELinux,或者您以非标准配置运行服务,您可能需要排除 SELinux 可能会阻断的问题。请注意,在多数情况下,SELinux 拒绝通常代表存在错误的配置。
10.3.1. 识别 SELinux 拒绝
只执行此流程中的必要步骤 ; 在大多数情况下,您只需要执行第 1 步。
流程
当您的场景被 SELinux 阻止时,
/var/log/audit/audit.log
文件是第一个检查拒绝的更多信息。要查询 Audit 日志,请使用ausearch
工具。因为 SELinux 决策(如允许或禁止访问)已被缓存,且此缓存被称为 Access Vector Cache(AVC),所以在消息类型参数中使用AVC
和 USER_AVC
值,例如:# ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent
如果没有匹配项,请检查 audit 守护进程是否正在运行。如果没有,在您启动
auditd
后重复拒绝的场景,然后再次检查审计日志。如果
auditd
正在运行,但ausearch
输出中没有匹配项,请检查systemd
Journal 提供的信息:# journalctl -t setroubleshoot
如果 SELinux 活跃且 Audit 守护进程没有在您的系统中运行,则在
dmesg
命令输出中搜索某些 SELinux 信息:# dmesg | grep -i -e type=1300 -e type=1400
即使进行了前面的三个检查后,您仍可能找不到任何结果。在这种情况下,因为
dontaudit 规则
,AVC 拒绝可以被静默。临时禁用
dontaudit 规则
,允许记录所有拒绝信息:# semodule -DB
在重新运行拒绝的场景并使用前面的步骤查找拒绝信息后,以下命令会在策略中再次启用
dontaudit 规则
:# semodule -B
如果您应用了前面所有四个步骤,这个问题仍然无法识别,请考虑 SELinux 是否真正阻止了您的场景:
切换到 permissive 模式:
# setenforce 0 $ getenforce Permissive
- 重复您的场景。
如果问题仍然存在,则代表 SELinux 以外的系统阻断了您的场景。
10.3.2. 分析 SELinux 拒绝信息
在确认 SELinux 会阻止您的场景后,可能需要在进行修复前分析根本原因。
先决条件
-
policycoreutils-python-utils
和setroubleshoot-server
软件包安装在您的系统上。
流程
使用
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
如果上一步中的输出没有包含清晰的建议:
启用全路径审核查看访问对象的完整路径,并让其他 Linux Audit 事件字段可见:
# auditctl -w /etc/shadow -p w -k shadow-write
清除
setroubleshoot
缓存:# rm -f /var/lib/setroubleshoot/setroubleshoot.xml
- 重现问题。
重复步骤 1。
完成这个过程后,禁用全路径审核:
# auditctl -W /etc/shadow -p w -k shadow-write
-
如果
sealert
仅返回概括
性建议或建议使用audit2allow
工具添加新规则,请将您的问题与 审计日志中 SELinux 拒绝中列出的 示例匹配。
其它资源
-
您系统上的
sealert (8)
手册页
10.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
命令将 /srv/myweb/
目录的上下文以及该目录下的所有文件和目录添加到 SELinux 文件上下文配置中。semanage
实用程序不会更改上下文。以 root 用户身份,使用 restorecon
工具应用更改:
# 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
类型进行标记。这种类型用于用户主目录中的文件。使用 st v 命令
从您的主目录中移动文件可能会导致文件使用 user_home_t
类型进行标记。这个类型不应存在于主目录之外。使用 restorecon
实用程序将这些文件恢复到其正确类型:
# 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 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
请注意,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
软件包,再以 root 用户身份使用 semanage boolean -l
命令。
端口号
根据策略配置,服务只能在某些端口号中运行。尝试更改服务在没有更改策略的情况下运行的端口可能会导致服务无法启动。例如,以 root 用户身份运行 semanage port -l | grep http
命令以列出 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 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)
在 /var/log/audit/audit.log
中记录类似如下的 SELinux 拒绝信息:
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
a 选项
添加新记录; -t
选项定义类型; -p
选项定义协议。最后的参数是要添加的端口号。
个别情况、演变或损坏的应用程序以及被破坏的系统
应用程序可能会包含程序漏洞,从而导致 SELinux 拒绝访问。另外,SELinux 规则会不断演变 - SELinux 可能没有了解某个应用程序会以某种特定方式运行,因此即使应用程序按预期工作,也有可能出现拒绝访问的问题。例如,当一个 PostgreSQL 的新版本发布后,它可能会执行一些当前策略无法处理的操作,从而导致访问被拒绝,即使应该允许访问。
对于这种情况,在访问被拒绝后,使用 audit2allow
实用程序创建自定义策略模块以允许访问。您可以在 Red Hat Bugzilla 中报告 SELinux 策略中缺少的规则。对于 Red Hat Enterprise Linux 8,针对 Red Hat Enterprise Linux 8
产品创建程序错误,并选择 selinux-policy
组件。在此类错误报告中,包括 audit2allow -w -a
和 audit2allow -a
命令的输出。
如果应用程序请求主要的安全特权,这可能代表,应用程序可能已被破坏。使用入侵检测工具检查此类行为。
红帽客户门户网站中的 Solution Engine 也以文章的形式提供了相关的指导信息。它包括了您遇到的相同或非常类似的问题的解决方案。选择相关的产品和版本,并使用与 SELinux 相关的关键字,如 selinux 或 avc,以及您被阻断的服务或应用程序的名称,例如: selinux samba
。
10.3.4. 创建本地 SELinux 策略模块
在活跃的 SELinux 策略中添加特定的 SELinux 策略模块可以修复 SELinux 策略的某些问题。您可以使用此流程修复 红帽发行注记 中介绍的特定已知问题,或实施特定的 红帽解决方案。
只用红帽提供的规则。红帽不支持使用自定义规则创建 SELinux 策略模块,因为这不会超出 产品支持覆盖范围。如果您并不是相关系统的专家,请联系红帽销售代表并请求咨询服务。
先决条件
-
setools-console
和audit
软件包进行验证。
流程
使用文本编辑器打开新的
.cil
文件,例如:# vim <local_module>.cil
要让您的本地模块更好地组织,请在本地 SELinux 策略模块的名称中使用
local_
前缀。从已知问题或红帽解决方案中插入自定义规则。
重要不要自己编写规则。仅使用特定已知问题或红帽解决方案中提供的规则。
例如,要实现 SELinux 拒绝 cups-lpd 对 RHEL 解决方案中的 cups.sock 的读访问权限,请插入以下规则:
(allow cupsd_lpd_t cupsd_var_run_t (sock_file (read)))
在 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;
- 保存并关闭该文件。
安装策略模块:
# semodule -i <local_module>.cil
如果要删除使用
semodule -i
创建的本地策略模块,请参考不带.cil
后缀的模块名称。要删除本地策略模块,请使用semodule -r <local_module>
。重启与规则相关的任何服务:
# systemctl restart <service-name>
验证
列出 SELinux 策略中安装的本地模块:
# semodule -lfull | grep "local_" 400 local_module cil
由于本地模块具有优先级
400
,所以您也可以通过使用该值来从列表中过滤它们,例如使用semodule -lfull | grep -v ^100
命令。在 SELinux 策略中搜索相关的允许规则:
# sesearch -A --source=<SOURCENAME> --target=<TARGETNAME> --class=<CLASSNAME> --perm=<P1>,<P2>
其中
<SOURCENAME>
是源 SELinux 类型,<TARGETNAME>
是目标 SELinux 类型,<CLASSNAME>
是安全类或对象类名称,<P1>
和<P2>
规则的特定权限。例如,SELinux denies cups-lpd read access to cups.sock in RHEL 解决方案:
# 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 };
最后一行现在应包含
read
操作。验证相关服务受 SELinux 限制:
确定与相关服务相关的进程:
$ systemctl status <service-name>
检查上一命令输出中列出的进程的 SELinux 上下文:
$ ps -efZ | grep <process-name>
验证该服务是否不会导致任何 SELinux 拒绝:
# ausearch -m AVC -i -ts recent <no matches>
i
选项将数字值解译为人类可读的文本。
其它资源
10.3.5. 审计日志中的 SELinux 拒绝
Linux Audit 系统默认将日志条目存储在 /var/log/audit/audit.log
文件中。
要只列出与 SELinux 相关的记录,请使用 ausearch
命令并将消息类型参数设置为
,例如:
AVC
和 AVC_USER
# 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
这个条目最重要的部分是:
-
AVC:被拒绝
- SELinux 执行的操作,并记录在 Access Vector Cache(AVC)中. -
{ read }
- 已拒绝的操作 -
PID=6591
- 试图执行被拒绝操作的主体的进程标识符 -
comm="httpd"
- 用于调用分析的进程的命令名称 -
httpd_t
- 进程的 SELinux 类型 -
nfs_t
- 受进程操作影响的对象的 SELinux 类型 -
tclass=dir
- 目标对象类
以前的日志条目可转换为:
SELinux 拒绝了 PID 为 6591、httpd _t 类型为从
进程。
nfs_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
-
{ getattr }
-getattr
条目指示源进程正在尝试读取目标文件的状态信息。这在读取文件前发生。SELinux 会拒绝这个操作,因为进程会访问该文件,且没有适当的标签。通常看到的权限包括getattr
、读取和写入
。
-
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"
- 试图访问的对象(target)的 SELinux 上下文。在本例中,这是file1 的
SELinux 上下文。
这个 SELinux 拒绝信息可以被解释为:
SELinux 拒绝 PID 为 2465 的 httpd
进程使用 samba_share_t
类型访问 /var/www/html/file1
文件,除非有其他配置,否则在 httpd_t
域中运行的进程无法访问该文件。
其它资源
-
系统中的
auditd (8)
和ausearch (8)
手册页
10.3.6. 其它资源
- CLI 中的基本 SELinux 故障排除 (红帽知识库)
- SELinux 尝试告诉我什么?SELinux 错误的 4 个关键原因(fedora People)