Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Consequently, it is best not to store this pointer because it may be overwritten by a subsequent call to the getenv() function or invalidated as a result of changes made to the environment list through calls to putenv(), setenv(), or other means. Storing the pointer for later use can result in a dangling pointer or a pointer to incorrect data. This string should be referenced immediately and discarded; if later use is anticipated, the string should be copied so the copy can be safely referenced as needed.

The getenv() function is not thread-safe. Make sure to address any possible race conditions resulting from the use of this function.

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
bgColor#ccccff
langc
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
bgColor#ccccff
langc
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
bgColor#ccccff
langc
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
bgColor#ccccff
langc
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 environmental data.

RecommendationRule

Severity

Likelihood

Remediation Cost

Priority

Level

ENV00-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

Compass/ROSE

 

 

 

Related Guidelines

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"

...