|
Message-ID: <AANLkTinMUbREsYWFi1eOMoJ+jbPNaG7MuUbxt2oK3__3@mail.gmail.com> Date: Wed, 24 Nov 2010 09:52:47 -0500 From: Dan Rosenberg <dan.j.rosenberg@...il.com> To: oss-security@...ts.openwall.com Subject: Interesting behavior with struct initiailization 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.