Versions Compared

Key

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

...

This noncompliant code example is taken from a vulnerability in bash versions 1.14.6 and earlier that resulted in the release of CERT Advisory CA-1996-22. This vulnerability resulted from the sign extension of character data referenced by the string pointer in the yy_string_get() function in the parse.y module of the bash source code:

Code Block
bgColor#FFcccc
langc
static int yy_string_get() {
  register char *string;
  register int c;

  string = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (string && *string) {
    c = *string++;
    bash_input.location.string = string;
  }
  return (c);
}

...

This problem was repaired by explicitly declaring the string variable as unsigned char.

Code Block
bgColor#FFcccc
langc
static int yy_string_get() {
  register unsigned char *string;
  register int c;

  string = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (string && *string) {
    c = *string++;
    bash_input.location.string = string;
  }
  return (c);
}

...

In this compliant solution, the result of the expression *string++ is cast to (unsigned char) before assignment to the int variable c.

Code Block
bgColor#ccccff
langc
static int yy_string_get() {
  register char *string;
  register int c;

  string = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (string && *string) {
    /* cast to unsigned type */
    c = (unsigned char)*string++;

    bash_input.location.string = string;
  }
  return (c);
}

...

In this noncompliant example the result of the cast of *s to unsigned int may result in a value in excess of UCHAR_MAX because of integer promotions, consequently causing the function to violate VOID Guarantee that array indices are within the valid range, leading to undefined behavior.

Code Block
bgColor#ffcccc
langc
static const char table[UCHAR_MAX] = { /* ... /* };

int first_not_in_table(const char *str) {
  const char *s = str;
  for (; *s; ++s) {
    if (table[(unsigned)*s] != *s)
      return s - str;
  return -1;
}

...

This compliant solution casts the char value to unsigned char before allowing it to be implicitly promoted to a larger unsigned type.

Code Block
bgColor#ccccff
langc
static const char table[UCHAR_MAX] = { /* ... /* };

ptrdiff_t first_not_in_table(const char *str) {
  const char *s = str;
  for (; *s; ++s) {
    if (table[(unsigned char)*s] != *s)
      return s - str;
  return -1;
}

...