xorl %eax, %eax

Linux kernel Toshiba-ACPI Integer Overflow

leave a comment »

This was reported by Michael Buesch on lkml. The bug is quite simple, here is its code from drivers/platform/x86/toshiba_acpi.c in 2.6.30 release of the Linux kernel.

static int
dispatch_write(struct file *file, const char __user * buffer,
               unsigned long count, ProcItem * item)
        int result;
        char *tmp_buffer;

        /* Arg buffer points to userspace memory, which can't be accessed
         * directly.  Since we're making a copy, zero-terminate the
         * destination so that sscanf can be used on it safely.
        tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
        if (!tmp_buffer)
                return -ENOMEM;

        if (copy_from_user(tmp_buffer, buffer, count)) {
                result = -EFAULT;
        } else {
                tmp_buffer[count] = 0;
                result = item->write_func(tmp_buffer, count);
        return result;

As you can see, ‘count’ which is completely user controlled can be set to size_t-1 and the addition of 1 in kmalloc() will result in a wrap around zero because on an integer overflow. Because of this, kmalloc() will return ZERO_SIZE_PTR and since the check checks only for ‘tmp_buffer’ equal to NULL it will bypass it and perform the copy_from_user() call.
M. Buesch also gave a sample PoC code however, as a reader of this blog pointed out to me if we check out write() code in fs/read_write.c we’ll see that it internally invokes rw_verify_area() which includes this code:

int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
struct inode *inode;
loff_t pos;
int retval = -EINVAL;

inode = file->f_path.dentry->d_inode;
if (unlikely((ssize_t) count < 0)) return retval; [/sourcecode] Consequently, the PoC code written by M. Buesch will almost certainly fall into this check and return -EINVAL before reaching copy_from_user() routine.

Written by xorl

July 21, 2009 at 20:14

Posted in bugs, linux

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