Re: [RFC][PATCH] Randomize kernel base address on boot

Ingo Molnar
2011-05-28T12:18:44Z

* Linus Torvalds <torvalds@linux-foundation.org> wrote:

> On Fri, May 27, 2011 at 10:53 AM, H. Peter Anvin <hpa@zytor.com> wrote:
> >
> > That doesn't solve any problems with the memory map.
>
> Actually, it does.
>
> You can load the kernel at the same virtual address we always load
> it, and/or perhaps shift it up by just small amounts (ie "single
> pages" rather than "ten bits worth of pages")

Note that if we do not limit it to just 'a few pages' then padding
the randomization space into the kernel image:

*also solves the memory map problem in the dynamic randomization case*

Having half a megabyte of '__init buffer' at the beginning or end of
the kernel image is no big deal, it's more than enough for good
randomization and makes the whole thing image-loader invariant: we
can freely shift the 'real' kernel image within this larger boundary
without consulting RAM maps.

And yes, you are right that smarter randomization like reordering of
functions is probably more feasible with a static method - but i'm
not sure we'd like to reorder functions: they are often ordered by
importance within .c files, hence they are often ordered by cache
hotness, so keeping them together makes sense to optimize icache
footprint.

Further note that should anyone want to randomize the kernel position
within a larger range, memory maps can still be consulted - but
that's an optional enhancement, not a design requirement.

Note that such a larger range of randomization is not possible with
the static install-time randomization method, as it needs the consult
the memory maps on bootup.

So while i agree with you that install-time randomization has unique
properties, i do not agree that all of those unique properties are
advantages and thus i do not think that the case for static
randomization is nearly as clear-cut as you made it appear.

Furthermore, the two main complications of dynamic randomizations
that you highlighted are not really fundamental complications IMO:

- the memory map consulation complexity can be completely eliminated
in the dynamic randomization case as well

- the hibernation complication is overstated i think: if on
hibernation we save the randomization offset then the thawed
kernel can load at the very same address. [ We have no other
choice anyway, pointers to the kernel image are stored all
over the frozen image. ]

This skips re-randomization across hibernation but that's ok:
it's the functional equivalent of suspend-to-RAM.

Btw., there's another advantage of kernel image randomization in
general that i have not mentioned before:

- in addition to randomizing the kernel load physical image address,
on 64-bit x86 we could independently randomize the *virtual*
address of the kernel as well: within a rather large, 2GB address
space.

This makes the very first step of buffer overflow (and pointer
overwrite) attacks very hard: they'd have to find the right
executable needle within a 2GB haystack.

Combined with SMEP this needle is the *only* place where a kernel
mode exploit can execute. [*]

This kind of large-scale virtual address randomization could be
performed both dynamically (boot time) and statically (install time).

Thanks,

Ingo

[*] Assuming we get around sorting out the first 1MB compatibility
constraints that force us to turn off NX there currently, and
review the pagetables for all remaining system mode mapped
executable pages.