Tuesday, May 29, 2007
SELinux Tutorial
I have found very few resources for SELinux on the web, which I believe is a idea tool box for the security engineer or for that matter any average Linux user who plans to use programs of the web without examining them for hacks. I have divided up this tutorial into 2 main sections, the first of which describes why SELinux is the coolest security tool ever followed by a detailed tutorial with a running example of getting up and running with it in no time.
SELinux in a Nutshell
SELinux's MAC vs Linux's DAC
Security-enhanced Linux (SELinux) is an implementation of a mandatory access control mechanism. This mechanism is in the Linux kernel, checking for allowed operations after standard Linux discretionary access controls are checked. Under DAC, ownership of a file object provides potentially risky control over the object. A user can expose a file or directory to a security or confidentiality breach with a misconfigured chmod command and an unexpected propagation of access rights. A process started by that user, such as a CGI script, can do anything it wants to the files owned by the user. A compromised Apache HTTP server can perform any operation on files in the Web group. Malicious or broken software can have root-level access to the entire system, either by running as a root process or using setuid or setgid. In addition under DAC, there are really only two major categories of users, administrators and non-administrators. In order for services and programs to run with any level of elevated privilege, the choices are few and course grained, and typically resolve to just giving full administrator access. Solutions such as ACLs (access control lists) can provide some additional security for allowing non-administrators expanded privileges, but for the most part a root account has complete discretion over the file system. A MAC or non-discretionary access control framework allows you to define permissions for how all processes (subjects) interact with other parts of the system such as files, devices, sockets, ports, and other processes (objects). This is done through an administratively-defined security policy. These processes and objects are controlled through the kernel, and security decisions are made on all available information rather than just user identity. With this model, a process can be granted just the permissions it needs to be functional. This follows the principle of least privilege. Under MAC, for example, users who have exposed their data using chmod are protected by the fact that their data is a kind only associated with user home directories, and confined processes cannot touch those files without permission and purpose written into the policy.
Setting up SE Linux on FC6
Installing SELinux Development Packages
Usually the 2-CD install of FC6 does not include the development packages for SELinux. So we need to install those first.
$ yum install selinux-policy-devel
$ yum install setools-devel
$ yum install setools-gui
It is also generally a good idea to install the audit daemon i.e user space tools for 2.6 kernel auditing. We will need this to monitor our generated AVC denial messages.
$ yum install audit
$ /etc/init.d/auditd start
Working with the Policy Sources
Ever since FC started supporting modular policies, they have stopped shipping the targeted policy sources with Fedora. However the reference policy sources from Tresys are available for download and much easier to work with. While NSA's original example policy has very strong interdependencies between types and roles and therefore a very tight coupling of policy source modules, the reference policy has well-defined interfaces and no global use of type and other identifiers, In addition it layers all of its modules in 5 main categories of 'admin', 'apps', 'kernel', 'services' and 'system'.
The refpolicy at the time of writing this tutorial could be downloaded from http://oss.tresys.com/projects/refpolicy/wiki/DownloadRelease. After download run
$ make
$ make install-src
$ make install
The refpolicy will be compiled and installed into /etc/selinux/refpolicy/src/policy
Writing the Policy
I am going to describe how to write SELinux rules for a Linux Daemon Service particularly the Asterisk Call Server. The steps involved are pretty generic and can be used for any software you are planning to jail with selinux. When you download and install asterisk, take a note of where it installs its binaries, config, log files etc. We will need this knowledge to set up policy rules for it. Once you download and install the software try running it without selinux support; you can do this by typing
$ setenforce 0
$ /etc/init.d/asterisk start
This will switch selinux into permissive mode in which access checks still occur, but instead of denying unallowed access, it simply audits them. Now that we are certain that our daemon runs perfectly we are ready to write selinux policy files for it. Here is a listing of my asterisk.te (the main policy rules) file. I have commented each line in the listing to make it easier to understand.
asterisk.te
####################
policy_module(asterisk, 1.0)
####################
#
# Type declarations
#
# asterisk domain
type asterisk_t;
# asterisk entrypoint
type asterisk_exec_t;
#mark asterisk_t as a domain and asterisk_exec_t
#as an entry point into that domain
init_daemon_domain(asterisk_t, asterisk_exec_t)
# PID file /var/run/asterisk.pid
type asterisk_var_run_t;
files_pid_file(asterisk_var_run_t)
#configuration files
type asterisk_conf_t;
files_config_file(asterisk_conf_t)
#log files
type asterisk_log_t;
logging_log_file(asterisk_log_t)
#files and directories under /var/lib/asterisk
type asterisk_var_lib_t;
files_type(asterisk_var_lib_t)
# Log files - create, read, and append
allow asterisk_t asterisk_log_t : dir ra_dir_perms;
allow asterisk_t asterisk_log_t : file { create ra_file_perms };
logging_log_filetrans(asterisk_t, asterisk_log_t, file)
logging_search_logs(asterisk_t)
# configuration files - read
allow asterisk_t asterisk_conf_t : dir r_dir_perms;
allow asterisk_t asterisk_conf_t : file r_file_perms;
allow asterisk_t asterisk_conf_t : lnk_file { getattr read };
# PID file - create, read, and write
allow asterisk_t asterisk_var_run_t : dir rw_dir_perms;
allow asterisk_t asterisk_var_run_t : file create_file_perms;
files_pid_filetrans(asterisk_t, asterisk_var_run_t, file)
# /var/lib/asterisk files/dirs - create, read, write
allow asterisk_t asterisk_var_lib_t : dir create_dir_perms;
allow asterisk_t asterisk_var_lib_t : file create_file_perms;
files_var_lib_filetrans(asterisk_t, asterisk_var_lib_t, file)
files_var_lib_filetrans(asterisk_t, asterisk_var_lib_t, dir)
# Network Access
allow asterisk_t self : tcp_socket create_stream_socket_perms;
corenet_tcp_sendrecv_all_if(asterisk_t)
corenet_tcp_sendrecv_all_nodes(asterisk_t)
corenet_tcp_sendrecv_all_ports(asterisk_t)
corenet_non_ipsec_sendrecv(asterisk_t)
corenet_tcp_bind_all_nodes(asterisk_t)
corenet_tcp_bind_asterisk_port(asterisk_t)
sysnet_dns_name_resolve(asterisk_t)
Next we create a labeling policy in the form of file security contexts statements. We make use of the gen_context() template interface macro to handle both MLS/MCS and non MLS/MCS policies from the policy source. This file contains hard-coded listing of the directories for the asterisk daemon. The reader will have to change these paths for the application he is jailing via selinux.
asterisk.fc
################
#asterisk labeling policy
################
/usr/bin/asterisk -- gen_context(system_u:object_r:asterisk_exec_t, s0)
/etc/asterisk(/.*)? gen_context(system_u:object_r:asterisk_conf_t, s0)
/var/log/asterisk(/.*)? gen_context(system_u:object_r:asterisk_log_t, s0)
/var/lib/asterisk(/.*)? gen_context(system_u:object_r:asterisk_var_lib_t, s0)
/var/run/asterisk(/.*)? gen_context(system_u:object_r:asterisk_var_run_t, s0)
Finally the external interfaces file for the daemon declares an interface for reading the log files. This way other domains are allowed access by simply calling this interface.
asterisk.if
################
interface(`asterisk_read_log',`
gen_require(`
type asterisk_log_t;
`)
logging_search_logs($1)
allow $1 asterisk_log_t : dir search_dir_perms;
allow $1 asterisk_log_t : file r_file_perms;
The above three files are all the source code we need to write to set up a simple selinux jail for our asterisk server. They should be copied to a separate directory and compiled into a policy package asterisk.pp using make. A generic makefile for compiling loadable modules can be copied over from /usr/share/selinux/devel/
compiling the policy
$ make
installing the policy
$ /usr/sbin/semodule -i asterisk.pp
checking if the policy was successfully installed
$ /usr/sbin/semodule -l
asterisk 1.0
relabeling all the files/directories in the file context file
$ restorecon /usr/bin/asterisk
$ restorecon -R /etc/asterisk/ /var/log/asterisk /var/lib/asterisk
verifying that the labeling occurred correctly using ls -Z
$ ls -scontext /usr/bin/asterisk /var/log/asterisk
system_u:object_r:asterisk_exec_t /usr/bin/asterisk
/var/log/asterisk:
system_u:object_r:asterisk_log_t asterisk.log
start asterisk
$ /etc/init.d/asterisk start
verify that it is running
$ ps axZ | grep asterisk
check for AVC denials
$ /usr/bin/audit2allow -i < /var/log/audit/audit.log
Edit the asterisk.te file to make sure that accesses that we are not permitting are suppressed by adding dontaudit rules and finally restart the asterisk server with selinux set to enforcing
$ setenforce 1
$ /etc/init.d/asterisk restart
SELinux in a Nutshell
The Big challenge is to find ways to have secure systems knowing that flawed application software will always exist. SELinux is an implementation of the reference monitor concept, where the operating system isolates passive resources into distinct objects such as files and active entities such as running programs into subjects. The reference monitor mechanism would then validate access between subjects and object by applying a security policy as embodied in a set of access control rules. Access control decisions are based on security attributes associated with each subject and object. The complexity is a direct result of Linux being complex. There is certainly a trade off in providing a system with the granularity to control every single permission for every object class.
SELinux's MAC vs Linux's DAC
Security-enhanced Linux (SELinux) is an implementation of a mandatory access control mechanism. This mechanism is in the Linux kernel, checking for allowed operations after standard Linux discretionary access controls are checked. Under DAC, ownership of a file object provides potentially risky control over the object. A user can expose a file or directory to a security or confidentiality breach with a misconfigured chmod command and an unexpected propagation of access rights. A process started by that user, such as a CGI script, can do anything it wants to the files owned by the user. A compromised Apache HTTP server can perform any operation on files in the Web group. Malicious or broken software can have root-level access to the entire system, either by running as a root process or using setuid or setgid. In addition under DAC, there are really only two major categories of users, administrators and non-administrators. In order for services and programs to run with any level of elevated privilege, the choices are few and course grained, and typically resolve to just giving full administrator access. Solutions such as ACLs (access control lists) can provide some additional security for allowing non-administrators expanded privileges, but for the most part a root account has complete discretion over the file system. A MAC or non-discretionary access control framework allows you to define permissions for how all processes (subjects) interact with other parts of the system such as files, devices, sockets, ports, and other processes (objects). This is done through an administratively-defined security policy. These processes and objects are controlled through the kernel, and security decisions are made on all available information rather than just user identity. With this model, a process can be granted just the permissions it needs to be functional. This follows the principle of least privilege. Under MAC, for example, users who have exposed their data using chmod are protected by the fact that their data is a kind only associated with user home directories, and confined processes cannot touch those files without permission and purpose written into the policy.
DAC | MAC |
Object Owner has full power | Object Owner can have some power |
Complete trust in users | Only trust in administrators |
Decisions are based only on user id and object ownerships | Objects and tasks can themselves have IDs |
Impossible to control data flow | Makes data-flow control possible |
Setting up SE Linux on FC6
Installing SELinux Development Packages
Usually the 2-CD install of FC6 does not include the development packages for SELinux. So we need to install those first.
$ yum install selinux-policy-devel
$ yum install setools-devel
$ yum install setools-gui
It is also generally a good idea to install the audit daemon i.e user space tools for 2.6 kernel auditing. We will need this to monitor our generated AVC denial messages.
$ yum install audit
$ /etc/init.d/auditd start
Working with the Policy Sources
Ever since FC started supporting modular policies, they have stopped shipping the targeted policy sources with Fedora. However the reference policy sources from Tresys are available for download and much easier to work with. While NSA's original example policy has very strong interdependencies between types and roles and therefore a very tight coupling of policy source modules, the reference policy has well-defined interfaces and no global use of type and other identifiers, In addition it layers all of its modules in 5 main categories of 'admin', 'apps', 'kernel', 'services' and 'system'.
The refpolicy at the time of writing this tutorial could be downloaded from http://oss.tresys.com/projects/refpolicy/wiki/DownloadRelease. After download run
$ make
$ make install-src
$ make install
The refpolicy will be compiled and installed into /etc/selinux/refpolicy/src/policy
Writing the Policy
I am going to describe how to write SELinux rules for a Linux Daemon Service particularly the Asterisk Call Server. The steps involved are pretty generic and can be used for any software you are planning to jail with selinux. When you download and install asterisk, take a note of where it installs its binaries, config, log files etc. We will need this knowledge to set up policy rules for it. Once you download and install the software try running it without selinux support; you can do this by typing
$ setenforce 0
$ /etc/init.d/asterisk start
This will switch selinux into permissive mode in which access checks still occur, but instead of denying unallowed access, it simply audits them. Now that we are certain that our daemon runs perfectly we are ready to write selinux policy files for it. Here is a listing of my asterisk.te (the main policy rules) file. I have commented each line in the listing to make it easier to understand.
asterisk.te
####################
policy_module(asterisk, 1.0)
####################
#
# Type declarations
#
# asterisk domain
type asterisk_t;
# asterisk entrypoint
type asterisk_exec_t;
#mark asterisk_t as a domain and asterisk_exec_t
#as an entry point into that domain
init_daemon_domain(asterisk_t, asterisk_exec_t)
# PID file /var/run/asterisk.pid
type asterisk_var_run_t;
files_pid_file(asterisk_var_run_t)
#configuration files
type asterisk_conf_t;
files_config_file(asterisk_conf_t)
#log files
type asterisk_log_t;
logging_log_file(asterisk_log_t)
#files and directories under /var/lib/asterisk
type asterisk_var_lib_t;
files_type(asterisk_var_lib_t)
# Log files - create, read, and append
allow asterisk_t asterisk_log_t : dir ra_dir_perms;
allow asterisk_t asterisk_log_t : file { create ra_file_perms };
logging_log_filetrans(asterisk_t, asterisk_log_t, file)
logging_search_logs(asterisk_t)
# configuration files - read
allow asterisk_t asterisk_conf_t : dir r_dir_perms;
allow asterisk_t asterisk_conf_t : file r_file_perms;
allow asterisk_t asterisk_conf_t : lnk_file { getattr read };
# PID file - create, read, and write
allow asterisk_t asterisk_var_run_t : dir rw_dir_perms;
allow asterisk_t asterisk_var_run_t : file create_file_perms;
files_pid_filetrans(asterisk_t, asterisk_var_run_t, file)
# /var/lib/asterisk files/dirs - create, read, write
allow asterisk_t asterisk_var_lib_t : dir create_dir_perms;
allow asterisk_t asterisk_var_lib_t : file create_file_perms;
files_var_lib_filetrans(asterisk_t, asterisk_var_lib_t, file)
files_var_lib_filetrans(asterisk_t, asterisk_var_lib_t, dir)
# Network Access
allow asterisk_t self : tcp_socket create_stream_socket_perms;
corenet_tcp_sendrecv_all_if(asterisk_t)
corenet_tcp_sendrecv_all_nodes(asterisk_t)
corenet_tcp_sendrecv_all_ports(asterisk_t)
corenet_non_ipsec_sendrecv(asterisk_t)
corenet_tcp_bind_all_nodes(asterisk_t)
corenet_tcp_bind_asterisk_port(asterisk_t)
sysnet_dns_name_resolve(asterisk_t)
Next we create a labeling policy in the form of file security contexts statements. We make use of the gen_context() template interface macro to handle both MLS/MCS and non MLS/MCS policies from the policy source. This file contains hard-coded listing of the directories for the asterisk daemon. The reader will have to change these paths for the application he is jailing via selinux.
asterisk.fc
################
#asterisk labeling policy
################
/usr/bin/asterisk -- gen_context(system_u:object_r:asterisk_exec_t, s0)
/etc/asterisk(/.*)? gen_context(system_u:object_r:asterisk_conf_t, s0)
/var/log/asterisk(/.*)? gen_context(system_u:object_r:asterisk_log_t, s0)
/var/lib/asterisk(/.*)? gen_context(system_u:object_r:asterisk_var_lib_t, s0)
/var/run/asterisk(/.*)? gen_context(system_u:object_r:asterisk_var_run_t, s0)
Finally the external interfaces file for the daemon declares an interface for reading the log files. This way other domains are allowed access by simply calling this interface.
asterisk.if
################
interface(`asterisk_read_log',`
gen_require(`
type asterisk_log_t;
`)
logging_search_logs($1)
allow $1 asterisk_log_t : dir search_dir_perms;
allow $1 asterisk_log_t : file r_file_perms;
The above three files are all the source code we need to write to set up a simple selinux jail for our asterisk server. They should be copied to a separate directory and compiled into a policy package asterisk.pp using make. A generic makefile for compiling loadable modules can be copied over from /usr/share/selinux/devel/
compiling the policy
$ make
installing the policy
$ /usr/sbin/semodule -i asterisk.pp
checking if the policy was successfully installed
$ /usr/sbin/semodule -l
asterisk 1.0
relabeling all the files/directories in the file context file
$ restorecon /usr/bin/asterisk
$ restorecon -R /etc/asterisk/ /var/log/asterisk /var/lib/asterisk
verifying that the labeling occurred correctly using ls -Z
$ ls -scontext /usr/bin/asterisk /var/log/asterisk
system_u:object_r:asterisk_exec_t /usr/bin/asterisk
/var/log/asterisk:
system_u:object_r:asterisk_log_t asterisk.log
start asterisk
$ /etc/init.d/asterisk start
verify that it is running
$ ps axZ | grep asterisk
check for AVC denials
$ /usr/bin/audit2allow -i < /var/log/audit/audit.log
Edit the asterisk.te file to make sure that accesses that we are not permitting are suppressed by adding dontaudit rules and finally restart the asterisk server with selinux set to enforcing
$ setenforce 1
$ /etc/init.d/asterisk restart