The parameters of a variadic function are interpreted by the va_arg()
macro. The va_arg()
macro is used to extract the next argument from an initialized argument list within the body of a variadic function implementation. The size of each parameter is determined by the specified type
. If type
is inconsistent with the corresponding argument, the behavior is undefined and may result in misinterpreted data or an alignment error [[EXP36-C. Do not convert between pointers to objects with differing alignments]].
Because arguments to variadic functions are untyped, the programmer is responsible for ensuring that they are the same type as the corresponding parameter except for the following cases:
- one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;
- one type is pointer to
void
and the other is a pointer to a character type.
Non-Compliant Code Example (type interpretation error)
The C99 printf()
function is implemented as a variadic function. This non-compliant code example swaps its null-terminated byte string and integer parameters with respect to how they were specified in the format string. Consequently, the integer is interpreted as a pointer to a null-terminated byte string and dereferenced. This will likely cause the program to abnormally terminate. Note that the error_message
pointer is likewise interpreted as an integer.
const char *error_msg = "Error occurred"; /* ... */ printf("%s:%d", 15, error_msg);
Compliant Solution (type interpretation error)
This compliant solution is formatted so that the specifiers are consistent with their parameters.
const char *error_msg = "Error occurred"; /* ... */ printf("%d:%s", 15, error_msg);
As shown, care must be taken to ensure that the arguments passed to a format string function match up with the supplied format string.
Non-Compliant Code Example (type alignment error)
In this non-compliant code example, a type long long
integer is incorrectly parsed by the printf()
function with a %d
specifier. This code may result in data truncation or misrepresentation when the value is extracted from the argument list.
long long a = 1; char msg[128] = "Default message"; /* ... */ printf("%d %s", a, msg);
Because a long long
was not interpreted, if the long long
uses more bytes for storage, the subsequent format specifier %s
is unexpectedly offset, causing unknown data to be used instead of the pointer to the message.
Compliant Solution (type alignment error)
This compliant solution adds the length modifier ll
to the %d
format specifier so that the variadic function parser for printf()
extracts the correct number of bytes from the variable argument list for the long long
argument.
long long a = 1; char msg[128] = "Default message"; /* ... */ printf("%lld %s", a, msg);
Risk Assessment
Inconsistent typing in variadic functions can result in abnormal program termination or unintended information disclosure.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL11-A |
2 (medium) |
2 (probable) |
2 (medium) |
P8 |
L2 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[ISO/IEC 9899-1999]] Section 7.15, "Variable arguments"