Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 24 Nov 2010 09:59:11 -0500
From: Dan Rosenberg <dan.j.rosenberg@...il.com>
To: oss-security@...ts.openwall.com
Subject: Re: Interesting behavior with struct initiailization

Forgot to mention, my testing was done on gcc 4.4.3.

Also, s/initiailization/initialization

-Dan

On Wed, Nov 24, 2010 at 9:52 AM, Dan Rosenberg
<dan.j.rosenberg@...il.com> wrote:
> This topic has come up a few times recently on lkml, so I thought I'd
> share my findings here for the sake of spreading information.
>
> Lately, there have been a high number of instances in the Linux kernel
> where uninitialized stack bytes are leaked to unprivileged users as a
> result of copying structures to userland.  There's been recent
> discussion on the proper way to make sure this doesn't happen.
>
> There are three situations in which this might happen:
>
> ===============================
>
> 1. Lack of initialization
>
> This is the easiest to spot.  For example:
>
> ---
> struct test { int a; int b; int c; } arg;
>
> arg.a = 0;
> arg.b = 0;
>
> copy_to_user(ptr, &arg, sizeof(arg));
> ---
>
> The contents of arg.c will be leaked due to lack of initialization.
> This is known and expected behavior.
>
> ===============================
>
> 2. Lack of initialization of padding bytes
>
> gcc adds padding bytes to some structures to give them more natural
> alignment.  If these bytes aren't cleared using memset() or C99
> initialization (more on this soon), they'll be uninitialized and
> subsequently leaked:
>
> ---
> struct test { int a; char b; int c; } arg;
>
> arg.a = 0;
> arg.b = 0;
> arg.c = 0;
>
> copy_to_user(ptr, &arg, sizeof(arg));
> ---
>
> The three bytes padding after the "char b" member will remain
> uninitialized and are leaked in this example.
>
> ===============================
>
> 3. gcc does not clear padding bytes on full C99 initialization
>
> I think this is unexpected behavior (at least to me), and it's the
> reason I'm writing this post.  Normally, C99 initialization
> automatically zeros out padding bytes as well.  For example:
>
> ---
> struct test { int a; char b; int c; } arg = {};
>
> or
>
> struct test { int a; char b; int c; } arg = { .a = 1 };
> ---
>
> will set the specified fields, and zero out everything else, including
> padding bytes.  However, if you explicitly initialize every member
> using C99 initialization, the padding bytes won't be zeroed out:
>
> ---
> struct test { int a; char b; int c; } arg = { .a = 0, .b = 0, .c = 0 };
> ---
>
> This will leave the padding bytes after "char b" uninitialized,
> surprisingly.  I imagine this is an attempted optimization on gcc, but
> now it's coming back to bite (no pun intended) everyone who relied on
> this construct to prevent leakage.
>
> Regards,
> Dan
>

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.