SELinux 安全访问控制


SELinux 介绍

SELinux(Security Enhanced Linux)是在进行程序、文件等权限设置依据的一个内核模块。

传统的权限管理方式称为自主访问控制,SELinux使用的是委托访问控制:

  • 自主访问控制:

    自主访问控制(DAC,Discretionary Access Control)是依据进程的所有者与文件资源的rwx权限来决定文件的访问能力。

    DAC访问控制的缺陷:

    • root具有最高权限;
    • 用户可以取得进程来更改文件资源的访问权限。
  • 强制访问控制:

    SELinux导入了强制访问控制(MAC,Mandatory Access Control)的方法。MAC可以针对特定的进程与特定的文件资源来进行权限控制,控制的主体变成了进程而不是用户。

    此外这个主体进程也不能任意使用系统文件资源,因为每个文件资源也有针对该主体进程设置可取用的权限。

    这样,可以控制的项目和策略组合非常多,因此 SELinux 也提供一些默认的策略,并在该策略内提供多个规则,以便用户可以选择是否启用该控制规则。

SELinux 名词

  • 主体(Subject)

    SELinux 主要管理的就是进程。

  • 目标(Object)

    主体进程能否访问的目标资源一般就是文件系统。

  • 策略(Policy)

    由于进程与文件数量庞大,因此 SELinux 会依据某些服务来制订基本的访问安全性策略。目前提供三个主要的策略,分别是:

    • targeted:针对网络服务限制较多,针对本机限制较少,是默认的策略。
    • minimum:由 targeted 修订而来,仅针对选择的程序来保护。
    • mls(strict):完整的 SELinux 限制,限制方面较为严格。
  • 安全上下文(Security Context)

    主体能不能访问目标除了策略指定之外,主体与目标的安全上下文必须一致才能够顺利访问。安全上下文有点类似文件系统的 rwx。安全上下文的内容与设置非常重要,如果设置错误某些服务就无法访问文件系统,出现权限不符的错误信息。

    文件的安全上下文记录放置到文件的 inode 内。

    使用 ls -Z 命令可以查看安全上下文:

    [root@101c7 bin]$ ll -Z
    -rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 error.log
    -rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 nomarl.log

    安全上下文主要用冒号分为四个字段:身份识别,角色,类型,灵敏度。

  • 身份标识(Identify)

    相当于账号方面的身份标识,常见的有:

    • unconfined_u:表示不受 SELinux 限制的用户,也就是说该文件来自不受限的程序产生。
    • system_u:表示系统程序方面的标识,通常是系统自己产生的文件。

    系统或网络服务产生的大部分数据是 system_u,用户通过 bash 创建的文件,大多是不受限的 unconfined_u 身份。

  • 角色(Role)

    通过角色字段,我们可以知道这个数据是属于程序,文件资源还是代表用户,常见的有:

    • object_r:代表文件或目录;
    • system_r:代表进程,一般用户也会被指定为 system_r。

    角色字段最后面使用 _r 来结尾。

  • 类型(Type)

    在默认 targeted 策略中最重要的是类型字段,一个主体进程能不能读取到这个文件资源与类型字段有关。类型字段与文件与进程的定义不太相同,分别是:

    • type:在文件资源(Object)上面称为类型(Type);

    • domain:在主体程序(Subject)中则称为域(domain);

    domain 需要与 type 搭配,程序才能够顺利读取文件资源。

类型 domain 与 type

以 cron 程序举例看程序的域和文件的类型之间的关系.

先查询 cron 进程的安全上下文内容:

[root@101c7 thin1]$ ps -eZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 885 ?  00:00:02 crond
system_u:system_r:crond_t:s0-s0:c0.c1023 27679 ? 00:00:00 atd

cron 关联进程有两个,但它们的安全上下文一样:

  • 身份标识:角色为 system_u:system_r,说明 crond 和 atd 为系统进程.

  • 最重要的安全上下文类型为 crond_t 域.

