Movatterモバイル変換


[0]ホーム

URL:


CodeQL documentation
CodeQL resources

Non-constant format string

ID: cpp/non-constant-formatKind: path-problemSecurity severity: 9.3Severity: recommendationPrecision: highTags:   - maintainability   - correctness   - security   - external/cwe/cwe-134Query suites:   - cpp-security-extended.qls   - cpp-security-and-quality.qls

Click to see the query in the CodeQL repository

Theprintf function, related functions likesprintf andfprintf, and other functions built atopvprintf all accept a format string as one of their arguments. When such format strings are literal constants, it is easy for the programmer (and static analysis tools) to verify that the format specifiers (such as%s and%02x) in the format string are compatible with the trailing arguments of the function call. When such format strings are not literal constants, it is more difficult to maintain the program: programmers (and static analysis tools) must perform non-local data-flow analysis to deduce what values the format string argument might take.

Recommendation

If the argument passed as a format string is meant to be a plain string rather than a format string, then pass%s as the format string, and pass the original argument as the sole trailing argument.

If the argument passed as a format string is a parameter to the enclosing function, then consider redesigning the enclosing function’s API to be less brittle.

Example

The following program is meant to echo its command line arguments:

#include<stdio.h>intmain(intargc,char**argv){for(inti=1;i<argc;++i){printf(argv[i]);}}

The above program behaves as expected in most cases, but breaks when one of its command line arguments contains a percent character. In such cases, the behavior of the program is undefined: it might echo garbage, it might crash, or it might give a malicious attacker root access. One way of addressing the problem is to use a constant%s format string, as in the following program:

#include<stdio.h>intmain(intargc,char**argv){for(inti=1;i<argc;++i){printf("%s",argv[i]);}}

Example

The following program defines alog_with_timestamp function:

voidlog_with_timestamp(constchar*message){structtmnow;time(&now);printf("[%s] ",asctime(now));printf(message);}intmain(intargc,char**argv){log_with_timestamp("Application is starting...\n");/* ... */log_with_timestamp("Application is closing...\n");return0;}

In the code that is visible, the reader can verify thatlog_with_timestamp is never called with a log message containing a percent character, but even if all current calls are correct, this presents an ongoing maintenance burden to ensure that newly-introduced calls don’t contain percent characters. As in the previous example, one solution is to make the log message a trailing argument of the function call:

voidlog_with_timestamp(constchar*message){structtmnow;time(&now);printf("[%s] %s",asctime(now),message);}intmain(intargc,char**argv){log_with_timestamp("Application is starting...\n");/* ... */log_with_timestamp("Application is closing...\n");return0;}

An alternative solution is to allowlog_with_timestamp to accept format arguments:

voidlog_with_timestamp(constchar*message,...){va_listargs;va_start(args,message);structtmnow;time(&now);printf("[%s] ",asctime(now));vprintf(message,args);va_end(args);}intmain(intargc,char**argv){log_with_timestamp("%s is starting...\n",argv[0]);/* ... */log_with_timestamp("%s is closing...\n",argv[0]);return0;}

In this formulation, the non-constant format string toprintf has been replaced with a non-constant format string tovprintf. The analysis will no longer consider the body oflog_with_timestamp to be a problem, and will instead check that every call tolog_with_timestamp passes a constant format string.

References


[8]ページ先頭

©2009-2025 Movatter.jp