Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Mon, 22 Nov 2010 18:01:20 -0500
From: Dan Rosenberg <dan.j.rosenberg@...il.com>
To: oss-security@...ts.openwall.com
Subject: Linux kernel address leaks

I'd like to open up a discussion about this topic, and hopefully
brainstorm some potential solutions.

Some background:

There are dozens of interfaces, most notably in /proc, that leak raw
kernel addresses to unprivileged users.  The most common example is
the leakage of kernel socket structures via
/proc/net/{udp,tcp,raw,unix}, and several other packet families.
These addresses can be very useful when exploiting other kernel
vulnerabilities.

For example, given an arbitrary kernel write (without a corresponding
read vulnerability), these structures make appealing targets because
they are necessarily writable due to their location on the kernel
heap, and contain function pointers that can be easily triggered by
the attacker.  An attacker might open a unix socket, read back the
kernel address of its corresponding sock structure via /proc/net/unix,
calculate the offset in that structure to a particular function
pointer, overwrite that function pointer to point into arbitrary
attacker code by leveraging a kernel write vulnerability, and trigger
the invocation of that function pointer by performing an operation on
the socket.  I have written code that does exactly this - it's very
convenient and reliable.

Much work is in progress to harden the kernel.  One of the primary
goals is to make it such that even if an attacker has an arbitrary
write vulnerability, additional kernel read vulnerabilities are
required for a successful privilege escalation exploit.  Kees Cook has
been making some headway on this front, by ensuring that NX and
read-only memory is properly enforced for modules, and by making sure
statically declared function pointer tables are marked read-only where
possible.  Further work in this area will involve some combination of
kernel symbol hiding and potentially the randomization of the kernel
code base.

However, these measures won't make much of a difference if these leaks
via /proc remain - closing all of the doors except one still leaves an
easy entrance for attackers.  I recently proposed a series of patches
to attempt to resolve these leaks, but due to a number of potentially
valid criticisms, the patches were not accepted.  The fundamental
problem is that removing these addresses entirely makes debugging
difficult or impossible, and no suitable solution has been proposed
that adequately obfuscates these kernel addresses while retaining
their usefulness as unique identifiers.


The following points have been raised:

-Changing the output format (as in, number of fields) of these /proc
interfaces is unacceptable since it will break a number of userspace
tools.  This is not much of an issue, as long as the kernel addresses
are replaced with something else.

-A number of utilities require a unique identifier for each socket.
There has been some debate on this topic.  In most cases, the socket
inode is provided alongside the socket kernel address and could serve
as a unique identifier.  This is not always the case, and it is
questionable as to whether or not it is acceptable to rely on the
inode number alone [1].

-It may or may not be acceptable to replace the addresses with 0's
based on privilege level.

-If the output varies based on privilege level, it would be cleaner to
create a new format specifier (say, %pH) that performs the appropriate
logic, rather than cluttering up a large amount of code.  This has its
own ugliness though, since such a format specifier could not be used
in interrupt context due to the privilege checking required.

-Some kernel functionality may actually require kernel addresses to be
exposed in this way [2].  Even though this is a pain, it seems to me
that this is an argument that the situation is "too broken to fix",
which I don't buy.


Several obfuscation schemes have been proposed, none of which are
especially acceptable:

-Some have suggested randomly generating a value at boot and XORing
each pointer output with this value.  This has the disadvantage of
being practically useless for security, since it would be relatively
easy to infer the value of this global random value.

-Hashing the pointer is unacceptable, since 2^32 is a small enough
space to brute force.

-Built-in block ciphers seem out of the question as well, since most
are built as modules, and we don't want to break bare installations'
IP stacks.  In addition, as far as I know none allow a block length as
short as a pointer.


So I'm mostly out of ideas.  Any input would be appreciated, as I
think this is an issue that should no longer be ignored, and it's been
made clear that this is a battle I can't win on my own.  These issues
have been widely known for a long time now, and are fixed in
grsecurity by GRKERNSEC_HIDESYMS.  The solution employed by grsecurity
is to unconditionally replace pointer output with 0's, which is
unacceptable for the mainline kernel.

I'd even consider these issues as candidates for CVEs (dare I say
it?), as they fit the textbook definition of an "exposure".  But
that's a separate conversation I suppose.

Regards,
Dan

[1] http://marc.info/?l=linux-netdev&m=128954662503066&w=2
[2] http://marc.info/?l=linux-netdev&m=128959423804021&w=2

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.