|
|
Subscribe / Log in / New account

Kernel address randomization

By Jonathan Corbet
May 24, 2011
Last week's Kernel Page included a brief item about the hiding of kernel addresses from user space. This hiding has come under fire from a number of developers who say that it breaks things (perf, for example) and that it does not provide any real additional security. That said, there does seem to be a consensus around the idea that it's better if attackers don't know where the kernel keeps its data structures. As it turns out, there might be a better way to do that than simply hiding pointer values.

There is no doubt that having access to the layout of the kernel in memory is useful to attackers. As Dan Rosenberg put it:

I agree about the fact that kptr_restrict is an incomplete security feature. However, I disagree that it lacks usefulness entirely. Virtually every public kernel exploit in the past year leverages /proc/kallsyms or other kernel address leakage to target an attack.

The hiding of kernel addresses is meant to deprive attackers of that extra information, making their task harder. One big problem with that approach is that most systems out there are running stock distribution kernels. Getting the needed address information from the distributor's kernel package is not a particularly challenging task. So, on these systems, there is no real mystery about the layout of the kernel, regardless of whether pointer values are allowed to leak to user space or not.

While all of this was being discussed, another idea came out: why not randomize the location of the kernel in memory at boot time? Address space layout randomization has been used to resist canned attacks for a long time, but the kernel takes no such measure for itself. Given that the kernel image is relocatable, there is no real reason why it always needs to be loaded at the same address. If the kernel calculated a different offset for itself at every boot, it could subtract that offset from pointer values before passing them to user space. Those pointers could then be used by tools like perf, but they would no longer be helpful for anybody seeking to overwrite kernel data structures.

Dan has been looking into kernel-space randomization with some success; it turns out that simply relocating the kernel is not that hard. That said, he has run up against a few potential problems. The first of those is that there is very little entropy available at the beginning of the boot process, so the generation of a sufficiently random base address for the kernel is not entirely straightforward. It seems that enough bits of entropy can be derived from the real-time clock and time stamp counter to make it hard for an attacker to derive the base address later on, but a real random number would be better.

Next, as Linus pointed out, the kernel is not infinitely relocatable. There are a number of alignment requirements which constrain the kernel's placement, so, according to Linus, there is a maximum of 8-12 bits of randomization available. That means that an exploit attempt could find the right offset after a maximum of a few thousand tries. Given that computers can try things very quickly, that does not give a site administrator much time to respond.

As others pointed out, though, that amount of randomness is probably enough. Failed exploit attempts have a high probability of generating a kernel oops; even if an administrator does not notice the oops immediately, it should come to their attention at some point. So the ability to stealthily take over a system is gone. Beyond that, failed exploits may well take down the system entirely (especially if, as is the case with many RHEL systems, the "panic on oops" flag is set) or leave it in a state where further exploit attempts cannot work. There is, it seems, a real advantage to forcing an attacker to guess.

That advantage evaporates, though, if an attacker can somehow figure out what offset a given system used at boot time. Dan noticed one way that could happen: the unprivileged SIDT instruction can be used to locate the system's interrupt descriptor table. That location could, in turn, be used to calculate the kernel's base offset. Dynamic allocation of the table can solve that problem at the cost of messing with some tricky very-early-boot code. There could be other advantages to dynamically allocating the table, though; if the table were put into the per-CPU area, it might make the system a little more scalable.

So this problem can be solved, but there will, beyond doubt, be other places where it will be possible for an attacker to obtain a real kernel-space address. There are simply too many ways in which that information might leak into user space. Plugging all of those leaks looks like one of those long-term tasks that is never really done. It may, however, be possible to get close enough to done that attackers will not be able to count on knowing the true location of the kernel in a running system. That may be a bit of security through obscurity that is worth having.

Index entries for this article
KernelSecurity/Kernel hardening
SecurityLinux kernel


to post comments

Kernel address randomization

