Exercise 2.2 - Creating a Custom SELinux Application Policy

Return to Workshop

Exercise Description

This exercise will walk you through the steps required to handle AVC messages that are generated by SELinux, when an application violates existing policy. We will modify the already-created generic policy, in order to allow the application to run correctly, when we switch the policy to enforcing mode.

Step 1: Check for AVC denials

Now that our app is up and running, we can check the system logs for AVC (access vector cache, where SELinux caches decisions to grant or deny access) denial messages.

sudo ausearch -m AVC -ts today

There will (and should!) be quite a few denials returned from ausearch. Here are some from the example machine:

----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.764:25971): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.764:25971): arch=c000003e syscall=2 success=yes exit=4 a0=401a32 a1=0 a2=1b6 a3=24 items=0 ppid=1 pid=1022 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.764:25971): avc:  denied  { open } for  pid=1022 comm="testapp" path="/proc/meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1
type=AVC msg=audit(1552588580.764:25971): avc:  denied  { read } for  pid=1022 comm="testapp" name="meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.764:25972): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.764:25972): arch=c000003e syscall=41 success=yes exit=3 a0=a a1=2 a2=0 a3=7ffc9a8c3360 items=0 ppid=1022 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.764:25972): avc:  denied  { create } for  pid=1023 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.765:25973): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.765:25973): arch=c000003e syscall=4 success=yes exit=0 a0=7f22154460c1 a1=7f22110523f0 a2=7f22110523f0 a3=3 items=0 ppid=1022 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.765:25973): avc:  denied  { getattr } for  pid=1023 comm="testapp" path="/etc/resolv.conf" dev="dm-0" ino=67445450 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.765:25974): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.765:25974): arch=c000003e syscall=2 success=yes exit=3 a0=7f22154460c1 a1=80000 a2=1b6 a3=24 items=0 ppid=1022 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.765:25974): avc:  denied  { open } for  pid=1023 comm="testapp" path="/etc/resolv.conf" dev="dm-0" ino=67445450 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1
type=AVC msg=audit(1552588580.765:25974): avc:  denied  { read } for  pid=1023 comm="testapp" name="resolv.conf" dev="dm-0" ino=67445450 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.765:25975): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.765:25975): arch=c000003e syscall=42 success=yes exit=0 a0=3 a1=7f2211053dcc a2=10 a3=7f22110507a0 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.765:25975): avc:  denied  { connect } for  pid=1023 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.766:25976): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.766:25976): arch=c000003e syscall=16 success=yes exit=0 a0=3 a1=541b a2=7f2211050ea0 a3=7f22110507a0 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.766:25976): avc:  denied  { getattr } for  pid=1023 comm="testapp" path="socket:[1181449]" dev="sockfs" ino=1181449 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.769:25977): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.769:25977): arch=c000003e syscall=41 success=yes exit=3 a0=2 a1=1 a2=6 a3=7ffc9a8c35e0 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.769:25977): avc:  denied  { create } for  pid=1023 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.769:25978): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.769:25978): arch=c000003e syscall=42 success=no exit=-115 a0=3 a1=7ffc9a8c38d0 a2=10 a3=7ffc9a8c31e0 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.769:25978): avc:  denied  { name_connect } for  pid=1023 comm="testapp" dest=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=1
type=AVC msg=audit(1552588580.769:25978): avc:  denied  { connect } for  pid=1023 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.881:25982): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.881:25982): arch=c000003e syscall=55 success=yes exit=0 a0=3 a1=1 a2=4 a3=7ffc9a8c3b20 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.881:25982): avc:  denied  { getopt } for  pid=1023 comm="testapp" laddr=10.0.1.10 lport=57036 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1
----
time->Thu Mar 14 14:36:20 2019
type=PROCTITLE msg=audit(1552588580.881:25983): proctitle="/usr/local/sbin/testapp"
type=SYSCALL msg=audit(1552588580.881:25983): arch=c000003e syscall=52 success=yes exit=0 a0=3 a1=7ffc9a8c39f0 a2=7ffc9a8c39ec a3=7ffc9a8c3460 items=0 ppid=1 pid=1023 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="testapp" exe="/usr/local/sbin/testapp" subj=system_u:system_r:testapp_t:s0 key=(null)
type=AVC msg=audit(1552588580.881:25983): avc:  denied  { getattr } for  pid=1023 comm="testapp" laddr=10.0.1.10 lport=57036 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1