再查询可执行文件 crond,crontab 和配置文件目录/etc/cron.d 的安全上下文:

[root@101c7 thin1]$ ll -Zd /usr/sbin/crond /etc/crontab /etc/cron.d
-rwxr-xr-x. root root system_u:object_r:crond_exec_t:s0 /usr/sbin/crond
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/crontab
drwxr-xr-x. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d

安全上下文详情如下:

  • 身份标识都是系统进程

  • 配置目录/etc/cron.d 的类型为 system_cron_spool_t,

  • 可执行文件 crond 的类型为 crond_exec_t,

  • 可执行文件 crontab 的类型为 system_cron_spool_t.

分析可得以下结论:

  • 当执行类型为 crond_exec_t 的二进制文件/usr/sbin/crond 后,这个程序产生类型为 crond_t 域的进程 crond.

  • 而 crond_t 域类型进程能读取 system_cron_spool_t 类型的资源文件.

  • 域与类型对应关系已经被定义好,所以如果类型设置错误,即使文件 rwx 权限全开程序也读不了目标资源.

  • 最终能不能读取到正确数据,还要看 rwx 是否符合 Linux 权限的规范.

SELinux 启动管理

目前 SELinux 支持三种模式,分别是:

  • enforcing:强制模式,代表 SELinux 正在运行中,且已经正确开始限制 domain/type 了。
  • permissive:宽容模式,代表 SELinux 正在运行中,不过仅有警告日志记录,并没有实际限制。这种模式可作调试用。
  • disabled:关闭。

查询 SELinux 模式通过命令 getenforce

[root@101c7 bin]$ getenforce
Enforcing

查询 SELinux 的策略使用 sestatus 来查看,支持参数为:

参数 说明
-v 检查列于 /etc/sestatus.conf 内的文件与程序的安全上下文内容
-b 将目前策略的规则布尔值列出,即某些规则是否启动

列出目前的 SELinux 使用策略:

[root@101c7 thin1]$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      31

SELinux 的配置文件是 /etc/selinux/config

[root@101c7 bin]$ cat /etc/selinux/config 
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted 

里面设置了 SELinux 的模式与策略。如果改变策略或模式开关需要重启系统。

由 enforcing 变为 permissive 模式可以在系统运行时切换。

切换 SELinux 模式使用 setenforce 命令,0 为宽容模式,1 为强制模式:

[root@101c7 bin]$ setenforce 0
[root@101c7 bin]$ getenforce
Permissive

有时从 disabled 切换成 enforcing 模式后,系统必须针对文件写入安全标签(SELinux Label),会有一堆服务无法启动,提示权限错误。可以在 Permissive 状态下使用 restorecon -Rv / 来重新还原 SELinux 的类型。

SELinux 规则统计

查询规则启动状态可以使用 sestatus -bgetsebool -a 命令:

[root@101c7 thin1]$ sestatus -b
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      31

Policy booleans:
abrt_anon_write                             off
abrt_handle_event                           off
abrt_upload_watch_anon_write                on
antivirus_can_scan_system                   off
...
[root@101c7 thin1]$ getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
...

要查询规则具体内容,需要安装 setools 工具套件:

[root@101c7 thin1]$ yum install -y setools-console-*

使用 seinfo 工具查询规则统计信息:

[root@101c7 thin1]$ seinfo

Statistics for policy file: /sys/fs/selinux/policy
Policy Version & Type: v.31 (binary, mls)

   Classes:           130    Permissions:       272
   Sensitivities:       1    Categories:       1024
   Types:            4793    Attributes:        253
   Users:               8    Roles:              14
   Booleans:          316    Cond. Expr.:       362
   Allow:          107834    Neverallow:          0
   Auditallow:        158    Dontaudit:       10022
   Type_trans:      18153    Type_change:        74
   Type_member:        35    Role allow:         37
   Role_trans:        414    Range_trans:      5899
   Constraints:       143    Validatetrans:       0
   Initial SIDs:       27    Fs_use:             32
   Genfscon:          103    Portcon:           614
   Netifcon:            0    Nodecon:             0
   Permissives:         0    Polcap:              5

