Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Basically rewritten; needs review

A compiler might insert padding bytes to a structure to ensure that structure members appear in the correct location. Initializing The C Standard, subclause 6.7.2.1 discusses the layout of structure fields. It specifies that non-bit-field members are aligned in an implementation defined manner, and that there may be padding within or at the end of a structure.  Furthermore, initializing the members of the structure does not always initialize the guarantee initialization of the padding bytes. The C Standard, subclause 6.2.6.1 1 paragraph 6 [ISO/IEC 9899:2011], states:

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.

It is annotated with the following (footnote 51):

Thus, for example, structure assignment need not copy any padding bits.

As a result of being uninitializedunspecified, padding bytes could have contain random data (sensitive data). This , possibly sensitive, data. A pointer to such a structure could be passed to functions that do not have privilege. For example, there have been instances in the Linux kernel when uninitialized stack bytes were 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 initializedother functions, causing information leakage.

Noncompliant Code Example

In this noncompliant code example, the padding bytes after char b may not be initializedbe used within the structure, depending on the architecture:

Code Block
bgColor#FFCCCC
langc
#include <stddef.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 = {.a = 1, .b = 2, .c = 3};

  /* ... Perform operations on arg ... */

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

  /* ... */
}

The padding bytes can be explicitly initialized by calling memset():

Code Block
bgColor#FFCCCC
langc
#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;

  /* 
   * InitializesSet 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));

  /* ... */
}

Here, the compiler could However, compilers are free to implement arg.b = 2 in the following way:

...

by setting the low byte of a 32-bit register to 2, leaving the high bytes unchanged, and

...

storing all 32-bits of the register into memory

...

thereby leaking stack bytes to an unprivileged user. This may not be the case with all compilers, but compilers are free to implement it in their own way, so this example could leak data under some specific compiler. This would then leak the high bytes resident in the register to a user.

Compliant Solution (Structure Packing—GCC)

GCC allows specifying declaration attributes of variables and structures using the keyword __attribute__((__packed__)). This means that the GCC When this attribute is present, the compiler will not add any padding bytes ( for memory alignment) and will make variables or fields immediately next to each other, unless otherwise required to by the _Alignas alignment specifier, and will attempt to place fields at adjacent memory offsets when possible.

Code Block
bgColor#CCCCFF
borderStylesolid
#include <stddef.h>

struct test{
  int a;
  char b;
  int c;
} __attribute__((__packed__));

/* ... 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 = {.a = 1, .b = 2, .c = 3};

  /* ... Perform operations on arg ... */

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

  /* ... */
}

Compliant Solution (Structure

...

Packing—Microsoft Visual Studio)

Microsoft Visual Studio supports the #pragma pack() instead of the __packed__ attribute to attempt to ensure no suppress padding bytes are added [MSDN]:. The compiler will add padding bytes for memory alignment depending on the current packing mode, but still honors alignment specified by __declspec(align()).  In this compliant solution, the packing mode is set to one in an attempt to ensure all fields are given adjacent offsets.

Code Block
bgColor#CCCCFF
borderStylesolid
#include <stddef.h>

#pragma pack(push, 1) /* 1 byte */
struct test{
  int a;
  char b;
  int c;
};
#pragma pack(pop)
 
/* ... 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 = {1, 2, 3};

  /* ... Perform operations on arg ... */

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

  /* ... */
}

The pack pragma 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 of one byte unless otherwise specified.

Compliant Solution (

...

Padding

...

Bytes)

The padding Padding bytes could can be explicitly declared . It should be done carefully on the basis of the as fields within the structure, however this solution is not portable because it depends on the implementation and target memory architecture. The following solution assumes it will be run on an IA-32 architecture:

Code Block
bgColor#CCCCFF
borderStylesolid
#include <assert.h>
#include <stddef.h>

struct test{
  int a;
  char b;
  char padding_1, padding_2, padding_3;
  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) {

  /* Make sureEnsure c is the next byte after the last padding byte */
  static_assert(offsetof(struct test, c) == \

                offsetof(struct test, padding_3) + 1, \

                "Structure contains intermediate padding");
  /* Ensure there is no trailing padding */
  static_assert(sizeof(struct test) ==
                offsetof(struct test, c) + sizeof(int),
                "Error:Structure notcontains compiling for IA-32trailing padding");

  struct test arg = {.a = 1, .b = 2, .c = 3};
  arg.padding_1 = 0;
  arg.padding_2 = 0;
  arg.padding_3 = 0;

  /* ... Perform operations on arg ... */

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

  /* ... */
}

The C11 static_assert() macro , a feature of the C 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 DCL03-C. Use a static assertion to test the value of a constant expression for more details.

For example, in on an IA-32 machine, the explicit insertion of the padding bytes into the struct should ensure that no "invisible" no additional padding bytes are added by the compiler, and consequently the expression in both static_assert expressions should be true.

Explicitly,

Code Block
offsetof(struct test, c ) = 8

and

Code Block
offsetof(struct test, padding_3 ) = 7,

and consequently the expression should return 1.

However, if you were compiling for a different architecture and the compiler added padding bytes, then the memory would not be contiguous and the expression would return 0.

This approach ensures that no padding bytes are inserted.

Compliant Solution

However, it is still necessary to assert these details to ensure the safety of the solution.

Compliant Solution

A compliant solution which does not involve any vendor-specific language extensions, or architecture-specific explicit padding bytes, is to manually serialize the structure data before copying it to an untrusted contextIf setting memset of the original structure to 0 (as mentioned in the noncompliant example) does not work under some compilers, then copy the original structure to an unsigned char memory and pass that memory to the user as follows:

Code Block
bgColor#CCCCFF
borderStylesolid
#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 = {.a = 1, .b = 2, .c = 3};
  unsigned char r[sizeof(arg)];

    /* ...May Performbe operationslarger onthan argstrictly ...needed */

  unsigned /* Just before passing arg to the function */
  memset(r, 0, sizeof(r));
  memset(r+offsetof(struct test,a), arg.a,char buf[sizeof(arg)];
  size_t size = 0;
  
  *((int *)(buf + size)) = arg.a;
  size += sizeof(arg.a));
   memset(r+offsetof(struct test,b),*((char *)(buf + size)) = arg.b,;
  size += sizeof(arg.b));
   memset(r+offsetof(struct test,c),*((int *)(buf + size)) = arg.c,;
  size += sizeof(arg.c));
  /* Now pass r to the function */
    copy_to_user(usr_buf, rbuf, sizeof(rsize));

  /* ... */
}

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

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL39-C

Low

Unlikely

MediumHigh

P2

L3

P1

L3

Related Vulnerabilities

In practice, this type of security flaw can expose sensitive information to unintended parties. The Sun tarball vulnerability discussed in Secure Coding Principles & Practices: Designing and Implementing Secure Applications [Graff 2003] and Sun Security Bulletin #00122 [Sun 1993] shows a violation of this recommendation and its consequential leak of sensitive data. Attackers can also leverage this defect to retrieve sensitive information using techniques such as heap inspection.

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[ISO/IEC 9899:2011]Subclause 6.2.6.1, "General" (paragraph 6)
Subclause 6.7.2.1, "Structure and Union Specifiers"
[Graff 2003] 
[Sun 1993] 

 

...