Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

A

...

compiler

...

might

...

insert

...

padding

...

bytes

...

to

...

a

...

structure

...

to

...

ensure

...

that

...

structure

...

members

...

appear

...

in

...

the

...

correct

...

location.

...

Initializing

...

the

...

members

...

of

...

the

...

structure

...

does

...

not

...

always

...

initialize

...

the

...

padding

...

bytes.

...

According to ISO/IEC

...

9899:1999

...

(C99),

...

in

...

6.2.6.1,

...

paragraph

...

6,

...

When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.42)

42) Thus, for example, structure assignment may be implemented element-at-a-time

...

or

...

via

...

memcpy.

As a result of being uninitialized, padding bytes could have random data (sensitive data). This structure could be passed to functions that do not have privilege.

For Example, There have been instances in Linux kernel where uninitialized stack bytes are leaked to unprivileged users as a result of copying structures to user space.

Some Compilers do not initialize the padding bytes if all the members of the structure are initialized. 

Noncompliant Code Example

In this example, the padding bytes after char b are left uninitialized and are leaked.

Code Block
bgColor#FFCCCC
{color}
{quote}
As a result of being uninitialized, padding bytes could have random data (sensitive data). This structure could be passed to functions that do not have privilege.

For Example, There have been instances in Linux kernel where uninitialized stack bytes are leaked to unprivileged users as a result of copying structures to user space.

Some Compilers do not initialize the padding bytes if all the members of the structure are initialized. 

h1. {color:#003366}{*}Noncompliant Code Example{*}{color}

In this example, the padding bytes after char b are left uninitialized and are leaked.

{code:bgColor=#FFCCCC}
#include <stddef.h>

struct test{
  int a;
  char b;
  int c;
};

/* ... safely copy data to user space ... */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = {.a=1,.b=2,.c=3};

  /* ... perform operations on arg ... */

  /* copy arg to user space */
  copy_to_user(usr_buf, &arg, sizeof(arg));

 /* ... */
}
{code}
Code Block
bgColor#FFCCCC
#include <stddef.h>
#include <string.h>

struct test{
  int a;
  char b;
  int c;
};

/* ... safely copy bytes to user space ... */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg;

  /* initializes all bytes (including padding bytes) of the struct to zero */
  memset(&arg, 0, sizeof(arg));

  arg.a = 1;
  arg.b = 2;
  arg.c = 3;

  /* ... perform operations on arg ... */

  /* copy arg to user space */
  copy_to_user(usr_buf, &arg, sizeof(arg));

 /* ... */
}
{code}

Here,

...

the

...

compiler

...

could

...

implement

...

arg.b

...

=2

...

in

...

the

...

following

...

way,

...

  • setting

...

  • the

...

  • low

...

  • byte

...

  • of

...

  • a

...

  • 32-bit

...

  • register

...

  • to

...

  • 2,

...

  • leaving

...

  • the

...

  • high

...

  • bytes

...

  • unchanged,

...

  • storing

...

  • all

...

  • 32

...

  • bits

...

  • of

...

  • the

...

  • register

...

  • into

...

  • memory,

...

Thus

...

leaking

...

stack

...

bytes

...

to

...

unprivileged

...

user.

...

This

...

may

...

not

...

be

...

the

...

case

...

with

...

all

...

compilers.

...

But

...

the

...

compilers

...

are

...

free

...

to

...

implement

...

it

...

in

...

their

...

own

...

way.

...

So

...

the

...

above

...

example

...

could

...

leak

...

data

...

under

...

some

...

specific

...

compiler.

...

 

Compliant Solution 1(Structure

...

Packing

...

-

...

GCC)

GCC allows specifying attributes of variables and structures using the keyword _attribute((packed_)).

This means that that GCC will not add any padding bytes (for memory alignment) and make variables or fields immediately next to each other.

Code Block
bgColor#CCCCFF
borderStylesolid
*{color}

