Exercise 2.4 - Finishing the Policy

Return to Workshop

Exercise Description

In this final exercise, we will finish the testapp SELinux policy.

Section 1: A Last Interface

Step 1: Check for AVC denials

Let’s again restart our app, to get an updated list of denials.

sudo systemctl restart testapp

We only have a few denials left, and you will see that they all (probably!) reference /etc/resolv.conf or to /etc/hosts.

sudo ausearch -m AVC -ts recent | egrep '^type=AVC'
type=AVC msg=audit(1553195947.854:3270): avc:  denied  { getattr } for  pid=4651 comm="testapp" path="/etc/resolv.conf" dev="dm-0" ino=9311517 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(1553195947.854:3271): avc:  denied  { open } for  pid=4651 comm="testapp" path="/etc/hosts" dev="dm-0" ino=8389746 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(1553195947.854:3271): avc:  denied  { read } for  pid=4651 comm="testapp" name="hosts" dev="dm-0" ino=8389746 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1

Step 2: Interpret AVC messages

From the AVCs that we have, it seems clear that the application wants to try to resolve some hostnames to IP addresses. Most applications that access the network will need to be able to read system network configuration, and the interface for that is in /usr/share/selinux/devel/include/system/sysnetwork.if and is called sysnet_read_config.

#######################################
## <summary>
##      Read network config files.
## </summary>
## <desc>
##      <p>
##      Allow the specified domain to read the
##      general network configuration files.  A
##      common example of this is the
##      /etc/resolv.conf file, which has domain
##      name system (DNS) server IP addresses.
##      Typically, most networking processes will
##      require the access provided by this interface.
##      </p>
##      <p>
##      Higher-level interfaces which involve
##      networking will generally call this interface,
##      for example:
##      </p>
##      <ul>
##              <li>sysnet_dns_name_resolve()</li>
##              <li>sysnet_use_ldap()</li>
##              <li>sysnet_use_portmap()</li>
##      </ul>
## </desc>
## <param name="domain">
##      <summary>
##      Domain allowed access.
##      </summary>
## </param>
#
interface(`sysnet_read_config',`
        gen_require(`
                type net_conf_t;
        ')

        files_search_etc($1)
        allow $1 net_conf_t:file read_file_perms;

        ifdef(`distro_debian',`
                files_search_pids($1)
                allow $1 net_conf_t:dir list_dir_perms;
                read_files_pattern($1, net_conf_t, net_conf_t)
        ')

        ifdef(`distro_redhat',`
        files_search_all_pids($1)
        init_search_pid_dirs($1)
                allow $1 net_conf_t:dir list_dir_perms;
                allow $1 net_conf_t:lnk_file read_lnk_file_perms;
                read_files_pattern($1, net_conf_t, net_conf_t)
        ')
')

Step 3: Add the interface

So, as before, add an interface to your testapp.te file, using a line like this:

sysnet_read_config(testapp_t)

And compile your policy, and restart the service:

sudo ./testapp.sh
sudo systemctl restart testapp

…​and last, check to see if there are still any AVC denials:

sudo systemctl restart testapp
sudo ausearch -m AVC -ts recent | wc -l
0

Doesn’t it feel great to be almost done?

Section 2: Set Enforcing Mode

Step 1: Change the Domain to Enforcing

The last step that we need to take is to change our testapp.te file, so that the domain is enforcing. All we need to do, to accomplish this, is to comment out the line that says:

permissive testapp_t;

Once we do that, the final version of your policy should look like this:

cat 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:tcp_socket { connect create getattr getopt };
allow testapp_t self:udp_socket { connect create getattr };
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 })

corenet_tcp_connect_http_port(testapp_t)

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)

sysnet_read_config(testapp_t)

Step 3: Recompile and reload the policy

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

sudo ./testapp.sh

Step 4: 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 left:

sudo ausearch -m AVC -ts recent | egrep 'tcp|udp' | wc -l
0

And we are done.

End Result

This is the conclusion of the SELinux policy workshop. Please ask any questions that you have left, and thanks so much for coming!


Workshop Details

Domain
Workshop
Student ID

Return to Workshop