Why SELinux is inherently complex

May 26, 2016

The root of SELinux's problems is that SELinux is a complex security mechanism that is hard to get right. Unfortunately this complexity is not (just) simply an implementation artifact of the current SELinux code; instead, it's inherent in what SELinux is trying to do.

What SELinux is trying to do is understand 'valid' program behavior and confine programs to it at a fine grained level in an environment where all of the following are true:

  • Programs are large, complex, and can legitimately do many things (this is especially so because we are really talking about entire assemblages of programs, not just single binaries). After all, SELinux is intended to secure things like web servers, database engines, and mailers, all of which have huge amounts of functionality.

  • Programs legitimately access things that are spread all over the system and intermingled tightly with things that they should not be able to touch. This requires fine-grained selectivity about what programs can and cannot access.

  • Programs use and rely on outside libraries that can have unpredictable, opaque, and undocumented internal behavior, including about what resources those libraries access. Since we're trying to confine all of the program's observed behavior, this necessarily includes the behavior of the libraries that it uses.

All of this means that thoroughly understanding program behavior is very hard, yet such a thorough understanding is the core prerequisite for a SELinux policy that is both correct and secure. Even when you've got a thorough understanding once, the issue with libraries means that it can be kicked out from underneath you by a library update.

(Such insufficient understanding of program behavior is almost certainly the root cause of a great many of the SELinux issues that got fixed here.)

This complexity is inherent in trying to understand program behavior in the unconfined environment of a general Unix system, where programs can touch devices in /dev, configuration files under /etc, run code from libraries in /lib, run helper programs from /usr/bin, poke around in files in various places in /var/log and /var, maybe read things from /usr/lib or /usr/share, make network calls to various services, and so on. All the while they're not supposed to be able to look at many things from those places or do many 'wrong' operations. Your program that does DNS lookups likely needs to be able to make TCP connections to port 53, but you probably don't want it to be able to make TCP connections to port 25 (or 22). And maybe it needs to make some additional connections to local services, depending on what NSS libraries got loaded by glibc when it parsed /etc/nsswitch.conf.

(Cryptography libraries have historically done some really creative and crazy things on startup in the name of trying to get some additional randomness, including reading /etc/passwd and running ps and netstat. Yes, really (via).)

SELinux can be simple, but it requires massive reorganization of a typical Linux system and application stack. For example, life would be much simpler if all confined services ran inside defined directory trees and had no access to anything outside their tree (ie everything was basically chroot()'d or close to it); then you could write really simple file access rules (or at least start with them). Similar things could be done with services provided to applications (for example, 'all logging must be done through this interface'), requirements to explicitly document required incoming and outgoing network traffic, and so on.

(What all of these do is make it easier to understand expected program behavior, either by limiting what programs can do to start with or by requiring them to explicitly document their behavior in order to have it work at all.)

Sidebar: the configuration change problem

The problem gets much worse when you allow system administrators to substantially change the behavior of programs in unpredictable ways by changing their configurations. There is no scalable automated way to parse program configuration files and determine what they 'should' be doing or accessing based on the configuration, so now you're back to requiring people to recreate that understanding of program behavior, or at least a fragment of it (the part that their configuration changes affected).

This generously assumes that all points where sysadmins can change program configuration come prominently marked with 'if you touch this, you need to do this to the SELinux setup'. As you can experimentally determine today, this is not the case.


Comments on this page:

By Nick Cammorato at 2016-05-26 08:10:02:

I would caution you in projecting experiences with Fedora to CentOS and RHEL - they put a ton more work into policy and the SELinux experience when they bake fedora into RHEL, and running SELinux on a server is far less painful than on a workstation (way less programs) and no where near as painful as it was even just a few years ago.

With a good policy footing, which unfortunately only seems to exist in enterprise linuxes, SELinux rarely seems like anything more than an extra ownership / permission attribute and the booleans cover a lot of edge cases. Sure if you want to move /var/www to /opt/www you need to copy the labels, but you had to get the permissions right before, now you just have an extra step. There's some extra granularity in that now you can more tightly control things like sockets and network connections(but also ways to make this p. squishy), but how is that a bad thing? Does this add complexity? Of course! But so does any permission model! Is it unnecessary? Well, it depends.

And if anything troubleshooting is p. easy these days. setenforce permissive, do the thing, grep denied /var/log/audit.log | audit2allow. 9 times out of 10, there will be a boolean. The 10th time you get a policy that isn't great but will get you running in a better state than selinux being off. It really, really has gotten a lot better.

The big problem I see is that it's pretty much just RedHat putting in the work, which means you only get anything approaching a pleasant experience with it there.

By dac.override at 2016-05-26 11:24:19:

sed -i 's/complex/flexible/'

SELinux is not inherently complex. It is instead inherently flexible. It is a "flexbile, customizable mandatory access control framework that allows for fine-grained mandatory access control (but it does not have to be fine-grained)". This is what defines SELinux.

Have something you need done? SELinux is your best bet, because of its flexiblity, and because it is customizable.

Red Hat is not the only entity working on policy. Red Hat is not (actively) working with upstream reference policy because their branches diverged due to different priorities. I would argue that Red Hat priorities put the focus more on acceptance. Whereas upstream tries to stick to it's "least privilege" roots (different audiences to entertain).

Then there is me in the middle. I am just a hobbyist with a passion for the SELinux framework. I like to micro manage every single entity in my system and I have too much time on my hands. To me this is just like a good game of Sim City.

I maintain and use a SELinux security policy that is both geared towards desktop use, and embraces least privilege.

https://github.com/DefenSec/dssp

Want to try it out? here is a link to a Fedora 24 LiveCD with DSSP:

https://tfirg.asu.su/2016/05/06/this-should-work-new-fedora24dssplive-iso/

Written on 26 May 2016.
« SELinux is beyond saving at this point
Your overall anti-spam system should have manual emergency blocks »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu May 26 02:37:04 2016
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.