Section 1: Update the policy to allow access to /proc

Step 1: Interpret AVC messages

In the first audit message, we see these AVC messages:

type=AVC msg=audit(1552588580.764:25971): avc:  denied  { open } for  pid=1022 comm="testapp" path="/proc/meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1
type=AVC msg=audit(1552588580.764:25971): avc:  denied  { read } for  pid=1022 comm="testapp" name="meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1

If we look at them both closely, we can see that the testapp process is being denied open on /proc/meminfo, and read on /proc, in general. So, we need to find the interface that will allow those accesses, and add it to our testapp.te file.

Step 2: Find the right interface

SELinux interface definitions are located in /usr/share/selinux/devel/include, if you install the selinux-policy-devel package. If we search for /proc, in files named *.if (interface definitions):

cd /usr/share/selinux/devel/include
find . -type f -name "*.if" -exec grep -H '/proc' {} \; | grep "system state information"

We see that in the results, there is a line that says:

./kernel/kernel.if:##	Allows caller to read system state information in /proc.

That makes sense, so let’s see what interface has that comment. Searching for it finds this stanza:

########################################
## <summary>
##      Allows caller to read system state information in /proc.
## </summary>
## <desc>
##      <p>
##      Allow the specified domain to read general system
##      state information from the proc filesystem (/proc).
##      </p>
##      <p>
##      Generally it should be safe to allow this access.  Some
##      example files that can be read based on this interface:
##      </p>
##      <ul>
##              <li>/proc/cpuinfo</li>
##              <li>/proc/meminfo</li>
##              <li>/proc/uptime</li>
##      </ul>
##      <p>
##      This does not allow access to sysctl entries (/proc/sys/*)
##      nor process state information (/proc/pid).
##      </p>
## </desc>
## <param name="domain">
##      <summary>
##      Domain allowed access.
##      </summary>
## </param>
## <infoflow type="read" weight="10"/>
## <rolecap/>
#
interface(`kernel_read_system_state',`
        gen_require(`
                attribute kernel_system_state_reader;
        ')

        typeattribute $1 kernel_system_state_reader;
')

This interface takes a single parameter (look in the <param…​> section), which is the name of the SELinux domain to be allowed access. In this case, the domain name is testapp, matching the name of our application and policy module.

Step 3: Add the interface to the policy

To allow this, add the interface to testapp.te, with a line, in the testapp local policy section, like this:

kernel_read_system_state(testapp_t)

The file should now look like this:

cat ~/src/policy/testapp.te
policy_module(testapp, 1.0.0)

########################################
#
# Declarations
#

type testapp_t;
type testapp_exec_t;
init_daemon_domain(testapp_t, testapp_exec_t)

permissive testapp_t;

type testapp_var_run_t;
files_pid_file(testapp_var_run_t)

########################################
#
# testapp local policy
#
allow testapp_t self:process { fork };
allow testapp_t self:fifo_file rw_fifo_file_perms;
allow testapp_t self:unix_stream_socket create_stream_socket_perms;

manage_dirs_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t)
manage_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t)
manage_lnk_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t)
files_pid_filetrans(testapp_t, testapp_var_run_t, { dir file lnk_file })

domain_use_interactive_fds(testapp_t)

files_read_etc_files(testapp_t)

kernel_read_system_state(testapp_t)

logging_send_syslog_msg(testapp_t)

miscfiles_read_localization(testapp_t)

Keeping things in alphabetic order doesn’t make any difference to SELinux, but makes the file easier to read.

Step 4: Recompile and reload the policy

Now, let’s recompile the policy, and reload it into memory.

cd ~/src/policy
sudo ./testapp.sh

Step 5: Restart the application

To see if that fixed the problem, let’s restart the application:

sudo systemctl restart testapp

…​and see if there are any AVC messages about /proc:

sudo ausearch -m AVC -ts recent | grep meminfo | wc -l
0

Hooray! One AVC down, quite a few to go.

End Result

We’ve now made our first additions to the type enforcement file. Hopefully, this is starting to make sense. Don’t hesitate to talk to your instructor about anyything that we have done that isn’t clear.


Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop