Security Anti-Pattern: MLS for Guards
This article was requested, and was a long time coming anyway.
I’ve gone over Multi-Level Security (MLS) a little bit before. It’s basically a security policy that is implemented by many trusted operating systems (such as Trusted Solaris) that is hierarchical and inflexible by nature. Specifically Bell-LaPadula (BLP) is used by many operating systems because it reflects the real world security policy used by the government and military. In BLP subjects and objects have a label consisting of a level (Secret, Top Secret, Unclassified, etc) and a set of non-hierarchical categories (US Only, Army, etc).
The sensitivies are hierarchical in that a higher sensitivity process labeled top secret can read and write top secret objects but only read unclassified objects. This prevents the ‘downgrade’ of classified information. For systems that conform to this kind of policy it makes perfect sense, a multi-level desktop system allows users to keep top secret and unclassified material on the same system but does not allow the release of top secret data to unclassified environments or users. Lower levels can also write to higher levels, in some cases. This may seem bad but considering what the policy is trying to accomplish allowing an unclassified process to write a top secret document doesn’t disclose top secret data. The catch is that the unclassified process would never be able to read the document after writing it. This policy is only usable for confidentiality, to prevent information from being released inappropriately. It cannot address integrity or other security goals I have mentioned in other articles.
Because traditional trusted operating systems only implemented BLP (and in some rare cases Biba for integrity) the users of such systems (primarily government and military) had to use it even when it wasn’t appropriate. One such case is a guard, or cross domain solution (CDS). A CDS is a system that allows two or more networks of differing security properties to be connected to one another. A typical CDS can connect a top secret to a secret network, for example, and allow information from the secret network onto the top secret network but not vice versa. CDS’s also do the opposite, allowing a controlled release of information from top secret to secret, or between two coalition networks (Such as Australia and the US). CDS’s always have some safety mechanism built in to prevent malicious data, or inappropriate data from going across it (if it didn’t it wouldn’t be any more useful than a crossover cable between the networks). These safety mechanisms are virus scanners, “dirty word” filters, document disassemblers (for example to take a word document and convert it to plain text or pdf), etc. The type of safety mechanism primarily depends on what kinds of networks the system is connecting.
For now we’ll talk about the first case, letting information flow from a secret network to a top secret network. Since a BLP system is designed to let information go from secret to top secret already it seems like an obvious fit, right? If the CDS was a very simple system with a process to read incoming data, a virus filter and an outgoing process it seems like a BLP policy would be fine. We are going to call the set of processes that pass data through the system the pipeline.
Wrong, there are actually multiple issues here. Because the lower levels would be allowed to write to higher levels, but not read from them we could label the incoming process Unclassified, the middle process Secret and the outgoing process Top Secret. This allows flow from the incoming process to the outgoing process. The main problem here is that since the levels are hierarchical there is nothing that stops the Unclassified process from writing directly to the Top Secret process (oops). Well, people figured this out and thought of a great work-around. Remember those categories? Categories allow reading and writing when the subject dominates (or has a superset) the categories of the object. So you give the incoming process categories that dominate the categories of the middle process but not the outgoing process.
So that problem is solved (albeit in an interesting way) but CDS’s are never that simple (I mean never). The requirements that are imposed on CDS’s specify pesky little things like logging, auditing, monitoring, emergency shutdown, etc. So now our simple CDS needs all processes to be able to talk to a logging system, and a monitoring system must ask the processes for their state and get back a response. So now we have one or more huge processes that can talk to and receive data from every process in the pipeline. That wouldn’t be so bad except the functional requirements of every guard I’ve seen says that those logs have to end up on the high side for consumption, which is obvious, they certainly can’t go to the low side because that would be a violation of the security policy. This, of course, allows information to flow through the logging and monitoring process out the other side without going through the set of filters. Sure, the advocates will say the logging and monitoring system is part of the TCB (Trusted Computing Base), the part of the system that is trusted to not do nasty things, but in a system like this do you want such processes to be trusted?
The above (totally professionally done) diagram shows the attack vector that would be used to get data through such a system. Because the logging/monitoring app is allowed to violate the MAC policy it is possible to use it to bypass filters 2, 3 and 4.
So basically its impossible to use a BLP policy on a guard and ensure that all data is passed through all filters before it reaches the other side, the policy simply wasn’t made for that kind of thing. It has been the standard operating procedure to shoehorn CDS’s into that policy for a very long time, however.
Before I get into how SELinux helps this I’ll quickly cover the other two types of guards I previously mentioned. First the High-to-Low guard. This kind of guard basically allows controlled downgrading of information; it will run filters like a ‘dirty word’ filter to ensure nothing that shouldn’t be getting downgraded isn’t. It may also redact some data. This CDS is a direct violation of the BLP policy, as such the processes essentially have to be MAC Exempt, or not subject to the policy, essentially making the existence of the policy irrelevant, it should be easy to see why this is an inappropriate use of BLP. The second was a CDS between two coalition partners. In this case the BLP policy doesn’t even mean anything since there is no high side and low side, merely ‘different’ sides.
So, those are the reasons why BLP is inappropriate for CDS’s, why is SELinux different?
SELinux primarily uses type enforcement for policy decisions. Type enforcement allows fine grained policy to be written for all subjects and objects on the system. In the case of CDS’s you can literally say incoming process can write to virus scanner (but not read) and virus scanner can write to outgoing process. We call this an assured pipeline. This can be used for any size or type of pipeline, we even have a tool called CDS Framework that lets you visualize the CDS system. But wait, what about all that logging and auditing and monitoring? Simple, since the policy can describe arbitrary relationships between processes we can break that logging and monitoring process up into filter size chunks, then allow each filter to read and write from the logging and monitoring app. The logging and monitoring app can then send its logs through the same pipeline as the data, it will end up on the high side but there is no additional large process you have to trust to allow it to happen. Using type enforcement we can ensure that every single bit of information that comes leaves the guard passed through every filter (we can’t, of course guarantee that the filters worked). Since type enforcement is not hierarchical the direction of the CDS doesn’t matter, we can do the same thing for High-to-Low that we do for Low-to-High, or even between coalition networks.
The above diagram shows a possible CDS configuration using type enforcement. It allows for logging and monitoring and simply passes those messages back through the filters to get them to the high side. In this configuration no single part of the pipeline is trusted to violate the policy, and filters can never be bypassed. This policy would be impossible to enforce with BLP.
Don’t take this to mean that I hate MLS and never think it’s useful. I’m not saying it kicks puppies (although it does occasional pee on rugs I’m told). MLS has a time and a place, just like everything else. The point I’m trying to make is that it shouldn’t be used if it isn’t appropriate, as has been done in the past (and continues to be done today).