introduction to SELinux
(Written by Paul Cobbaut, https://github.com/paulcobbaut/, with contributions by: Alex M. Schapelle, https://github.com/zero-pytagoras/)
Security Enhanced Linux or SELinux
is a set of
modifications developed by the United States National Security Agency
(NSA) to provide a variety of security policies for Linux. SELinux was
released as open source at the end of 2000. Since kernel version 2.6 it
is an integrated part of Linux.
SELinux offers security! SELinux can control what kind of access users
have to files and processes. Even when a file received chmod 777
,
SELinux can still prevent applications from accessing it (Unix file
permissions are checked first!). SELinux does this by placing users in
roles
that represent a security context. Administrators have very
strict control on access permissions granted to roles.
SELinux is present in the latest versions of Red Hat Enterprise Linux, Debian, CentOS, Fedora, and many other distributions..
selinux modes
selinux
knows three modes: enforcing, permissive and disabled. The
enforcing
mode will enforce policies, and may deny access based on
selinux rules
. The permissive
mode will not enforce policies, but
can still log actions that would have been denied in enforcing
mode.
The disabled
mode disables selinux
.
logging
Verify that syslog
is running and activated on boot to enable logging
of deny messages in /var/log/messages
.
[root@linux ~]# chkconfig --list syslog
syslog 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Verify that auditd
is running and activated on boot to
enable logging of easier to read messages in
/var/log/audit/audit.log
.
[root@linux ~]# chkconfig --list auditd
auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
If not activated, then run
chkconfig --levels 2345 auditd on
and
service auditd start
.
[root@linux ~]# service auditd status
auditd (pid 1660) is running...
[root@linux ~]# service syslog status
syslogd (pid 1688) is running...
klogd (pid 1691) is running...
The /var/log/messages
log file will tell you that selinux
is
disabled.
root@linux:~# grep -i selinux /var/log/messages
Jun 25 15:59:34 deb106 kernel: [ 0.084083] SELinux: Disabled at boot.
Or that it is enabled.
root@linux:~# grep SELinux /var/log/messages | grep -i Init
Jun 25 15:09:52 deb106 kernel: [ 0.084094] SELinux: Initializing.
activating selinux
On RHEL you can use the GUI tool to activate selinux
, on Debian there
is the selinux-activate
command. Activation requires a
reboot.
root@linux:~# selinux-activate
Activating SE Linux
Searching for GRUB installation directory ... found: /boot/grub
Searching for default file ... found: /boot/grub/default
Testing for an existing GRUB menu.lst file ... found: /boot/grub/menu.lst
Searching for splash image ... none found, skipping ...
Found kernel: /boot/vmlinuz-2.6.26-2-686
Updating /boot/grub/menu.lst ... done
SE Linux is activated. You may need to reboot now.
getenforce
Use getenforce
to verify whether selinux is enforced
,
disabled
or permissive
.
[root@linux ~]# getenforce
Permissive
The /selinux/enforce
file contains 1 when enforcing, and 0 when
permissive mode is active.
root@fedora13 ~# cat /selinux/enforce
1root@fedora13 ~#
setenforce
You can use setenforce
to switch between the
Permissive
or the Enforcing
state once selinux
is activated..
[root@linux ~]# setenforce Enforcing
[root@linux ~]# getenforce
Enforcing
[root@linux ~]# setenforce Permissive
[root@linux ~]# getenforce
Permissive
Or you could just use 0 and 1 as argument.
[root@linux ~]# setenforce 1
[root@linux ~]# getenforce
Enforcing
[root@linux ~]# setenforce 0
[root@linux ~]# getenforce
Permissive
[root@linux ~]#
sestatus
You can see the current selinux
status and policy with
the sestatus
command.
[root@linux ~]# sestatus
SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: permissive
Mode from config file: permissive
Policy version: 21
Policy from config file: targeted
policy
Most Red Hat server will have the targeted
policy. Only
NSA/FBI/CIA/DOD/HLS use the mls
policy.
The targted policy will protect hundreds of processes, but lets other processes run \'unconfined\' (= they can do anything).
/etc/selinux/config
The main configuration file for selinux
is
/etc/selinux/config
. When in permissive
mode, the file
looks like this.
The targeted policy is selected in /etc/selinux/config
.
[root@linux ~]# 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 - SELinux is fully disabled.
SELINUX=permissive
# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted
DAC or MAC
Standard Unix permissions use Discretionary Access Control
to set
permissions on files. This means that a user that owns a file, can make
it world readable by typing chmod 777 $file
.
With selinux
the kernel will enforce Mandatory Access Control
which
strictly controls what processes or threads can do with files
(superseding DAC). Processes are confined by the kernel to the minimum
access they require.
SELinux MAC is about labeling and type enforcing! Files, processes, etc are all labeled with an SELinux context. For files, these are extended attributes, for processes this is managed by the kernel.
The format of the labels is as follows:
user:role:type:(level)
We only use the type
label in the targeted policy.
ls -Z
To see the DAC permissions on a file, use ls -l
to display user and
group owner
and permissions.
For MAC permissions there is new -Z
option added to
ls
. The output shows that file in /root
have a XXXtype
of admin_home_t
.
[root@linux ~]# ls -Z
-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 install.log
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 install.log.syslog
[root@linux ~]# useradd -m -s /bin/bash pol
[root@linux ~]# ls -Z /home/pol/.bashrc
-rw-r--r--. pol pol unconfined_u:object_r:user_home_t:s0 /home/pol/.bashrc
-Z
There are also some other tools with the -Z switch:
mkdir -Z
cp -Z
ps -Z
netstat -Z
...
/selinux
When selinux is active, there is a new virtual file system named
/selinux
. (You can compare it to /proc and /dev.)
[root@linux ~]# ls -l /selinux/
total 0
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 access
dr-xr-xr-x. 2 root root 0 Apr 12 19:40 avc
dr-xr-xr-x. 2 root root 0 Apr 12 19:40 booleans
-rw-r--r--. 1 root root 0 Apr 12 19:40 checkreqprot
dr-xr-xr-x. 83 root root 0 Apr 12 19:40 class
--w-------. 1 root root 0 Apr 12 19:40 commit_pending_bools
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 context
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 create
-r--r--r--. 1 root root 0 Apr 12 19:40 deny_unknown
--w-------. 1 root root 0 Apr 12 19:40 disable
-rw-r--r--. 1 root root 0 Apr 12 19:40 enforce
dr-xr-xr-x. 2 root root 0 Apr 12 19:40 initial_contexts
-rw-------. 1 root root 0 Apr 12 19:40 load
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 member
-r--r--r--. 1 root root 0 Apr 12 19:40 mls
crw-rw-rw-. 1 root root 1, 3 Apr 12 19:40 null
-r--------. 1 root root 0 Apr 12 19:40 policy
dr-xr-xr-x. 2 root root 0 Apr 12 19:40 policy_capabilities
-r--r--r--. 1 root root 0 Apr 12 19:40 policyvers
-r--r--r--. 1 root root 0 Apr 12 19:40 reject_unknown
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 relabel
-r--r--r--. 1 root root 0 Apr 12 19:40 status
-rw-rw-rw-. 1 root root 0 Apr 12 19:40 user
Although some files in /selinux
appear wih size 0, they
often contain a boolean value. Check /selinux/enforce
to
see if selinux is running in enforced mode.
[root@linux ~]# ls -l /selinux/enforce
-rw-r--r-- 1 root root 0 Apr 29 08:21 /selinux/enforce
[root@linux ~]# echo $(cat /selinux/enforce)
1
identity
The SELinux Identity
of a user is distinct from the user
ID. An identity is part of a security context, and (via domains)
determines what you can do. The screenshot shows user root
having
identity user_u
.
[root@linux ~]# id -Z
user_u:system_r:unconfined_t
role
The selinux role
defines the domains that can be used. A
role
is denied to enter a domain, unless the role
is explicitely
authorized to do so.
type (or domain)
The selinux context
is the security context of a
process. An selinux type
determines what a process can do. The
screenshot shows init running in type init_t
and the mingetty\'s
running in type getty_t
.
[root@linux ~]# ps fax -Z | grep /sbin/init
system_u:system_r:init_t:s0 1 ? Ss 0:00 /sbin/init
[root@linux ~]# ps fax -Z | grep getty_t
system_u:system_r:getty_t:s0 1307 tty1 Ss+ 0:00 /sbin/mingetty /dev/tty1
system_u:system_r:getty_t:s0 1309 tty2 Ss+ 0:00 /sbin/mingetty /dev/tty2
system_u:system_r:getty_t:s0 1311 tty3 Ss+ 0:00 /sbin/mingetty /dev/tty3
system_u:system_r:getty_t:s0 1313 tty4 Ss+ 0:00 /sbin/mingetty /dev/tty4
system_u:system_r:getty_t:s0 1320 tty5 Ss+ 0:00 /sbin/mingetty /dev/tty5
system_u:system_r:getty_t:s0 1322 tty6 Ss+ 0:00 /sbin/mingetty /dev/tty6
The selinux type
is similar to an selinux domain
, but
refers to directories and files instead of processes.
Hundreds of binaries also have a type:
[root@linux sbin]# ls -lZ useradd usermod userdel httpd postcat postfix
-rwxr-xr-x. root root system_u:object_r:httpd_exec_t:s0 httpd
-rwxr-xr-x. root root system_u:object_r:postfix_master_exec_t:s0 postcat
-rwxr-xr-x. root root system_u:object_r:postfix_master_exec_t:s0 postfix
-rwxr-x---. root root system_u:object_r:useradd_exec_t:s0 useradd
-rwxr-x---. root root system_u:object_r:useradd_exec_t:s0 userdel
-rwxr-x---. root root system_u:object_r:useradd_exec_t:s0 usermod
Ports also have a context.
[root@linux sbin]# netstat -nptlZ | tr -s ' ' | cut -d' ' -f6-
Foreign Address State PID/Program name Security Context
LISTEN 1096/rpcbind system_u:system_r:rpcbind_t:s0
LISTEN 1208/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023
LISTEN 1284/master system_u:system_r:postfix_master_t:s0
LISTEN 1114/rpc.statd system_u:system_r:rpcd_t:s0
LISTEN 1096/rpcbind system_u:system_r:rpcbind_t:s0
LISTEN 1666/httpd unconfined_u:system_r:httpd_t:s0
LISTEN 1208/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023
LISTEN 1114/rpc.statd system_u:system_r:rpcd_t:s0
LISTEN 1284/master system_u:system_r:postfix_master_t:s0
You can also get a list of ports that are managed by SELinux:
[root@linux ~]# semanage port -l | tail
xfs_port_t tcp 7100
xserver_port_t tcp 6000-6150
zabbix_agent_port_t tcp 10050
zabbix_port_t tcp 10051
zarafa_port_t tcp 236, 237
zebra_port_t tcp 2600-2604, 2606
zebra_port_t udp 2600-2604, 2606
zented_port_t tcp 1229
zented_port_t udp 1229
zope_port_t tcp 8021
security context
The combination of identity, role and domain or type make up the
selinux security context
. The id
will show you your
security context in the form identity:role:domain.
[student@linux ~]$ id | cut -d' ' -f4
context=user_u:system_r:unconfined_t
The ls -Z
command shows the security context for a file in the form
identity:role:type.
[student@linux ~]$ ls -Z test
-rw-rw-r-- paul paul user_u:object_r:user_home_t test
The security context for processes visible in /proc defines both the type (of the file in /proc) and the domain (of the running process). Let\'s take a look at the init process and /proc/1/ .
The init process runs in domain init_t
.
[root@linux ~]# ps -ZC init
LABEL PID TTY TIME CMD
system_u:system_r:init_t 1 ? 00:00:01 init
The /proc/1/
directory, which identifies the init
process, has type
init_t
.
[root@linux ~]# ls -Zd /proc/1/
dr-xr-xr-x root root system_u:system_r:init_t /proc/1/
It is not a coincidence that the domain of the init
process and the
type of /proc/1/
are both init_t
.
Don\'t try to use chcon
on /proc! It will not work.
transition
An selinux transition
(aka an selinux labelling)
determines the security context that will be assigned. A transition of
process domains is used when you execute a process. A transition of file
type happens when you create a file.
An example of file type transition.
[pol@linux ~]$ touch test /tmp/test
[pol@linux ~]$ ls -Z test
-rw-rw-r--. pol pol unconfined_u:object_r:user_home_t:s0 test
[pol@linux ~]$ ls -Z /tmp/test
-rw-rw-r--. pol pol unconfined_u:object_r:user_tmp_t:s0 /tmp/test
extended attributes
Extended attributes are used by selinux
to store security contexts.
These attributes can be viewed with ls
when selinux
is
running.
[root@linux home]# ls --context
drwx------ paul paul system_u:object_r:user_home_dir_t paul
drwxr-xr-x root root user_u:object_r:user_home_dir_t project42
drwxr-xr-x root root user_u:object_r:user_home_dir_t project55
[root@linux home]# ls -Z
drwx------ paul paul system_u:object_r:user_home_dir_t paul
drwxr-xr-x root root user_u:object_r:user_home_dir_t project42
drwxr-xr-x root root user_u:object_r:user_home_dir_t project55
[root@linux home]#
When selinux is not running, then getfattr
is the tool
to use.
[root@linux etc]# getfattr -m . -d hosts
# file: hosts
security.selinux="system_u:object_r:etc_t:s0\000"
process security context
A new option is added to ps
to see the selinux security
context of processes.
[root@linux etc]# ps -ZC mingetty
LABEL PID TTY TIME CMD
system_u:system_r:getty_t 2941 tty1 00:00:00 mingetty
system_u:system_r:getty_t 2942 tty2 00:00:00 mingetty
chcon
Use chcon
to change the selinux security context.
This example shows how to use chcon
to change the type
of a file.
[root@linux ~]# ls -Z /var/www/html/test42.txt
-rw-r--r-- root root user_u:object_r:httpd_sys_content_t /var/www/html/test4\
2.txt
[root@linux ~]# chcon -t samba_share_t /var/www/html/test42.txt
[root@linux ~]# ls -Z /var/www/html/test42.txt
-rw-r--r-- root root user_u:object_r:samba_share_t /var/www/html/test42.txt
Be sure to read man chcon
.
an example
The Apache2 webserver
is by default targeted with SELinux
. The next
screenshot shows that any file created in /var/www/html
will by
default get the httpd_sys_content_t
type.
[root@linux ~]# touch /var/www/html/test42.txt
[root@linux ~]# ls -Z /var/www/html/test42.txt
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/h\
tml/test42.txt
Files created elsewhere do not get this type.
[root@linux ~]# touch /root/test42.txt
[root@linux ~]# ls -Z /root/test42.txt
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /root/test42.txt
Make sure Apache2
runs.
[root@linux ~]# service httpd restart
Stopping httpd: [ OK ]
Starting httpd: [ OK ]
Will this work ? Yes it does.
[root@linux ~]# wget http://localhost/test42.txt
--2014-04-12 20:56:47-- http://localhost/test42.txt
Resolving localhost... ::1, 127.0.0.1
Connecting to localhost|::1|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 0 [text/plain]
Saving to: “test42.txt”
...
Why does this work ? Because Apache2 runs in the httpd_t
domain and
the files in /var/www/html
have the httpd_sys_content_t
type.
[root@linux ~]# ps -ZC httpd | head -4
LABEL PID TTY TIME CMD
unconfined_u:system_r:httpd_t:s0 1666 ? 00:00:00 httpd
unconfined_u:system_r:httpd_t:s0 1668 ? 00:00:00 httpd
unconfined_u:system_r:httpd_t:s0 1669 ? 00:00:00 httpd
So let\'s set SELinux to enforcing
and change the type
of this file.
[root@linux ~]# chcon -t samba_share_t /var/www/html/test42.txt
[root@linux ~]# ls -Z /var/www/html/test42.txt
-rw-r--r--. root root unconfined_u:object_r:samba_share_t:s0 /var/www/html/t\
est42.txt
[root@linux ~]# setenforce 1
[root@linux ~]# getenforce
Enforcing
There are two possibilities now: either it works, or it fails. It works
when selinux
is in permissive mode
, it fails when in
enforcing mode
.
[root@linux ~]# wget http://localhost/test42.txt
--2014-04-12 21:05:02-- http://localhost/test42.txt
Resolving localhost... ::1, 127.0.0.1
Connecting to localhost|::1|:80... connected.
HTTP request sent, awaiting response... 403 Forbidden
2014-04-12 21:05:02 ERROR 403: Forbidden.
The log file gives you a cryptic message...
[root@linux ~]# tail -3 /var/log/audit/audit.log
type=SYSCALL msg=audit(1398200702.803:64): arch=c000003e syscall=4 succ\
ess=no exit=-13 a0=7f5fbc334d70 a1=7fff553b4f10 a2=7fff553b4f10 a3=0 it\
ems=0 ppid=1666 pid=1673 auid=500 uid=48 gid=48 euid=48 suid=48 fsuid=4\
8 egid=48 sgid=48 fsgid=48 tty=(none) ses=1 comm="httpd" exe="/usr/sbin\
/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1398200702.804:65): avc: denied { getattr } for p\
id=1673 comm="httpd" path="/var/www/html/test42.txt" dev=dm-0 ino=26324\
1 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:objec\
t_r:samba_share_t:s0 tclass=file
type=SYSCALL msg=audit(1398200702.804:65): arch=c000003e syscall=6 succ\
ess=no exit=-13 a0=7f5fbc334e40 a1=7fff553b4f10 a2=7fff553b4f10 a3=1 it\
ems=0 ppid=1666 pid=1673 auid=500 uid=48 gid=48 euid=48 suid=48 fsuid=4\
8 egid=48 sgid=48 fsgid=48 tty=(none) ses=1 comm="httpd" exe="/usr/sbin\
/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
And /var/log/messages
mentions nothing of the failed download.
setroubleshoot
The log file above was not very helpful, but these two packages can make your life much easier.
[root@linux ~]# yum -y install setroubleshoot setroubleshoot-server
You need to reboot
for this to work...
So we reboot, restart the httpd server, reactive SELinux Enforce, and do the wget again... and it fails (because of SELinux).
[root@linux ~]# service httpd restart
Stopping httpd: [FAILED]
Starting httpd: [ OK ]
[root@linux ~]# getenforce
Permissive
[root@linux ~]# setenforce 1
[root@linux ~]# getenforce
Enforcing
[root@linux ~]# wget http://localhost/test42.txt
--2014-04-12 21:44:13-- http://localhost/test42.txt
Resolving localhost... ::1, 127.0.0.1
Connecting to localhost|::1|:80... connected.
HTTP request sent, awaiting response... 403 Forbidden
2014-04-12 21:44:13 ERROR 403: Forbidden.
The /var/log/audit/
is still not out best friend, but take a look at
/var/log/messages
.
[root@linux ~]# tail -2 /var/log/messages
Apr 12 21:44:16 centos65 setroubleshoot: SELinux is preventing /usr/sbin/h\
ttpd from getattr access on the file /var/www/html/test42.txt. For complete \
SELinux messages. run sealert -l b2a84386-54c1-4344-96fb-dcf969776696
Apr 12 21:44:16 centos65 setroubleshoot: SELinux is preventing /usr/sbin/h\
ttpd from getattr access on the file /var/www/html/test42.txt. For complete \
SELinux messages. run sealert -l b2a84386-54c1-4344-96fb-dcf969776696
So we run the command it suggests...
[root@linux ~]# sealert -l b2a84386-54c1-4344-96fb-dcf969776696
SELinux is preventing /usr/sbin/httpd from getattr access on the file /va\
r/www/html/test42.txt.
***** Plugin restorecon (92.2 confidence) suggests *********************
If you want to fix the label.
/var/www/html/test42.txt default label should be httpd_sys_content_t.
Then you can run restorecon.
Do
# /sbin/restorecon -v /var/www/html/test42.txt
...
We follow the friendly advice and try again to download our file:
[root@linux ~]# /sbin/restorecon -v /var/www/html/test42.txt
/sbin/restorecon reset /var/www/html/test42.txt context unconfined_u:objec\
t_r:samba_share_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[root@linux ~]# wget http://localhost/test42.txt
--2014-04-12 21:54:03-- http://localhost/test42.txt
Resolving localhost... ::1, 127.0.0.1
Connecting to localhost|::1|:80... connected.
HTTP request sent, awaiting response... 200 OK
It works!
booleans
Booleans are on/off switches
[root@linux ~]# getsebool -a | head
abrt_anon_write --> off
abrt_handle_event --> off
allow_console_login --> on
allow_cvs_read_shadow --> off
allow_daemons_dump_core --> on
allow_daemons_use_tcp_wrapper --> off
allow_daemons_use_tty --> on
allow_domain_fd_use --> on
allow_execheap --> off
allow_execmem --> on
You can set and read individual booleans.
[root@linux ~]# setsebool httpd_read_user_content=1
[root@linux ~]# getsebool httpd_read_user_content
httpd_read_user_content --> on
[root@linux ~]# setsebool httpd_enable_homedirs=1
[root@linux ~]# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on
You can set these booleans permanent.
[root@linux ~]# setsebool -P httpd_enable_homedirs=1
[root@linux ~]# setsebool -P httpd_read_user_content=1
The above commands regenerate the complete /etc/selinux/targeted directory!
[root@linux ~]# cat /etc/selinux/targeted/modules/active/booleans.local
# This file is auto-generated by libsemanage
# Do not edit directly.
httpd_enable_homedirs=1
httpd_read_user_content=1