xorl %eax, %eax

Linux kernel sigaltstack(2) 4-byte Information Leak

with 2 comments

I just saw this vulnerability reported by Eugene Teo to oss-security mailing list. The bug was initially reported by Ulrich Drepper. Here is the vulnerable system call from kernel/signal.h of 2.6.30 release of the Linux kernel.

int 
do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
{
        stack_t oss;
        int error;

        if (uoss) {
                oss.ss_sp = (void __user *) current->sas_ss_sp;
                oss.ss_size = current->sas_ss_size;
                oss.ss_flags = sas_ss_flags(sp);
        }

        if (uss) {
                void __user *ss_sp;
     ...
        }

        if (uoss) {
                error = -EFAULT;
                if (copy_to_user(uoss, &oss, sizeof(oss)))
                        goto out;
        }

        error = 0;
out:
        return error;
}

As you can see, it uses a stack_t structure to describe the information returned to the user using copy_to_user() routine. This structure is defined at arch/x86/include/asm/signal.h like this:

typedef struct sigaltstack {
        void __user *ss_sp;
        int ss_flags;
        size_t ss_size;
} stack_t;

What U. Drepper noticed is that there is a padding of 4 additional bytes in 64-bit processors that can result to a 4 byte information leak from the kernel. Specifically, the padding is between ‘ss_flags’ and ‘ss_size’ since void * has size of 8 bytes in 64-bit architectures, and size_t which can be found at arch/x86/include/asm/posix_types_64.h is of unsigned long type, meaning 8 bytes as well. However, int type will remain 4 bytes long. In order to have alignment between the 4 bytes long ‘ss_flags’ variable and ‘ss_size’, 4 additional bytes are added as padding. Of course, since this structure is directly (not initialized first) used and then copied to userspace using copy_to_user(), 4 padding bytes will be uninitialized and result in an information disclosure vulnerability when copied to the userspace. To fix this, U. Drepper changed the first if clause so that the structure is initialized regardless of the ‘uoss’ user controlled pointer like this:

        int error;
 
-       if (uoss) {
-               oss.ss_sp = (void __user *) current->sas_ss_sp;
-               oss.ss_size = current->sas_ss_size;
-               oss.ss_flags = sas_ss_flags(sp);
-       }
+       oss.ss_sp = (void __user *) current->sas_ss_sp;
+       oss.ss_size = current->sas_ss_size;
+       oss.ss_flags = sas_ss_flags(sp);
 
        if (uss) {

And he also changed the copy operation to copy separately each of the three members, of course, not including the padding like that:

        }
 
+       error = 0;
        if (uoss) {
                error = -EFAULT;
-               if (copy_to_user(uoss, &oss, sizeof(oss)))
+               if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
                        goto out;
+               error = __put_user(oss.ss_sp, &uoss->ss_sp) |
+                       __put_user(oss.ss_size, &uoss->ss_size) |
+                       __put_user(oss.ss_flags, &uoss->ss_flags);
        }
 
-       error = 0;
 out:
        return error;

Now, it performs a range check using access_ok() macro and then copies the three members of stack_t structure one at a time using __put_user(). If any of these fail, it exits with the equivalent error code. This issue has been fixed in 2.6.31-rc5-git1 and an exploit code has already been published by Jon Oberheide.

Written by xorl

August 4, 2009 at 20:39

Posted in bugs, linux

2 Responses

Subscribe to comments with RSS.

  1. thanks for sharing.

    what serious or useful information can ever be leaked?

    and consider successive calls to get lots of this information from the stack, if we don’t know what’s their address how can we make sense of this shuffled 4 bytes we receive?

    lallous

    August 5, 2009 at 21:19

  2. lallous it depends on the previous contents of stack space where stack_t structure is allocated. To get an idea you can read this post: https://xorl.wordpress.com/2009/01/06/manipulating-uninitialized-variables/
    Of course, 4 bytes is not anything special but under certain circumstances it could contain interesting data from the previously used stack space.

    xorl

    August 5, 2009 at 21:47


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