Hacks From Pax: SELinux Policy Development

    Date17 Nov 2005
    Posted ByBrittany Day
    Hi, and welcome to the final entry in my series of articles on SELinux. My last three articles have provided an overview and history of SELinux, discussed how SELinux makes access decisions, and explained how to administer an SELinux system. Today we'll build on the SELinux knowledge we've gained and learn how to perform basic customization of our system's security policy.

    Customizing your system's SELinux policy can be necessary when running an application your policy is unaware of. Particularly, web based applications might need customization of Apache policy in order to run properly.

    Setting Up a Policy Development Environment

    For the purposes of this article, I'll assume you have a server running EnGarde Secure Community 3.0 (a free downloadable ISO image is available). Engarde Secure Linux is a good base for learning SELinux policy since it is a server system only, which allows for a policy that is easier to understand than distributions such as Fedora which include many policy modules for X11 and other desktop applications.

    First, log in as root and transition to the sysadm_r role. Generally policy development is best done with SELinux in permissive mode, so use the setenforce command to set the proper mode. Be sure your system is upgraded to the latest release by issuing the apt-get update command, and then install the necessary policy development packages by entering apt-get install make m4 gcc python engarde-policy-sources. Other packages may be installed due to dependencies.

    Compiling Policy

    Once this is done, you should change to the policy sources directory which is /etc/selinux/engarde/src/policy/. The main part of the policy sources is the policy/modules directory, which contains directories that contain your actual policy source modules for all services and applications constrained by SELinux.

    The first time you compile a policy, you must make the configuration files by typing make conf in the main policy directory. This creates the modules.conf and policy.conf files. Now you can compile the policy by entering make policy. This gathers all the modules and compiles them into a binary policy that is directly used by SELinux.

    The next step is to install the newly compiled policy by issuing the make install command. Next, you must reload the policy by typing make reload. If you have changed file specifications, you also need to relabel based on the new policy, this is done by typing make relabel. Finally, return to enforcing mode using the setenforce command.

    One way to speed up this process is to issue all of the compilation commands in a single command line, as shown below.

    # setenforce 0 && make policy install reload relabel reload && setenforce 1

    Auditing An Application

    Now that you have a policy development environment and are able to compile SELinux policy, you can make policy changes to correct any audited messages in your system log or enable a permission needed by an application you use.

    You must create some source files when adding security policy statements that only apply to the local system, since if you add statements to existing files they will be overwritten during policy updates. Create local files by issuing these commands:

    touch /etc/selinux/engarde/src/policy/policy/modules/admin/local.fc
    touch /etc/selinux/engarde/src/policy/policy/modules/admin/local.te
    touch /etc/selinux/engarde/src/policy/policy/modules/admin/local.if

    Next, edit the /etc/selinux/engarde/src/policy/policy/modules.conf file and add a line reading local = base and save the file. Recompile the policy and check the output to ensure your local.* files were included.

    Let's say, for example, that you've installed some PHP scripts on your website that function fine in permissive mode, but fail when you enable enforcing mode, since the scripts are attempting an action that SELinux does not allow.

    The first step would be to open a terminal to the server, ensure you're logged in to the sysadm_r role, and execute the following commands:

    # setenforce 0
    # dmesg -c
    # watch audit2allow -d

    These commands will allow you to view the missing SELinux permissions in real time. The audit2allow command is the single most useful tool when troubleshooting SELinux problems. When run with the -d switch, it monitors the dmesg output for SELinux audit errors, and automatically converts these errors into the correct allow command that could be added to the policy to permit the denied action.

    With the above commands running and your system in permissive mode, run through the parts of your application that are causing trouble and you should see your audit2allow terminal start outputting allow statements. Review these statements, since they may be unsafe due to incorrect file labeling and may be far too permissive.

    For example, your audit2allow output may recommend giving your application full read/write access to the etc_t type. This would allow writing of many files in the /etc directory that belong to other applications and would be unsafe. The correct way to design your policy would be to change the type of the files your application is actually accessing to something narrower and more restricted so you can allow write access to only that new type.

    If you're unsure what file is being accessed, look at your system log and search it for the actual denial message. The denial message will look something like the following:

    Oct 19 14:38:54 paxtest kernel: audit(1129747134.276:0): avc: denied { read } for name=messages dev=hda6 ino=2146393 scontext=root:staff_r:staff_t tcontext=system_u:object_r:var_log_t tclass=file

    The ino entry in the denial message indicates the inode of the file that the denial refers to. You can locate this file by using a find command thusly:

    # find / -inum 2146393

    If you need to assign a different file context to a file, edit the $policy/policy/modules/admin/local.fc. The .fc files are lists of regular expressions matching a full file path followed by a security context to assign to that file during a relabel. Look at other existing .fc files in the policy for an idea of how these work. Once you assign a new context to a file, recompile and relabel, then perform your application testing again to generate a new list of allow statements that take the new context into account.

    Modifying Policy

    Once you have your list of all your allow statements, examine them carefully and try to understand what you are allowing before adding them to policy. One weakness of audit2allow is that it is unaware of macros contained in the policy, so grep through your policy sources for allow statements close to the ones you'd like to add and try to find appropriate macros to use instead. If you're planning on doing a lot of policy customization it's a good idea to familiarize yourself with the existing policy sources so you're aware what macros are available.

    The $policy/policy/support/obj_perm_sets.spt is one good place to start, it contains macros that expand out to useful permissions groupings. For example, rather than allowing a domain the ioctl, read, getattr, lock, write, and append permissions to a given type, you can simply assign it the rw_file_perms macro instead. This helps keep policy readable later on.

    Once you have generated your needed allow statements, add them to the $policy/policy/modules/admin/local.te file and recompile the policy. If your application still won't work in enforcing mode, just repeat the process until you can run it with no SELinux audit errors.

    Always keep your policy changes in the $policy/policy/modules/admin/local.* files. These files are included in the package empty and intended for local policy customization. If you change a file that belongs to a service and contains rules already your changes will be lost when the policy is upgraded, so keep local changes in the local.te and local.fc files where they belong.

    If you find a problem in existing policy, add your changes to local.* but provide a patch to the policy maintainers so they can include it in a later build. Most SELinux policies are being constantly developed and revised since the technology is still fairly new, and your upstream maintainers will thank you for your help.

    Policy development can be difficult at the beginning, but I think you'll find that as you make progress you'll be learning not only about SELinux but about the details of what your applications are really doing under the hood. You'll not only be making your system more secure, you'll be learning about the low level details of your system and its services. SELinux development has already resulted in upstream patches to many applications that had hidden bugs that were only found because SELinux alerted policy developers to the kernel level actions the applications were attempting.

    I hope you enjoyed reading this SELinux series as much as I enjoyed writing it. Until next time, stay secure and keep your policy locked down tight.
    Pax Dickinson has over ten years of experience in systems administration and software development on a wide variety of hardware and software platforms. He is currently employed by Guardian Digital as a systems programmer where he develops and implements security solutions using EnGarde Secure Linux. His experience includes UNIX and Windows systems engineering and support at Prudential Insurance, Guardian Life Insurance, Philips Electronics and a wide variety of small business consulting roles.

    You are not authorised to post comments.

    Comments powered by CComment

    LinuxSecurity Poll

    What do you think of the articles on LinuxSecurity?

    No answer selected. Please try again.
    Please select either existing option or enter your own, however not both.
    Please select minimum 0 answer(s) and maximum 3 answer(s).
    [{"id":"87","title":"Excellent, don't change a thing!","votes":"25","type":"x","order":"1","pct":54.35,"resources":[]},{"id":"88","title":"Should be more technical","votes":"5","type":"x","order":"2","pct":10.87,"resources":[]},{"id":"89","title":"Should include more HOWTOs","votes":"16","type":"x","order":"3","pct":34.78,"resources":[]}]["#ff5b00","#4ac0f2","#b80028","#eef66c","#60bb22","#b96a9a","#62c2cc"]["rgba(255,91,0,0.7)","rgba(74,192,242,0.7)","rgba(184,0,40,0.7)","rgba(238,246,108,0.7)","rgba(96,187,34,0.7)","rgba(185,106,154,0.7)","rgba(98,194,204,0.7)"]350

    We use cookies to provide and improve our services. By using our site, you consent to our Cookie Policy.