Please create an account to participate in the Slashdot moderation system


Forgot your password?
Programming Security Linux

How To Exploit NULL Pointers 139

An anonymous reader writes "Ever wondered what was so bad about NULL pointer exceptions? An MIT Linux kernel programmer explains how to turn any NULL pointer into a root exploit on Linux. (There was also a previous installment about virtual memory and how to make NULL pointers benign.)"
This discussion has been archived. No new comments can be posted.

How To Exploit NULL Pointers

Comments Filter:
  • by NumberField ( 670182 ) * on Tuesday April 13, 2010 @05:19PM (#31839144)
    I was intrigued by the ./ posting, which claimed that the tutorial would show how to exploit any NULL pointer dereference. The actual article, however, requires a CALL to the NULL pointer. While some NULL pointer bugs are function pointers, many are not. Kernel code that merely reads or writes data to a NULL pointer will not be exploitable as shown.
  • by marcansoft ( 727665 ) <<moc.tfosnacram> <ta> <rotceh>> on Tuesday April 13, 2010 @05:30PM (#31839264) Homepage

    One of the many exploits that we've used to own the Wii (in fact, the very first runtime IOS exploit that we used, which I found and implemented) was a NULL pointer dereference bug, and it wasn't even a function pointer.

    I wrote a detailed blog post [] about it recently. The short version is that they doubly dereference a near-NULL address and write to it, and NULL happens to be real physical memory that we control (call it 'insecure', if you wil). The double dereference lets us direct the write anywhere, including the stack, and it's game over. That's the "usermode" exploit. Privilege escalation into the kernel is trivial because they have some huge kernel holes. The fact that they map the 'insecure' memory as executable (!) in every application makes it even easier.

  • by Chris Burke ( 6130 ) on Tuesday April 13, 2010 @05:33PM (#31839296) Homepage

    I thought the BigMem kernel patches a few years back put the kernel in it's own VM, with minimal copying into userspace VM space, or am i missing something?

    I don't know what that patch did (BigMem implies something like using 2MB pages, but what's in a name?), but I do know that the author is right about address space switches being expensive and not something you'd want to do on every system call, or any system call that is expected to return control to the same process for that matter.

    In practice I don't ever see CR3 writes ( CR3 points to the root of the page table, so writing it is how you switch address spaces) in system calls. Though I am not sure exactly what kernel rev or patch level the benchmark traces are taken from. Still, sounds like it's probably right to me.

  • by Alex Belits ( 437 ) * on Tuesday April 13, 2010 @05:48PM (#31839436) Homepage

    If you have a bug in kernel code that causes NULL pointer dereference, it can be used for various nastiness (in this case, privilege escalation).

    This is why kernel shouldn't do it, and this is why it was an actual kernel bug that was exploited by so-called NULL pointer exploits. This is why those bugs were fixed.

    Apparently some readers have an impression that what was posted is an actual exploit that works on a current kernel by dereferencing NULL pointer in userspace. In reality it relies on a buggy module being introduced, so kernel NULL dereference can be triggered by the user.

  • Re:Shush Now (Score:2, Interesting)

    by gman003 ( 1693318 ) on Tuesday April 13, 2010 @06:01PM (#31839540)

    Considering that null function pointer bugs are a dime a dozen on any system, finding one of those is easy. TFA also points out that the mmap protection code in Linux has been historically weak, although there don't seem to be any open bugs at the moment.

    So the article could have been better titled as "Why null function pointer bugs are serious business", but "How to exploit null [function] pointers" is still pretty accurate.

  • Re:OS dependent (Score:5, Interesting)

    by Imagix ( 695350 ) on Tuesday April 13, 2010 @06:07PM (#31839588)
    But it's a bad summary. They missed the rather critical phrase "how to turn any NULL pointer dereference in the kernel into a root exploit". This isn't about any NULL pointer.
  • Re:Exceptons? (Score:4, Interesting)

    by Hurricane78 ( 562437 ) <deleted@slashdot ... minus physicist> on Tuesday April 13, 2010 @06:16PM (#31839688)

    But then it is not an exploit, since the kernel always is root anyway.

  • Re:Exceptons? (Score:3, Interesting)

    by Chris Burke ( 6130 ) on Tuesday April 13, 2010 @06:46PM (#31839936) Homepage

    Exception handling is immaterial anyway. It's not like you need language support for exceptions to check the value of an untrusted pointer against the NULL constant.

    Yeah but constantly checking sucks, as does recovery.

    Personally I use the method described by the uh... GGP? The dude what I first replied to. Basically, I refrain from using root access to tell the OS to let me map page 0, and then refrain from mmap()ing page 0. Then I let the hardware detect the illegal access for me. =D

  • by Anonymous Coward on Tuesday April 13, 2010 @08:27PM (#31840656)

    Yes, the kernel memory would still be in the user's page table. But that doesn't matter because it's not in the user segments. Kernel code would have to explicitly distinguish between user mode access and kernel mode access (which IMHO is good). Kernel code would not accidentally execute user code, or access user data instead of kernel data.

    Actually the better solution was the Motorola 68k series: separate address spaces for kernel and user. To access user space memory from the kernel on behalf of applications, you use special forms of move instructions. This also gives the kernel access to all 32 bit physical address space (no need for high memory) and a full 4GB of virtual address space for every application. The 68k is dead, but I liked its MMU, at least the integrated versions (68040 and 68060). The PPC MMU is sometimes weird, but it also had good ideas,
    like using a huge virtual address space to map all virtual memory of the system, avoiding the need to flush TLB on context switches. The implementation of the hash table sucks; however, hash tables would have been fine for the higher levels, but the lower level
    should have been normal linear tables.

  • Re:OS dependent (Score:3, Interesting)

    by russotto ( 537200 ) on Tuesday April 13, 2010 @08:32PM (#31840674) Journal

    So a read from a NULL pointer produces junk data (actually interrupt machine code) and a write is fatal.

    IIRC, the first two words of the AIX page 0 are 0xdeadbeef 0xbadfca11. Because of the way the AIX function pointers work, calling page 0 results in the PC being set to 0xdeadbeef and R2 to 0xbadfca11, and the register dump (for the misaligned PC) immediately tells you what you did wrong. (The reason AIX page 0 is readable is for a specific compiler optimization -- the case "if (foo && *foo)" and its cousins. If page 0 is guaranteed readable, the short circuit can be ignored and a branch avoided)

    As for " how to turn any NULL pointer into a root exploit"... not. First you have to be able to map page zero, and then the NULL pointer read must be a function pointer. The author says "it's quite common that a NULL pointer dereference is, or can be easily turned into, a NULL function pointer dereference", but that seems a bit handwavy to me.

  • by rk ( 6314 ) on Tuesday April 13, 2010 @09:03PM (#31840886) Journal

    68k is alive and well in the embedded market with ColdFire and DragonBall processors.

  • by Chris Burke ( 6130 ) on Tuesday April 13, 2010 @09:21PM (#31840974) Homepage

    I strongly disagree.

    With the entire industry. It's okay. You're not the only one to have maintained the belief that segments are not useless crap. ;)

    Segmented addressing got a bad name from the days of real mode

    That wasn't "segmentation" in the academic sense, and it's the academic sense of segmentation, what is actually implemented in 32-bit protected mode, that has the well-deserved bad reputation among the engineers implementing and coding for it. Since the default in 32-bit mode was to effectively eliminate segmentation, it only made sense to just get rid of it.

    That's not really hard to handle, especially since the code/data part is automatically handled by the processor.

    In the sense that you don't have to specify that your code accesses use the code segment and data accesses use the data segment by default. However you still have to explicitly change code and data descriptors when changing between OS and user land and those operations are also not performance-neutral. They are rather slow in fact. Not as bad as a CR3 switch, but bad enough you don't want to do two (per segment, so four) just so the kernel can return the value in it's time_t structure.

    And that's before adding on the performance penalty of having to do an extra addition for every access when not using zero-base segments. You realize how many man-years of performance widgets you've undone by doing that? :)

    Kernel code would have to explicitly distinguish between user mode access and kernel mode access (which IMHO is good).

    In theory, but the exact case in question (mmap) is one where you want the both kernel and application to have the fastest access to the mmap()ed region possible. Which, in case you were wondering, means you can't just map two linear addresses to the same physical page, one for the user and one for the kernel, because that results in TLB thrashing. And when you take that and then add all the other cases where the kernel needs to regularly access something that might be mapped in user land, and suddenly you've just recreated the need for far pointers, and passing around far pointers results in the same possibility for badly formed pointers as before. Remember, if making sure all your pointers were valid was easy we wouldn't have this problem in the first place.

    There's a reason why even when IA32 provided these segmentation facilities that nobody used them. And it's not prejudice from the 16-bit days, as if that could explain why nobody else has implemented segmentation.

    Good riddance to bad rubbish I say. Modern ISAs ftw, even if they're still CISCy. :)

  • by ArsenneLupin ( 766289 ) on Wednesday April 14, 2010 @05:54AM (#31843122)

    changing address spaces, which is a costly operation in any architecture.

    Not necessarily. What if Intel had real segments, pointing each to a separate address space rather than just being windows into a same global address space.

    In a perfect world, each segment would have its own CR3 (page table root), and it would not only be more secure, but also more performant (no flushing of kernel's TLB cache when switching from one process to the other), and would have allowed better "big memory" support under 32 bit systems.

  • by noidentity ( 188756 ) on Wednesday April 14, 2010 @03:01PM (#31848248)

    Think of NULL as more of a symbol than a word. It represents an idea that goes beyond the simple meaning of the word null when used in programing contexts.

    I'll grant you that when the term is used alone. "Did you get NULL again?" Still, when paired with pointer, the capitalization seems redundant, sort of like writing PIN number, cold temperature, and the like.

Testing can show the presense of bugs, but not their absence. -- Dijkstra