LWN.net Logo

Address space randomization in 2.6

Arjan van de Ven has posted a series of patches which add some address space randomization to the 2.6 kernel. With these patches applied, each process's stack will begin at a random location, and the beginning of the memory area used for mmap() (which is where shared libraries go, among other things) will be randomized as well. These patches represent an improvement in the kernel's security infrastructure, but the reception on the public lists has been surprisingly hostile.

Many buffer overflow exploits, especially those used in large-scale attacks, contain hardcoded addresses. An exploit which overflows a stack variable will place some executable code on the stack; it then overwrites the return pointer so that the broken function "returns" into the exploit code. If you look at a given distribution's shipped version of a vulnerable program, an exploit will always be able to place its payload at the same address on the stack, so it can contain that address directly. If, instead, the exploit author does not know ahead of time where the payload will end up, actually getting the computer to execute that code will be much harder.

That is why the stack randomization patch helps. When the stack location is deterministic, a relatively simple exploit can be made to work on all systems running the vulnerable distribution. If the stack moves, instead, hardcoded addresses no longer work.

Moving the mmap() area has similar benefits. One popular type of exploit prepares the stack and then "returns" into a shared library somewhere. That return can, for example, cause the application to behave as if it had intentionally called system() or a similar library function. Moving the libraries around makes these attacks harder.

One of the biggest complaints that has been raised is that the amount of randomization is insufficient. The patches, as posted, vary the stack base within a 64KB area and the mmap() base within a 1MB range. Alignment requirements prevent just any address from being used with the result that only a relatively small number of possible base addresses exists. So a determined attacker could repeatedly run a hardcoded exploit with some assurance that, within a reasonable amount of time, the stack would land at the right place and the exploit would work. Placing a long series of no-op instructions at the beginning of the payload can also make an exploit more robust when faced with randomization.

Arjan responds that the amount of randomization is not the issue at the moment. He is trying to get the infrastructure into the kernel and tested in a minimally disruptive way; the degree of randomization can be tweaked upward later on. That amount may never get as high as some people would like, at least on 32-bit systems, because it cuts back on the available virtual address space. But it is likely to go up once the developers are convinced that things are working.

In any case, a larger randomness makes the problem harder, but does not change its fundamental nature. With the ability to keep trying, an attacker will eventually get around any degree of randomization possible on 32-bit systems (64-bit systems are a different story). Thus, says Ingo Molnar:

conclusion: stack randomisation (and other VM randomisations) are not a tool against local attacks (which are much easier and faster to brute-force) or against targeted remote attacks, but mainly a tool to degrade the economy of automated remote attacks.

Randomization is not a magic bullet which solves a wide range of security problems. It does make an attack harder, however, and that can only be a good thing.


(Log in to post comments)

Not the best solution

