Some functions in the C standard library are not guaranteed to be reentrant with respect to threads. Some functions (such as strtok()
and asctime()
) return a pointer to the result stored in function-allocated memory on a per-process basis. Other functions (such as rand()
) store state information in function-allocated memory on a per-process basis. Multiple threads invoking the same function can cause concurrency problems, which often result in abnormal behavior and can cause more serious vulnerabilities, such as abnormal termination, denial-of-service attack, and data integrity violations.
According to the C11 C Standard, the following library functions may contain data races when invoked by multiple threads:
API | Recommendation |
---|---|
rand() , srand() | MSC30-C. Do not use the rand() function for generating pseudorandom numbers |
getenv() , getenv_s() | ENV00-C. Do not store the pointer to the string returned by getenv() |
strtok() | strtok_s() in C11 Annex K, or strtok_r() in POSIX |
strerror() | strerror_s() in C11 Annex K, or strerror_r() in POSIX |
asctime() , ctime() ,localtime() , gmtime() | asctime_s() , ctime_s() , localtime_s() , gmtime_s() in C11 Annex K |
setlocale() | Protect multithreaded access to locale-specific APIs with a mutex |
ATOMIC_VAR_INIT , atomic_init() | Do not attempt to initialize an atomic variable from multiple threads |
tmpnam() | tmpnam_s() in C11 Annex K, tmpnam_r() in POSIX |
mbrtoc16() , c16rtomb() ,mbrtoc32() , c32rtomb() | Do not call with a null mbstate_t * argument |
...
Consider a multithreaded application that encounters an error while calling a system function. The strerror()
function returns a human-readable error string given an error number. The C Standard, subclause 7.24.6.2 [ISO/IEC 9899:2011], specifically states that strerror()
is not required to avoid data races. Conventionally, it could rely on a static array that maps error numbers to error strings, and that array might be accessible and modifiable by other threads.
...
This compliant solution uses the POSIX strerror_r()
function, which has the same functionality as strerror()
but guarantees thread-safety:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <errno.h> #include <stdio.h> #include <string.h> enum { BUFFERSIZE = 64 }; void f(FILE *fp) { fpos_t pos; errno = 0; if (0 != fgetpos(fp, &pos)) { char errmsg[BUFFERSIZE]; if (strerror_r(errno, errmsg, BUFFERSIZE) != 0) { /* Handle error */ } printf("Could not get the file position because of %s\n", errmsg); } } |
...
Race conditions caused by multiple threads invoking the same library function can lead to abnormal termination of the application, data integrity violations, or denial-of-service attack.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON33-C | mediumMedium | probableProbable | highHigh | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
Tool | Version | Checker | Description |
---|---|---|---|
|
| A module written in Compass/ROSE can detect violations of this rule |
...
Bibliography
...
Section 2.9.1 | [ISO/IEC 9899:2011] | Subclause 7.24.6.2, "The |
[Open Group 1997b] | Section 10.12, "Thread-Safe POSIX.1 and C-Language Functions" |
...