Posted May 26, 2011 4:32 UTC (Thu) by jonabbey (guest, #2736) [Link] (4 responses)

This sounds a bit better than just 'security through obscurity'. Random numbers are used in all public key crypto systems, and we don't describe those systems as STO.

If randomization of the kernel addresses can give 8-12 bits of uncertainty and the kernel will tend to fail in obvious ways if they guess wrong, that's pretty darn good.

By the by, does this 8-12 bits of uncertainty figure hold true for both 32bit and 64bit x86?

Kernel address randomization

Posted May 26, 2011 7:14 UTC (Thu) by dlang (guest, #313) [Link] (3 responses)

no, 32 bit has very little flexibility, this is the gains for 64 bit systems

Kernel address randomization

Posted May 27, 2011 22:38 UTC (Fri) by PaXTeam (guest, #24616) [Link] (2 responses)

i386 kernels have 1/2/3GB of kernel space to play with (minus vmalloc/fixmap/gaps/etc), amd64 kernels have 2GB (minus vsyscall/module area/etc). so for practical purposes, you could get the same amount of entropy for both cases.

Kernel address randomization

Posted May 27, 2011 22:49 UTC (Fri) by dlang (guest, #313) [Link] (1 responses)

the issue is that that 1/2/3G of kernel space is in a total of 4G of address space, and given the size of the kernel and the alignment requirements, things are a bit limited

on amd64 you have much more address space to work with, so that 2G of kernel space can be moved to far more locations

Kernel address randomization

Posted May 28, 2011 22:13 UTC (Sat) by PaXTeam (guest, #24616) [Link]

> the issue is that that 1/2/3G of kernel space is in a total of 4G of
> address space, and given the size of the kernel and the alignment
> requirements, things are a bit limited

the exact same limits apply to amd64 kernels as well.

> on amd64 you have much more address space to work with, so that 2G of
> kernel space can be moved to far more locations

you're wrong, the kernel image cannot be at arbitrary addresses, it *must* be in the top 2GB of the 64 bit virtual address space. i suggest you study the amd64 ABI and in particular -mcmodel=kernel.

Kernel address randomization

Posted May 26, 2011 11:17 UTC (Thu) by ebirdie (guest, #512) [Link]

Really interesting, thank you.

What I can say, the boot time offset randomization should make every running kernel different in the World, of course, until every running kernel has this feature in effect. Further, this should make automated hack attempts a bit harder.

Combined to the above I came to think about this LWN.net article a while back: Persistent storage for a kernel's "dying breath", https://lwn.net/Articles/434821/.

It would be interesting to have a snapshot of the system after an oops caused by kernel memory poking. After a while, an active and automatic detection system could be useful to analyze and put aside the easy oops snapshots. Just wondering, if anybody already does this and this way gathers valuable information?

Kernel address randomization

Posted May 27, 2011 12:50 UTC (Fri) by deater (subscriber, #11746) [Link] (3 responses)

This should make bisecting a kernel problem fun, especially if the address layout only makes the problem appear on average half the time.

Same with trying to reproduce a hang that locks your system only some of the time. Did you remember to write down the random offset at boot-time just in case?

There can also be interesting performance analysis implications. Randomized userspace processes can vary a few percent in performance when randomized if poorly written (SPEC 2000 perlbench (*cough*)). Things like taking addresses of variables and using them as keys in hash tables, etc.

Kernel address randomization

Posted May 27, 2011 22:10 UTC (Fri) by oak (guest, #2786) [Link] (2 responses)

>This should make bisecting a kernel problem fun, especially if the address
>layout only makes the problem appear on average half the time.

>Same with trying to reproduce a hang that locks your system only some of
>the time. Did you remember to write down the random offset at boot-time
>just in case?"

If the crash happens always "at the same place", and the kernel address is e.g. 4kB aligned, the lower bits would still be the same and could work as identification.

Kernel address randomization

Posted May 28, 2011 20:42 UTC (Sat) by viro (subscriber, #7872) [Link] (1 responses)

... and if the crash depends on the location of kernel and simply doesn't happen on half of the boot attempts due to differences in that? Good luck narrowing things down to commit that has caused it...

Kernel address randomization

Posted Jul 11, 2011 4:40 UTC (Mon) by kevinm (guest, #69913) [Link]

So long as the Oops includes the blinding value that was in use, and you can force it for subsequent testing via kernel command-line, that should be enough.

This isn't security through obscurity

Posted May 27, 2011 20:09 UTC (Fri) by david.a.wheeler (subscriber, #72896) [Link]

This isn't security through obscurity at all. In "security through obscurity" you're trying to hide how the system is designed, under the theory that no one could ever find out (ha!). This doesn't try to hide the design at all; here, you're countering an attacker even if the attacker knows this is going on (hopefully). Using unknown, easily-changed data to make a system hard to attack is well-accepted; passwords and crypto keys are also based on this idea.


Copyright © 2011, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds