By Jake Edge
September 8, 2010
One of the heralded features that was supposed to come with moving the graphics
modesetting code into the kernel (i.e. kernel modesetting or KMS) was that
it would—finally—allow systems to rid themselves of an enormous
body of code running as root: the X server. KMS has made its way into
distributions now, but for the most part there has been no switch to
running the X server as a non-privileged user. Progress is being made, but
there is another missing piece, at least for multi-user systems: some way
for processes to enforce exclusive access to files they want to open.
One need only look at the recent kernel hole that was exposed by
root-privileged X servers for a good reason to want an unprivileged X. It
is a complicated chunk of code that is exposed to all manner of attacks, both
local and, potentially, from across the network. It has been the source of
vulnerabilities in the past and almost certainly will be again in the
future. Reducing its privileges and possibly running it as a separate user
will
make any attacks against it less potent or completely ineffective—the
recent exploit would have been stopped cold for example.
Prior to KMS, the X server had to do all manner of poking at the hardware
to get its job done, and that required root privileges. Once that code
moved into the kernel, the X server just needed to be able to access the
devices provided. The graphics device driver enforces exclusive access so
that other processes on the same machine cannot intercept—or
interfere with—graphics commands, but there is another set of devices,
/dev/input/*, that is more problematic.
In current systems, where X runs as root, it owns the files in
/dev/input and the permissions only allow root to access them. If
X were to run as either the logged-in user or some other separate user,
overly restrictive permissions could not be used. For multi-user
systems, regular users could end up with a "dangling" reference—in
the form of an open file descriptor—to an input device. Once another
user started X, that
reference could be used for keystroke logging.
One possible solution would be to add a revoke() system call to
Linux. That call would disconnect all processes from a file and allow the
caller to have exclusive access. Unfortunately, no one has found an
acceptable way to add revoke() capabilities to the
kernel. There have been several attempts over the years (we most recently
looked at one in
2007), but it is a hard
problem to solve, mostly due to things like mmap()-ed files and
the private copy-on-write mappings that are generated by fork().
With a working revoke(), the X server could just ensure that it is
the only process that has access to the input stream. An alternative would
be to have the X server run as a system user that lives in a specific group
with access to the input devices, but that has flaws of its own. An
exploit against the server would potentially give an attacker a means to
access all users that are logged into X sessions, so a malicious local user
or some remote exploit of a vulnerable X program might be able to affect
all users of
the system.
Keystroke logging can obviously lead to root compromise if someone types in
the root password, but there are other things that users type that they
don't want exposed, of course. Passwords for other systems (e.g. ssh, web
applications) and all kinds of sensitive information (e.g. financial data for
Gnucash or Kmoney) are input into X sessions. While it would be nice to
get away from running X as root, the benefit needs to outweigh the
cost—easy keystroke logging does not pass that bar.
The Moblin mobile distribution pioneered
"non-root-X" and its descendant MeeGo has continued down that path, but
neither of those distributions allows for multiple users. If there are no
other users
that could get access to the input devices, it is fairly straightforward to
run the X server as the logged-in user, which is what Moblin/MeeGo do.
Ubuntu has been looking at the
problem as well. There is a blueprint
for the feature that is targeted for Ubuntu 10.10, but with a "Low"
priority and it has not made an appearance in the recently released Beta.
Unlike MeeGo, Ubuntu and other distributions will need to deal with
multi-user use case, which seems to be the sticking point.
Fedora also recently discussed a non-root X server, after Mike McGrath asked about it on fedora-devel. That led to
Matthew Garrett's security
quote-of-the-week pointing out the problem with input devices and no
revoke(). While
some thought that was a good argument for PackageKit's ability to perform
root-privileged actions without a password being typed in, Gregory Maxwell
was quick to point out the flaw in that
thinking:
This is an improvement because if Fedora removes "the need to ever
type a root password" by simply allowing packagekit to give the user
all the root abilities the user needs then the attacker doesn't need
to wait around for the user to do something privileged, they can just
ask packagekit as the user to do it for them. I'm sure this will save
a lot of time.
So, at least for multi-user systems, we are still a ways out from seeing X
servers running as a non-root user. The hardware access issues have been
resolved—for those graphics cards that have KMS drivers—but there
are still underlying plumbing issues that haven't been. For older
hardware without KMS drivers, or those with proprietary-only drivers, X is
always going to have to run as root.
It would be nice
to limit the damage an exploit can do to only the user that got exploited,
rather than the entire system or all logged-in X users. But that will
require revoke() which doesn't seem to be in the pipeline.
Conceptually, revoke() is a completely reasonable addition to the
kernel, and it really isn't clear why we don't have it yet. It is
certainly something that the security community could be working on to
remove it as a barrier to a more secure X server.
Starting out by running X as a system user with various udev permission-switching rules and some kind of
arbiter like ConsoleKit as Ubuntu is attempting might be the right
approach. It definitely seems like Ubuntu has made the most visible
progress toward the goal. Other distributions may be taking a wait-and-see
approach in the interim.
(
Log in to post comments)