{color:#000000}GCC allows specifying attributes of variables and structures using the keyword _{color}{color:#000000}{_}attribute{_}{color}{color:#000000}_((_{color}{color:#000000}{_}packed{_}{color}{color:#000000}\_)).{color}

{color:#000000}This means that that GCC will not add any padding bytes (for memory alignment) and make variables or fields immediately next to each other.{color}
{code:borderStyle=solid|bgColor=#CCCCFF}
struct test{
 int a;
 char b;
 int c;
} __attribute__((__packed__));
.
struct test arg = {.a=1,.b=2,.c=3};
.
.
// perform operation on arg
.
.
// Copy arg to user space
copy_to_user(ptr, &arg, sizeof(arg));
{code}

h1. {color:#003366}{*}Compliant Solution 

Compliant Solution 2(Structure

...

Packing

...

-

...

MSVC)

...

In case of MSVC, use #pragma pack()

...

instead

...

of

...

_

...

packed

...

_

...

attribute

...

to

...

ensure

...

no

...

padding

...

bytes

...

are

...

added.

Code Block
bgColor#CCCCFF
borderStylesolid
{color}

{code:borderStyle=solid|bgColor=#CCCCFF}
#pragma pack(1) // 1 byte
struct test{
 int a;
 char b;
 int c;
};
.
struct test arg = {.a=1,.b=2,.c=3};
.
.
// perform operation on arg
.
.
// Copy arg to user space
copy_to_user(ptr, &arg, sizeof(arg));
{code}{*}pack*&nbsp;takes effect at the first&nbsp;struct declaration after the pragma is seen.&nbsp;The alignment of a member will be on a boundary that is a multiple of 1 byte.

h1. {color:#003366}{*}Compliant Solution 3(Adding Padding bytes)*{color}

The padding bytes could be explicitly declared. This should be done carefully based on the memory architecture.

The following solution assumes to be implemented in an IA32 machine.

{code:borderStyle=solid|bgColor=#CCCCFF}

pack takes effect at the first struct declaration after the pragma is seen. The alignment of a member will be on a boundary that is a multiple of 1 byte.

Compliant Solution 3(Adding Padding bytes)

The padding bytes could be explicitly declared. This should be done carefully based on the memory architecture.

The following solution assumes to be implemented in an IA32 machine.

Code Block
bgColor#CCCCFF
borderStylesolid
struct test{
 int a;
 char b;
 char padding_1, padding_2, padding_3;
 int c;
};
static_assert(offsetof(struct test, c) ==  (offsetof(struct test, padding_3) + 1) );
struct test arg = {.a=1,.b=2,.c=3};
arg.padding_1 = 0;
arg.padding_2 = 0;
arg.padding_3 = 0;
// perform operation on arg
.
.
// Copy arg to user space
copy_to_user(ptr, &arg, sizeof(arg));
{code}
The&nbsp;static

The static_assert()

...

 macro,

...

a

...

feature

...

of

...

the

...

C1X

...

standard,

...

accepts

...

a

...

constant

...

expression

...

and

...

an

...

error

...

message.

...

The

...

expression

...

is

...

evaluated

...

at

...

compile

...

time

...

and,

...

if

...

false,

...

the

...

compilation

...

is

...

terminated

...

and

...

the

...

error

...

message

...

is

...

output.

...

See

...

recommendation

...

DCL03-C.

...

Use

...

a

...

static

...

assertion

...

to

...

test

...

the

...

value

...

of

...

a

...

constant expression

For Example, In an IA32 machine,

The padding bytes inserted should ensure that no padding bytes are added and thus the expression in static_assert should be true

i.e.

offsetof(struct test, c ) = 8

offsetof(struct test, padding_3 ) = 7

But, if there is padding bytes added then,

The memory would not be continuous and the expression would return 0. 

This approach ensures that no padding bytes are inserted.

Compliant Solution 4

If memset of the original structure to zero (as mentioned in the Non-Compliant example 2) does not work under some compilers, then copy the original structure to an unsigned char memory and pass that memory to the user as shown below.

Code Block
bgColor#CCCCFF
borderStylesolid
 expression|seccode:DCL03-C. Use a static assertion to test the value of a constant expression]

For Example, In an IA32 machine,

The padding bytes inserted should ensure that no padding bytes are added and thus the expression in static_assert should be true

i.e.

offsetof(struct test, c ) = 8

offsetof(struct test, padding_3 ) = 7

But, if there is padding bytes added then,

The memory would not be continuous and the expression would return 0.&nbsp;

This approach ensures that no padding bytes are inserted.

h1. {color:#003366}{*}Compliant Solution 4{*}{color}

{color:#000000}If memset of the original structure to zero (as mentioned in the Non-Compliant example 2) does not work under some compilers, then copy the original structure to an unsigned char memory and pass that memory to the user as shown below.{color}

{code:borderStyle=solid|bgColor=#CCCCFF}
struct test{
 int a;
 char b;
 int c;
};
struct test  arg = { .a = 1, .b = 2, .c = 3 };
unsigned char r[sizeof arg];
.
.
// Do all operations on arg
.
.
// just before passing arg to the function
memset(r,0,sizeof r); // initialize everything to zero
memcpy(r+offsetof(struct test,a),&arg.a,sizeof arg.a);
memcpy(r+offsetof(struct test,b),&arg.b,sizeof arg.b);
memcpy(r+offsetof(struct test,c),&arg.c,sizeof arg.c);
//now pass r to the function
 copy_to_user(ptr, r, sizeof(r));
{code}
{color:#000000}This ensures that no uninitialized padding bytes are copied to unprivileged users.{color}

{color:#003366}{*}Risk Assessment{*}{color}
|| {color:#003366}Recommendation{color} || {color:#003366}Severity{color} || {color:#003366}Likelihood{color} || {color:#003366}Remediation Cost{color} || {color:#003366}Priority{color} || {color:#003366}Level{color} ||
| {color:#000000}DCL39-C{color} | {color:#000000}low{color} | {color:#000000}unlikely{color} | {color:#000000}medium{color} | {color:green}{*}P2{*}{color} | {color:green}{*}L3{*}{color}\\
\\ |

h2. Related Guidelines

[ISO/IEC 9899:1999|https://www.securecoding.cert.org/confluence/display/seccode/AA.+References#AA.References-ISO%2FIEC98991999] Section 

This ensures that no uninitialized padding bytes are copied to unprivileged users.

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

DCL39-C

low

unlikely

medium

P2

L3

Related Guidelines

ISO/IEC 9899:1999 Section 6.2.6.1

...

p6

Bibliography

...

DCL20-C.

...

Always

...

specify

...

void

...

even

...

if

...

a

...

function

...

accepts

...

no

...

arguments      02. Declarations and Initialization (DCL)      Image Added