可以看到当前 v31 版本的规则(Booleans)总共有 316 条。此外 seinfo 加参数还可以查询其他种类信息:

参数 说明
–all 列出所有信息
-u 列出所有身份标识种类
-r 列出所有角色种类
-t 列出所有类别种类
-b 列出所有规则种类

SELinux 规则查询

使用 sesearch 命令可以用来搜索规则。命令语法:sesearch [-A] [-s 主体程序类型] [-t 目标类别] [-b 规则]

主要参数:

参数 说明
-A 列出后面的数据中,允许"读取或放行"的相关数据
-s 后面接域类型,例如 -s httpd_t
-t 后面接类别,例如 -t user_home_dir_t
-b 后面接 SELinux 规则,如 -b httpd_enable_ftp_server

例如找出 crond_t 这个域类型的进程能够读取的文件类型:

[root@101c7 thin1]$ sesearch -A -s crond_t | grep spool
   allow crond_t system_cron_spool_t : dir { ioctl read getattr lock search open } ; 
   allow crond_t var_spool_t : file { ioctl read getattr lock open } ; 
   allow daemon user_cron_spool_t : file { ioctl read write getattr lock append } ;

allow 后面接进程域类型和文件类型,冒号后表明资源类型,大括号 {} 内为允许的动作。

例如第一条表示允许 crond_t 域类型进程对 system_cron_spool_t 类型的文件夹读取,打开,查看属性等操作。

再使用 semanage 查一下 httpd_enable_homedirs 这条规则的含义:

[root@101c7 thin1]$ semanage boolean -l | grep httpd_enable_homedirs
SELinux boolean                State  Default Description
httpd_enable_homedirs          (off  ,  off)  Allow httpd to enable homedirs

在 description 一列介绍了规则内容是允许 httpd 程序去读取使用者主文件夹。

再使用 sesearch 来搜索 httpd_enable_homedirs 规则里面具体规定:

