What does it all mean?

It was probably mid 2003 after the effects of Sapphire, Nimda and Code Red that Intel and AMD both started working with Microsoft to patch the x86 architecture itself. The inherent flaw is two fold; for one, malicious code should not write past the end of an array like line from fingerd, and second the computer should not continue to happily execute the machine code on the stack.

For those not familiar with the stack, here is a quick illustration of how memory looks to an x86 based machine. All memory is divided up into several segments; the stack, heap, and code (or text). Segments are then further divided into pages. Generally, a program executes and runs from the "code" segment. The heap stores dynamically loaded memory, static variables, global variables - anything that need exist during the duration of the program's executable life. The stack is the wild west of memory; function parameters, general variables and arrays end up here. Memory on the stack is reused; once we have processed a function whatever junk it left over in memory resides there.


In the fingerd example from the previous page, writing more than 512 characters to the array begins to overwrite components of the program. When a program begins to load an array, a special byte after the array (called a return address) tells the computer to go back to the code segment and continue to run the program. Unfortunately if a malicious input overwrites the return address with an address in the stack, the computer will execute the code at the location designated, rather than the code the return address pointed to.

NX attempts to correct the buffer overflow issue by disallowing the computer from executing memory in specific pages of the stack. Thus if a malicious input overwrites the portion of the stack and the return address with a clever piece of machine code, NX signals the kernel to panic and the program is terminated.

Thus, some issues are addressed with buffer overflows. It makes it much harder for a malicious input to load a payload into memory with any astounding effects, since we cannot execute some pages of memory on the stack. What NX doesn't stop are buffer overflows that do not rely on their own payload. A malicious input can still overwrite the return address and direct exectution to some other code segment that can cause nefarious deeds - such as a function that creates a file before the user is correctly identified as having the rights to do so. The program might also utilize shared libraries and external system functions like execve, which would give the input identical privileges to the user executing the program. A clever return address combined with initialization of some parameters on the stack would result in execve replicating a payload without machine code.

This is not to say that NX protection is not a step in the right direction. In fact, NX/XD is a good first step to locking down the x86 architecture, as long as it's adopted correctly. OpenBSD and the Execshield projects have made the largest progress with implementing non-executable writable pages and other features, if only in software. However, NX does not completely eliminate buffer overflow exploits, and thus far it has only caused more problems than it has solved with Windows SP2.

Special thanks to D.J. Bernstein, who provided the technical background for the majority of this primer.

Index
Comments Locked

17 Comments

