xorl %eax, %eax

Linux kernel SGI GRU Driver Off-by-One Overwrite

with 13 comments

This bug was reported by Michael Buesch. You can find the vulnerable code at drivers/misc/sgi-gru/gruprocfs.c and specifically, here is that code from 2.6.30 release of the Linux kernel.

static ssize_t options_write(struct file *file, const char __user *userbuf,
                             size_t count, loff_t *data)
{
        unsigned long val;
        char buf[80];

        if (copy_from_user
            (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
                return -EFAULT;
        buf[count - 1] = '';
        if (!strict_strtoul(buf, 10, &val))
                gru_options = val;

        return count;
}

This function is used to handle write operations to the equivalent procfs file. As you can see, it invokes copy_from_user() using user controlled ‘count’ only if this is less than sizeof(buf), that is 80 according to the previous allocation. However, the NULL termination does not perform the same check and directly uses the user controlled ‘count’ minus one. Because of this, a user with +w access to that procfs file can write a NULL byte to arbitrary locations in kernel memory. The patch is:

+	memset(buf, 0, sizeof(buf));
 	if (strncpy_from_user(buf, userbuf, sizeof(buf) - 1) < 0)
 		return -EFAULT;
-	buf[count - 1] = '';
 	if (!strict_strtoul(buf, 10, &val))

Which initializes the whole ‘buf’ to zero, thus no need for NULL termination and removes the buggy code.

About these ads

Written by xorl

July 21, 2009 at 08:44

Posted in bugs, linux

13 Responses

Subscribe to comments with RSS.

  1. I know where I would write one! ;)

    Maybe I’ll write the exploit for fun, reusing cheddar_bay, since exploitation with this one is trivial :p

    -Brad

    spender

    July 21, 2009 at 11:58

  2. spender there are numerous ways to exploit this :)
    One simple way is trigger a dereference by overwriting 1 byte of an address (offset from buf[] in this case) of a function pointer and then mmap() to that location your evil code and finally trigger a call to that function pointer.

    xorl

    July 21, 2009 at 12:17

  3. Can you know buf 100% reliably though? I thought of an idea to know buf 100% reliably, then you would reliably overwrite the highest byte in a rarely-used (but non-zero) file_operations fptr, and then rinse and repeat the old cheddar bay code :p

    -Brad

    spender

    July 21, 2009 at 12:23

  4. No, I don’t know 100% reliably the location of buf[], using your way of course you have to overcome any mmap_min_addr since the function pointer you mention will be dereferenced to NULL. Of course, since you already have cheddar bay ready it’s not that hard :P
    Nevertheless, I think it would be much better if you overwrite a function pointer outside mmap_min_addr range since you’ll not have to mess with it at all.

    xorl

    July 21, 2009 at 12:32

  5. Why will it be dereferenced to NULL? It can’t in fact, or it wouldn’t be used. What I would do is target some fptr which I know points to some known function that I have the symbol (and thus the address for). So then I can mask off bytes using separate 0 writes and thus wind up with an address like 0x00ab0000 or something of the sort, do my mmap there (which is above mmap_min_addr) and away we go ;)

    Let’s go talk about copy_from_user :p

    -Brad

    spender

    July 21, 2009 at 12:39

  6. Oh.. that’s what I meant in my first comment.
    Sorry for the misunderstanding :P

    Once again I’m not home right now, I’ll login to talk to you tonight if I can (tonight means about 22:00-23:00 local time, where local time is Athens, Greece :P)

    xorl

    July 21, 2009 at 12:49

  7. I’d stay on the stack.

    qaaz

    July 21, 2009 at 17:05

  8. @qaaz: I’m not really sure that I get what you mean by “staying on the stack”. Probably overwriting something which is close to buf[] on the stack but as I said, I’m not 100% sure that this is what you meant.

    xorl

    July 21, 2009 at 22:54

  9. here’s my exploit ;)

    http://grsecurity.net/~spender/exploit_demo.c

    It would be a real one but this driver only works on some special SGI x86 architecture. If anyone actually has this hardware they can make the modifications mentioned to my exploit and have something that works reliably :p

    -Brad

    Bradley Spengler

    July 21, 2009 at 23:23

  10. Hola people,

    Why not use this null byte to overwrite task_struct->cred->uid directly instead of MMAPing a code and jumping there? We are going for root after all, right? :-) Of course, one must locate the address of the task’s task_struct in order to use this technique (via an info leak maybe?). I am still practicing my kernel skills, so, maybe I am wrong.

    Btw, spender, can you probably tell us more about how to reliably locate buf[]? Sounds interesting.

    huku

    July 26, 2009 at 21:43

  11. @huku: I thought about that as well, you now, the elegant BSD way but this will require at lest two overwrites since in most cases UIDs are like 1000 or something, so in hex you have 0x000003EB. In addition to this, this is not a 100% arbitrary overwrite since write(2) doesn’t allow negative integers, this limits you to 0-0x80000000 offsets. If you can reliably find your task’s UID there then it would be neat.

    I think I can answer spender’s question as well, you can also read his PoC/sample-exploit code posted above. He allocates 1GB of memory and then performs a write to the procfs file with a count in the range of his allocated space. The kernel will page this page since it was touched and using mincore(2) spender’s exploit locates the altered page. This gives more or less, the location of buf[]. Then since he knows in which page to look, he uses a for loop which fills that page with non-zero data and does a zero write to buf[] and attempts to find the zero in that page. This is what he does to find the location of his write operation in buf[] which is really cool I think. :)
    spender, correct me if I’m wrong.

    xorl

    July 26, 2009 at 23:11

  12. I couldn’t sleep and decided to have a look at spender’s PoC. Indeed, using mincore() in order to locate the paged-in page is really neat. Very cool idea.

    huku

    July 27, 2009 at 01:04

  13. can we monitor the write operation in linux. all i want is to control the write operation or monitor all the write operation done by the system.
    plz do help me out.

    Raj

    November 9, 2009 at 15:53


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 63 other followers