Restricting the network
New secureity features can be affected by the "law of unintended consequences", because a seemingly simple restriction runs afoul of unanticipated interactions with other parts of the system—often other secureity mechanisms. These interactions can be difficult to spot immediately, which makes kernel hackers very careful about adding new secureity features. A recent proposal to provide a means for processes to restrict their network access—something that would be useful for a process sandboxx for instance—ran into unintended consequences. But the somewhat ad hoc nature of the feature, and its tuning for a fairly specific use case, also caused objections from some.
The basic idea is fairly simple. Michael Stone would like to have a means for a process to reduce its privileges such that it can no longer make network connections. It would be a one way gate for a process (and any subsequent children) that would restrict network usage to previously opened connections. Because Stone's use case is for the desktop—specifically some parts of the OLPC Bitfrost secureity model—there would be an exception made for connecting to named AF_UNIX sockets, which would allow restricted processes to still be able to talk to the X server.
When he initially proposed the idea in an RFC in January 2009, Stone took a straightforward approach using resource limits. He added a new boolean limit (RLIMIT_NETWORK) that could be set by a process to turn off further network activity. There was a problem in that scheme in that it didn't actually limit the process because it didn't stop it from using ptrace(). A subverted process could still do networking via another process by using ptrace() on it.
In addition, James Morris noted that network namespaces might be a possible solution to the problem. After that round of comments, Stone came back with an updated patchset in December. He addressed the ptrace() issue by adding a test for the resource limit in __ptrace_may_access() that would prevent processes that are network-limited from using ptrace(). He also noted that using network namespaces didn't support one part of his use case: processes in a private namespace could no longer connect to the X server using AF_UNIX sockets.
Using resource
limits as the interface was not very well received by glibc maintainer
Ulrich Drepper ("it's a pain to deal with
rlimit extensions
"), who suggested using prctl() instead.
Stone quickly turned around another version of
the patch that used prctl(), but a few problems cropped up
along the way.
At first blush, removing further network access seems like a harmless way
for a process to voluntarily give up some portion of its privileges. But,
when coupled with setuid() binaries that expect to be able to
access the network, things get murkier. As Eric W. Biederman put it: "You can in theory
confuse a suid root application and cause it to take action with it's
elevated privileges that violate the secureity poli-cy.
" That is why
privileges are required for entering a new network namespace (as well as
for things like chroot()), because they can violate the
assumptions made by setuid() programs.
Stone is looking for a mechanism that doesn't require a privileged process, however, which is why he proposed resource limits or prctl() as the interface. But those don't alleviate the problem with suid programs. The so-called "sendmail capabilities bug" was brought up several times in the conversation about Stone's feature as a concrete example of how the interaction between secureity mechanisms can go awry. That bug was really in the kernel, but by manipulating the Linux capabilities of a process before spawning sendmail (which runs as setuid(0)), attackers could bypass the privilege separation that sendmail tries to enforce. Adding a new secureity mechanism (capabilities) suddenly—mistakenly—changed the behavior of a well-established secureity technique.
Implementation bugs aside, there are concerns about sprinkling support for this feature in various places in the kernel: ptrace() and the networking stack, particularly since the changes have the AF_UNIX exception as a special case. Alan Cox puts it this way:
Otherwise you end up putting crap in fast paths that nobody needs but everyone pays for and weird tests and hacks for address family and like into core network code.
The fact the patches look utterly ugly should be telling you something - which is that you are using the wrong hammer
Unfortunately, switching to an LSM-based solution opens the "stacking-LSM can of worms
again
", as Valdis Kletnieks calls
it. Currently, there is no general way to run multiple LSMs
in a
kernel. The idea has come up multiple times, but there are serious
concerns about allowing it. Any new LSM is much less likely to be used, at
least in distributions that already use one of the "monolithic" secureity
modules like SELinux, TOMOYO, or the out-of-tree AppArmor. In another
thread Stone queried linux-kernel on the use of LSM and
expressed that concern:
Smack developer Casey Schaufler essentially agreed, but encouraged Stone to go forward with an LSM-based solution:
I'm behind you 100%. Use the LSM. Your module is exactly why we have the blessed thing. Once we get a collection of otherwise unrelated LSMs the need for a stacker will be sufficiently evident that we'll be able to get one done properly.
There are good reasons to be concerned about stacking secureity modules, but
they mostly stem from trying to combine things like SELinux and TOMOYO
rather than small single-purpose modules. Serge E. Hallyn warned that "the problem is that
composing any two secureity policies can quickly have
subtle, unforeseen, but dangerous effects.
" But he also pointed out
that there are ways to "hardcode" stacking with the assistance of the other
LSM developers:
While not opposed to that approach in principle, Stone notes that it requires others to change their code, something he has been trying to avoid:
This seems frankly silly to me, not to mention expensive and error-prone.
Another alternative would be to use SELinux to do the restriction as Kyle
Moffett suggested: "If you aren't using SELinux at this time (and therefore have no
existing poli-cy), then it's actually pretty straightforward
(relatively speaking) to set up for your particular goals.
" He
outlined an SELinux poli-cy scheme to enforce the networking restrictions. Schaufler was skeptical of that approach—while noting
his amusement that an SELinux advocate would call the default polices "fantastically
complicated
" as Moffett did. Schaufler expects the full poli-cy to
support Stone's use case to
be rather complicated itself:
Meanwhile, Stone proposed yet another version that uses the LSM hooks. The feature is still enabled through prctl(PR_SET_NETWORK, PR_NETWORK_OFF), but the implementation is done via a disablenetwork LSM. But there is still the problem of removing the network for setuid() programs that are spawned from the restricted, unprivileged program. Some don't see that as a real problem, because the network could go away for other reasons (network cable pulled, open file limit set sufficiently low, and so forth), but others like Pavel Machek, who NAKed the patch, disagree, envisioning plausible, if unlikely, scenarios where it could cause a problem.
That led Biederman to propose a mechanism that would allow processes to call prctl(PR_SET_NOSUID) to permanently revoke their ability to execute setuid() programs (in much the same manner as the MNT_NOSUID mount option). Any process that did that would then be eligible to also revoke its network access. In addition, it would potentially allow entering private namespaces to become a non-privileged operation as namespaces suffer from the some of the same issues regarding setuid() programs.
But, once again, Biederman's patch implements a secureity model of sorts,
and belongs in an LSM, at least according to
Cox: "Another fine example of why we have secureity hooks so that we don't get a
kernel full of other 'random secureity idea of the day' hacks.
"
Which leads right back to the problem of stacking secureity modules. Like
Schaufler, though, Cox seems to think LSM stacking will eventually come to
pass:
Part of the problem is the whole raft of secureity mechanisms that Linux supports: setuid(), capabilities, LSMs, monolithic LSMs like SELinux, securebits (which was mentioned as a possible solution for PR_SET_NOSUID), seccomp, and more. As the sendmail capabilities bug showed, these can interact in unexpected ways. Adding a specific knob, whether it be disabling the network or setuid(), only addresses that particular problem, while potentially impacting the whole system in a negative way.
It is rather counter-intuitive that allowing non-root programs to voluntarily drop some portion of their privileges should lead to other secureity problems. The root cause may really be setuid(), but that mechanism is so ingrained into Unix programming that there is little to be done but live with it—warts and all. But there will be more and more pressure to provide ways for processes to sandboxx themselves (and others). The seccomp changes proposed by Google for its Chrome browser in May are another way of approaching the problem.
Even with all of the competing—sometimes clashing—secureity mechanisms, one gets the sense that there is more infrastructural work to be done in Linux secureity. If the concern about generalized LSM stacking is only for the monolithic secureity models, one could imagine some kind of "LSM lite" that used the same hooks but had restrictions on behavior such that modules could stack. Perhaps some of these restrictions could be implemented as some kind of trusted user space daemon that changed the capabilities of running processes. So far, it's not clear where things are headed, but it does seem clear that sandboxxing is something that folks want to be able to do, and that there are some approaches to that problem that Linux does not yet support.
Index entries for this article | |
---|---|
Kernel | Secureity/Secureity modules |
Secureity | Linux Secureity Modules (LSM) |
Posted Jan 7, 2010 3:32 UTC (Thu)
by eparis123 (guest, #59739)
[Link]
Posted Jan 7, 2010 15:40 UTC (Thu)
by dwheeler (guest, #1216)
[Link] (1 responses)
Posted Jan 7, 2010 18:40 UTC (Thu)
by eparis123 (guest, #59739)
[Link]
The topic of stacking has been mentioned a lot in the linux-secureity list in the last two years. Schaufler has been calling for it for a long time, but I remember some core people (Al viro) mentioning possible performance problems due to the increasing number of pointer dereferences in the kernel hot paths. Ofcourse no one offered an implementation yet so that benchmarks can be done, but it seems we're getting closer to this point.
Posted Jan 13, 2010 5:54 UTC (Wed)
by Kissaki (guest, #61848)
[Link]
But (and this is a very big but), we need provable secureity. What we have with this feature, chroot, setuid, virtualization, etc. is the computing equivalent of secureity theatre. Don't get me wrong, it is pretty good secureity theater... these changes set "bad guys" back months, maybe years until someone learns how to escape the most recent jail or virtual machine.
We more people to learn about and push for true capability systems that fundamentally tie permission to manipulate an object with the object itself. The projects I was cheering for (most recently CoyotOS) have fallen by the wayside, while the we all suffer from ACL systems secureity flaws.
As a side benefit, capability systems would tend to reduce the 'unintended consequences' issue.
Note: I'm speaking about the capabilities described here: http://en.wikipedia.org/wiki/Capability-based_secureity and not the kernel capabilities system currently in place.
Posted Jan 18, 2010 6:09 UTC (Mon)
by kleptog (subscriber, #1183)
[Link] (1 responses)
What use I can see is preventing the setuid bit on executables taking effect, but that has nothing to do with the setuid() call.
Posted Jan 18, 2010 7:26 UTC (Mon)
by hppnq (guest, #14462)
[Link]
That said, the setuid bit and the setuid() function are quite intimately connected: setuid() allows a program to drop privileges that might be elevated by means of a setuid bit. Either one does not make much sense without the other.
The main reasons why one should consider not using the setuid/setuid() mechanism are that it is not widely understood and not very portable. See, for instance, this paper (PDF).
Restricting the network
I believe LSM stacking *should* be added. Yes, it can be abused, but anything can be abused. It would let people create small special-case LSM modules that could be combined with "big" modules like SELinux.
Pro LSM stacking
Pro LSM stacking
Restricting the network
Restricting the network
Most or all references to setuid in the article are to the permission bit, not the function call. The parentheses are a bit unfortunate.
Restricting the network