跳到内容跳到页面导航:上一页 [access key p]/下一页 [access key n]
documentation.suse.com / SELinux 查错

SELinux 查错

出版日期:2025-03-20
内容

包含 enforcing 模式 SELinux 的系统可能会导致拒绝访问错误,从而导致应用程序无法正常运行。您可以使用 audit2allowsetroubleshoot 以用户友好的方式分析拒绝访问错误消息。

原因

本文说明如何在不降低系统安全性的情况下解决 SELinux 导致的拒绝访问错误。

工作量

读完本文大约需要 30 分钟。

目标

您可以使用后文所述的工具之一来调试 SELinux 拒绝访问错误。

要求
  • 一个正在运行的系统,其中已启用 SELinux。

1 /var/log/audit/audit.log 文件

默认情况下,如果 SELinux 是导致出错的原因,系统会将与此结果相关的日志消息发送到 /var/log/audit/audit.log 文件。

注意
注意:空的 /var/log/audit/audit.log

如果您看到空的 /var/log/audit/audit.log,这通常表示 auditd 服务未运行。在这种情况下,请执行以下步骤:

  1. 启动 auditd 服务:

                > 
                sudo
                systemctl start auditd
  2. 使用以下命令在系统目标中启用该服务

                > 
                sudo
                systemctl enable auditd

/var/log/audit/audit.log 文件存储拒绝访问错误、服务事件等的消息。

例 1: “/etc/audit/audit.log 中的示例行”中,可以看到 /var/log/audit/audit.log 内容的部分示例。

例 1︰ /etc/audit/audit.log 中的示例行
type=DAEMON_START msg=audit(1348173810.874:6248): auditd start, ver=1.7.7 format=raw kernel=3.0.13-0.27-default auid=0 pid=4235 subj=system_u:system_r:auditd_t res=success
type=AVC msg=audit(1348173901.081:292): avc:  denied  { write } for  pid=3426 comm="smartd" name="smartmontools" dev=sda6 ino=581743 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=dir
type=AVC msg=audit(1348173901.081:293): avc:  denied  { remove_name } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state~" dev=sda6 ino=582390 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=dir
type=AVC msg=audit(1348173901.081:294): avc:  denied  { unlink } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state~" dev=sda6 ino=582390 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file
type=AVC msg=audit(1348173901.081:295): avc:  denied  { rename } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state" dev=sda6 ino=582373 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file
type=AVC msg=audit(1348173901.081:296): avc:  denied  { add_name } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state~" scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=dir
type=AVC msg=audit(1348173901.081:297): avc:  denied  { create } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state" scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file
type=AVC msg=audit(1348173901.081:298): avc:  denied  { write open } for  pid=3426 comm="smartd" name="smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state" dev=sda6 ino=582390 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file
type=AVC msg=audit(1348173901.081:299): avc:  denied  { getattr } for  pid=3426 comm="smartd" path="/var/lib/smartmontools/smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state" dev=sda6 ino=582390 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file
type=AVC msg=audit(1348173901.309:300): avc:  denied  { append } for  pid=1316

日志中每条消息的外观如下:

  type=AVC msg=audit(1348173901.081:299): avc:  denied  { getattr } for  pid=3426 comm="smartd" path="/var/lib/smartmontools/smartd.WDC_WD2500BEKT_75PVMT0-WD_WXC1A21E0454.ata.state" dev=sda6 ino=582390 scontext=system_u:system_r:fsdaemon_t tcontext=system_u:object_r:var_lib_t tclass=file

消息的每一行可分解为若干部分。例如,最后一行包含以下部分:

type=AVC

每个 SELinux 相关审计日志行都以类型标识(例如 type=AVC)开头。请注意,如果包含 type=SYSCALL 的消息后接在类型不同但 msg 值相同的消息后面,则它可能会提供有关事件的更多信息。

msg=audit(1348173901.309:300)

这是时戳,它是以纪元时间(自 1970 年 1 月 1 日开始经过的秒数)写入的。您可以针对纪元时间表示法中点号前面的部分使用 date -d,以确定该事件是何时发生的:

> date -d @1348173901
Thu Sep 20 16:45:01 EDT 2012
avc: denied { append }

被拒绝的特定操作。在本例中,系统已拒绝将数据追加到文件。在浏览审计日志文件时,您可以看到其他系统操作,例如 write open、getattr 等。

for pid=1316

发起操作的命令或进程的进程 ID

comm="rsyslogd"

与该 PID 关联的特定命令

name="smartmontools"

操作主体的名称

dev=sda6 ino=582296

相关文件的块设备和 inode 编号

scontext=system_u:system_r:syslogd_t

源环境,即操作发起者的环境

tclass=file

主体的类标识

2 使用 audit2allow 分析 /var/log/audit/audit.log

您不必亲自解释 /var/log/audit/audit.log 中的事件,而可以使用 audit2allow 命令。

该命令可帮助您分析 /var/log/audit/audit.log 中晦涩难懂的日志消息。audit2allow 查错会话始终由三个不同的命令组成。首先,可以使用 audit2allow -w -a 以更易于理解的方式显示审计信息。默认情况下,audit2allow -w -a 会处理 audit.log 文件。如果您要分析 audit.log 文件中的特定消息,请将其复制到临时文件,并使用以下命令分析该文件:

      > 
      sudo
      audit2allow -w -i FILENAME
例 2︰ 分析审计消息
> sudoaudit2allow -w -i testfile
type=AVC msg=audit(1348173901.309:300): avc:  denied  { append } for  pid=1316
comm="rsyslogd" name="acpid" dev=sda6 ino=582296
scontext=system_u:system_r:syslogd_t tcontext=system_u:object_r:apmd_log_t tclass=file
发生此问题的原因是:

缺少类型强制 (TE) 允许规则。

要生成可加载的模块以允许这种访问,请运行

            > 
            sudo
            audit2allow

要确定具体哪条规则拒绝了访问,您可以使用 audit2allow -a 显示已记录到 audit.log 文件中的所有事件中的强制规则,或使用 audit2allow -i FILENAME 显示应用于存储在特定文件中的消息的规则:

例 3︰ 查看哪些行拒绝了访问
> sudoaudit2allow -i testfile
#============= syslogd_t ==============
allow syslogd_t apmd_log_t:file append;

要创建您可以加载以允许先前被拒绝的访问的 SELinux 模块 mymodule,请运行

      > 
      sudo
      audit2allow -a -R -M mymodule

如果您要对已记录到 audit.log 文件中的所有事件执行此操作,请使用 -a -M 命令参数。要仅针对特定文件中的特定消息执行此操作,请按下面的示例所示使用 -i -M

例 4︰ 创建允许先前被拒绝的操作的策略模块
> sudoaudit2allow -i testfile -M example
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i example.pp

audit2allow 命令所示,您现在可按以下方式运行此模块:使用 semodule -i 命令,后接 audit2allow 为您创建的模块的名称(在上例中为 example.pp)。

3 使用 setroubleshoot 分析 AVC 消息

要以用户友好的方式分析 AVC 拒绝访问错误消息,可以使用 setroubleshoot 工具。

3.1 setroubleshoot 概览

3.1.1 什么是 setroubleshoot

setroubleshoot 是可以从内核收集 SELinux 审计事件并对其进行分析的工具。如果发生此类事件,setroubleshoot 会通知管理员。

3.1.2 setroubleshoot 组件

SELinux 查错过程涉及以下组件,默认情况下,所有这些组件均已安装在 SUSE Linux Micro 上。

  • setroubleshoot-server 提供以下工具:

    • setroubleshootd - 用于处理传入请求和插件定义的主守护程序。该守护程序是按需激活的,不需要通过 systemd 服务来运行。它只能由特权用户和专门的 setroubleshoot 用户来管理。

    • /var/lib/setroubleshoot/setroubleshoot_database.xml 文件中的警报数据库

    • sealert - 用于分析 /var/log/audit.log 的命令行用户界面

    • sedispatch - 审计调度程序,用于扫描 SELinux AVC 消息并将其转换为 DBus 消息,然后将其传递给守护程序。

  • setroubleshoot-plugins - 插件用于 AVC 消息分析,并提供有关如何解决问题的建议。

3.1.3 setroubleshoot 的工作原理

setroubleshoot 包含守护程序和分析插件。当插件检测到问题时,会向守护程序报告此问题,然后守护程序将检查这是否为已知问题。如果不是,则将新问题连同建议的解决方案一起添加到数据库中。

3.1.4 setroubleshoot 的优点

setroubleshoot 提供以下功能来帮助您解决 SELinux 安全系统上的问题:

  • 发生 AVC 拒绝访问错误时向管理员发送警报。

  • 自动分析 AVC 拒绝访问错误。

  • 建议可能的修复方法,例如调整系统配置或安装更新等。

  • 浏览以前的警报。

3.2 配置 setroubleshoot

尽管 setroubleshoot 的配置不需要调整,但在某些特殊用例中,您可能需要更改默认值。以下章节提供了一般用例。

setroubleshoot 的配置文件是 /etc/setroubleshoot。通常,除了设置电子邮件通知之外,您无需修改其他配置。但是,如果您需要更改配置,可以编辑该文件,或使用 setroubleshootd 命令配置特定项目。命令语法如下:

        # 
        setroubleshootd -c
