Twenty years ago, when it became apparent how important Linux would become, the U.S. National Security Agency created a mandatory access control (MAC) architecture for Linux. As in other realms, security is always important, but sometimes it’s especially important. From its creation and extending to today, Security-Enhanced Linux (SELinux) has blocked tampering threats and prevented attempts to bypass application security.

I hasten to stress that you should not adopt SELinux just because the extra-robust security functionality exists. Yes, I know how much security matters to your business, but SELinux isn’t for everyone. Running SELinux takes extra time, requires far more hands-on involvement than other Linux distributions, and demands deep knowledge about Linux architecture.

In fact, if you set it up haphazardly, you are asking for trouble. Several SELinux professionals told me that the most common problems with SELinux occur when the operating system is deployed poorly. That’s because SELinux's fundamental security approach (restrict everything unless explicitly permitted) is the exact opposite of Linux's (permit everything unless explicitly forbidden).

In short, if you set up SELinux right, you avoid problems. If you don't, you encounter trouble.

How do you get it done right? I’m glad you asked.

What is SELinux?

Technically speaking, SELinux is a set of Linux patches and user tools that add MAC security to the operating system. They defend the OS to lock down any hacked or misbehaving application, making it unable to damage data or other applications.

MAC is a fundamentally different approach to Linux security. The previous (and still more common) Unix/Linux security methodology is discretionary access control (DAC).

With traditional Linux DAC security, the root user is omnipotent, for better or worse. Each process runs under a user and group. For example, the Apache web server httpd process runs as the user apache under the group apache. Thus, the httpd process has access to all Apache files and directories. If it's cracked, the hacked httpd process can access, modify, and destroy all files that belong to Apache.

Or, as Red Hat cloud strategy evangelist Thomas Cameron explained in a SELinux for Mere Mortals presentation, "You can chmod +rwx your home directory and nothing will stop you. We give you the gun, and there's your foot."

With SELinux MAC, the sysadmin defines how processes interact with other server components. And here's the important part: All access is explicitly granted. A sysadmin determines whether a given process can access files, pipes, ports, and so on. There is no access by default, even if you're the root user.

SELinux defines what can be done with each object according to a set policy. For instance, by default, the Apache user can access only the /var/www/html directory.

If the DAC and MAC conflict, the SELinux policy takes priority. So, let’s say that—as root—you change the ownership of httpd to anyone by running the command chmod 777 httpd; the default SELinux policy still prevents Joe Random User from killing the web server.

However, don't think SELinux is all about securing individual programs. As Dan Walsh, a Red Hat consulting engineer who is also known as Mr. SELinux, writes, "SELinux does not worry so much about executing individual programs, although it can do this. SELinux is basically about defining the access of a process type."

The confusion due to MAC and DAC’s fundamentally different security approaches causes many sysadmins to disable SELinux whenever they encounter it. Indeed, two virtual private server companies until recently disabled SELinux on Fedora Server instances by default.

As with many other high-performance tools, from powerful race cars to rocket engines, you only benefit from SELinux with a steady hand, dedicated training, and a real need for its features. Use SELinux when security is Job One for your company, not for ordinary line-of-business needs. For example, you might not want to use it on internal development servers, but it's another story for a high-profile website.

Labels matter

The trick to using SELinux well is to understand its differences from the Linux you know and love.

One first step in running SELinux is to make sure you have all the pieces in place. Check that you installed the SELinux troubleshooting tools: setools, setroubleshoot, and setroubleshoot-server. For some reason I can't fathom, these programs aren't installed by default in some SELinux packages.

One hugely important concept is labels—and a lot of trouble happens when you don’t grasp this SELinux concept.

In SELinux, every process, file, directory, and system object has a label. Policy rules control access between labeled processes and labeled objects. These labels are stored as extended attributes on the file system. For objects that aren't files, such as processes and ports, the kernel manages the labels.

Unfortunately, in some contexts, a label assigned to a process is also called a domain; you won’t be the first person to be confused. However, any time you run into documentation discussing SELinux domains, just remember it's just talking about labels.

The correct label format is user:role:type:level. Get to know this syntax well, because as you'll see shortly, bad labeling is the source of many SELinux problems.

Make a policy of it

SELinux governs processes with policies. Usually, a policy is made up of a labeling file, a rule file, and an interface file. These are compiled to produce a policy file, which is then loaded into the Linux kernel. You can load or unload SELinux policies without rebooting.

A policy is comprised of explicit permission rules. For instance, a httpd policy may let a httpd process run with specified configuration, log, and content directories, using a specific startup script on specific ports, such as 80, 443, and 8080.

Policies can be very fine-grained. You can set them to grant access depending on users, files, directories, sockets ports, and more.

Need a crash course in composable infrastructure? Get the Dummies Guide.

Permissive mode is your friend

One way to get into trouble—particularly with policies—is to implement them without testing them thoroughly beforehand. Otherwise, you find yourself “testing the locks” by locking yourself out of the house.

So, as you establish SELinux policies, you need to make sure SELinux won't lock up vital processes. One way to see what problems lie ahead is to run SELinux in permissive mode.

In permissive mode, SELinux allows any and all processes to run. If you make a mistake, it doesn’t lock down the OS with a potentially insecure process; instead, it presents you with an error message.

The other two SELinux modes are enforcing (a.k.a. restrictive) and disabled:

  • In enforcing mode, applications stop running if they're misbehaving or their policy is set incorrectly.
  • In disabled mode, you have SELinux installed, but it won't do anything. This is often used when SELinux has stopped a program in its tracks, which you need to keep running.

During your own testing phase, it’s a good idea to work in permissive mode. You can switch between enforcing and permissive modes if you boot with a kernel that supports SELinux Development mode (CONFIG_SECURITY_SELINUX_DEVELOP=y). If this flag is not set (it is in the /etc/selinux/config file), SELinux starts in enforcing mode.

To see which mode you're in, run sestatus. To switch to/from enforcing to permissive, run the setenforce command. This command supports enforcing/1 or permissive/0 as arguments. So either of these turn on SELinux in full defense mode:

# sestatus 1

# sestatus enforcing

Keep in mind that SELinux's MAC policies trumps Linux's default DAC policies. A common error is to assume a given process runs as it always has. However, with SELinux, you must use a policy to explicitly give the process—and all its components—permission to run.

It's always DNS… I mean, it’s always labeling

In networking, the truism is that when anything goes wrong, it's always DNS. (Because it is.)

When you are troubleshooting SELinux, you should always look to mislabeling for the source of your woes.

For example, if your Apache server can't find its website files and is throwing fits, odds are it's because something hasn't been correctly labeled. Typically, this causes Apache (or any other program) to either stop running or be unable to access its data. To fix these, use the SELinux Policy Management command, semanage.

When you know the label:

# semanage fcontext -a -t httpd_sys_content_t '/srv/myweb(/.*)?'

If you know the file with the equivalent labeling:

# semanage fcontext -a -e /srv/myweb /var/www

Or, in either case, you can restore the context with:

# restorecon -vR /srv/myweb

Track down misbehaving programs

Let's say your Apache instance is not working. What do you do?

The first step is to confirm that it's an SELinux problem. If a problem goes away after you set a program to permissive mode, you know the root cause is with your SELinux settings or policies. To find out, use the semanage command. After all, something may have changed since you did the initial setup, and that adjustment can trigger a SELinux failure. For example, if you changed an Apache HTML file by editing it in your personal directory and then moved it to the web directory, SELinux will fail because that "edited" file won't have the correct label.

The next step is to allow the Apache web server (a.k.a. httpd_t) to run in such a way that it generates SELinux error messages rather than just failing in some spectacular but confusing fashion. Use:

# semange permissive -a httpd_t

Simultaneously, your other processes run under SELinux's restricted mode protection. This can be very handy, because the error messages are more likely to give you useful debugging information.

Once you have that process running without any error messages, you can return it to enforcing mode with:

# semanage permissive -d httpd_t

To check on the current SELinux mode status of your processes, run:

# semanage permissive -l

To view everything about how a particular program is running, use the command:

# ps auxZ | grep httpd

The Z flag gives you the SELinux context for a given file or process. In this example, this tells you that the httpd process is using the httpd_t type, the system_r role, and the system_u user. Usually, you care about the type only when troubleshooting. You can also use the Z option with other shell commands.

In SELinux terms, processes and files are labeled with an SELinux context. A context contains such information as the SELinux user, role-based access control (RBAC), type, type enforcement (TE), and optionally, its Multi-Level Security level. All of these factor into making SELinux access control decisions.

