Kernel address randomization
There is no doubt that having access to the layout of the kernel in memory is useful to attackers. As Dan Rosenberg put it:
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 | |
---|---|
Kernel | Security/Kernel hardening |
Security | Linux kernel |
Posted May 26, 2011 4:32 UTC (Thu)
by jonabbey (guest, #2736)
[Link] (4 responses)
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?
Posted May 26, 2011 7:14 UTC (Thu)
by dlang (guest, #313)
[Link] (3 responses)
Posted May 27, 2011 22:38 UTC (Fri)
by PaXTeam (guest, #24616)
[Link] (2 responses)
Posted May 27, 2011 22:49 UTC (Fri)
by dlang (guest, #313)
[Link] (1 responses)
on amd64 you have much more address space to work with, so that 2G of kernel space can be moved to far more locations
Posted May 28, 2011 22:13 UTC (Sat)
by PaXTeam (guest, #24616)
[Link]
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
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.
Posted May 26, 2011 11:17 UTC (Thu)
by ebirdie (guest, #512)
[Link]
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?
Posted May 27, 2011 12:50 UTC (Fri)
by deater (subscriber, #11746)
[Link] (3 responses)
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.
Posted May 27, 2011 22:10 UTC (Fri)
by oak (guest, #2786)
[Link] (2 responses)
>Same with trying to reproduce a hang that locks your system only some of
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.
Posted May 28, 2011 20:42 UTC (Sat)
by viro (subscriber, #7872)
[Link] (1 responses)
Posted Jul 11, 2011 4:40 UTC (Mon)
by kevinm (guest, #69913)
[Link]
Posted May 27, 2011 20:09 UTC (Fri)
by david.a.wheeler (subscriber, #72896)
[Link]
Kernel address randomization
Kernel address randomization
Kernel address randomization
Kernel address randomization
Kernel address randomization
> address space, and given the size of the kernel and the alignment
> requirements, things are a bit limited
> kernel space can be moved to far more locations
Kernel address randomization
Kernel address randomization
Kernel address randomization
>layout only makes the problem appear on average half the time.
>the time. Did you remember to write down the random offset at boot-time
>just in case?"
Kernel address randomization
Kernel address randomization
This isn't security through obscurity