Powered by Blogger.

Monday, March 17, 2014

SElinux Modules

What about the whole concept of open source, freedom and the ability to modify applications to suit our needs rather than we modifying ourselves to suit the application’s needs?
Thankfully, SELinux gives us the power and complete freedom to achieve all this. There are two ways in which we can approach the whole concept of customising SELinux:
  1. Modifying the source of the policy (easily available through source RPMs).
  2. Developing modules that can be compiled and loaded along with the base policy.
For beginners, intermediate-level users and also for production purposes, I would not recommend the first option unless it is absolutely necessary. It requires more in-depth knowledge and experience to modify the core policy—we will take a look at this option in a later part of this series.
For most of us, the second option of building policy modules will suffice. It is an easier approach and also lets us develop a better understanding of the SELinux policy language before we delve deeper into it by modifying the core policy.

Customising the default policy — Power to the people

As discussed above, we will customise the default targeted policy by adding our own modules. To do so we will use the semodule command.
semodule is the tool used to manage SELinux policy modules, including installing, upgrading, listing and removing modules. It is installed by the policycoreutils RPM. The man page, as usual, gives further details and helpful instructions on how to use the command.

Listing SELinux modules

To list modules, use the following:
[root@vbg ~]# semodule -l
If you execute this command on a freshly installed system with SELinux enabled, you will see a list of modules. A sample output on my system follows:
[root@vbg ~]# semodule -l
amavis  1.1.0
ccs     1.0.0
clamav  1.1.0
dcc     1.1.0
evolution       1.1.0
iscsid  1.0.0
mozilla 1.1.0
mplayer 1.1.0
nagios  1.1.0
oddjob  1.0.1
openoff 1.0.0
pcscd   1.0.0
pyzor   1.1.0
razor   1.1.0
ricci   1.0.0
smartmon        1.1.0
tmp     1.0.1
vbg     1.0.3
What this means is that the default SELinux installation does come with some modules loaded that are not part of the base policy. Looking more closely into the output of the above command, we see that in my system there are 18 policy modules installed. Each row of the above output corresponds to a policy module.
The output of the semodule -l command gives us two columns of information: Module Name and Module Version. Thus we can see that the amavis module has a version number of 1.1.0 whereas the vbg module has a version 1.0.3.
Also, these are the modules currently loaded into the memory and are active along with the base policy. But, where are these modules located? What difference do they make to the overall SELinux policy? How are they loaded and removed?
Let’s try to answer the above questions, one by one.
These are binary policy modules that, by default, have a file extension of .pp (Policy Package). Generally, the module name and the file name is kept the same, though it’s not mandatory. Therefore, we need to look up a file named amavis.pp (Policy Package for the Amavis daemon). By default, the location of this file is/etc/selinux/targeted/modules/active/modules/. If you go into this folder and list the contents, you will see the policy package files of all the currently loaded modules.
The policy modules obviously make a lot of difference. That’s what they were created for. To observe the difference they make, let’s use the wonderful seinfo tool discussed earlier.
To get an overall idea of the SELinux policy currently loaded, we shall use the command seinfo. A sample output from my system is shown below:
[root@vbg modules]# seinfo

Statistics for policy file: /etc/selinux/targeted/policy/policy.21
Policy Version & Type: v.21 (binary, MLS)

   Classes:            61    Permissions:       220
   Types:            1516    Attributes:        148
   Users:               3    Roles:               6
   Booleans:          211    Cond. Expr.:       187
   Sensitivities:       1    Categories:       1024
   Allow:           82576    Neverallow:          0
   Auditallow:         28    Dontaudit:        5086
   Role allow:          5    Role trans:          0
   Type_trans:       1400    Type_change:        17
   Type_member:         0    Range_trans:        23
   Constraints:        47    Validatetrans:       0
   Fs_use:             15    Genfscon:           64
   Portcon:           264    Netifcon:            0
   Nodecon:             8    Initial SIDs:       27
We can see that there are 1,516 types and 82,576 allow rules being recognised by SELinux. You can redirect this output to a temporary file just for comparison, later. You could use the following command:
[root@vbg modules]# seinfo > /tmp/org-selinux-policy
Let’s now remove one of the loaded modules. As an example, let us remove the amavis module.