SECTION.OPTION=VALUE

例如,要设置 from_address 选项,请运行如下命令:

        # 
        setroubleshootd -c
email.from_address="example@mail.com"

3.2.1 配置 setroubleshoot 日志记录级别

默认日志记录级别(sealert_logsetroubleshootd_log 的值)设置为 warning。但是,您可以将该值设置为下列其中一项:

critical

仅记录导致系统无法正常运行的严重错误。

error

报告可能影响系统的严重错误。

warning

指出发生了意外情况,或者不久的将来可能会出现问题。但系统可按预期运行。

info

记录确认系统正常运行的信息。

debug

记录用于调试的详细信息。

3.2.2 配置 setroubleshoot 以发送电子邮件通知

如果系统中发生 AVC 拒绝访问错误,setroubleshoot 可向您发送电子邮件通知。

要获取这些通知,请执行以下步骤:

  1. 打开 /etc/setroubleshoot/setroubleshoot.conf

  2. 在该文件中,根据需要调整以下配置项目:

    smtp_host

    如果 SMTP 服务器未在本地主机上运行,请填写服务器地址。

    smtp_port

    默认值为 25。通常不需要对此值进行任何调整。

    from_address

    添加发件人地址。

    subject

    配置所有邮件的通用主题。

    recipients_filepath

    指定通知收件人列表的位置。

    use_sendmail

    如果您使用 SendMail,请设置为 true

  3. recipients_filepath 选项定义的路径(默认为 /var/lib/setroubleshoot/email_alerts-recipients)中创建邮件收件人文件。

    每个电子邮件地址必须独占一行。注释以 # 符号表示。

3.2.3 配置 setroubleshoot 数据库

可以更改 setroubleshootd 数据库中的记录数量、数据库位置或文件名前缀。

database_dir

指定数据库 XML 文件所在目录的绝对路径。

filename

配置数据库文件名的自定义前缀。然后,文件名如下所示:FILENAME_PREFIX_database.xml

max_alerts

定义数据库中的记录数上限。指定 0 表示记录数没有限制。

max_alert_age

超过设置限制的警报将从数据库中删除。可使用以下单位:年、月、天、小时、分钟和秒,甚至可以使用复数形式;并且可以使用多个单位,例如 3 weeks 2 days(相当于 23 天)。如果留空,则表示没有限制。

3.2.4 配置 setroubleshoot 以从远程服务器收集信息

可以配置 setroubleshoot 以从远程服务器收集 SELinux 审计数据。为此请配置地址列表。

[listen_for_client] address_list

在服务器端。

[client_connect_to] address_list

在客户端。

列表中的地址采用以下格式:

          [{FAMILY}]ADDRESS[:PORT_NUMBER]

其中 {FAMILY}{inet}{unix}%{path}s。如果地址族为 inet,则您可以选择性地指定端口号,否则端口号将设置为 default_port 配置选项指定的默认值。默认值 {unix}%{path}s hostname 表示侦听本地 Unix 域套接字。

3.3 运行 /var/log/audit/audit.log 分析

要让 setroubleshoot 工具分析审计日志文件,请运行以下命令:

        > 
        sudo
        sealert -a /var/log/audit/audit.log

在以下示例输出中,有两个端口值已指派到 SSHD 服务:

100% done
found 1 alerts in /var/log/audit/audit.log
--------------------------------------------------------------------------------

SELinux is preventing sshd from name_bind access on the tcp_socket port 2222.

*****  Plugin bind_ports (92.2 confidence) suggests   ************************ 

If you want to allow sshd to bind to network port 2222
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 2222  1
    where PORT_TYPE is one of the following: ssh_port_t, vnc_port_t, xserver_port_t.

*****  Plugin catchall_boolean (7.83 confidence) suggests   ******************

If you want to allow nis to enabled
Then you must tell SELinux about this by enabling the 'nis_enabled' boolean.

Do
setsebool -P nis_enabled 1

*****  Plugin catchall (1.41 confidence) suggests   **************************

If you believe that sshd should be allowed name_bind access on the port 2222 tcp_socket by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'sshd' --raw | audit2allow -M my-sshd
# semodule -X 300 -i my-sshd.pp

Additional Information:
...

First Seen                    2024-02-07 14:26:27 UTC
Last Seen                     2024-02-08 03:30:12 UTC
Local ID                      b5cbdd75-3f8d-425d-af75-f6cbf1540ffd 

Raw Audit Messages
type=AVC msg=audit(1707363012.797:25): avc:  denied  { name_bind } for  pid=841 comm="sshd" src=2222 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0


Hash: sshd,sshd_t,unreserved_port_t,tcp_socket,name_bind

1

bind_ports 插件为此处出现的问题提供了最合适的解决方案。