DAC(自主式存取控制):当某个程序对文件进行存取时,系统会依据程序的拥有者与文件的rwx权限来决定有无存取的能力,这种存取文件的方式成为自助式存取控制。由于root具有最高权限,如果该程序属于root,在该模式下被攻破后会有极大安全问题。一旦rwx权限未谨慎开放(例如对所有人开启rwx),控制该程序的用户也就可以对文件进行存取操作。

MAC(委任式存取操作):以政策规则制定特定程序读取特定文件。即使获取到root执行的程序控制权,所能获取的权限因规则限制不一定能具备所有root的权限(即无法操作其他程序的目录文件)。

使用 DAC/MAC 产生的不同结果,以 Apache 为例说明

如上图所示未DAC和MAC的对比,在DAC模式下,一旦httpd服务被拿下,攻击者便可以访问到所有文件;在MAC模式下,攻击者仅能访问对httpd服务开放的网站目录,无法访问其他重要文件。

SELinux,全称Security Enhanced Linux,安全增强的linux的意思。SELinux是通过MAC来控制程序的。

运行模式

主体(Subject):SELinux的主题就是程序

目标(Object):程序能否存取的目标资源是文件系统

政策(Policy):由于程序和文件数量庞大,所以SELinux会依据服务来指定基本的存取安全性政策。三个主要的政策:

  • targeted:针对网络服务限制较多,针对本机限制较少,是默认的政策;
  • minimum:由 target 修订而来,仅针对选择的程序来保护;
  • mls:完整的 SELinux 限制,限制方面较为严格。

安全性本文(security context):主体与目标的安全性本文必须一致才能够顺利存取。 有点类似文件系统的 rwx , 如果设置错误,你的某些程序就无法存取文件系统,会一直出现“权限不符”的错误。

SELinux 运行的各元件之相关性

如上图所示为Selinux的流程,先通过政策规则的放行,然后再进行安全性本文对比,如果全部通过SELinux的工作到此结束,最后一步还有DAC模式下的权限流程。

安全性本文

安全性本文存在于主体程序中与目标文件资源中。程序在内存内,所以安全性本文可以存入是没问题。 由于安全性本文是放置到文件的 inode 内的,因此主体程序想要读取目标文件资源时,同样需要读取inode,这inode内就可以比对安全性本文以及 rwx 等权限值是否正确,而给予适当的读取权限依据。

# ls -Z
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 CentosManager

如上面的指令输出所示,安全性本文主要取三个字段,这三个字段的含义是:

Identify:role:type
身份识别:角色:类型

身份识别:相当于账号方面的身份识别,具体有以下几种类型:

  • unconfined_u:不受限的用户,也就是说,该文件来自于不受限(不受 SELinux 所限制的 bash 程序所产生的文件)的程序所产生的。
  • system_u:系统用户,大部分就是系统自己产生的文件。

角色:这个字段可以告诉我们数据是属于程序、文件还是使用者,具体有以下几种类型:

  • object_r:代表的是文件或目录等文件资源;
  • system_r:代表的是程序,一般使用者也会被指定成为 system_r

类型:在默认的 targeted 政策中, Identify 与 Role 字段基本上是不重要的,重要的在于这个类型字段。基本上,一个主体程序能不能读取到这个文件资源,与这个字段有关。而类型字段在文件与程序的定义不太相同,分别是:

  • type:在文件资源 (Object) 称为类型 (Type);
  • domain:在主体程序 (Subject) 称为领域 (domain)
# ps -eZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 681 ? 00:00:00 crond

# ll -Zd /usr/sbin/crond /etc/crontab /etc/cron.d /var/spool/cron
drwxr-xr-x. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/crontab
-rwxr-xr-x. root root system_u:object_r:crond_exec_t:s0 /usr/sbin/crond
drwx------. root root system_u:object_r:user_cron_spool_t:s0 /var/spool/cron

如上查询安全性本文命令所示,当执行/usr/sbin/crond后,程序的domain类型是crond_t,它可以读取的配置文件则为 system_cron_spool_t 这种的类型。因此/etc/crontab, /etc/cron.d 以及 /var/spool/cron都是相关的 SELinux 类型。但最终文件是否读取还需要看rwx的权限限制。

