测试中时常涉及到SELinux, 但是又不太懂咋回事. 学习一下, 整理出来, 希望可以帮到有疑惑的人

默认情况下, linux的权限隔离是依据用户的权限来划分的, 称为自主访问控制(DAC). 而SELinux是根据进程和资源划分类和访问权限的. 两者不矛盾, 可以一起存在.

准备工作

要使用和管理selinux, 需要一些命令, 需要安装一下:

以centos7为例:

sesearch: yum install setools-console

semanage:

1
2
3
4
5
6
7
8
$ yum provides semanage
...
policycoreutils-python-2.5-34.el7.x86_64 : SELinux policy core python utilities
Repo : base
Matched from:
Filename : /usr/sbin/semanage

$ yum install policycoreutils-python-2.5-34.el7.x86_64

sealert: 与semanage类似. 比如centos7是yum install setroubleshoot-server-3.2.30-8.el7.x86_64. 当然没有它也不要紧.

工作模式

  1. enforcing:强制模式。违反 SELinux 规则的行为将被阻止记录到日志中
  2. permissive:宽容模式。违反 SELinux 规则的行为只会记录到日志中。一般为调试用。
  3. disabled:关闭 SELinux。

通过命令getenforce可以查看当前状态, 通过setenforce可以更改它.

Ubuntu如果没有命令, 可以apt install selinux-utils安装. 默认情况下Ubuntu不启用SELinux, 而是apparmor

查看规则

使用sesearch -A可以查看所有允许的规则. (非”允许规则”就是不允许)

举例:

1
2
$ sesearch -A|grep syslogd_t
allow syslogd_t tmp_t : dir { ioctl read write getattr lock add_name remove_name search open } ;

格式为ALLOW (src type) (dst type):class { allowed attributes };

通过chcon -u aaa_u -r bbb_r -t ccc_t test可以临时修改文件的规则

semanage fcontext --list 可以查看文件或者文件夹对于的type规则.

semodule -l可以查看已经安装的module里封装的规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ semodule -l
...
varnishd 1.2.0
vdagent 1.1.1
vhostmd 1.1.0
virt 1.5.0
vlock 1.2.0
vmtools 1.0.0
vmware 2.7.0
vnstatd 1.1.0
vpn 1.16.0
w3c 1.1.0
watchdog 1.8.0
wdmd 1.1.0
...

如果我们想了解vmtools的规则, 可以这样:

1
$ semodule -E vmtools

执行完成后, 可以看到目录下生成了vmtools.pp文件.

使用sedismod查看规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ sedismod vmtools.pp
Reading policy...
libsepol.policydb_index_others: security: 0 users, 4 roles, 112 types, 4 bools
libsepol.policydb_index_others: security: 1 sens, 1024 cats
libsepol.policydb_index_others: security: 101 classes, 0 rules, 0 cond rules
libsepol.policydb_index_others: security: 0 users, 4 roles, 112 types, 4 bools
libsepol.policydb_index_others: security: 1 sens, 1024 cats
libsepol.policydb_index_others: security: 101 classes, 0 rules, 0 cond rules
Binary policy module file loaded.
Module name: vmtools
Module version: 1.0.0


Select a command:
1) display unconditional AVTAB
2) display conditional AVTAB
3) display users
4) display bools
5) display roles
6) display types, attributes, and aliases
7) display role transitions
8) display role allows
9) Display policycon
0) Display initial SIDs

a) Display avrule requirements
b) Display avrule declarations
c) Display policy capabilities
l) Link in a module
u) Display the unknown handling setting
F) Display filename_trans rules

f) set output file
m) display menu
q) quit

Command ('m' for menu):

