Sunday, February 19, 2012

SELinux Policy Generation

This post is going to be all about creating SELinux policy. Let me start by laying down the information that I know. I know that there are two tools that we can use to create a basic framework for me to get started. The first is the Fedora SELinux Policy Generation Tool otherwise known as polgengui. The second, non-gui version, is called selpolgen. In my example I have an application, that I created, called magic8. This is basically a program that has a client and a server component. The client sends a request to the server via port 77 and the server responds with some response. Now, I am trying to confine the server daemon to only be able to read the file "response.txt" and only append to the file "magic8d.log". This all just for practice in using the policy generation tool. I will use the GUI version as a starting point. To me it appears as if there is no manpage for either of the tools discussed above. For the record I am using 64-bit Fedora 16 and I have installed the following packages via yum:
libcap-devel
libcap-ng-devel
policycoreutils-gui.x86_64
setools-devel
First, let's start out by ensuring that our SELinux is set to permissive mode. We can check this by running the command getenforce. This will tell you what mode SELinux is in either permissive or enforcing. We can toggle the mode by running sudo setenforce 0 or sudo setenforce 1. This will set SELinux to permissive or enforcing, respectively. We want to be in permissive mode so that once we compile and install our policy we can debug the policy without SELinux blocking our every move. We can start the SELinux Policy Generation tool by going to Applications -> System Tools -> SELinux Policy Generation Tool. Once the tool starts you will be asked for what kind of policy you are creating:
I am creating a policy for a User Application but you should select the option that applies to you. Select your option and then click forward. Next, you are asked for the name of your policy and then the name and location of the executable for the application. I called my policy magic8d since I am creating policy for the Magic8 daemon and the executable is called magic8d and located in /usr/local/magic8.

Click forward once you have entered your information. The next screen asks you what user_roles will transition to 'magic8d.' This is asking what type of role is going to start the application. In an SELinux targeted policy environment every user is unconfined and since this application is utilizing a privileged port we must use sudo to start the daemon. In either case we should select unconfined.
Click forward. This screen asks you what port(s) we need to bind to. This application only uses port 77 through TCP. So the only thing we need to do here is enter 77 in the TCP box. You should enter the port number(s) that your application binds to. If you aren't sure what if any port your application binds to you can leave it blank. Later during the debugging process we can add this exception to the policy.
Click forward. This screen asks you what port(s) your application connects to. Note that this is different than binding. In our case our daemon will send information to a client again via port 77 so we must also add port 77 under the TCP area.
Click forward. Next is a list of other common functions that our application could perform. This particular application writes syslog messages so we need to select that option. For this purpose we can leave all the others blank. Again if you do not know you can leave them all blank and later in the debugging process we can add the functionality to the policy.
 Click forward. The next screen is asking you which files this application manages. My application uses two files. A file called "responce.txt" and a logfile called "magic8.log." I will add both of these files to this screen but later I will need to go back and refine the policy for both of these files. I will explain in more detail later.
Click forward. Next we will be given an opportunity to add any booleans that this application uses. My application does not use any booleans so I will leave this screen blank.
Click forward. Next we are asked where we want the policy generator to put our policy files. The default should be your home folder. This is good for me so I will leave it unchanged.
Click apply. The popup box tells you the name of the four files that this policy generator has created. In my case the Policy Generator made magic8d.te, magic8d.if, magic8d.fc, and magic8d.sh. The .te file is the type enforcement file. This is the main file the defines what our application is allowed to do. The .if file is the Interface file and this defines the permissions for the interations with files and file descriptors. The .fc file is the file contexts file and contains a list of the the files that are associated with our application and what their security context will be. Lastly, the .sh file is the setup script. We will run this script to install our policy once we are done editing it.
Click ok on this popup box. The SELinux Policy Generation Tool window will remain open. You can close it if you like, we will not need it from here on out.