# echo "10 * * * *  root sleep 60s" >> /root/crondtest
# echo "10 * * * *  root sleep 60s" >> /etc/cron.d/crondtest2
# mv /root/crondtest /etc/cron.d
# ll -Z /etc/cron.d/*
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d/0hourly
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest2
# systemctl restart crond
# tail /var/log/cron
Nov 11 13:38:30 localhost crond[8794]: ((null)) Unauthorized SELinux context=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 file_context=unconfined_u:object_r:admin_home_t:s0 (/etc/cron.d/crondtest)
Nov 11 13:38:30 localhost crond[8794]: (root) FAILED (loading cron table)

如上面的命令所示,在不同文件下创建crond任务时,由于安全性本文与文件存放位置的安全性本文不一致,重启服务读取配置时候会出现SELinux告警。如果纠正告警在后面讲述。

SELinux模式

enforcing:强制模式,代表SELinux运行中,且已经正确的开始限制domain/type;

permissive:宽容模式:代表SELinux运行中,仅会产生告警,不会实际限制domain/type的存取。

disabled:关闭SELinux运行。

SELinux 的三种类型与实际运行流程图示意

如上图所示为三种模式的流程图。

获取当前SELinux模式:

# getenforce 
Enforcing

获取SELinux政策:

# sestatus 
SELinux status:                 enabled    #是否启动SELinux
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   #是否含有MLS的模式机制
Policy deny_unknown status:     allowed   #是否默认抵挡未知的主题程序
Max kernel policy version:      31

SELinux配置文件:

# sestatus [-vb]
选项与参数:
-v  :检查列于 /etc/sestatus.conf 内的文件与程序的安全性本文内容;
-b  :将目前政策的规则布林值列出,即某些规则 (rule) 是否要启动(0/1)
# cat /etc/selinux/config 
SELINUX=enforcing   #模式配置(enforcing|disable|permissive)
SELINUXTYPE=targeted   #政策配置(targeted|mls|minimum)

SELinux可以在运行状态下随时切换enforcing和permissive模式。但是更改政策后需要重启主机。由enfrocing或permissive更改成disable或者逆操作也要重启主机。

# setenforce [0|1]
选项与参数:
0 :转成 permissive 宽容模式;
1 :转成 Enforcing 强制模式
# getenforce 
Enforcing
# setenforce 0
# getenforce 
Permissive
# setenforce 1
# getenforce 
Enforcing

规则管理

查询规则状态

# getsebool [-a] [规则的名称]
选项与参数:
-a  :列出目前系统上面的所有SELinux规则的布林值为打开或关闭值
# getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
auditadm_exec_content --> on
......

查看政策统计数据

# yum install setools-console -y
# seinfo [-trub]
选项与参数:
-u  :列出 SELinux 的所有身份识别 (user) 种类
-r  :列出 SELinux 的所有角色 (role) 种类
-t  :列出 SELinux 的所有类别 (type) 种类
-b  :列出所有规则的种类
# 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:            4794    Attributes:        258
   Users:               8    Roles:              14
   Booleans:          316    Cond. Expr.:       362
   Allow:          107901    Neverallow:          0
   Auditallow:        158    Dontaudit:       10082
   Type_trans:      18154    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

查询各个规则规范的主体程序能够读取的文件的SELinux Type

# sesearch [-A] [-s 主体类别] [-t 目标类别] [-b 布林值]
选项与参数:
-A  :列出后面数据中,允许“读取或放行”的相关数据
-t  :后面还要接类别,例如 -t httpd_t
-b  :后面还要接SELinux的规则,例如 -b httpd_enable_ftp_server
查找crond_t这个主体程序能够读取的文件的SELinux Type
# 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 crond_t cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
   allow crond_t cron_spool_t : dir { ioctl read write getattr lock add_name remove_name search open } ; 
   allow crond_t user_cron_spool_t : dir { ioctl read write getattr lock add_name remove_name search open } ; 
   allow daemon user_cron_spool_t : file { ioctl read write getattr lock append } ; 
   allow crond_t var_spool_t : dir { ioctl read getattr lock search open } ; 
   allow crond_t system_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
   allow crond_t user_cron_spool_t : lnk_file { read getattr } ; 
   allow crond_t user_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
   allow crond_t system_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
   allow crond_t user_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
如上所示crond_t可以读取system_cron_spool的文件、目录类型等

查看为什么crond_t不可以读取刚才的实验文件crondtest
# ll -Z /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/crondtest
# sesearch -A -s crond_t | grep "admin_home_t"
   allow crond_t admin_home_t : lnk_file { read getattr } ; 
   allow userdom_filetrans_type admin_home_t : lnk_file { read getattr } ; 
   allow domain admin_home_t : dir { getattr search open } ; 
   allow userdom_filetrans_type admin_home_t : dir { ioctl read write getattr lock add_name remove_name search open } ; 
   allow crond_t admin_home_t : dir { ioctl read getattr lock search open } ; 
   allow domain admin_home_t : lnk_file { read getattr } ; 
由上所示,没有定义admin_home_t的类型的文件读取规则

查看规则信息

# yum provides semanage 
# yum -y install policycoreutils-python.x86_64
# getsebool -a| grep "httpd"
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
......
# semanage boolean -l |grep "httpd_can_sendmail"
httpd_can_sendmail             (off  ,  off)  Allow httpd to can sendmail
从以上信息可知httpd_can_sendmail的功能是允许httpd发送邮件


# sesearch -A -b  httpd_can_sendmail
Found 50 semantic av rules:
   allow httpd_suexec_t mta_exec_type : file { ioctl read getattr map execute execute_no_trans open } ; 
   allow httpd_sys_script_t bin_t : dir { getattr search open } ; 
   allow system_mail_t httpd_sys_script_t : fifo_file { ioctl read write getattr lock append } ; 
   allow httpd_t spamc_exec_t : file ioctl ; 
   allow httpd_t spamc_exec_t : file { ioctl read getattr map execute execute_no_trans open } ; 
......
从以上信息可知httpd程序可操作哪些TYPE的文件、目录

修改规则状态

# setsebool  [-P]  “规则名称” [0|1]
选项与参数:
-P  :直接将设置值写入配置文件,该设置数据未来会生效的!
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs 1
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

安全性本文管理

手动修改文件的type

# chcon [-R] [-t type] [-u user] [-r role] 文件
# chcon [-R] --reference=范例档 文件
选项与参数:
-R:连同该目录下的次目录也同时修改;
-t:后面接安全性本文的类型字段;
-u:后面接身份识别;
-r:后面街角色;
-v:将变动的结果列出来;
--reference=范例档:拿某个文件当范例来修改后续接的文件的类型
订正crondtest文件的type,然后重启服务观察日志是否无报错
# ll -Z /etc/cron.d/*
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d/0hourly
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest2
# chcon -v -t system_cron_spool_t /etc/cron.d/crondtest
changing security context of ‘/etc/cron.d/crondtest’
# ll -Z /etc/cron.d/*
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d/0hourly
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest2

自动订正文件的type

# restorecon [-Rv] 文件或目录
选项与参数:
-R  :连同次目录一起修改;
-v  :显示详情
# chcon -v -t admin_home_t /etc/cron.d/crondtest
changing security context of ‘/etc/cron.d/crondtest’
# ll -Z /etc/cron.d/*
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d/0hourly
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest2
# restorecon -Rv /etc/cron.d
restorecon reset /etc/cron.d/crondtest context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
# ll -Z /etc/cron.d/*
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d/0hourly
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /etc/cron.d/crondtest2

查询目录的默认type(restorecon就是以默认type为基准进行订正的)

#  semanage fcontext -l | grep -E '^/etc/cron\\.d\W+'
/etc/cron\.d(/.*)?                                 all files          system_u:object_r:system_cron_spool_t:s0 

修改目录的默认type

# semanage fcontext -{a|d|m}  file_spec
选项与参数:

-a :增加;
-m :修改;
-d :删除
# mkdir /opt/mycron
# cp /etc/cron.d/crondtest /opt/mycron/
# ll -dZ /opt/mycron /opt/mycron/crondtest
drwxr-xr-x. root root unconfined_u:object_r:usr_t:s0   /opt/mycron
-rw-r--r--. root root unconfined_u:object_r:usr_t:s0   /opt/mycron/crondtest
# semanage fcontext -l | grep   "^/opt[^/]"
/opt                                               all files          system_u:object_r:usr_t:s0 
# semanage fcontext -a -t system_cron_spool_t "/opt/mycron(/.*)?"
# semanage fcontext -l | grep   "^/opt/mycron"
/opt/mycron(/.*)?                                  all files          system_u:object_r:system_cron_spool_t:s0 
# restorecon -Rv /opt/mycron/
restorecon reset /opt/mycron context unconfined_u:object_r:usr_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
restorecon reset /opt/mycron/crondtest context unconfined_u:object_r:usr_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
# ll -dZ /opt/mycron /opt/mycron/crondtest 
drwxr-xr-x. root root unconfined_u:object_r:system_cron_spool_t:s0 /opt/mycron
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /opt/mycron/crondtest

setroubleshoot

setroubleshoot服务会将SELinux错误写入日志,并给与订正建议。先由 auditd 去调用 audispd 服务,然后 audispd 服务去启动 sedispatch 程序,sedispatch 再将原本的 auditd 讯息转成 setroubleshootd 的讯息,进一步储存。

# yum install setroubleshoot-server setroubleshoot -y
# service  auditd stop
Stopping logging:                                          [  OK  ]
# service  auditd start
Redirecting to /bin/systemctl start auditd.service

例如vsftpd服务中访问root创建的文件会出现以下SELinux告警

Nov 11 15:52:54 localhost setroubleshoot: SELinux is preventing /usr/sbin/vsftpd from getattr access on the file /home/ftptest/test.txt. For complete SELinux messages run: sealert -l 3d375d2b-2bad-4501-a640-aba345e601e8
Nov 11 15:52:54 localhost python: SELinux is preventing /usr/sbin/vsftpd from getattr access on the file /home/ftptest/test.txt.#012#012*****  Plugin restorecon (92.2 confidence) suggests   ************************#012#012If you want to fix the label. #012/home/ftptest/test.txt default label should be user_home_t.#012Then 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.#012Do#012# /sbin/restorecon -v /home/ftptest/test.txt#012#012*****  Plugin catchall_boolean (7.83 confidence) suggests   ******************#012#012If you want to allow ftpd to full access#012Then you must tell SELinux about this by enabling the 'ftpd_full_access' boolean.#012#012Do#012setsebool -P ftpd_full_access 1#012#012*****  Plugin catchall (1.41 confidence) suggests   **************************#012#012If you believe that vsftpd should be allowed getattr access on the test.txt file by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'vsftpd' --raw | audit2allow -M my-vsftpd#012# semodule -i my-vsftpd.pp#012

可以查看告警详细情况

# sealert -l 3d375d2b-2bad-4501-a640-aba345e601e8
SELinux is preventing /usr/sbin/vsftpd from getattr access on the file /home/ftptest/test.txt.

*****  Plugin restorecon (92.2 confidence) suggests   ************************

If you want to fix the label. 
/home/ftptest/test.txt default label should be user_home_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 /home/ftptest/test.txt

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

If you want to allow ftpd to full access
Then you must tell SELinux about this by enabling the 'ftpd_full_access' boolean.

Do
setsebool -P ftpd_full_access 1

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

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



Additional Information:
Source Context                system_u:system_r:ftpd_t:s0-s0:c0.c1023
Target Context                unconfined_u:object_r:admin_home_t:s0
Target Objects                /home/ftptest/test.txt [ file ]
Source                        vsftpd
Source Path                   /usr/sbin/vsftpd
Port                          <Unknown>
Host                          MiWiFi-R4AC-srv
Source RPM Packages           vsftpd-3.0.2-29.el7_9.x86_64
Target RPM Packages           
Policy RPM                    selinux-policy-3.13.1-268.el7.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Host Name                     MiWiFi-R4AC-srv
Platform                      Linux MiWiFi-R4AC-srv 3.10.0-1160.el7.x86_64 #1
                              SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64
Alert Count                   2
First Seen                    2021-11-11 15:51:23 CST
Last Seen                     2021-11-11 15:52:51 CST
Local ID                      3d375d2b-2bad-4501-a640-aba345e601e8

Raw Audit Messages
type=AVC msg=audit(1636617171.719:527): avc:  denied  { getattr } for  pid=17748 comm="vsftpd" path="/home/ftptest/test.txt" dev="dm-2" ino=71 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file permissive=0


type=SYSCALL msg=audit(1636617171.719:527): arch=x86_64 syscall=stat success=no exit=EACCES a0=55c56af77110 a1=55c56af6bee0 a2=55c56af6bee0 a3=a items=0 ppid=17743 pid=17748 auid=4294967295 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=4294967295 comm=vsftpd exe=/usr/sbin/vsftpd subj=system_u:system_r:ftpd_t:s0-s0:c0.c1023 key=(null)

Hash: vsftpd,ftpd_t,admin_home_t,file,getattr

从上面我们可以得到三种订正建议以及符合性,结合情况分析第一种最为适用