这里我们输入1, 显示unconditional规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unconditional avtab:
--- begin avrule block ---
decl 1:
allow vmtools_t vmtools_exec_t : [file] { entrypoint };
allow vmtools_t vmtools_exec_t : [file] { ioctl read getattr lock map execute execute_no_trans open };
type_transition [initrc_domain] vmtools_exec_t : [process] vmtools_t;
allow vmtools_helper_t vmtools_helper_exec_t : [file] { entrypoint };
allow vmtools_helper_t vmtools_helper_exec_t : [file] { ioctl read getattr lock map execute execute_no_trans open };
allow vmtools_t self : [capability] { sys_rawio sys_time };
allow vmtools_t self : [fifo_file] { ioctl read write getattr lock append open };
allow vmtools_t self : [unix_stream_socket] { ioctl read write create getattr setattr lock append bind connect listen accept getopt setopt shutdown };
allow vmtools_t self : [unix_dgram_socket] { ioctl read write create getattr setattr lock append bind connect getopt setopt shutdown };
allow vmtools_t vmtools_tmp_t : [dir] { ioctl read write getattr lock add_name remove_name search open };
allow vmtools_t vmtools_tmp_t : [dir] { ioctl read write create getattr setattr lock unlink link rename add_name remove_name reparent search rmdir open };
allow vmtools_t vmtools_tmp_t : [dir] { ioctl read write getattr lock add_name remove_name search open };
allow vmtools_t vmtools_tmp_t : [file] { ioctl read write create getattr setattr lock append unlink link rename open };
allow vmtools_t vmtools_tmp_t : [dir] { ioctl read
....

Security Context

img

进程的type也称为Domain.

unconfined_t是无限制的domain. 一般登录用户启动的程序为这个domain.

ls -Z可以查看文件的security context.

1
2
3
4
[root@localhost vv]# ls -Z /root/
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 initial-setup-ks.cfg
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 t2

ps -auxZ可以查看进程的security context.

1
2
3
4
system_u:system_r:kernel_t:s0   root        569  0.0  0.0      0     0 ?        S<   May04   0:00 [xfs-eofblocks/s]
system_u:system_r:kernel_t:s0 root 572 0.0 0.0 0 0 ? S May04 0:00 [xfsaild/sda1]
system_u:system_r:auditd_t:s0 root 654 0.0 0.0 55504 460 ? S<sl May04 0:00 /sbin/auditd
system_u:system_r:audisp_t:s0 root 656 0.0 0.0 84548 580 ? S<sl May04 0:00 /sbin/audispd

Domain Transition

假如进程A属于Domain a, 它启动了一个程序X, 程序X启动后的Domain是Domain b. 我们就称之为Domain Transition.

实现这个需要满足3个前提:

  1. Domain a 和Domain b有程序文件X的 execute 属性

  2. Domain a允许迁移到Domain b. (即 process transition 属性)

  3. 文件X是Domain b的 entrypoint. 比如

    1
    2
    $ sesearch -A|grep vmtools_t|grep entrypoint
    allow vmtools_t vmtools_exec_t : file { ioctl read getattr lock map execute execute_no_trans entrypoint open } ;

    如果是在pp文件里, 就形如 type_transition [initrc_domain] vmtools_exec_t : [process] vmtools_t;

举例: init_thttpd_t的Domain Transition:

先查看vftpd的文件和进程的security context:

1
2
3
4
[root@localhost ~]# ls -Z /usr/sbin/vsftpd
-rwxr-xr-x. root root system_u:object_r:ftpd_exec_t:s0 /usr/sbin/vsftpd
[root@localhost ~]# ps -auxZ|grep vftpd
system_u:object_r:ftpd_t:s0-s0:c0.c1023 root 2829 0.0 0.0 112660 964 pts/1 R+ 07:42 0:00 grep --color=auto vftpd

可以看到文件是ftpd_exec_t type, 进程的domain是ftpd_t( 如果没有配置SELinux, 进程的security context可能是unconfined_u:unconfined_r:unconfined_t)

接下来查看init_t到ftpd_exec_t的规则:

1
2
3
[root@localhost ~]# sesearch -s init_t -t ftpd_exec_t -c file -p execute -Ad
Found 1 semantic av rules:
allow init_t ftpd_exec_t : file { read getattr execute open } ;

可以看到init_t有ftpd_exec_t Type的execute属性

1
2
3
[root@localhost ~]# sesearch -s ftpd_t -t ftpd_exec_t -c file -p entrypoint -Ad
Found 1 semantic av rules:
allow ftpd_t ftpd_exec_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ;

可以看到ftpd_t有ftpd_exec_t Type的execute属性

1
2
3
[root@localhost ~]# sesearch -s init_t -t ftpd_t -c process -p transition -Ad
Found 1 semantic av rules:
allow init_t ftpd_t : process transition ;

错误信息的处理

通过ausearch命令可以获取错误消息. 也可以直接读取/var/log/audit/audit.log, 带有AVC(Access Vector Cache, 很奇葩的名字)的就是拒绝的log.

比如: 执行runcon system_u:system_r:syslogd_t:s0 /bin/ls -l /会失败, 查看错误结果:

1
2
$ ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR|grep runcon
type=AVC msg=audit(1651855998.065:528): avc: denied { entrypoint } for pid=4634 comm="runcon" path="/usr/bin/ls" dev="dm-0" ino=25307027 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
  • avc: denied - the action performed by SELinux and recorded in Access Vector Cache (AVC)
  • { entrypoint} - the denied action
  • pid=4634- the process identifier of the subject that tried to perform the denied action
  • comm="runcon" - the name of the command that was used to invoke the analyzed process
  • syslogd_t - the SELinux type of the process
  • bin_t - the SELinux type of the object affected by the process action
  • tclass=file - the target object class

翻译一下就是, 进程runcon(pid:4634)下从syslogd_t类型去运行bin_t类型的 “/usr/bin/ls”文件时, syslogd_t没有该文件的entrypoint权限.

这是为什么呢? 我的猜想是, runcon由于是用户启动的, 所以在unconfined_t域, runcon会调用setexeccon, 该函数功能是在下一次执行execve的时候, 更改加载程序的security context. 这个操作应该会触发一个Domain Transition, 从unconfined_t 到 syslogd_t, 而Domain Transition有3个前提, 其中一个是就是需要目标domain有文件的entrypoint属性. 而syslogd_t没有bint_t的entrypoint属性. 从而导致没有权限.

添加规则

使用audit2allow可以生成规则建议:

1
2
3
4
5
6
7
8
[root@localhost ~]# ausearch -m AVC|grep  runcon
type=AVC msg=audit(1651857472.707:540): avc: denied { entrypoint } for pid=4774 comm="runcon" path="/usr/bin/ls" dev="dm-0" ino=25307027 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
[root@localhost ~]# ausearch -m AVC|grep runcon|audit2allow -a

#============= syslogd_t ==============

#!!!! WARNING: 'bin_t' is a base type.
allow syslogd_t bin_t:file entrypoint;

生成规则:

1
2
3
4
5
$ ausearch -m AVC|grep  runcon|audit2allow -M test2
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i test2.pp

它会生成两个文件test2.pptest2.te, te文件就是规则的实际描述文件,

安装规则: semodule -i test2.pp

安装后查看:

1
2
3
[root@localhost ~]# sesearch -A|grep syslogd_t|grep entrypoint
allow syslogd_t bin_t : file { ioctl read getattr lock map execute execute_no_trans entrypoint open } ;
allow syslogd_t syslogd_exec_t : file { ioctl read getattr lock map execute execute_no_trans entrypoint open } ;

可以看到规则已经添加进去了.

ALLOWING ACCESS: AUDIT2ALLOW

WRITING A CUSTOM SELINUX POLICY

其它

通过runcon可以以特定domain运行特定程序

参考

An Introduction to SELinux on CentOS 7 – Part 2: Files and Processes

WRITING A CUSTOM SELINUX POLICY