Posted Feb 3, 2005 5:42 UTC (Thu) by Ross (guest, #4065) [Link]

Stack protection and/or canaries are better solutions. They offer stronger
protection (canaries can be a full 32 bits, and stack protection can prevent
overflows no matter how many guesses an attacker gets). Randomization of
addresses are unfortunate because they make programs non-deterministic.
One of the nice things about a virtualized environment with address
separation is that running the same program will produce the same results
sans device I/O or wall-clock timings. That said it can be useful as an
additional layer... it just should not be something which we depend on for
security.

Not the best solution

Posted Feb 3, 2005 19:24 UTC (Thu) by bronson (subscriber, #4806) [Link]

Stack randomization makes BUGGY programs non-deterministic. But then, so does running the program on a different platform. I don't understand your complaint. If you're that worried, just turn randomization off on your development machine.

Aren't canaries a relatively large performance hit? I've written some inner loops that would definitely notice the time needed to generate the canary and check it every time you call a subroutine.

Not the best solution

Posted Mar 10, 2005 3:47 UTC (Thu) by Ross (guest, #4065) [Link]

(I know I'm following up very late so you are probably not going to see
this. But a newer article linked to this and I ran across your post.)

Not only buggy programs but any program that uses "%p" for example. And
the case I was thinking about was specifically dealing with buggy code:
it is nice to be able to reproduce crashes by providing the same inputs to
the program and re-running it if for no other reason that to verify the bug
before submitting a report.

Not the best solution

Posted Jun 25, 2006 0:53 UTC (Sun) by bluefoxicy (guest, #25366) [Link]

Dude, if you jump around bad in randomized code with addresses shifting about every time you start the program over again, you're going to have weird results-- mainly, the program hits bad instructions or unmapped areas and crashes. The more randomization, the more crashes you get.

When not randomizing, sometimes you'll run across something that screws with memory badly for a while; turns your window orange; halts it; produces strange noises; and crashes in some other object file entirely. For example a heap buffer overflow, that can get the heap manager (C library, libc) to try to alter "allocator information" in random memory addresses (hence, double-frees, heap overflows, etc as security attacks). This might not crash the program in certain cases; but if you randomize the address space, then those certain cases will certainly crash the program in one run or another.

Address space randomization in 2.6

Posted Feb 3, 2005 11:14 UTC (Thu) by nix (subscriber, #2304) [Link]

Notably, if you prelink things this turns off some of the randomization (stacks are randomized, but the mmap() area can't be, because the whole point of prelink is to fix the load addresses of libraries and eliminate the need for them to be relocated).

But this is no real problem, as long as you use the -R option to prelink, which does a static randomization (but the addresses are still random, so an attacker must still brute-force things).

Move along, nothing to see here

Posted Feb 3, 2005 13:17 UTC (Thu) by brugolsky (subscriber, #28) [Link]

This piece would have been better titled Red Hat Conspiracy of the Week. In this week's drama, Red Hat attempts to crush all value-added secure distributions by distributing snake oil to the masses.

If a group uses an intrusive kernel patch, and a well-known kernel hacker seeks to have code merged that will shrink at least part of that patch down to the tweaking of a single constant, what again is the problem?

The whole thread is absurd -- anyone who cares so much about address space randomization ought to run on a 64-bit platform!

Move along, nothing to see here

Posted Feb 12, 2005 15:18 UTC (Sat) by spender (subscriber, #23067) [Link]

Being such an expert on the subject, can you please tell me the number of addressable bytes of memory on the following 64 bit architectures:
ALPHA
SPARC64
X86-64

Now, since you're also such an expert on the topic, please tell me how many bits of randomization you can provide for the brk-managed heap, the mmap base, and stack for the above architectures.

Please also inform me of how many applications on the above architectures are built 64-bit and thus can make use of such randomization.

Looking forward to your reply.

The "it stops automated remote attacks" position is pretty funny. What about automated bruteforcing remote attacks? Surely that's the next step that will show this feature by itself to be what it is: obscurity. It has more real benefit for other architectures that support the NX bit properly, but if your goal is to provide protection against "automated remote attacks" for the general user, shouldn't your solution be targeted towards the architecture the general user uses?

Address space randomization in 2.6

Posted Feb 3, 2005 14:08 UTC (Thu) by scripter (subscriber, #2654) [Link]

The principle of defense in depth leads me to think that address randomization combined with canaries is better than a single solution alone.

Address space randomization in 2.6

Posted Feb 3, 2005 23:40 UTC (Thu) by dang (guest, #310) [Link]

take a look at what is up in FC4.....

Address space randomization in 2.6

Posted Feb 10, 2005 6:21 UTC (Thu) by aarchiba (guest, #27728) [Link]

Not to sound like djb, but:

A program that allows stack-smashing really has a security hole, and needs to be fixed. Making exploits more cumbersome may be more of an obstacle to white hats trying to prove that a hole is really a hole then to black hats trying to break in. Now if the randomization code caused buggy programs to *crash* then I'd go for it...

Address space randomization in 2.6

Posted Mar 17, 2005 12:59 UTC (Thu) by farnz (guest, #17727) [Link]

Yes, the program needs to be fixed; however, in the gap between black hats discovering a security hole, and white hats fixing it, I'd rather have something which makes exploiting it harder, than hope that the black hats don't come and get me.

Randomization causes exploitable buggy code to go from permanently exploitable to crashes on most of the attempts. If (say) Apache on Debian Woody has an exploitable hole, without randomization, the black hat determines the exploit on his local machine (crashing Apache several times into the bargain), then he can exploit all vunerable machines on the Internet without risk of being caught.

With randomization, most attempts to work out the address space on the remote machine cause Apache to crash; a good admin notices his servers crashing, and investigates why. Bear in mind that the average exploit involves inducing the program to run code it shouldn't; if the location in memory of that code is random, your chances of actually running valid code have dropped.

Non-exec stack is better

Posted Mar 18, 2005 18:36 UTC (Fri) by BrucePerens (guest, #2510) [Link]

For the stack, making stack pages non-executable is better. I think it works for everything but X86-32, intel left a protection bit out of the page design and the Solar Designer patch (which nobody likes either because it uses a segment) can still protect stacks on X86-32. Can anyone confirm if X86-64 has the protection bit?

Bruce

Non-exec stack is better

Posted Mar 19, 2005 5:25 UTC (Sat) by Han (guest, #28614) [Link]

http://www.bsdatwork.com/2003/08/13/essence_of_openbsd/

ORN: Two AMD Hammer (x86-64) boxes have been donated to the project so that OpenBSD will support this architecture. What are your thoughts about this processor? Is it better from a security standpoint than x86 (non-executable pages of memory, etc.)?

drahn: The Hammer implementation is much nicer in that it has a per-page execute bit; this allows W^X support with no special tricks. Other than this and a >32-bit address space, the machine is basically just a standard PC. OK, I have to admit that at the current time the fastest processors available are PCs (x86 based).

Copyright © 2005, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds