The variable parameters of a variadic function, this is, those that correspond with the position of the ellipsis, 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 the type is inconsistent with the corresponding argument, the behavior is [undefined|BB. Definitions#undefined behavior] and may result in misinterpreted data or an alignment error \[[EXP36-C. Do not convert pointers into more strictly aligned pointer types]\].

The variable arguments to a variadic function are not checked for type by the compiler.  Therefore, the programmer is responsible for ensuring that they are compatible with the corresponding parameter after the default argument promotions:

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|AA. C References#ISO/IEC 9899-1999]\] Section 6.5.2.2, "Function calls"; 7.15, "Variable arguments"


DCL10-A. Maintain the contract between the writer and caller of variadic functions      02. Declarations and Initialization (DCL)       DCL12-A. Create and use abstract data types