Nuts and Bolts Admin Story: SELinux Lead image: © Pavel Ignatov,
© Pavel Ignatov,

Practical SELinux

Protective Shield

Although SELinux is designed as a shield rather than a weapon, it still makes many admins wince. This is hard to understand, however, because operation is now uncomplicated, and SE adds enormous value in terms of the security of the entire system. By Thorsten Scherf

In my company, we have somehow adopted a policy of trying new developments out first on family members before they are released to the general public. I mainly choose my wife and my son as guinea pigs; however, my wife owns a Mac, so new policies are primarily tested on my son's computer.

When my son is sitting in front of his Fedora system, he usually only has three applications running, the web browser, his favorite game, and an IRC client, which he uses to chat with friends about the game – or so he claims.

I recently set up the SELinux Targeted policy for testing on my son's Fedora system, and his account is mapped to the SELinux user_u. This gives him access to all network resources, but it rules out setuid and setgid. When I log in to the system, my account is mapped to staff_u, so I also get access to sudo and can thus manage the computer.

This setup has been running for a while now on my son's computer, and there have been no major problems. If a program does not run as it should, it typically helps to start the setroubleshoot daemon to isolate and resolve the problem.

The daemon leaves a message in the logfile, /var/log/messages, with exact instructions on how the problem can be solved. On desktop systems, an applet also provides information on whether access was blocked by SELinux.

Malware Protection

We also have a family laptop in the living room; my wife and son mainly log in to this machine and run the web browser and an IRC client. Of course, it makes sense to safeguard the accounts on this family computer, too, so I changed the two user accounts from user_u to xguest_u. Now, this SELinux user account does allow access to the network, but only via the Firefox web browser; all other network access is prevented.

This approach prevents any malware that might have found its way from the web onto our family computer from accessing the network. It isn't even possible to launch this stuff from the download folder (or for it to auto-start).

However, this behavior can be changed in SELinux. After all, the computer is not just for playing; people actually need to work on it from time to time. Using a Boolean variable, you can adjust the desired run-time behavior:

# getsebool allow_xguest_exec_content
allow_xguest_exec_content --> off

I previously set up mapping to the SELinux user xguest_u with the use of semanage:

# semanage login -m -s xguest_u linus
# semanage login -l | grep linus
linus xguest_u s0

This means my son can log in like before; however, his account is now mapped by SELinux to the xguest user:

$ id -Z

Access to the network is still possible via the HTTP port 80, but all other access is prohibited:

$ ping
ping: icmp open socket: Permission denied
$ nc -v 25
nc: connect to port 25 (tcp) failed: Permission denied
$ nc -v 80
Connection to 80 port [tcp/http] succeeded

So far, so good; however, this setup also effectively blocks access to the IRC server. If I try to launch the IRC client, the error message in Listing 1 appears in the log. I wanted to resolve this shortcoming from the outset and develop a corresponding SELinux policy module that allows access to an IRC server, even if the logged-in user is mapped to the SELinux xguest_u account.

Listing 1: Log Error Message

Aug 16 15:50:34 tscherf setroubleshoot: SELinux is preventing /usr/bin/xchat
from name_connect access on the tcp_socket. For complete SELinux messages
run sealert -l482a1457-4fdc-4d8c-91d0-d5ddf4b23891

My Own Rules

When I call sealert, the tool tells me that access to the IRC port 6667 is blocked. A call to audit2allow confirms this and suggests that I extend the standard ruleset to include the following entry:

# grep xchat /var/log/audit/audit.log | audit2allow
allow xguest_t ircd_port_t:tcp_socket name_connect;

From other policy developments, I know that an interface is available for access to most network ports; I checked this again by appending the option -R to the call to audit2allow. Lo and behold, the suggestion has now changed to using the corenet_tcp_connect_ircd_port interface with the xguest_t argument. If I now use the -M option to append a module name to the tool, it generates a ready-to-use policy module that I can add to the standard ruleset.

Source Code Included

Fortunately, the tool generates not only the binary module but also the source code. I can use this to secure the option of switching access to the IRC port on and off using a Boolean. I thus extended the type enforcement file generated by audit2allow to include the appropriate instructions for a Boolean.

If the RPM package, selinux-policy, is installed, you will have a Makefile in the /usr/share/selinux/devel folder on your Fedora system that provides an easy approach to converting the source files into a new, binary policy module (Listing 2). I then loaded the module generated in this way into the SELinux standard ruleset:

Listing 2: Makefile

# make -f /usr/share/selinux/devel/Makefile
Compiling targeted xguest_irc module
/usr/bin/checkmodule:   loading policy configuration from tmp/xguest_irc.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 10) to tmp/xguest_irc.mod
Creating targeted xguest_irc.pp policy package
rm tmp/xguest_irc.mod.fc tmp/xguest_irc.mod
semodule -i xguest_irc.pp

The following command now shows that a corresponding rule is known to the system:

$ sesearch -A -s xguest_t -t ircd_port_t
Found 1 semantic av rules:
 allow xguest_t ircd_port_t : tcp_socketname_connect ;

This policy has now been running for a while on the family computer and, as of yet, no one has complained. Access to the web and communication with the friends on IRC still work without problem. If any program should now attempt to break into the network, it will be effectively prevented. Thanks to the dynamic policy, I can even disable access to the IRC server if required:

setsebool xguest_use_irc off

Finally, Listing 3 shows the complete call to audit2allow with the policy module I manually modified for access to an IRC server.

Listing 3: Policy Module

# grep xchat /var/log/audit/audit.log | audit2allow -R -M xguest_irc
require {
  type xguest_t;
## <desc>
## <p>a
## Allow xguest users to use IRC
## </p>
## </desc>
gen_tunable(xguest_use_irc, true)