图源:
什么是SELinux
SELinux全称Security Enhanced LInux,它是一个由NSA(美国国家安全局)发起的,旨在增强Linux安全特性的一个额外的内核模块。
最初SELinux诞生的原因是NSA发现虽然Linux本身的权限管理已经做的很不错了,如果是有经验的系统管理员负责Linux主机的日常使用和维护,并不会出现致命的漏洞。但是如果是一般用户进行管理和维护,很可能就不是那么一回事了,比如之前不是很懂Linux的时候,我就随意更改测试服务器上的文件权限,尤其是为了解决权限问题,经常会把代码文件的权限设置为777
,这显然是一种错误和会带来潜在安全风险的操作。
为了解决这个问题,NSA在原来Linux的文件权限控制的基础之上,增加了一层安全特性,以为文件权限管理提供额外的安全保护,这就是SELinux。
更多关于SELinux的内容可以阅读 http://www.nsa.gov/research/selinux/
事实上,对于文件系统的权限管理,大致可以分为两种不同的形式:
-
DAC
传统对文件系统的权限管理方式为DAC(Discretionary Access Control,自主式存取控制),就是由进程的拥有者对文件的访问权限RWX决定是否有相应的操作权限。这种方式有几个缺点:
-
root
有最高权限,可以随意执行任何操作。如果使用root
账号的人经验丰富就是一种优点,但如果不是,则可能会因为某个疏忽的操作带来一些潜在的风险。 -
可以通过命令(如chmod)很容易地改变资源的权限。和上边的原因一样,可能会带来潜在风险。
-
-
MAC
SELinux使用的是MAC(mandatory access control,强制访问控制),在这种访问控制模式下,限制的主体会从用户变为进程或线程,限制的对象是文件、目录、端口等资源。主体和对象各自具有一组安全属性,每当需要进行授权检测时,操作系统会检查主体和对象的安全属性,以决定是否应当授权。
这样就会避免上边的问题,即使是
root
用户,即使将目录修改为777
,只要SELinux处于启用状态,依然可以杜绝某些安全漏洞。更多关于MAC的背景内容可以阅读
MAC和DAC可以用下边的图表表示:
图源:
SELinux的运作模式
SELinux由这几部分组成:
-
主体(Subject)
SELinux中需要管理(限制)的主体是进程或线程。
-
目标(Object)
目标就是文件系统上的资源,比如文件、目录、端口等。
-
策略(Policy)
由于操作系统中存在大量的进程和文件,无法一一管理,所以SELinux通过设定一些策略来进行统一管理,由策略决定哪些进程需要管理,以及如何管理。一个策略中会有多条规则,每条规则可以关闭或开启。策略通过这些规则来详细规定某个服务是否对某些资源具有相关权限。
规则是模块化和可扩展的,新安装的程序可以通过添加新模块的方式添加新的规则。同样的,用户也可以手动添加或删除规则。
在CentOS7中,默认提供三个策略:
-
targeted
:默认使用的策略,针对网络服务限制较多,对于本地服务限制较少。 -
minimum
:以targeted
为基础,仅针对选定的网络服务进行限制。 -
mls
:多级安全保护,会对所有进程进行限制。是最严格最完整的SELinux规则,安全度最高,但不易使用。
-
-
安全上下文(Security Context)
安全上下文分为两部分:主体的和目标的,只有主体和目标的安全上下文对应上,才能具有相应的操作权限。
上面几个组成部分之间的关系可以用下边的图表说明:
图源:
整个流程是这样的:
-
进程会请求SELinux赋予访问权限
-
SELinux会在当前使用的策略中查找进程对应的规则,如果有,就按照规则去检查安全上下文
-
如果安全上下文能对应上,SELinux层面就会放行,进程就可以按照Linux上传统的RWX方式判断是否有操作权限。如果对应不上,SELinux就会拒绝访问。
安全上下文
使用命令ls -Z
可以查看文件和目录的安全上下文:
[icexmoon@xyz ~]$ ls -Z
drwxrwxr-x. icexmoon icexmoon unconfined_u:object_r:home_bin_t:s0 bin
drwxrwxr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 shell_scripts
-rw-rw-r--. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 test.py
-rw-rw-r--. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 tmp.bak.log
-rw-rw-r--. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 tmp.tar
-rw-rw-r--. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 tmp.tar.log
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 公共
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 模板
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 视频
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 图片
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 文档
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 下载
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 音乐
drwxr-xr-x. icexmoon icexmoon unconfined_u:object_r:user_home_t:s0 桌面
其中unconfined_u:object_r:home_bin_t:s0
就是SELinux中目标的上下文,字段以:
分隔,含义为:
-
user
(用户):主要分为两类:
system_u
为系统服务创建的文件,unconflined_u
为用户进程创建的文件。 -
role
(角色):均为
object_r
表示一个文件 -
type
(类型):这是在
targeted
模式下唯一需要关注的字段,只有主体的类型和目标的类型对应上,才会认为安全上下文匹配上了,进而赋予权限。
进程的安全上下文
类似的,我们也可以查看进程的安全上下文字段:
[icexmoon@xyz ~]$ ps -eZ
LABEL PID TTY TIME CMD
system_u:system_r:init_t:s0 1 ? 00:00:04 systemd
system_u:system_r:kernel_t:s0 2 ? 00:00:00 kthreadd
system_u:system_r:kernel_t:s0 4 ? 00:00:00 kworker/0:0H
system_u:system_r:kernel_t:s0 6 ? 00:00:01 ksoftirqd/0
system_u:system_r:kernel_t:s0 7 ? 00:00:00 migration/0
system_u:system_r:kernel_t:s0 8 ? 00:00:00 rcu_bh
system_u:system_r:kernel_t:s0 9 ? 00:00:01 rcu_sched
system_u:system_r:kernel_t:s0 10 ? 00:00:00 lru-add-drain
system_u:system_r:kernel_t:s0 11 ? 00:00:00 watchdog/0
system_u:system_r:kernel_t:s0 13 ? 00:00:00 kdevtmpfs
system_u:system_r:kernel_t:s0 14 ? 00:00:00 netns
system_u:system_r:kernel_t:s0 15 ? 00:00:00 khungtaskd
...省略...
system_u:system_r:kernel_t:s0 2265 ? 00:00:01 kworker/0:2
system_u:system_r:kernel_t:s0 2307 ? 00:00:00 kworker/0:3
system_u:system_r:sshd_t:s0-s0:c0.c1023 2308 ? 00:00:00 sshd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2316 ? 00:00:00 sshd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2317 pts/0 00:00:00 bash
system_u:system_r:abrt_t:s0-s0:c0.c1023 2339 ? 00:00:00 abrt-dbus
system_u:system_r:ksmtuned_t:s0 2388 ? 00:00:00 sleep
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2389 pts/0 00:00:00 ps
主体(进程)的上下文字段与目标的类似:
-
user
(用户):system_u
为系统服务进程,受到限制。unconfined_u
为不会受到限制的进程,通常为用户开启的(如bash)。 -
role
(角色):system_r
为系统服务进程,受到限制。unconfined_r
为不会受到限制的进程,通常为用户开启的。 -
type
(类型):这是在
targeted
模式下唯一需要关注的字段,只有主体的类型和目标的类型对应上,才会认为安全上下文匹配上了,进而赋予权限。
可以使用crond
这个服务进程进行说明:
[icexmoon@xyz ~]$ ps -eZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 1257 ? 00:00:01 crond
system_u:system_r:crond_t:s0-s0:c0.c1023 1259 ? 00:00:00 atd
[icexmoon@xyz ~]$ ll -dZ /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
可以看到,crond
的type
是crond_t
,而理论上crond
会操作的相关文件(/etc/crontab
)等的相关type
是system_cron_spool_t
和crond_exec_t
,所以在SELinux中必然有相关规则可以让crond_t
这个类型对应到system_cron_spool_t
和crond_exec_t
这两个类型上。
这个过程可以用下图进行表示:
图源:
这可以通过下面的实验进行测试:
[root@xyz ~]# cd ~
[root@xyz ~]# vim checktime
[root@xyz ~]# cat checktime
10 * * * * root sleep 60s
[root@xyz ~]# mv checktime /etc/cron.d
[root@xyz ~]# 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 unconfined_u:object_r:admin_home_t:s0 checktime
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 raid-check
-rw-------. root root system_u:object_r:system_cron_spool_t:s0 sysstat
[root@xyz ~]# systemctl restart crond
[root@xyz ~]# tail /var/log/cron
Aug 30 12:30:02 xyz CROND[2107]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Aug 30 15:30:01 xyz CROND[2247]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Aug 30 15:40:01 xyz CROND[2420]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Aug 30 15:50:02 xyz CROND[2583]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Aug 30 15:51:00 xyz crond[1257]: (CRON) INFO (Shutting down)
Aug 30 15:51:00 xyz crond[2610]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 21% if used.)
Aug 30 15:51:01 xyz crond[2610]: ((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/checktime)
Aug 30 15:51:01 xyz crond[2610]: (root) FAILED (loading cron table)
Aug 30 15:51:01 xyz crond[2610]: (CRON) INFO (running with inotify support)
Aug 30 15:51:01 xyz crond[2610]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
日志中说的很清楚,因为主体(crond
这个服务进程)的类型system_cronjob_t
和目标(/etc/cron.d/checktime
这个配置文件)的类型admin_home_t
对应不上,所以不能通过SELinux授权。
这是因为使用mv
移动文件时会保留了原来的安全上下文而非/etc/cron.d
目录应该有的安全上下文。
模式的启动、关闭与查看
SELinux共有3种模式:
-
Enforcing
:强制模式,表示SELinux正常运行中,会对不符合安全上下文的授权请求进行限制 -
Permissive
:宽容模式,虽然SELinux运行,但是对于不和要求的授权请求,仅会产生警告信息,不会进行实际限制。 -
Disabled
:关闭模式。
这3种模式可以用下图表示:
图源:
如果需要查看当前系统的SELinux处于何种模式:
[root@xyz ~]# getenforce
Enforcing
要查看更多SELinux的相关信息:
[root@xyz ~]# sestatus
SELinux status: enabled # 已启用
SELinuxfs mount: /sys/fs/selinux # selinux相关文件挂载点
SELinux root directory: /etc/selinux # 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@xyz ~]# 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 values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted # 策略
可以在配置文件种修改SELinux的运行模式和加载的策略。
SELinux 的启动与关闭
如果修改了SELInux加载的策略,则需要重新启动系统,如果将运行模式从Enforcing
或Permissive
修改为Disabled
(或者反过来),同样需要重启系统。这是因为SELinux是整合在Linux系统内核中的。
此外,如果是从Disabled
修改为Enforcing
或Permissive
,则在重启系统时SELinux需要花费比较长的一段时间重写系统中所需的SELinux安全上下文,而且在重写完毕后会自动重新启动系统。
SELinux在Enforcing
和Permissive
之间切换则不需要重启,只需要:
[root@xyz ~]# setenforce 0
[root@xyz ~]# getenforce
Permissive
[root@xyz ~]# setenforce 1
[root@xyz ~]# getenforce
Enforcing
0
表示Permissive
,1
表示Enforcing
。
在某些情况下,将SELinux从
Disabled
切换到Enforcing
,可能会导致出现/lib/xxx
中文件没有读写权限,进而导致系统重启失败。这是因为重启时SELinux重写安全上下文时缺少权限出错导致。这时候需要将SELinux切换到Permissve
,并使用restorecon -Rv
重写相关目录的安全上下文。
策略内的规则管理
getsebool
getsebool
可以用来查询SELinux中各个规则的bool值:
[root@xyz ~]# 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
authlogin_nsswitch_use_ldap --> off
authlogin_radius --> off
authlogin_yubikey --> off
...省略
-a
参数可以输出所有规则的bool值。
seinfo
这个工具CentOS7没有默认安装,需要先安装:
[root@xyz ~]# yum install setools-console-*
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
...省略
seinfo
可以查询SELinux相关的概况信息,:
[root@xyz ~]# 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
输出的信息中Types: 4793
表明当前SELinux中有4793
个安全上下文类型,Booleans: 316
表明有316
条规则。
sesearch
sesearch
命令可以在SELinux加载的规则中检索具体的规则,并输出:
[root@xyz ~]# 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 } ;
[root@xyz ~]# ll /etc/cron.d/checktime
可以看到,这里的规则的确表明主体类型为crond_t
的进程可以操作cron_spool_t
类型的文件(read write create
)。
这里-s
参数表明在查询主体类型(subject
),对应的,如果要查询目标类型,使用-t
(target
),如果要查询某个bool
规则,使用-b
(boolean
)。-A
(allow
)参数用于查询允许规则。
下面我们看允许规则中有没有之前创建的配置文件checktime
对应的读写权限:
[root@xyz ~]# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/checktime
[root@xyz ~]# sesearch -A -s crond_t | grep admin_home_t
allow crond_t admin_home_t : lnk_file { read getattr } ;
allow domain admin_home_t : dir { getattr search open } ;
allow userdom_filetrans_type admin_home_t : lnk_file { read getattr } ;
allow domain admin_home_t : lnk_file { read getattr } ;
allow crond_t admin_home_t : dir { ioctl read getattr lock search open } ;
allow userdom_filetrans_type admin_home_t : dir { ioctl read write getattr lock add_name remove_name search open } ;
可以看到,只有dir
和lnk_file
的相关规则,并没有file
的规则,也就是说crond
并不能操作类型为admin_home_t
的文件。
再看一个例子,这个例子用于查看httpd_enable_homedirs
这个bool
规则相关的信息:
[root@xyz ~]# getsebool -a | grep httpd_enable_home
httpd_enable_homedirs --> off
[root@xyz ~]# semanage boolean -l | grep httpd_enable_homedirs
httpd_enable_homedirs (关 , 关) Allow httpd to enable homedirs
[root@xyz ~]# 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 getattr lock open } ;
allow httpd_sys_script_t cifs_t : lnk_file { read getattr } ;
allow httpd_suexec_t user_home_dir_t : lnk_file { read getattr } ;
allow httpd_t cifs_t : file { ioctl read getattr lock open } ;
...省略
setsebool
setsebool
可以修改bool
规则的值:
[root@xyz ~]# setsebool -P httpd_enable_homedirs 1
[root@xyz ~]# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on
[root@xyz ~]# setsebool -P httpd_enable_homedirs 0
[root@xyz ~]# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
-P
(policy)参数用于将相关数据写入规则文件,所以修改的时候最好加上这个参数。
安全上下文的修改
在涉及到SELinux相关的问题的时候,我们需要先考虑SELinux的运行模式,再考虑加载的策略,以及具体的规则是否放行,最后还要考虑安全上下文是否匹配。
chcon
使用chcon
(change context)可以修改指定文件的安全上下文类型:
[root@xyz ~]# ll -Z /etc/hosts
-rw-r--r--. root root system_u:object_r:net_conf_t:s0 /etc/hosts
[root@xyz ~]# chcon -vt net_conf_t /etc/cron.d/checktime
正在更改"/etc/cron.d/checktime" 的安全环境
[root@xyz ~]# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:net_conf_t:s0 /etc/cron.d/checktime
-v
参数可以输出修改结果,-t
参数表明是要修改安全上下文类型。
除了手动填写安全上下文类型,还可以指定一个文件,直接修改成和文件一样的安全上下文信息:
[root@xyz ~]# chcon -v --reference=/etc/shadow /etc/cron.d/checktime
正在更改"/etc/cron.d/checktime" 的安全环境
[root@xyz ~]# ll -Z /etc/shadow /etc/cron.d/checktime
-rw-r--r--. root root system_u:object_r:shadow_t:s0 /etc/cron.d/checktime
----------. root root system_u:object_r:shadow_t:s0 /etc/shadow
参数--reference
用于指定作为参照的文件。
需要注意的是这里不仅类型,其它的安全上下文字段也被修改了。
restorecon
使用restorecon
(restore context)可以“自动修复”文件的安全上下文信息:
[root@xyz ~]# restorecon -Rv /etc/cron.d
restorecon reset /etc/cron.d/checktime context system_u:object_r:shadow_t:s0->system_u:object_r:system_cron_spool_t:s0
[root@xyz ~]# 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:system_cron_spool_t:s0 checktime
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 raid-check
-rw-------. root root system_u:object_r:system_cron_spool_t:s0 sysstat
[root@xyz ~]# systemctl restart crond
[root@xyz ~]# tail /var/log/cron
Aug 30 17:01:01 xyz run-parts(/etc/cron.hourly)[3532]: starting 0anacron
Aug 30 17:01:01 xyz run-parts(/etc/cron.hourly)[3544]: finished 0anacron
Aug 30 17:01:01 xyz run-parts(/etc/cron.hourly)[3532]: starting mcelog.cron
Aug 30 17:01:01 xyz run-parts(/etc/cron.hourly)[3550]: finished mcelog.cron
Aug 30 17:02:02 xyz crond[2610]: ((null)) Unauthorized SELinux context=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 file_context=system_u:object_r:shadow_t:s0 (/etc/cron.d/checktime)
Aug 30 17:02:02 xyz crond[2610]: (root) FAILED (loading cron table)
Aug 30 17:09:03 xyz crond[2610]: (CRON) INFO (Shutting down)
Aug 30 17:09:03 xyz crond[3662]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 20% if used.)
Aug 30 17:09:04 xyz crond[3662]: (CRON) INFO (running with inotify support)
Aug 30 17:09:04 xyz crond[3662]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
参数-R
用于递归处理子目录和子文件,类似于rm -r
,-v
用于输出相关信息。
可以看到,使用restorecon
命令后checktime
文件的安全上下文信息和其它同级文件一样了,而且crond
服务进程也可以正常重启了。
semanage
之所以restorecon
命令可以“自动恢复”错乱的SELinux安全上下文信息,是因为系统中保存了相关目录下默认的安全上下文信息应该是什么的规则,可以使用semanage
命令查看:
[root@xyz ~]# semanage fcontext -l | grep -E '^/etc |^/etc/cron*'
...省略
/etc/cron\.d(/.*)? all files system_u:object_r:system_cron_spool_t:s0
/etc/cron\.daily/[sm]locate regular file system_u:object_r:locate_exec_t:s0
/etc/cron\.weekly/(c)?fingerd regular file system_u:object_r:fingerd_exec_t:s0
...省略
这里显示的很清楚,对于符合/etc/cron\.d(/.*)?
这个路径规则(即/etc/cron.d
目录下的所有文件和子目录),其安全上下文默认都是system_u:object_r:system_cron_spool_t:s0
。
类似的,如果我们希望我们创建的某个目录下的文件建立的时候也有一个默认的安全上下文,则也需要通过semanage
添加相应的规则:
[root@xyz ~]# mkdir /srv/mycron
[root@xyz ~]# ll -dZ /srv /srv/mycron
drwxr-xr-x. root root system_u:object_r:var_t:s0 /srv
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0 /srv/mycron
[root@xyz ~]# semanage fcontext -l | grep -E '^/srv |^/srv/.*'
/srv/.* all files system_u:object_r:var_t:s0
/srv/([^/]*/)?www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
/srv/([^/]*/)?ftp(/.*)? all files system_u:object_r:public_content_t:s0
/srv/([^/]*/)?rsync(/.*)? all files system_u:object_r:public_content_t:s0
/srv/([^/]*/)?www/logs(/.*)? all files system_u:object_r:httpd_log_t:s0
/srv/node(/.*)? all files system_u:object_r:swift_data_t:s0
/srv/gallery2(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
/srv/lib/gitosis(/.*)? all files system_u:object_r:gitosis_var_lib_t:s0
/srv/gallery2/smarty(/.*)? all files system_u:object_r:httpd_sys_rw_content_t:s0
/srv/loopback-device(/.*)? all files system_u:object_r:swift_data_t:s0
/srv all files system_u:object_r:var_t:s0
[root@xyz ~]# semanage fcontext -a -t system_cron_spool_t "/srv/mycron(/.*)?"
[root@xyz ~]# semanage fcontext -l | grep -E '^/srv |^/srv/.*'
/srv/.* all files system_u:object_r:var_t:s0
/srv/([^/]*/)?www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
/srv/([^/]*/)?ftp(/.*)? all files system_u:object_r:public_content_t:s0
/srv/([^/]*/)?rsync(/.*)? all files system_u:object_r:public_content_t:s0
/srv/([^/]*/)?www/logs(/.*)? all files system_u:object_r:httpd_log_t:s0
/srv/node(/.*)? all files system_u:object_r:swift_data_t:s0
/srv/gallery2(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
/srv/lib/gitosis(/.*)? all files system_u:object_r:gitosis_var_lib_t:s0
/srv/gallery2/smarty(/.*)? all files system_u:object_r:httpd_sys_rw_content_t:s0
/srv/loopback-device(/.*)? all files system_u:object_r:swift_data_t:s0
/srv all files system_u:object_r:var_t:s0
/srv/mycron(/.*)? all files system_u:object_r:system_cron_spool_t:s0
[root@xyz ~]# cp /etc/cron.d/checktime /srv/mycron
[root@xyz ~]# ll -Z /srv/mycron
-rw-r--r--. root root unconfined_u:object_r:var_t:s0 checktime
[root@xyz ~]# restorecon -Rv /srv/mycron
restorecon reset /srv/mycron context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
restorecon reset /srv/mycron/checktime context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
[root@xyz ~]# ll -Z /srv/mycron
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 checktime
其中-a
参数用于添加规则,-m
为修改规则,-d
为删除规则。
在示例中,虽然已经添加了规则,但拷贝文件到/srv/mycron
下的时候安全上下文并非我们希望的安全上下文,这是因为/srv/mycron
目录本身的安全上下文不对,所以需要使用restorecon
命令修复。
一个网络服务案例
遇到SELinux相关的问题,需要查看相关的日志。SELinux使用auditd
与setroubleshootd
两个服务产生错误日志。
setroubleshoot
setroubleshootd
服务会将SELinux的相关错误及解决方法记录到/var/log/messages
与/var/log/setroubleshoot/*
中,这个服务需要两个应用:setroubleshoot
与setroubleshoot-server
。
在CentOS 6.X之前,SELinux的相关信息由auditd
与setroubled
两个进程记录,在CentOS 6.X之后,都整合到了auditd
这个服务中,所以安装setroubleshoot-server
之后需要重启auditd
服务。
如果要确认系统中有没有安装setroubleshoot
应用,可以:
[root@xyz ~]# rpm -qa | grep setroubleshoot
setroubleshoot-3.2.30-8.el7.x86_64
setroubleshoot-plugins-3.0.67-4.el7.noarch
setroubleshoot-server-3.2.30-8.el7.x86_64
[root@xyz ~]#
实例:FTP服务器
这里通过一个FTP服务来说明SELinux问题排查。
先创建一个给FTP服务使用的账号:
[root@xyz ~]# useradd -s /sbin/nologin ftptest
[root@xyz ~]# echo 'password' | passwd --stdin ftptest
更改用户 ftptest 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]# grep ftptest /etc/passwd
ftptest:x:1513:1513::/home/ftptest:/sbin/nologin
下面安装FTP软件vsftpd
:
[root@xyz ~]# yum install vsftpd
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
* updates: mirrors.aliyun.com
...省略
启动服务:
[root@xyz ~]# systemctl restart vsftpd
[root@xyz ~]# systemctl enable vsftpd
Created symlink from /etc/systemd/system/multi-user.target.wants/vsftpd.service to /usr/lib/systemd/system/vsftpd.service.
[root@xyz ~]# systemctl status vsftpd
● vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)
Active: active (running) since 一 2021-08-30 17:48:04 CST; 33s ago
Main PID: 4135 (vsftpd)
CGroup: /system.slice/vsftpd.service
└─4135 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
8月 30 17:48:04 xyz.icexmoon.centos systemd[1]: Starting Vsftpd ftp daemon...
8月 30 17:48:04 xyz.icexmoon.centos systemd[1]: Started Vsftpd ftp daemon.
[root@xyz ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1458/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1234/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1240/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1562/master
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 733/rpcbind
tcp6 0 0 :::21 :::* LISTEN 4135/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1234/sshd
tcp6 0 0 ::1:631 :::* LISTEN 1240/cupsd
tcp6 0 0 ::1:25 :::* LISTEN 1562/master
tcp6 0 0 :::111 :::* LISTEN 733/rpcbind
可以看到vsftpd
服务已经开始监听21端口了。
往ftp的公共目录拷贝两个文件作为测试文件:
[root@xyz ~]# cp -a /etc/securetty /etc/sysctl.conf /var/ftp/pub
[root@xyz ~]# ll /var/ftp/pub
总用量 8
-rw-------. 1 root root 221 4月 1 2020 securetty
-rw-r--r--. 1 root root 449 10月 13 2020 sysctl.conf
下面进行一些匿名用户访问测试:
[root@xyz ~]# cp -a /etc/securetty /etc/sysctl.conf /var/ftp/pub
[root@xyz ~]# ll /var/ftp/pub
总用量 8
-rw-------. 1 root root 221 4月 1 2020 securetty
-rw-r--r--. 1 root root 449 10月 13 2020 sysctl.conf
[root@xyz ~]# clear
[root@xyz ~]# curl ftp://localhost
drwxr-xr-x 2 0 0 42 Aug 30 09:55 pub
[root@xyz ~]# curl ftp://localhost/pub/
-rw------- 1 0 0 221 Apr 01 2020 securetty
-rw-r--r-- 1 0 0 449 Oct 13 2020 sysctl.conf
[root@xyz ~]# curl ftp://localhost/pub/sysctl.conf
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
[root@xyz ~]# curl ftp://localhost/pub/securetty
curl: (78) RETR response: 550
[root@xyz ~]# chmod a+r /var/ftp/pub/securetty
[root@xyz ~]# curl ftp://localhost/pub/securetty
console
vc/1
vc/2
vc/3
vc/4
vc/5
无法从家目录下载文件的问题分析与解决
在实际操作之前,需要先修改一个vsftpd
的pam
模块配置:
[root@xyz ~]# vim /etc/pam.d/vsftpd
[root@xyz ~]# cat /etc/pam.d/vsftpd
#%PAM-1.0
session optional pam_keyinit.so force revoke
auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
#auth required pam_shells.so
auth required pam_nologin.so
auth include password-auth
account include password-auth
session required pam_loginuid.so
session include password-auth
[root@xyz ~]# systemctl restart vsftpd
需要将其中的pam_shells.so
这个pam模块替换为pam_nologin.so
模块,详细原因可以参考。
经过测试发现,CentOS 7.9版本已经修复了这个问题,ftp用户是可以正常查看和下载自己家目录的文件的,所以就没有然后了。
一般账号从非正规目录上传/下载文件
[root@xyz ~]# mkdir /srv/gogogo
[root@xyz ~]# chgrp ftptest /srv/gogogo
[root@xyz ~]# echo 'test' > /srv/gogogo/test.txt
[root@xyz ~]# curl ftp://ftptest:password@localhost//srv/gogogo
curl: (78) RETR response: 550
[root@xyz ~]# curl ftp://ftptest:password@localhost//srv/gogogo/
[root@xyz ~]# curl ftp://ftptest:password@localhost//srv/gogogo/test.xt
curl: (78) RETR response: 550
[root@xyz ~]# curl ftp://ftptest:password@localhost//srv/gogogo/test.txt
curl: (78) RETR response: 550
可以查看日志文件:
[root@xyz ~]# grep sealert /var/log/messages | tail
Aug 30 18:25:50 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the directory gogogo. For complete SELinux messages run: sealert -l ee06faec-2d36-459e-8eeb-f69eab6a8d4b
Aug 30 18:28:24 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the directory gogogo. For complete SELinux messages run: sealert -l ee06faec-2d36-459e-8eeb-f69eab6a8d4b
Aug 30 18:28:31 xyz setroubleshoot: SELinux is preventing /usr/sbin/vsftpd from getattr access on the file /srv/gogogo/test.txt. For complete SELinux messages run: sealert -l 16f7093f-cf15-4e0f-b39c-497a8902dd4b
Aug 30 18:28:34 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the file test.txt. For complete SELinux messages run: sealert -l 528bea46-effe-4f09-8b1f-4c2f1eb42b71
可以按照建议运行:
[root@xyz ~]# sealert -l 528bea46-effe-4f09-8b1f-4c2f1eb42b71
SELinux is preventing vsftpd from read access on the 文件 test.txt.
***** 插件 catchall_boolean (57.6 置信度) 建议 ************************************
如果你想 allow ftpd to full access
Then 必须启用 'ftpd_full_access' 布尔值告知 SELinux 此情况。
Do
setsebool -P ftpd_full_access 1
***** 插件 catchall_labels (36.2 置信度) 建议 *************************************
如果你想允许 vsftpd有 read 访问 test.txt $TARGET_类
Then 必须更改 test.txt 中的标签
...省略
这里会按照可信度依次显示建议的解决方案,其中第一个建议是通过启用ftpd_full_access
规则让ftpd
服务可以访问所有的目录和文件,这显然不是我们希望的。第二个建议是让我们给test.txt
文件加一个安全上下文类型,这正是我们应该采用的:
[root@xyz ~]# ll -Zd /var/ftp/
drwxr-xr-x. root root system_u:object_r:public_content_t:s0 /var/ftp/
[root@xyz ~]# semanage fcontext -a -t public_content_t "/srv/gogogo(/.*)?"
[root@xyz ~]# restorecon -Rv /srv/gogogo
restorecon reset /srv/gogogo context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:public_content_t:s0
restorecon reset /srv/gogogo/test.txt context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:public_content_t:s0
[root@xyz ~]# curl ftp://ftptest:password@localhost//srv/gogogo/test.txt
test
这里我们是要把/srv/gogogo
目录当作ftp公共目录/var/ftp
一样使用,所以这里使用的安全上下文类型参考了/var/ftp
的,修改后的确可以使用curl
访问了。
无法修改FTP端口的问题和解决
有时候可能某个软件常用的端口会被其它应用占用,我们不得不改用不常用的端口,但是这可能会受到SELinux的限制而无法正常修改。
这里我们将FTP服务的端口修改为555试试看:
[root@xyz ~]# vim /etc/vsftpd/vsftpd.conf
[root@xyz ~]# tail /etc/vsftpd/vsftpd.conf
# sockets. If you want that (perhaps because you want to listen on specific
# addresses) then you must run two copies of vsftpd with two configuration
# files.
# Make sure, that one of the listen options is commented !!
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
listen_port=555
[root@xyz ~]# systemctl restart vsftpd
Job for vsftpd.service failed because the control process exited with error code. See "systemctl status vsftpd.service" and "journalctl -xe" for details.
在vsftp
的配置文件结尾加上端口指定为555
的设置后重启服务,结果出现错误。
查看SELinux的错误日志:
[root@xyz ~]# grep sealert /var/log/messages | tail
Aug 30 18:25:50 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the directory gogogo. For complete SELinux messages run: sealert -l ee06faec-2d36-459e-8eeb-f69eab6a8d4b
Aug 30 18:28:24 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the directory gogogo. For complete SELinux messages run: sealert -l ee06faec-2d36-459e-8eeb-f69eab6a8d4b
Aug 30 18:28:31 xyz setroubleshoot: SELinux is preventing /usr/sbin/vsftpd from getattr access on the file /srv/gogogo/test.txt. For complete SELinux messages run: sealert -l 16f7093f-cf15-4e0f-b39c-497a8902dd4b
Aug 30 18:28:34 xyz setroubleshoot: SELinux is preventing vsftpd from read access on the file test.txt. For complete SELinux messages run: sealert -l 528bea46-effe-4f09-8b1f-4c2f1eb42b71
Aug 30 18:46:46 xyz setroubleshoot: SELinux is preventing vsftpd from name_bind access on the tcp_socket port 555. For complete SELinux messages run: sealert -l 33d121d1-0c3d-40a8-9d63-6e2b4ea70cb5
端口请求被拒绝了,运行建议内容:
[root@xyz ~]# sealert -l 33d121d1-0c3d-40a8-9d63-6e2b4ea70cb5 | less
其中第一条92%可信度的建议是通过semanage
添加一个555端口的设置,这显然是我们需要的:
[root@xyz ~]# semanage port -a -t ftp_port_t -p tcp 555
[root@xyz ~]# systemctl restart vsftpd
[root@xyz ~]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1458/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1234/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1240/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1562/master
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 733/rpcbind
tcp6 0 0 :::22 :::* LISTEN 1234/sshd
tcp6 0 0 ::1:631 :::* LISTEN 1240/cupsd
tcp6 0 0 ::1:25 :::* LISTEN 1562/master
tcp6 0 0 :::555 :::* LISTEN 5175/vsftpd
tcp6 0 0 :::111 :::* LISTEN 733/rpcbind
[root@xyz ~]# curl ftp://localhost:555/pub/
-rw-r--r-- 1 0 0 221 Apr 01 2020 securetty
-rw-r--r-- 1 0 0 449 Oct 13 2020 sysctl.conf
添加后可以正常运行了。
参考资料
文章评论