Move files

Another command you should expect to use a lot with SELinux is restorecon. This resets the default context on files and directories, and in doing so, it follows the policy you set. For example, imagine that you move a file from your development directory to the httpd directory. When the file changes location, it doesn't move with the appropriate security context. That’s because the mv command retains the existing context.

To make the file ready for Apache to use under SELinux, you need to run a command such as:

# restorecon -vR /srv/www/foo.com/html/example_file.html /var/www/html/

That isn’t the only way to fix the problem. Another is to change the context command with the label. (Choose whichever you are most comfortable with.)

# chcon -t httpd_system_content_t /srv/www/foo.com/html/example_file.html

Or change the context command with the reference label:

# chcon --reference /var/www/html/ /srv/www/foo.com/html/example_file.html

As usual, check the log files

If you suspect that SELinux is blocking a program from running, check the logs. When SELinux denies an action, an Access Vector Cache (AVC) message is logged to the /var/log/audit/audit.log and /var/log/messages files or (depending on your Linux setup) the journald daemon logs it.

Some of the most common searches to find AVC error messages are:

All error messages

ausearch -m avc

Today's error messages

ausearch -m avc -ts today

Error messages from the past 10 minutes

ausearch -m avc -ts recent

Or, to find SELinux denials for a particular service, use the -c comm-name option, where comm-name is the executable’s name. For example, httpd for the Apache web server or smbd for Samba.

To get a more user-friendly error report, use the sealert command:

# sealert -l [message_ID]

Fill in the message_ID with the AVC message number, which you picked up from ausearch. You'll see a friendlier explanation of what went wrong, and a suggestion for a fix. These suggestions are usually worth following up.

You can also use AVC messages to help create SELinux policies. Use the audit2allow command to gather data from denied operations and generate SELinux policy-allow rules. Or, in human terms, it’s like hearing someone say, “You don’t have a key,” and responding, “OK, then give me the key!”

Start by finding out why a process was denied:

# audit2allow -w -a

That may be all you need. But if it isn’t, and you are unsure what rule would let the process run, SELinux can offer assistance. To see what audit2allow suggests, type:

# audit2allow -a

If you like what you see, create a custom policy module by typing:

# audit2allow -a -M example

The -M flag instructs the command to create a type enforcement (.te) file with the specified name. It also compiles the rule into a policy package (.pp). You install this new SELinux policy with the command:

# semodule -i mypolicy.pp

But audit2allow isn't a cure-all. As Red Hat points out, "Modules created with audit2allow may allow more access than required. It is recommended that policy created with audit2allow be posted to an SELinux list, such as fedora-selinux-list, for review."

When things go really wrong

You’ve tried everything. "You've tried scrubbing them out, soaking them out, but you can still come out with…"—gather round, readers of a certain age, and repeat after me—"ring around the collar." In other words, nothing has worked.

If things go completely awry with your server, you can turn off SELinux by updating the configuration file orm using the boot parameter. But if you do that, SELinux can't generate contexts for new or modified files. Thus, when you turn SELinux back on, it won't know what to do with them and the operating system will heavily restrict how they can be run or read. In short, it will be a mess.

The fix is to do a full file system relabel when booting with SELinux enabled. This is a pain.

If you are working in permissive mode (which is likely), run the following commands:

# touch /.autorelabel
# reboot

If you've been running SELinux in enforcing mode, do this with the following commands:

# fixfiles -F onboot
# reboot

You don't want to resort to this, but if you must, you must.

Rebooting may take a while. That's because, in this circumstance, SELinux relabels every last file.

As Paul Frields, a Red Hat engineering manager, points out, if you’ve been running in disabled mode, it's "like wallpapering over a leak. When you remove the wallpaper, you’re likely to find water damage."

Next steps

Over time, SELinux was merged into the Linux kernel 2.6 mainline. Today, it's primarily maintained by Red Hat Linux security developers.

Now it’s time to begin using your SELinux skills—and to learn more. For a useful general overview, watch Security-Enhanced Linux for Mere Mortals. For ongoing advice about using SELinux, follow Dan Walsh's SELinux blog. Of course, Red Hat's SELinux documentation is essential reading. Gentoo Linux's SELinux pages are also helpful.