November 28th, 2006

How do I make local customizations in RHEL 5?

With the release of Red Hat Enterprise Linux 5 Beta 2, I am getting more questions about customizing policy.  In RHEL4 we advised people to install the selinux-policy-targeted-sources packages and then to create a local.te file in the /etc/selinux/targeted/src/policy/domains/misc directory.  You could use audit2allow to translate the AVC messages into allow rules and then the admin could rebuild policy and reload.  The problem with this was that everytime a new policy package got released it would have to exec the Makefile in order to try to keep the local policy.  Well with the release of Red Hat Enterprise Linux 5, this all changes.  We have eliminated the "sources" rpm packages altogether.  We are treating the policy packages more like the kernel, and if you want to look at the sources used to build the policy, you need to install source rpm, selinux-policy-XYZ.src.rpm.  We have added an selinux-policy-devel package, which I will talk about later. 

So what does an administrator do when he wants to make some small modifications to policy?

We have introduced the concept of modular policy.  This allows vendors to ship SELinux policy separate from the OS Policy.  It also allows administrators to make local changes to policy and not have to worry about the next policy install.  Modular policy was introduced in Fedora Core 5 and more features were added in Fedora Core 6. The major command that was added was semodule.
>man semodule

SEMODULE(8)                           NSA                          SEMODULE(8)

       semodule - Manage SELinux policy modules.

       semodule [options]... MODE [MODES]...

       semodule is the tool used to manage SELinux policy modules, including installing, upgrading, listing and remov-
       ing modules.  semodule may also be used to force a rebuild of policy from the module store and/or  to  force  a
       reload  of policy without performing any other transaction.  semodule acts on module packages created by semod-
       ule_package.  Conventionally, these files have a .pp suffix (policy package), although this is not mandated  in
       any way.


If you want to view the policy modules on a system you can use the semodule -l command

# 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
nagios  1.1.0
oddjob  1.0.1
pyzor   1.1.0
razor   1.1.0
ricci   1.0.0
smartmon        1.1.0

This command does not show you the base policy module which is also installed. You can read all about loadable policy modules at tresys.  Also the excellent book,
SELinux by Example,  has some great information on SELinux and modules.  And no I do not recieve commisions.  :^)

If you look in /usr/share/selinux/targeted/ you will see a lot of policy package (*.pp) files there.  These files are included in the selinux-policy rpm and are used to build the policy file. 
So lets get back to builind a local policy module. Lets look at an example. Currenly there is a bug in policy.  The ypbind init script executes the setsebool command which in turn tries to use the terminal.  This is generating a denial

type=AVC msg=audit(1164222416.269:22): avc:  denied  { use } for  pid=1940 comm="setsebool" name="0" dev=devpts ino=2 scontext=system_u:system_r:semanage_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=fd

While this is not a big deal, since everything works correctly, it can be an aggravation.  To eliminate this AVC, you could use audit2allow to generate a rule that looks like this.

# grep setsebool /var/log/audit/audit.log  | audit2allow
allow semanage_t init_t:fd use;

But since we do not have policy sources what do you do? Well audit2allow now has the  ability to build policy modules.

#  grep setsebool /var/log/audit/audit.log  | audit2allow -M mysemanage
Generating type enforcment file: mysemanage.te
Compiling policy
checkmodule -M -m -o mysemanage.mod mysemanage.te
semodule_package -o mysemanage.pp -m mysemanage.mod

******************** IMPORTANT ***********************

In order to load this newly created policy package into the kernel,
you are required to execute

semodule -i mysemanage.pp

The audit2allow rule has actually gone out and built a type enforcement file (mysemanage.te).  audit2allow  then executed the checkmodule command to compile a module file (mysemanage.mod). Finally it uses the semodule_package package up a policy package (mysemanage.pp). If you look at the te file:

cat mysemanag.te
module mysemanage 1.0;

require {
        class fd use;
        type init_t;
        type semanage_t;
        role system_r;

allow semanage_t init_t:fd use;

You will see three sections in the te file.  The first section is the module command which identifies the name of the module and its version. This must be unigue, which is why I prefix "my" on my module names.  If I created a semanage module and one already existed the system would try to replace the existing module package with mine.  The last part of the module line is the version.  semodule has the ability to update module packages and will check the version versus the currently installed version.

The next block of the te file is the require block.  This is used to tell the policy loader semodule, which type, classes and roles are required to be already in the system policy before this module can be installed.  If any of these fields are undefined, the semodule command will fail.

Finally are the allow rules.  Now we could modify this line to dontaudit, since semodule does not need to access the file descriptor.

Why do we have to run the semodule_package command?

This command basically wraps up different policy files together in a policy package.  Usually just the module and potentially a file context file. The final step for the administrator is to load the policy package with the semodule command.

# semodule -i mysemanage.pp

This command will recompile the policy file and regenerate the file context file.  The changes are permanent and will survive a reboot.  Also the policy package file mysemanage.pp can be copied to other machines and installed using semodule.

Audit2allow shows you the commands it executed to create the policy package so you can edit the te file to add new rules if you want or change the allow to dontaudit. You could then recompile and repackage the policy package to be installed again.

There is no limit to the number of policy packages so you could create one for each local modification you want to make, or you could continue to edit one, but make sure your "require" statements match all of the allow rules.