[root@101c7 thin1]$ sesearch -A -b httpd_enable_homedirs
Found 77 semantic av rules:
   allow httpd_t user_home_dir_t : lnk_file { read getattr } ; 
   allow httpd_suexec_t user_home_dir_t : dir { getattr search open } ; 
   allow httpd_t nfs_t : lnk_file { read getattr } ; 
   allow httpd_sys_script_t nfs_t : file { ioctl read geta

共有 77 条相关规定,如果规则没有启用,httpd_t 域类型进程就无法读取使用者主文件夹。这是由 sestatus 查到的 Policy deny_unknown status 设置规定默认抵挡未知的主题程序。

SELinux 规则开闭

当确认要关闭或开启某条规则可以使用 setsebool 来管理。例如启动 httpd_enable_homedirs 规则:

[root@101c7 thin1]$ getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
[root@101c7 thin1]$ setsebool -P httpd_enable_homedirs 1
[root@101c7 thin1]$ getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

安全上下文修改

修改文件的安全上下文可以使用 chcon 命令。命令格式:chcon [-R] [-t type] [-u user] [-r role] 文件

参数说明如下:

参数 说明
-R 递归修改目录
-t 接安全上下文的类型字段,如 thhpd_sys_content_t
-u 接身份识别
-r 接角色
-v 显示详细结果
–reference=参考文件 用参考文件作为范例修改目标文件的安全上下文

例如修改 1.txt 文件的安全上下文类型为 net_conf_t

[root@101c7 thin1]$ chcon -v -t net_conf_t 1.txt
changing security context of ‘1.txt’
[root@101c7 thin1]$ ll -Z 1.txt 
-rw-r--r--. root root unconfined_u:object_r:net_conf_t:s0 1.txt

另一种修改方式,例如将 /etc/shadow 的安全上下文套用到 1.txt 文件上:

[root@101c7 thin1]$ chcon -v --reference=/etc/shadow 1.txt
changing security context of ‘1.txt’
[root@101c7 thin1]$ ll -Z /etc/shadow 1.txt 
-rw-r--r--. root root system_u:object_r:shadow_t:s0    1.txt
----------. root root system_u:object_r:shadow_t:s0    /etc/shadow

安全上下文恢复

如果想要将目录的安全上下文类型错误恢复到默认值,可以使用 restorecon 命令。

restorecon 命令可用 -R 来递归修改目录,例如恢复 /etc/cron.d/ 下面的文件安全上下文类型为默认值:

[root@101c7 thin1]$ mv 1.txt /etc/cron.d/ ; ll -Z /etc/cron.d/
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 0hourly
-rw-r--r--. root root system_u:object_r:shadow_t:s0    1.txt
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 raid-check
[root@101c7 thin1]$ restorecon -Rv /etc/cron.d ; ll -Z /etc/cron.d/
restorecon reset /etc/cron.d/1.txt context system_u:object_r:shadow_t:s0->system_u:object_r:system_cron_spool_t:s0
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 0hourly
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 1.txt
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 raid-check

可以看到移动到/etc/cron.d/ 的文件 1.txt 安全上下文类型从 shadow_t 恢复成了 system_cron_spool_t

安全上下文默认值修改

之所以用 restorecon 命令可以恢复目录内的文件安全上下文类型,是因为目录和文件有个安全上下文默认值设定。

可以通过 semanage 命令来查询与修改安全上下文类型默认值。

常用参数:

参数 说明
fcontext 用在安全性上下文标签(默认值)方面的用途,-l 查询
-a 增加,可以增加一些目录的默认安全上下文类型设置
-m 修改
-d 删除

例如查询 /etc/cron.d 目录的默认值:

[root@101c7 thin1]$ semanage fcontext -l | grep -E "/etc/cron\\\.d\("
/etc/cron\.d(/.*)?                                 all files          system_u:object_r:system_cron_spool_t:s0 

修改 ftp_port_t 端口策略,增加一个端口 955 作为 FTP 端口:

[root@101c7 home]$ semanage port -a -t ftp_port_t -p tcp 955; semanage port -l | grep 955
ftp_port_t                     tcp      955, 21, 989, 990

修改目录 /root/myps 的安全上下文类型为 system_cron_spool_t

[root@101c7 ~]$ ll -dZ /root/myps/* /root/myps /root 
dr-xr-x---. root root system_u:object_r:admin_home_t:s0 /root
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 /root/myps
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /root/myps/ip.txt
[root@101c7 ~]$ semanage fcontext -a -t system_cron_spool_t "/root/myps(/.*)?"
[root@101c7 ~]$ ll -dZ /root/myps/* /root/myps /root 
dr-xr-x---. root root system_u:object_r:admin_home_t:s0 /root
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 /root/myps
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /root/myps/ip.txt
[root@101c7 ~]$ semanage fcontext -l | grep -E "/root/myps\("
/root/myps(/.*)?                                   all files          system_u:object_r:system_cron_spool_t:s0 
[root@101c7 ~]$ restorecon -Rv /root/myps
restorecon reset /root/myps context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
restorecon reset /root/myps/ip.txt context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
[root@101c7 ~]$ ll -dZ /root/myps/* /root/myps
drwxr-xr-x. root root unconfined_u:object_r:system_cron_spool_t:s0 /root/myps
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /root/myps/ip.txt

修改了以后再用 restorecon 命令还原默认值,所有其目录和文件的安全上下文类型变成了新设置的值。

SELinux 日志查询

首先检查用于 SE 日志记录的服务 auditd(setroubleshoot)是否启动中:

[root@101c7 ~]$ systemctl status auditd
● auditd.service - Security Auditing Service
   Loaded: loaded (/usr/lib/systemd/system/auditd.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2021-09-09 15:08:51 EDT; 1 weeks 1 days ago

默认情况下系统会自动启动。这里使用 httpd 服务来测试:

[root@101c7 bin]$ ps aux -Z | grep http
system_u:system_r:httpd_t:s0    root      60730  0.0  0.1 230444  5204 ?        Ss   10:30   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    60731  0.0  0.0 230576  3732 ?        S    10:30   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    60732  0.0  0.0 230576  3736 ?        S    10:30   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    60733  0.0  0.0 230576  3736 ?        S    10:30   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    60734  0.0  0.0 230576  3720 ?        S    10:30   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    60735  0.0  0.0 230576  3732 ?        S    10:30   0:00 /usr/sbin/httpd -DFOREGROUND

查询得知 httpd 的进程安全上下文类型为 httpd_t 域。增加首页内容:

[root@101c7 bin]$ echo "Today is 9.14" > /var/www/html/index.html

通过浏览器访问服务器的 IP 地址可看到刚建页面。此时浏览器会通过 httpd 这个进程去读取 /var/www/html/index.html 文件。

查询一下 index.html 文件的安全上下文:

[root@101c7 bin]$ ll -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html

看到文件安全上下文类型为 httpd_sys_content_t,查询一下 httpd_t 域类型与它的关系:

[root@101c7 ~]$ sesearch -A -s httpd_t | grep httpd_sys_content_t
   allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ; 
   allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ; 
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock map open } ; 
   allow daemon httpd_sys_content_t : dir { getattr search open } ; 
   allow httpd_t httpd_sys_content_t : dir { ioctl read write getattr lock add_name remove_name search open } ; 

接着测试一下错误的安全上下文类型,可以将网页数据在 /root 文件夹下面生成,再移动到 /var/www/html/

[root@101c7 bin]$ echo "Now is 22:41" > index.html
[root@101c7 bin]$ mv index.html /var/www/html/
mv: overwrite a€?/var/www/html/index.htmla€?? y

再次访问 index.html,结果变成了 Forbidden 拒绝访问:

[root@101c7 home]$ curl 127.0.0.1/index.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /index.html
on this server.</p>
</body></html>

把 Selinux 转换工作模式再访问试试:

[root@101c7 home]$ setenforce 0
[root@101c7 home]$ curl 127.0.0.1/index.html
Now is 23:41
[root@101c7 home]$ setenforce 1

切换 SELinux 到警告模式后访问 index.html 正常,可以确定是 SELinux 的问题。看下 index.html 的安全上下文:

[root@101c7 bin]$ ll -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /var/www/html/index.html

安全上下文类型为 admin_home_t,查询一下与 httpd_t 的关系:

[root@101c7 ~]$ sesearch -A -s httpd_t | grep admin_home_t
   allow domain admin_home_t : dir { getattr search open } ; 
   allow domain admin_home_t : lnk_file { read getattr } ; 

结果显示没有结果,也就默认会被拒绝掉。到 /var/log/messages 下面查看下日志,果然有记录:

[root@101c7 ~]$ tail -f /var/log/messages
Sep 18 08:40:32 101c7 setroubleshoot: failed to retrieve rpm info for /var/www/html/index.html
Sep 18 08:40:32 101c7 setroubleshoot: SELinux is preventing httpd from getattr access on the file /var/www/html/index.html. For complete SELinux messages run: sealert -l c7d023db-6ae4-4397-9a6b-5b1061f5a9fa

来自 setroubleshoot 的报告指出 SELinux 拒绝了 httpd 读取 /var/www/html/index.html 的请求,运行 sealert -l 命令来查看报告。看看 sealert 给出的报告:

[root@101c7 ~]$ sealert -l c7d023db-6ae4-4397-9a6b-5b1061f5a9fa
SELinux is preventing httpd from getattr access on the file /var/www/html/index.html.

*****  Plugin restorecon (99.5 confidence) suggests   ************************

If you want to fix the label. 
/var/www/html/index.html default label should be httpd_sys_content_t.
Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions to access a parent directory in which case try to change the following command accordingly.
Do
# /sbin/restorecon -v /var/www/html/index.html

*****  Plugin catchall (1.49 confidence) suggests   **************************

If you believe that httpd should be allowed getattr access on the index.html file 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 'httpd' --raw | audit2allow -M my-httpd
# semodule -i my-httpd.pp


Additional Information:
Source Context                system_u:system_r:httpd_t:s0
Target Context                unconfined_u:object_r:admin_home_t:s0
Target Objects                /var/www/html/index.html [ file ]
Source                        httpd
Source Path                   httpd
Port                          <Unknown>
Host                          101c7
Source RPM Packages           
Target RPM Packages           
Policy RPM                    selinux-policy-3.13.1-268.el7_9.2.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Host Name                     101c7
Platform                      Linux 101c7 3.10.0-1160.41.1.el7.x86_64 #1 SMP Tue
                              Aug 31 14:52:47 UTC 2021 x86_64 x86_64
Alert Count                   6
First Seen                    2021-09-18 08:39:24 EDT
Last Seen                     2021-09-18 08:52:01 EDT
Local ID                      c7d023db-6ae4-4397-9a6b-5b1061f5a9fa

Raw Audit Messages
type=AVC msg=audit(1631969521.111:5038): avc:  denied  { getattr } for  pid=60731 comm="httpd" path="/var/www/html/index.html" dev="dm-0" ino=33829126 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file permissive=0


Hash: httpd,httpd_t,admin_home_t,file,getattr

报告指出报错原因 99.5% 是因为:index.html 文件的默认 label 应该为 httpd_sys_content_t,这是我们已经知道的错误原因,并且下面给出了解决办法,运行命令 /sbin/restorecon -v /var/www/html/index.html 来修复这一错误。

接着报告提示 1.49% 的可能原因是遇到了 bug,可以运行命令 ausearch -c 'httpd' --raw | audit2allow -M my-httpdsemodule -i my-httpd.pp 来报告错误。

先试下后面这条命令:

[root@101c7 ~]$ ausearch -c 'httpd' --raw | audit2allow -M my-httpd
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i my-httpd.pp

[root@101c7 ~]$ semodule -i my-httpd.pp

然后在浏览器访问 http 服务器,惊讶地发现可以访问了,日志 /var/log/messages 里面没有报错,显然最后一条命令起了作用。现在通过在 /root 下面新建 index.html 再转移到 /var/www/html/ 的方式也不会拒绝访问了。

查询一下 httpd_tadmin_home_t 的关系:

[root@101c7 home]$ sesearch -A -s httpd_t | grep admin_home_t
   allow domain admin_home_t : dir { getattr search open } ; 
   allow domain admin_home_t : lnk_file { read getattr } ; 
   allow httpd_t admin_home_t : file { read getattr open } ; 

果然系统给我们新建了一条策略来解决这一问题。由此可见,只要知道分析错误日志,SELinux 的 targeted 模式还是很灵活的,不必急着装好系统后就把 SELinux 关掉。

另外 /var/log/audit 下面也有日志,不过有用的信息并不多:

[root@101c7 home]$ audit2why < /var/log/audit/audit.log 
type=AVC msg=audit(1631972305.031:5057): avc:  denied  { open } for  pid=60735 comm="httpd" path="/var/www/html/index.html" dev="dm-0" ino=50435189 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:home_root_t:s0 tclass=file permissive=1

        Was caused by:
                Missing type enforcement (TE) allow rule.

                You can use audit2allow to generate a loadable module to allow this access.