...
| Code Block | ||
|---|---|---|
| ||
void incorrect_password(const char *user) {
/* user names are restricted to 256 characters or less */
static const char *msg_format
= "%s cannot be authenticated.\n";
size_t len = strlen(user) + sizeof(msg_format);
char *msg = (char *) malloc(len);
if (!msg) {
/* handle error condition */
}
int ret = snprintf(msg, len, msg_format, user);
if (ret < 0 || ret >= len) {\
/* Handle Errorerror */
}
fprintf(stderr, msg);
free(msg);
msg = NULL;
}
|
The incorrect_password() function constructs msg in dynamically allocated memory by first calculating the size of the message, allocating dynamic storage, and then constructing the message in the allocated memory using the snprintf() function. The addition operations are not checked for integer overflow because the length of the string referenced by user is known to be have a length of 256 or less. Because the %s characters are replaced by the string referenced by user in the call to snprintf(), one less byte is required to store the resulting string and terminating NULL-byte character. This is a common idiom for displaying the same message in multiple locations or when the message is difficult to build. The resulting code contains a format-string vulnerability, however, because the msg includes untrusted user input and is passed as the format-string argument in the call to fprintf().
Compliant Solution (fputs())
This code example compliant solution fixes the flaw in problem by replacing the fprintf() call with a call to fputs(), which does not treat msg like a format string, but outputs it to stderr as is.
| Code Block | ||
|---|---|---|
| ||
void incorrect_password(const char *user) {
/* user names are restricted to 256 characters or less */
static const char *msg_format
= "%s cannot be authenticated.\n";
size_t len = strlen(user) + sizeof(msg_format);
char *msg = (char *) malloc(len);
if (!msg) {
/* handleHandle error condition */
}
int ret = snprintf(msg, len, msg_format, user);
if (ret < 0 || ret >= len) {\
/* Handle Errorerror */
}
if (fputs(msg, stderr) == EOF) {
/* Handle Errorerror */
}
free(msg);
msg = NULL;
}
|
Compliant Solution (fprintf())
A This simpler compliant solution merely passes the untrusted user input as one of the variadic arguments to fprintf() and not as part of the format string, eliminating the possibility of a format-string vulnerability.
...
| Wiki Markup |
|---|
This noncompliant code example is exactly the same as the first noncompliant code example, but uses the POSIX function {{syslog()}} \[[Open Group 04|AA. C References#Open Group 04]\] instead of the {{fprintf()}} function, which is also susceptible to format-string vulnerabilities. |
| Code Block | ||
|---|---|---|
| ||
void incorrect_password(const char *user) {
/* user names are restricted to 256 characters or less */
static const char *msg_format
= "%s cannot be authenticated.\n";
size_t len = strlen(user) + sizeof(msg_format);
char *msg = (char *) malloc(len);
if (!msg) {
/* handleHandle error condition */
}
int ret = snprintf(msg, len, msg_format, user);
if (ret < 0 || ret >= len) {\
/* Handle Errorerror */
}
syslog(LOG_INFO, msg);
free(msg);
msg = NULL;
}
|
...
Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location, and , consequently , execute arbitrary code with the permissions of the vulnerable process.
...