...
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 | ||||
|---|---|---|---|---|
| ||||
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 | ||||
|---|---|---|---|---|
| ||||
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 | ||||
|---|---|---|---|---|
| ||||
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 | ||||
|---|---|---|---|---|
| ||||
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 | ||||
|---|---|---|---|---|
| ||||
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;
}
|
...