Now, let's first check out the .fc file. As I said before I will need to refine the default policy because of the files that my application accesses. Specifically I will need to create a policy that allows my application to read and only read the file "responce.txt" we do not need to read any other files. Further I will refine the policy to write and only write the logfile "magic8.log" and we do not need to write to any other files. By default the policy generation tool will allow read, write, execute, delete, and create access to any files we specified for it to manage. I will now describe how to refine the policy. Here is what my .fc file looks like originally:
 What I need to do here is create two types. A read type and a write type. I need to change the security contexts of the files associated with the application. I did this blelow. As you can see the security context (system_u:object_r:magic8d_w_t,s0) is given to magic8.log and this will be my write only type and the security context (system_u:object_r:magic8d_r_t,s0) is given to responce.txt and this will be my read only type.
Save and close this file. Now lets look at the .te file. Here is my original file:
 Right now we are only concerned with lines 15 and 16
...
15 type magic8d_rw_t;
16 files_type(magic8d_rw_t)
...
These lines declare the type that is associated with the files that we changed in the .fc file. We need two change these two lines and add two more.
...
15 type magic8d_w_t;
16 files_type(magic8d_w_t)
17 type magic8d_r_t;
18 files_type(magic8d_r_)
... 
We must also comment out line 31, change line 32 and add the following line:
...
31 #manage_dirs_pattern(magic8d_t, magic8d_rw_t, magic8d_rw_t)
32 manage_files_pattern(magic8d_t, magic8d_r_t, magic8d_r_t)
33 manage_files_pattern(magic8d_t, magic8d_w_t, magic8d_w_t)...
We need to make these changes because our program does not manage any directories and we changed the magic8d_rw_t type.
Close and save this file. Next open up the .if file. This is by far the most complicated file and even I am not sure what everything in this file is supposed to do. There are many changes that you need to make. The basic idea is that everytime we see the type magic8d_rw_t we need to either change it to magic8d_r_t or magic8d_w_t and then where relevant we need to add the approprite command for the other type. Here are the changes that I made:
The first instance that I found was on line 37. This is in the search rw directories section. My application doesn't really search any directories. So I shouldn't need to allow this feature. On line 37 I will change magic8d_rw_t to magic8d_r_t and also add the line magic8d_w_t just below it. I will now also comment out lines 41 and 42 because I do not need to allow permission to search these directories.
The next instance is on line 57. This is in the read rw file files section. I need to change line 57 to
...
type magic8d_r_t;
...
Then I need to  change lines 60 and 61 to:
...
60 allow $1 magic8d_r_t:file read_file_perms;
61 allow $1 magic8d_r_t:dir list_dir_perms;
...
I do not need to add the magic8d_w_t type to this section because we do not need to read those files.
The next instance occurs on line 77 in the manage rw files section. I will change line 77 and add the next line:
...
77 type magic8d_r_t;
78 type magic8d_w_t;
...
I don't need to worry about the application managing these files so I will comment out line  81.
The next instance occurs on line 97 in the create, read, write rw dirs section. I will again change line 97 and add the following line:
...
97 type magic8d_r_t;
98 type magic8d_w_t;
...
Now, since the application doesn't manage any directories (all files are in the current directory) I will I comment out line 101.
The next instance occurs on line 179 in the administrative section. I will change line 179 and add the following line:
...
179 type magic8d_r_t;
180 type magic8d_w_t;
...
Next I will change line 187 and add the following line:
...
187 admin_pattern($1, magic8d_r_t)
188 admin_pattern($1, magic8d_w_t)
...
We need to make one more addition to this file before we are finished. We need to create a rule that will allow us to write to the files that we need to write to. We can do this by mimicing the section for reading files. Here is what I added:
...
interface(`magic8d_read_rw_files',`
    gen_require(`
        type magic8d_w_t;
    ')

    allow $1 magic8d_w_t:file write_file_perms;
    allow $1 magic8d_w_t:dir list_dir_perms;
    files_search_rw($1)
')
...
We are now finished with this file. If you did it completely when you do a ctrl + f for magic8d_rw_t the only results you should find will be commented out. All of mine are so I am finished.

Our next step is to install the policy and then debug the policy. We will use the SELinux troubleshooter for debugging and if you haven't already done so ensure that your SELinux is in permissive mode by following the steps that I outlined above. In the terminal navigate to your home directory and run the following command:

sudo ./magic8d.sh

If you forget to do sudo the script will prompt you to use sudo. If your build was successful your output should look something like this:

[bill@localhost ~]$ sudo ./magic8d.sh
Building and Loading Policy
+ make -f /usr/share/selinux/devel/Makefile
Compiling targeted magic8d module
/usr/bin/checkmodule:  loading policy configuration from tmp/magic8d.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 14) to tmp/magic8d.mod
Creating targeted magic8d.pp policy package
rm tmp/magic8d.mod tmp/magic8d.mod.fc
+ /usr/sbin/semodule -i magic8d.pp
+ /sbin/restorecon -F -R -v /usr/local/magic8/magic8d
/sbin/restorecon reset /usr/local/magic8/magic8d context unconfined_u:object_r:usr_t:s0->system_u:object_r:magic8d_exec_t:s0
+ /sbin/restorecon -F -R -v /usr/local/magic8/response.txt
/sbin/restorecon reset /usr/local/magic8/response.txt context unconfined_u:object_r:usr_t:s0->system_u:object_r:magic8d_r_t:s0
+ /sbin/restorecon -F -R -v /usr/local/magic8/magic8.log
/sbin/restorecon reset /usr/local/magic8/magic8.log context unconfined_u:object_r:usr_t:s0->system_u:object_r:magic8d_w_t:s0
+ /usr/sbin/semanage port -a -t magic8d_port_t -p tcp 77
+ /usr/sbin/semanage port -a -t magic8d_port_t -p tcp 77
/usr/sbin/semanage: Port tcp/77 already defined

At this point the policy has been installed and you are ready to debug. Again with SELinux in permissive mode. Run your application and put it through the wringer. Since your policy is probably not perfect you should receive notifications from the SELinux Troubleshooter. Take a look at these alerts and see what your program tried to do that you didn't allow it to do. Since SELinux is in permissive mode the application was still allowed to proceed but it still added an alert in the audit.log file to say that it would have been denied if SELinux was set to enforcing. In FC16 if you look in the details section of the alert it will give you the reccommended way to let SELinux allow your application this function. In general you have three choices. You can choose to ignore the problem and report it as a bug to the developer of the app because their program shouldn't have that functionality, add the privlege in your SELinux policy or tell SELinux to ignore that action and do not audit that particular privilege for the application. You can check that your application started under the correct security context by running 


ps -eZ | grep magic8d

and you should recieve something like the following:

unconfined_u:unconfined_r:magic8d_t:s0-s0:c0.c1023 21549 pts/0 00:00:00 magic8d

In this case my policy was successfully installed and is working correctly. I have received no alerts so at this point I can set SELinux to enforcing and continue testing. Once I am confident in my policy then I can deploy my policy and application to a production server.

*NOTE*
It is wise to create policy in a virtual environment because while debugging you will set your SELinux policy to permissive mode. On a production server this could lead to undesirable results. I made this only as a reference and I take no responsibility for the result of your actions while following my guide.

5 comments:

  1. Thank you for the kind comments. That was my goal with this post and with this whole blog, to have a place where people can go to learn how to perform tasks to secure their networks or their systems. In my endeavors to find how to generate quality SELinux policy I came up empty handed. I am hoping that by sharing this knowledge with someone else I make their job just a little bit easier.

    ReplyDelete
  2. Hi! when I run the command " ps -eZ | grep magic8d " not seen nothing appears . Can you tell me how to run the process magic8d?
    I am researching write and checks policy in SELinux, I have some reference material but do not fully understand how to write and test policy, you can help me a post or examples specific ?
    Thanks!

    ReplyDelete
  3. Yes, magic8d was a specific daemon (executable) that I was using in this example. If there is a specific appliction that you are writing policy for then you would replace magic8d with the name of that application.

    ReplyDelete
    Replies
    1. I'm very happy to receive your comment! Thank for your comment! I also know it. Could you suggest me to simulate how policy work? I think your post is very helpful.
      Thank you very much!

      Delete
  4. This comment has been removed by the author.

    ReplyDelete