...
The localeconv(), setlocale(), and strerror() functions have similar caveats. Do not access the objects returned by any of these functions after a subsequent call.
Noncompliant Code Example
This noncompliant code example compares the value of the TMP and TEMP environment variables to determine if they are the same:
...
This code example is noncompliant because the string referenced by tmpvar may be overwritten as a result of the second call to the getenv() function. As a result, it is possible that both tmpvar and tempvar will compare equal even if the two environment variables have different values.
Compliant Solution
This compliant solution uses only the C malloc() and strcpy() functions to copy the string returned by getenv() into a dynamically allocated buffer:
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
const char *temp = getenv("TMP");
if (temp != NULL) {
tmpvar = (char *)malloc(strlen(temp)+1);
if (tmpvar != NULL) {
strcpy(tmpvar, temp);
} else {
/* Handle error */
}
} else {
/* Handle error */
}
temp = getenv("TEMP");
if (temp != NULL) {
tempvar = (char *)malloc(strlen(temp)+1);
if (tempvar != NULL) {
strcpy(tempvar, temp);
} else {
/* Handle error */
}
} else {
/* Handle error */
}
if (strcmp(tmpvar, tempvar) == 0) {
printf("TMP and TEMP are the same.\n");
} else {
printf("TMP and TEMP are NOT the same.\n");
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
Compliant Solution (C11 Annex K)
C11 Annex K provides the getenv_s()function for getting a value from the current environment. However, note that according to the standard, getenv_s() can still have data races with other threads of execution that modify the environment list.
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
size_t requiredSize;
errno_t err;
err = getenv_s(&requiredSize, NULL, 0, "TMP");
if (err) {
/* Handle error */
}
tmpvar = (char *)malloc(requiredSize * sizeof(char));
if (!tmpvar) {
/* Handle error */
}
err = getenv_s(&requiredSize, tmpvar, requiredSize, "TMP" );
if (err) {
/* Handle error */
}
err = getenv_s(&requiredSize, NULL, 0, "TEMP");
if (err) {
/* Handle error */
}
tempvar = (char *)malloc(requiredSize * sizeof(char));
if (!tempvar) {
/* Handle error */
}
err = getenv_s(&requiredSize, tempvar, requiredSize, "TEMP" );
if (err) {
/* Handle error */
}
if (strcmp(tmpvar, tempvar) == 0) {
printf("TMP and TEMP are the same.\n");
} else {
printf("TMP and TEMP are NOT the same.\n");
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
Compliant Solution (Windows)
Windows also provides the _dupenv_s() and wdupenv_s() functions for getting a value from the current environment [MSDN]. The _dupenv_s() function searches the list of environment variables for a specified name. If the name is found, a buffer is allocated; the variable's value is copied into the buffer, and the buffer's address and number of elements are returned. By allocating the buffer itself, _dupenv_s() and _wdupenv_s() provide a more convenient alternative to getenv_s() and _wgetenv_s().
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
size_t len;
errno_t err = _dupenv_s(&tmpvar, &len, "TMP");
if (err) {
/* Handle error */
}
err = _dupenv_s(&tempvar, &len, "TEMP");
if (err) {
/* Handle error */
}
if (strcmp(tmpvar, tempvar) == 0) {
printf("TMP and TEMP are the same.\n");
} else {
printf("TMP and TEMP are NOT the same.\n");
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
Compliant Solution (POSIX)
POSIX provides the strdup() function, which can make a copy of the environment variable string [IEEE Std 1003.1:2013]. The strdup() function is also included in Extensions to the C Library—Part II [ISO/IEC TR 24731-2:2010].
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
const char *temp = getenv("TMP");
if (temp != NULL) {
tmpvar = strdup(temp);
if (tmpvar == NULL) {
/* Handle error */
}
} else {
/* Handle error */
}
temp = getenv("TEMP");
if (temp != NULL) {
tempvar = strdup(temp);
if (tempvar == NULL) {
/* Handle error */
}
} else {
/* Handle error */
}
if (strcmp(tmpvar, tempvar) == 0) {
printf("TMP and TEMP are the same.\n");
} else {
printf("TMP and TEMP are NOT the same.\n");
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
Risk Assessment
Storing the pointer to the string returned by getenv(), localeconv(), setlocale(), or strerror() can result in overwritten data.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
ENV34-C | Low | Probable | Medium | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Automated Detection
Tool | Version | Checker | Description |
|---|---|---|---|
|
|
|
Related Guidelines
| CERT C++ Secure Coding Standard | ENV00-CPP. Do not store the pointer to the string returned by getenv() |
| ISO/IEC TR 24731-2 | |
| ISO/IEC TS 17961 | Using an object overwritten by getenv, localeconv, setlocale, and strerror [libuse] |
Bibliography
| [IEEE Std 1003.1:2013] | Chapter 8, "Environment Variables" XSH, System Interfaces, strdup |
| [ISO/IEC 9899:2011] | Subclause 7.22.4, "Communication with the Environment" Subclause 7.22.4.6, "The getenv Function"Subclause K.3.6.2.1, "The getenv_s Function" |
| [MSDN] | _dupenv_s() and _wdupenv_s() |
| [Viega 2003] | Section 3.6, "Using Environment Variables Securely" |
...