Networking

Practical SELinux: Port contexts and handling access alerts


After introducing and recommending SELinux a couple of weeks ago, I followed up with some of the basics - learning about setting file contexts with the semanage tool. This time, I'll show you how to set other contexts, and also look at how to handle reported access violations.

Previously, we concentrated on file contexts; yet another common and useful type of context to set is one related to ports. Using Apache as an example again, we know that Apache typically listens to ports 80 and 443. Default policy allows for this. If we wanted to have Apache listen on port 888 as well, however, this would not be permitted.

For instance, if you have:

<VirtualHost secret.foo.com:888>
...

in your httpd.conf file and attempted to restart Apache, it would fail as follows:

# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd: (13)Permission denied: make_sock: could not bind to address [::]:888
(13)Permission denied: make_sock: could not bind to address 0.0.0.0:888
no listening sockets available, shutting down
Unable to open logs
                                                           [FAILED]

What happened? Looking in /var/log/messages is a great place to start:

Apr  2 15:34:03 cerberus setroubleshoot: SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 888. For complete SELinux messages. run sealert -l b9797116-ceaa-4dc8-acbc-b2fdb1dd1cfd

This is fairly useful and gives the exact command to view the alert in detail. The information used to construct this is stored in /var/log/audit/audit.log, but using sealert to view it is much easier:

# sealert -l b9797116-ceaa-4dc8-acbc-b2fdb1dd1cfd
SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 888.
*****  Plugin bind_ports (92.2 confidence) suggests  *************************
If you want to allow /usr/sbin/httpd to bind to network port 888
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 888
    where PORT_TYPE is one of the following: ntop_port_t, http_cache_port_t, http_port_t.
*****  Plugin catchall_boolean (7.83 confidence) suggests  *******************
If you want to allow system to run with NIS
Then you must tell SELinux about this by enabling the 'allow_ypbind' boolean.
Do
setsebool -P allow_ypbind 1
*****  Plugin catchall (1.41 confidence) suggests  ***************************
If you believe that httpd should be allowed name_bind access on the port 888 tcp_socket by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# grep httpd /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp

The sealert tool offers a lot of information here, including suggestions on how to resolve the issue. Out of the three suggestions it provides, the first is the one we want. We need Apache to listen to this port. The third suggestion would work as well, but the first is the easiest of the bunch (provided the correct context is chosen). In this case, it isn't to be used for caching, but serving up content, so the httpd_port_t type is the one to use:

# semanage port -a -t http_port_t -p tcp 888
# semanage port -l | grep http_port
http_port_t                    tcp      888, 80, 443, 488, 8008, 8009, 8443
pegasus_http_port_t            tcp      5988

Incidentally, semanage port -l works the same for ports as semanage fcontext -l works for file contexts. In the above, we can see that the http_port_t type is now applied to port 888, and Apache should start. When it does, you can verify it is listening to the port with netstat:

# netstat -lpn --tcp | grep 888
tcp        0      0 :::888                      :::*                        LISTEN      28463/httpd

If you make a mistake, it is easy enough to delete the type. Also, if you wanted to prevent a service from binding on a particular port, the semanage delete (-d) argument is used (the rest of the arguments are identical to the add command):

# semanage port -d -t http_port_t -p tcp 888
# semanage port -l | grep http_port
http_port_t                    tcp      80, 443, 488, 8008, 8009, 8443
pegasus_http_port_t            tcp      5988

The final tools to get a quick introduction are the getsebool and setsebool tools. SELinux has a number of boolean macros that allow or deny certain types of functionality. For instance, Apache has a mechanism to allow users to have their own personal web sites using the ~/public_html/ directory (which shows up as http://foo.com/~user/). By default, SELinux does not permit this type of functionality, as seen by the value of the httpd_enable_homedirs boolean:

# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off

This in itself isn't very descriptive, so semanage can provide further information:

# semanage boolean -l | grep httpd
...
httpd_enable_homedirs          -> off   Allow httpd to read home directories
...

Incidentally, using semanage boolean -l is a great way to see what booleans can be set and what they are used for.

To enable allowing httpd to read home directories, we would use setsebool:

# setsebool httpd_enable_homedirs 1
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

This will persist only while the system is running. To save this boolean change to the SELinux policy files, you must use the persistent change (-P) option to setsebool:

# setsebool -P httpd_enable_homedirs 1

There is, obviously, so much more to SELinux, but these are the basics. Knowing how to change boolean settings, how to change the ability to access certain ports, files, and directories, as well as how to obtain information on SELinux violations, should provide you with the confidence to give SELinux a try. It isn't nearly as scary as I thought it was a few years ago, and using SELinux now, on supported and recent distributions, will provide you with tools that are better and easier to use than those provided a decade ago. If you have been running a system capable of using SELinux, but have had it running in Disabled mode, you owe it to yourself to give it a try in at least Permissive mode. For a little bit of time and effort, it could save you when the next 0-day flaw that is applicable to you comes around (and, honestly, they seem to be coming around a lot more often than they used to).

About

Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.

0 comments