Friday, August 21, 2015

SELinux: An Introduction

SELinux:  An Introduction
6/11/2005
 

SELinux is an implementation of a Mandatory Access Control architecture called 
Flask, using the Linux Kernel.  Up until its release such systems were not very 
widespread.  Currently however, Fedora Core 3 comes with SELinux installed, 
and many other distributions such as Debian and Slackware are adopting it.

According to the NSA, a MAC is needed when "protection decisions must not be 
decided by the object owner, and the system must enforce the protection 
descisions over the wishes or intentions of the object owner". 

Flask evolved from a long line of NSA research on such MAC systems.  
Mandatory Access Controls were originally built to enforce security clearances 
given to users for objects in the system.  SELinux takes the concept one step 
farther, applying such restrictions to almost every definable object a system could 
have.

Non SELinux systems use a Discretionary Access control system which is 
"vulnerable to tampering and bypass, and malicious or flawed applications can 
easily cause failures in system security."  This is due to the fact that actions are 
limited only by user identity and ownership, not by role.  

For example, an attacker gaining control of a program in a DAC system is 
allowed to do anything with that control, and can access anything the user the 
process runs as can access.  This is often not a good thing, as it allows the 
corrupted process to do malicious things regardless of what role the program 
originally was meant for.

SELinux policy helps solve this problem by allowing for very fine grained access 
control.  Some policies are separation policies to enforce legal and classification 
restrictions on data, containment policies to restrict process access to data and 
files, integrity policies to protect against modifications to data, and invocation 
policies to control how processes run on the system.

In order for SELinux to function on Fedora Core 3, install libselinux, selinux-
policy-strict, setools, checkpolicy, and policycoreutils rpms.  
The system-config-securitylevel and setools-gui rpms are also helpful to see 
some good examples of policies assignable to a user.  In order to compile some 
of the later examples, you will need a also need the libselinux-devel and selinux-
policy-strict-sources rpms.

SELinux accomplishes Mandatory Access Control with Flask and a "combination 
of a Type Enforcement (TE) model and a Role-Based Access Control (RBAC) 
model.”  The TE model is implemented by “binding a security attribute called a 
type to each object". 


Classes of objects are defined in the 
/etc/selinux/strict/src/policy/flask/security_classes file.
A class is a kind of object such as a filesystem, file, directory, or socket.  Classes 
each have an access vector defining what functions they preform.  Access 
vectors are defined here: 
/etc/selinux/strict/src/policy/flask/access_vectors
The file class can read, write, create, and append for example, while the socket 
class can also read and write along with the bind, listen and connect.  Types 
given to processes are also known as domains.
The second part of flask, Role-Based Access Control, assigns roles to users.  
The roles are then allowed some access vectors to various types.  The 
combination of user, role and type is a security “context”.
The SELinux policy determines which security contexts are allowed.
If SELinux is enabled on a Linux kernel, security contexts will be available for 
viewing.  
View the context of a file:
 [root@xoci ~]# ls --context /etc/passwd
-rw-r--r-- root root system_u:object_r:etc_t /etc/passwd
View the context of a sshd process:
[root@xoci ~]# ps ax --context | grep sshd
 2886 system_u:system_r:kernel_t      /usr/sbin/sshd

You can also view information on the current policy with the seinfo program.  This 
also seems to be hard coded to the strict policy.  Try it with a few settings:
seinfo -t show types, seinfo -u show users, seinfo -r show roles
SELinux is configured in the /etc/selinux/config file.  For testing purposes use the 
following settings:
SELINUX=permissive #(logs but does not enforce)
SELINUXTYPE=strict
Permissive mode will print warnings but not deny access, and is very useful 
when writing your policy or debugging a program.  On fedora research only 
seemed to have success compiling policies of the strict type, as it seems setools 
on fedora has a path hard coded to the strict policy.
Once SELinux is configured, try to compile and install a policy from source.  This 
is done from the /etc/selinux/strict/etc/policy directory.
The following make commands work:
make policy will make the policy but not install it
make load will make and load the policy
make relabel will relabel the type of any files to match the policy.
make load takes the files in the policy source directory, and attempts to process 
them with the m4 macro processor into a policy.conf file. This file is then passed 
to the SELinux policy compiler checkpolicy, which creates the the binary policy 
/etc/selinux/strict/policy/policy.18 for loading into the kernel.
After running a make load try rebooting the machine and login as root.
Create a new user account, setest.  Login with this account.
setest@pc-00071 ~]$ id -Z
user_u:user_r:user_t
The SILinux policy assigns the above context by default to undefined users.
Add the user_r and staff_r roles to setest by editing 
/etc/selinux/strict/src/policy/users.
user setest roles { user_r staff_r };
Save the file and run make load again.  Then login setest and check the context.
[setest@pc-00071 home]$ id -Z
setest:user_r:user_t
Try changing roles to staff_r
[setest@pc-00071 ~]$ newrole -r staff_r
Authenticating setest.
Password:
setest@pc-00071 ~]$ id -Z
setest:staff_r:staff_t  

SELinux allows for the creation of new types as well.  Create a new file here:
/etc/selinux/strict/src/policy/types/custom.te
Add a new type declaration to this file:
type setestfile_t, file_type, sysadminfile;
This adds a new type to the policy, setestfile_t with the attributes of file_type and 
sysadminfile.
The different attributes for types are listed in /etc/selinux/strict/src/policy/attrib.te.
Adding a new role requires modifying 
/etc/selinux/strict/src/policy/domains/user.te.
To add the setest_r role, add these to the user.te file:
full_user_role(setest) 
priv_user(setest)
Then modify /etc/selinux/strict/src/policy/macros/user_macros.te by adding:
role setest_r types $1;
Run make load again, and then do a seinfo -t | grep setest_t
You should see a list of types starting with setest_t, including setest_home_dir_t 
and  setest_home_t for examples.  What happened was the macro processor 
created all the default types to go along with the role.  
Next add setest_r:setest_t to /etc/selinux/strict/src/policy/appconfig/default_type.  
This ensures that SELinux knows what domain to place a user in when first 
logging in.

Now allow some access to the new setestfile_t, edit custom.te again and add:
allow user_t setestfile_t:file { read };
allow setest_t setestfile_t:file { read write execute };
Then add setest_r to the list of roles granted to the user setest in the users file.
Now that a new user, type and role have been created, run some tests to see if 
the kernel is actualy using them.  Logged in as setest:
[setest@pc-00071 ~]$ touch afile
[setest@pc-00071 ~]$ ls --context afile
-rw-rw-r--  setest   setest   setest:object_r:user_home_t      afile
Try to chang the context of afile: chcon -t setestfile_t.
This works because we are in permissive mode, but it leaves the following log:
Jun 11 06:01:12 pc-00071 kernel: audit(1118487672.558:0): avc:  denied  { 
relabelto } for  pid=22595 exe=/usr/bin/chcon name=afile dev=dm-0 ino=2142232 
scontext=setest:user_r:user_t tcontext=setest:object_r:setestfile_t tclass=file

What this means is the kernel noted that the context  setest:user_r:user_t 
executed a relabelto on a  user_home_t object.  Since this was not explicitly 
allowed in the policy an error message is generated.
The user_r can only read this file, so cat afile is allowed but echo "test" >> afile 
creates an error message for the "append" attribute.
SELinux also has C libraries which can be used in programs.  The following code 
shows how to manipulate security contexts and print out SELinux information.
#include <stdio.h>
#include <stdlib.h>
#include <selinux/selinux.h>
#include <selinux/context.h>
//this code prints selinux related information
int main (int argc, char **argv)
{
  printf("Checking if selinux is enabled...\n");
  if(is_selinux_enabled())
    {printf("this program is running on a SELinux kernel\n");} 
  else
    {printf("this program is not running on a SELinux kernel\n");}
  int permissive = 0;
  int enforcing = 1;
  if(security_getenforce() == permissive)
    {printf("SELinux is running in permissive mode\n");}
  if(security_getenforce() == enforcing)
    {printf("SELinux is running in enforcing mode\n");}
  int rcc;
  typedef char* security_context_t; 
  security_context_t scon;
  printf("getting this program's current context...\n");
  rcc = getcon(&scon);
     if (rcc < 0) 
     {
        perror("getcon");
        return -1;
     }
     printf("this program's security_context_t is: = %s\n",scon);
     context_t newcon;
     //creat a new context_t from the contents of scon
     newcon = context_new(scon);

     //free the memory used by scon
     freecon(scon);
     //display context attributes
     char* newcontexttype;
     newcontexttype = context_type_get(newcon);
     printf("this program's context_t type is: %s\n",newcontexttype);
     char* newcontextrole;
     newcontextrole = context_role_get(newcon);
     printf("this program's context_t role is: %s\n",newcontextrole);
     char* newcontextuser;
     newcontextuser = context_user_get(newcon);
     printf("this program's context_t user is: %s\n",newcontextuser);
     rcc = context_type_set(newcon, "faketype_t");
     rcc = context_role_set(newcon, "fakerole_r");
     rcc = context_user_set(newcon, "fakeuser_u");
     printf("context after setting fake type, role and user: 
%s\n",context_str(newcon));
     //check if context selinux is enabled and the context is valid 
     printf("Verifing security context...\n");
     if(security_check_context(newcon) < 0)
       {printf("invalid context: %s\n",context_str(newcon));}
     else
       {printf("valid context: %s \n",context_str(newcon));}
    return 0;
}

Compile this code with the following options:
gcc -lselinux -o print_selinux_status print_selinux_status.c
The code should output the following:

[user@pc-00071 final]$ ./print_selinux_status 
Checking if selinux is enabled...
this program is running on a SELinux kernel
SELinux is running in permissive mode
getting this program's current context...
this program's security_context_t is: = setest:user_r:user_t
this program's context_t type is: user_t
this program's context_t role is: user_r
this program's context_t user is: user
context after setting fake type, role and user: fakeuser_u:fakerole_r:faketype_t
invalid context: fakeuser_u:fakerole_r:faketype_t

The kernel also prints a check_context error:
 Jun 11 06:38:50 pc-00071 kernel: audit(1118489930.704:0): avc:  denied  { 
check_context } for  pid=22934 
exe=/home/user/final/print_selinux_statusscontext=setest:user_r:user_t 
tcontext=system_u:object_r:security_t tclass=security

This is because the user_r role does not have access to run functions using the 
check_context attribute.  Specifically, the security_check_context() function 
requires the calling process context be allowed to check_context on the 
system_u:object_r:security_t context.
Programs can change the context of their next exec by using the execve funtion.  
Here is a simple example which runs less, allowing you to see what context the 
process was run as.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <selinux/selinux.h>
#include <selinux/context.h>

//http://www.frech.ch/man/man3p/execve.3p.html

int main (int argc, char **argv)
{
typedef char* security_context_t; 
  security_context_t scon;
  int rcc;
 printf("getting this program's current context...\n");
  rcc = getcon(&scon);
     if (rcc < 0) 
     {
        perror("getcon");
        return -1;
     }
     printf("this program's security_context_t before setexeccon is: = %s\n",scon);
int ret;
char *cmd[] = { "less", "/etc/passwd", (char *)0 };
char *env[] = { "HOME=/usr/home", "LOGNAME=home", "TERM=vt220",(char *)0 
};
setexeccon("setest:setest_r:setest_t");
ret = execve ("/usr/bin/less", cmd, env);
}

Running this code with the setest:user_r:user_t  context of the command shell 
prints a kernel error.  This is due to the transition not being explicitly allowed in 
the SELinux policy.  When set to enforcing mode the power of selinux can be 
harnessed to defeat attacks which use a corrupted process to launch other 
processes.  SELinux could prevent or log any such attempts to operate outside 
the normal conditions needed for the service. Here is an example log of a context 
transition being denied.



Jun 11 06:58:15 pc-00071 kernel: audit(1118491095.820:0): avc:  denied  { 
transition } for  pid=23006 exe=/home/setest/execve_example path=/usr/bin/less 
dev=dm-0 ino=1348733 scontext=setest:user_r:user_t 
tcontext=setest:setest_r:setest_t tclass=process

In order to allow transitions between types, add this to the custom.te file:
allow user_t setest_t:process transition;

Once the transition is allowed, run the program again:
setest@pc-00071 ~]$ ./execve_example
then check the running processes with ps ax --context

After the setexeccon gives a new context, execve executes its arguments with 
that context.  
Running in memory: 23118 setest:setest_r:setest_t        less /etc/passwd
but the user who called execve_example only had setest:user_r:user_t context.

SELinux seems to be the future of security with Linux.  Using SELinux allows for 
greater control over every aspect of the operating system, to a degree never 
before seen in a publicly available operating system which can operate on 
commodity hardware.  These two facts combined should make a powerful 
combination which will continue to attract developers and administrators to 
SELinux.  SELinux being included in Fedora Core 3 shows that the ideas 
proposed are mature enough for mainstream adoption.  

References:

Stephen Smalley, "Configuring the SELinux Policy", January 2003
http://www.nsa.gov/selinux/papers/policy2.pdf (11 June 2005)

Peter Loscocco and Stephen Smalley, "Integrating Flexible Support for Security
Policies into the Linux Operating System", June 2001
http://www.nsa.gov/selinux/papers/freenix01/freenix01.html (11 June 2005)

Redhat, "Bugzilla Bug 125737  setools Makefile has incorrect policy install 
location defined" June 2004,
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=125737 (11 June 2005)

Mayank Sharma, "SELinux: Playing with fire" (January 2005)
http://security.linux.com/security/05/01/25/1423211.shtml?tid=124&tid=123&tid=113&t
id=35 (11 June 2005)

Faye Coker, "Getting Started with SE Linux HOWTO" (March 2004)
http://www.lurking-grue.org/GettingStartedWithNewSELinuxHOWTO.pdf (11 June 
2005)

Faye Coker, "Writing SE Linux Policy HOWTO" (March 2004)
http://www.lurking-grue.org/WritingSELinuxPolicyHOWTO.pdf (11 June 2005)

Kerry Thompson, "SELinux" (March 2003)
http://www.samag.com/documents/s=7835/sam0303a/0303a.htm (11 June 2005)

Ram Varma, "SELinux Programming" (April 2005)
http://www.ensl.cs.gwu.edu/resources/SELinux_20Programming (5 June 2005)

Susan Douglas and Korry Douglas, 2004, "Linux Timesaving Techniques for 
Dummies" , John Wiley & Sons.

Russel Coker, "SE Linux API Documentation" (January 2004)
Also, irc conversations with him in #selinux of irc.freenode.net (June 2005)

John Barkley, "Security in Open Systems" (July 1994)
http://csrc.nist.gov/publications/nistpubs/800-7/main.html (June 11 2005)


No comments:

Post a Comment