View All Comments

  • Andyvan - Saturday, November 20, 2004 - link

    I have three quibbles about the article:

    1) "As the program starts flipping through the code in its array (which is actually called a stack), it reaches the function gets()."

    I think you've mixed a couple of concepts together here. The code is *not* in the stack. They're two different sections of memory.

    I would reword this as:

    "As the program starts executing the code of the main routine, it reaches the function gets()."

    2) "And since line exists inside a stack in memory, writing past the end of line actually starts to overwrite critical pieces of the program!"

    This may be more of a nit: I would say that it will overwrite data critical to the program. The code proper is not in the stack, and so you can't actually overwrite the *code* when you go off the end of 'line'.

    I'll understand if you don't accept this quibble.

    3) "When a program begins to load an array, a special byte after the array (called a return address) tells the computer to go back to the code segment and continue to run the program."

    I don't believe the return address is actually a byte, as that would only support an address with an 8-bit range. Isn't it a four byte value?

    -- Andyvan
  • sluramod - Wednesday, November 3, 2004 - link

    Maybe it is offtopic, but...

    What are the good reasons for abandoning segmentation and segment protection on x86? Sorry if this is a stupid question...

    Alexei.
  • emboss - Sunday, October 24, 2004 - link

    If you're going to be picky on terminology, at least get it right :) Segmented memory hasn't been used since Windows 3. The correct term to use is sections ("All memory is divided up into several SECTIONS").

    Also, the 286 most definately did not support a NX bit for pages. Primarily because the 286 didn't do paging. What was introduced with the 286 (and still remains on modern CPUs) is segment protection (executable, writable, readable, plus a few less-easily expained attributes). However, since segmentation has been abandoned (with good reason) and the flat address space model has taken over, this "protection" is of no use.

    Finally, a system with NX ideally shouldn't be any more stable than a system without it. User-space programs are isolated the kernel (and other user-space programs) so any damage they do is limited to themselves. In which case terminating the program immediately just speeds up the process of ending the program when something gets corrupted :)

    And if a kernel-mode component gets killed because it violated NX protection, then you're gonna get a BSOD or equivalent, so again, you're not much better off.

    The one thing it MAY help is stopping corrupted data from getting written to disk. But overall I don't think it would have much of an effect from this point of view either.
  • Bitpower - Sunday, October 24, 2004 - link

    What I was trying to say was that a computer system that has NX on it, would be more 'stable' then a computer system without it, since another important side effect of NX is that besides protecting you against viruses, it also will protect you against certain program crashes where there is a buffer underrun.
  • Pax Team - Sunday, October 24, 2004 - link

    software bugs vs. exploit techniques:

    in a reply above you suggested that instead of relying on 200,000 programmers to fix their bugs we should rely on NX and similar hardware features. i.e., it appeared to me as if fixing bugs and intrusion prevention techniques were mutually exclusive (wouldn't be the first time i've misunderstood someone ;-).

    as for my comment: software bugs (or let's just talk about memory corruption bugs) come in many flavours, such as various forms of buffer overflows (stack or heap based, linear or non-linear, single or multiple), integer handling bugs (that can create buffer overflows in turn), user-supplied format strings, etc. these bugs can be fixed (for good) by reading the code, finding them and modyfing the code properly. this is what needs many eyes (and lots of time and expertise) and in practice it's never been 100% efficient, hence the need for intrusion prevention technologies that try to prevent or mitigate the effects of bugs.

    orthogonal to bugs there are exploits that make use of the bugs by exploiting the level of access they (inadvertantly) give to the attacked program. memory corruption bugs can give at most arbitrary read-write access to the target program's memory (e.g., a user-supplied format string bug comes very close to giving this level of access while a 'traditional' strcpy() based stack overflow provides only limited write access).

    an exploit technique describes the way a given bug is made use of. note that this implies that a given bug can be exploited by different techniques and a given technique can make use of different kinds of bugs - hence my saying that these categories (bugs vs. exploit techniques) are orthogonal (and one can and should attack this two-dimensional problem space from either dimension).

    what exploit techniques can we speak of? this normally depends on how your defense mechanisms (intrusion prevention system) work. in PaX we assume arbitrary read-write bugs (i.e., the most powerful category, every memory corruption bug falls within), and this allows us to split the exploit techniques into 3 main categories only, you can read about them at http://pax.grsecurity.net/docs/pax.txt .

    PS: your guess about Intel/AMD beginning to work on NX in mid-2003 is not quite correct, amd64 (the architecture) has always had NX, at least since 2000 i guess. linux itself didn't make use of it until late 2002 though: http://www.x86-64.org/lists/discuss/msg03016.html .

    PS2: contact email address is on the PaX homepage.
  • Bitpower - Thursday, October 21, 2004 - link

    Make a couple typos.

    EDITED VERSION OF MY LAST COMMENT (read this one instead):

    Just curious, but why in the above article, doesn't the author address the other very important advantage of NX, which has nothing to do with viruses? I would think that it is one of the most important advantages of NX is it would make your computer a lot more stable. And this advantage is totally seperate and has nothing to do with virus protection.

    Did you ever had an application or game that you use cause your computer to totally crash and lock up, and the only way out of it was to reboot? Then from the description of NX above, it would also protect you against certain crashes. So it would also act like a "crash guard", thus preventing poorly written programs or programs that have bugs from accidentally overwriting its own code with random junk and causing your machine to totally crash.

    I think its ability to act like a crash guard is as important, if not more important, then its ability to virus protect. So while virus protection is a very important ability of NX, I would also think NXs ability to act like a "crash guard" for your system is just as important.

    Am I the only person who thought of this second advantage of NX, as a crash guard? Myself, I don't care about the virus protection since I constantly scan my computer. But I would be very interested in the abillity to use NX for crash guarding and helping to increase the stability of my machine against programs that are buggy.
  • Bitpower - Thursday, October 21, 2004 - link

    Just curious, by why in the above article, doesn't the author address the only very important advantage of NX, which has NOTHING to do with viruses? I would think that one of the MOST IMPORTANT advantages of NX is it would make your computer a lot more stable. And this advantage is totally seperate and has nothing to do with virus protection.

    Did you ever had an application or game that you use cause your computer to totally crash and lock up, and the only way out of it was to reboot? Then from the description of NX above, it would also protect you against certain crashes. So it would also act like a "crash guard", thus preventing poorly written programs or programs that have bugs from accidentally overwriting its own code with random junk and causing your machine to totally crash.

    I think its ability to act like a crash guard is as important, if not more important, then its ability to virus protect.

    Am I the only person who thought of this second advantage of NX, as a crash guard?
  • KristopherKubicki - Thursday, October 21, 2004 - link

    Pax Team:

    Correct about W^X and Execsheild; same for NX as well too.

    "Prescott supports the NX - for 'no execute' -- feature that blocks worms and viruses from executing code after creating a buffer overflow on the machine", said Paul Otellini, Intel's COO.

    The scope of the article was to show that NX doesnt do what Intel's COO even believes it does.

    I am a little confused about your second paragraph though, can you please elaborate? Thanks for the feedback. Please email me when you get a chance.

    Kristopher
  • Pax Team - Sunday, October 17, 2004 - link

    OpenBSD's W^X is only a subset of what PaX has implemented for 4 years now, but thanks for the praise anyway ;-). As for ExecShield, it doesn't implement W^X, data and bss sections in libraries remain both writable and executable. And both OpenBSD and ExecShield are vulnerable to executing existing code that can trivially circumvent W^X separation and execute injected shellcode.

    Also, you're mixing up software bugs (that your 200,000+ programmers can fix) with exploit techniques (some of which properly used hardware features can prevent). The two sets are orthogonal, not mutually exclusive.

    As for MIPS, as far as i know, none of them has true hardware NX bit support, although on some models it might be possible to simulate the behaviour, but it's lots of hacking and is mostly an academic exercise only, not useful for production.
  • KristopherKubicki - Saturday, October 16, 2004 - link

    WarcraftIII: Although I agree with your comments on programming error, let's look at the last 20 years of programming as an example. If we have the ability to stop Buffer Overflows do we rely on 4 processor makers or 200,000+ C programmers to fix the problem; either of which can fix the errors with equal amounts of work?

    NX is OK, I am just illustrating it doesn't do what it says. It might have stopped some older worms, but when the next worm hits that moves around the eip to somewhere it shouldn't and "buffer overflows" all those NX protection machines don't you think people are going to be upset?

    Most RISC and MIPS processors have utilized some form of NX protection since their inception, by the way.

    Finally, I would like to add that OpenBSD's w^x protection (writeable xor execute; no execute on any writable segment) is probably the most elegent solution yet to the buffer overflow issue. It still is vulnerable to maliciously modified return pointers, but it doesnt advertise that it isn't.

    Kristopher

Log in

Don't have an account? Sign up now