Removing SELinux modules

To remove a loaded SELinux module, use the semodule command with the -r option and the module name as the argument. For example:
[root@vbg modules]# semodule -r amavis
This removes the amavis module.
To ensure that the above command has worked, list all the currently loaded modules:
root@vbg modules]# semodule -l
ccs     1.0.0
clamav  1.1.0
dcc     1.1.0
evolution       1.1.0
iscsid  1.0.0
mozilla 1.1.0
mplayer 1.1.0
nagios  1.1.0
oddjob  1.0.1
openoff 1.0.0
pcscd   1.0.0
pyzor   1.1.0
razor   1.1.0
ricci   1.0.0
smartmon        1.1.0
tmp     1.0.1
vbg     1.0.3
To understand the difference made by the removal of the amavis package, again redirect the output ofseinfo to a file:
[root@vbg modules]# seinfo > /tmp/new-selinux-policy
…and run a diff on the two files:
[root@vbg modules]# diff /tmp/org-selinux-policy /tmp/new-selinux-policy
6c6
<    Types:            1516    Attributes:        148 --- >    Types:            1507    Attributes:        148
8c8
<    Booleans:          211    Cond. Expr.:       187 --- >    Booleans:          210    Cond. Expr.:       186
10,11c10,11
<    Allow:           82576    Neverallow:          0
<    Auditallow:         28    Dontaudit:        5086 --- >    Allow:           81929    Neverallow:          0
>    Auditallow:         28    Dontaudit:        5062
13c13
<    Type_trans:       1400    Type_change:        17 --- >    Type_trans:       1387    Type_change:        17
You will see that removing amavis has made the following changes:
  • Reducing the number of ‘types’ from 1,516 to 1,507
  • Reducing the number of ‘Booleans’ from 211 to 210
  • Reducing the number of ‘allow rules’ from 82,576 to 81,929
  • Reducing the number of ‘type transition rules’ from 1400 to 1,387, and so on…
Thus, we see that by using modules, we can at least add types, Booleans and rules to the core policy. That is pretty much what we want to do when we need to modify the default policy to suit our needs.
From what we’ve just covered, it is clear that we need to create SELinux policy modules—thereby creating new types, Booleans and various rules.

Creating SELinux modules

SELinux policy modules need to be written in the SELinux policy language. It is not a complicated language at all, but like most programming languages, requires a certain structure and syntax to be followed while creating the modules.
Also, once the text files containing our desired modifications have been created, we need to compile them into a binary policy module (Policy Package). Once the Policy Package files have been created, they just need to be tested and then finally loaded to enable the desired functionality.
To enable the development and compilation of policy modules, install the selinux-policy-devel RPM. The installed RPM on my system is selinux-policy-devel-2.4.6-106.el5_1.3.
This module creates the /usr/share/selinux/devel/ directory, which contains ‘include’ files and a makefile for compilation. It also installs three files—example.teexample.fc and example.if—to assist you in the creation of policy modules.
The three files are important to understand the structure of policy modules:
  • The type enforcement file (a file with the .te extension—for example,/usr/share/selinux/devel/example.te) is the most important file. This contains the name of the module, its version and all the additions desired in the policy, such as types, rules, Booleans, etc.
  • The file contexts file (with the .fc extension—for example,/usr/share/selinux/devel/example.fc) contains the default security contexts to be provided for files created/used by the application for which we are creating the policy module.
  • The interface file (one with the .if extension—for example,/usr/share/selinux/devel/example.if) generally would contain macro definitions that assist in creating type enforcement rules.
The type enforcement file (.te) is mandatory, while the other two files (.fc and .if), if not required, need not be explicitly created. I would advise their use, but it generally depends on the kind of policy module to be developed.

Syntax of the type enforcement file

The most important thing for a policy module to be clearly distinguished is its name and version—the output of the semodule -l command. This is specified as the first line in a .te file aspolicy_module(,).
New types being introduced by the module are declared as type ;. Let’s create a small policy module called test to introduce a new type called lfy_t. Use the following steps to achieve the above:
  1. Create a work directory for building and compiling your SELinux modules.
  2. Copy the necessary files needed for compiling SELinux modules.
  3. Create at least a .te file for your SELinux module, specifying the module name and version number.
  4. Compile the source file above to a binary policy package file.
  5. Load the binary policy package.
  6. Test the changes in the SELinux Policy.
Step 1: Create a work directory for building and compiling your SELinux modules.
Instead of working in default directories, experience has taught me to work as a non-root user in non-default folders. Let us log in as the non-root user and make a working directory for our SELinux modules:
[vbg@vbg ~]$ mkdir test-selinux
[vbg@vbg ~]$ cd test-selinux/
[vbg@vbg test-selinux]$ cp /usr/share/selinux/
Step 2: Copy the necessary files needed for compiling SELinux modules.
The only important file that you need to copy to your working directory is the Makefile from the/usr/share/selinux/devel/ directory.
[vbg@vbg test-selinux]$ cp /usr/share/selinux/devel/Makefile .
[vbg@vbg test-selinux]$ ls
Step 3: Create at least a .te file for your SELinux module, specifying the module name and version number:
Create a new file called test.te and append the statements in it:
policy_module(test,1.0)

type lfy_t;
The above step specifies that we are creating a policy module named test with the version 1.0 and are declaring a new type to be introduced in the policy called lfy_t.
Step 4: Compile the source file above to a binary policy package file.
To compile the source, simply run make (ensure you have copied the Makefile in Step 2 shown above):
[vbg@vbg test-selinux]$ make
Compiling targeted test module
/usr/bin/checkmodule:  loading policy configuration from tmp/test.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 6) to tmp/test.mod
Creating targeted test.pp policy package
rm tmp/test.mod.fc tmp/test.mod
You should now have the compiled policy package file test.pp:
[vbg@vbg test-selinux]$ ls -l
total 60
-rw-r--r-- 1 vbg vbg   437 Sep 24 10:36 Makefile
-rw-rw-r-- 1 vbg vbg     0 Sep 24 10:36 test.fc
-rw-rw-r-- 1 vbg vbg     0 Sep 24 10:36 test.if
-rw-rw-r-- 1 vbg vbg 22994 Sep 24 10:36 test.pp
-rw-rw-r-- 1 vbg vbg    37 Sep 24 10:36 test.te
drwxrwxr-x 2 vbg vbg  4096 Sep 24 10:36 tmp
To check if a type lfy_t exists, just use the following command:
[root@vbg devel]# seinfo -t |grep lfy
You will not receive any output. This shows that the type lfy_t does not exist in our policy currently.
Step 5: Load the binary policy package.
As the root user, use the semodule command to load the compiled test.pp policy package. The option to use with the semodule command is -i (which stands for insert).
[root@vbg devel]# semodule -i /home/vbg/test-selinux/test.pp
To confirm if the module has been successfully loaded, list all the modules:
[root@vbg devel]# semodule -l
cs     1.0.0
clamav  1.1.0
dcc     1.1.0
evolution       1.1.0
iscsid  1.0.0
mozilla 1.1.0
mplayer 1.1.0
nagios  1.1.0
oddjob  1.0.1
openoff 1.0.0
pcscd   1.0.0
pyzor   1.1.0
razor   1.1.0
ricci   1.0.0
smartmon        1.1.0
test    1.0
tmp     1.0.1
vbg     1.0.3
You can see that a module named test with version 1.0 has been loaded.
To check whether our new type has been added, retype the earlier command:
[root@vbg devel]# seinfo -t | grep lfy
lfy_t
This shows that we have successfully introduced a new type in our SELinux policy by adding a policy module.

Up next

In this article, we have covered the basics of policy modules. In the next part of the series, we will look at adding Allow Rules, Type Transition Rules, Booleans and other policy building blocks. We shall also look at the audit2allow tool that helps to create policy modules.
I hope the article has helped you understand the modular structure of SELinux. It is this modularity that allows administrators to easily create SELinux policy modules for whatever applications they deploy—without compromising the security of their system.

0 comments

Post a Comment