Versions Compared

Key

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

...

Depending on the implementation, a program may not consistently choose the same value if there are multiple environment variables with the same name. The GNU glibc library attempts to deal with this issue ( in getenv() and setenv()) by always using the first variable it comes across, and ignoring the rest. unsetenv() will remove all the entries matching the variable name.

Non-Compliant Coding Example

This non-compliant code example compares the value of the TMP and TEMP environment variables to determine if they are the same. This code example is non-compliant because the string referenced by tmpvar may be overwritten as a result of the second call to 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.

Code Block
bgColor#FFcccc

char *tmpvar;
char *tempvar;

tmpvar = getenv("TMP");
if (!tmpvar) return -1;
tempvar = getenv("TEMP");
if (!tempvar) return -1;

if (strcmp(tmpvar, tempvar) == 0) {
  puts("TMP and TEMP are the same.\n");
}
else {
  puts("TMP and TEMP are NOT the same.\n");
}

Compliant Solution (Windows)

Microsoft Visual Studio 2005 provides provides the getenv_s() and _wgetenv_s() functions for getting a value from the current environment.

Do not search or modify environ directly. Using a stable function such as getenv() or setenv() will prevent this issue.

Compliant Solution

Code Block
bgColor#ccccff
char *tmpvar;
char *tempvar;
size_t requiredSize;

getenv_s(&requiredSize, NULL, 0, "TMP");
tmpvar= malloc(requiredSize * sizeof(char));
if (!tmpvar) {
   /* handle error condition */
}
getenv_s(&requiredSize, tmpvar, requiredSize, "TMP" );

getenv_s(&requiredSize, NULL, 0, "TEMP");
tempvar= malloc(requiredSize * sizeof(char));
if (!tempvar) {
   /* handle error condition */
}
getenv_s(&requiredSize, tempvar, requiredSize, "TEMP" );

if (strcmp(tmpvar, tempvar) == 0) {
  puts("TMP and TEMP are the same.\n");
}
else {
  puts("TMP and TEMP are NOT the same.\n");
}

Compliant Solution (Windows)

Wiki Markup
Microsoft Visual Studio 2005 provides provides the {{\_dupenv_s()}} and {{\_wdupenv_s()}} functions for getting a value from the current environment.  \[[Microsoft Visual Studio 2005/.NET Framework 2.0 help pages|http://msdn2.microsoft.com/en-us/library/ms175774(VS.80).aspx]\].

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() provides a more convenient alternative to getenv_s(), _wgetenv_s().

It is the calling program's responsibility to free the memory by calling free().

Code Block
bgColor#ccccff

char *tmpvar;
char *tempvar;
size_t len;

errno_t err = _dupenv_s(&tmpvar, &len, "TMP");
if (err) return -1;
errno_t err = _dupenv_s(&tempvar, &len, "TEMP");
if (err) {
  free(tmpvar);
  return -1;
}

if (strcmp(tmpvar, tempvar) == 0) {
  puts("TMP and TEMP are the same.\n");
}
else {
  puts("TMP and TEMP are NOT the same.\n");
}
free(tmpvar);
free(tempvar);

Compliant Solution (POSIX)

The following compliant solution depends on the POSIX strdup() function to make a copy of the environment variable string.

Code Block
bgColor#ccccff

char *tmpvar = strdup(getenv("TMP"));
char *tempvar = strdup(getenv("TEMP"));
if (!tmpvar) return -1;
if (!tempvar) return -1;

if (strcmp(tmpvar, tempvar) == 0) {
  puts("TMP and TEMP are the same.\n");
}
else {
  puts("TMP and TEMP are NOT the same.\n");
}

Wiki Markup
If an environmental variable does not exist, the call to {{getenv()}} returns a null pointer.  In these cases, the call to {{strdup()}} should also return a null pointer, but it is important to verify this as this behavior is not guaranteed by POSIX \[[Open Group 04|AA. C References#Open Group 04]\]

Compliant Solution

This compliant solution is fully portable.

Code Block
bgColor#ccccff

char *tmpvar;
char *tempvar;
char *temp;

if ( (temp = getenv("TMP"temp;
char *tmpvar;

if ((temp = getenv("TEMP")) != NULL) {
  tmpvar= malloc(strlen(temp)+1);
  if (tmpvar != NULL) {
    strcpy(tmpvar, temp);
  }
  else {
    /* handle error condition */
  }
}
else {
 tmpvar[0] return -1;
}

if ( (temp = getenv= 'a';
  setenv("TEMP")) != NULL) {
  tempvar= malloc(strlen(temp)+1);
  if (tempvar != NULL) {
    strcpy(tempvar, temp);
  }
  , tmpvar, 1);
}
else {
    /* handle error condition */
  }
}
else {
  return -1;
}

if (strcmp(tmpvar, tempvar) == 0) {
  puts("TMP and TEMP are the same.\n");
}
else {
  puts("TMP and TEMP are NOT the same.\n");
}

Risk Assessment

Risk Assessment

An adversary could create several environment variables with the same name. If the program checks against one copy, but actually uses another, this could be a clear problem.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ENV02-A

3 (high)

1 (low)

1 (high)

P3

L3

Examples of vulnerabilities resulting from the violation of this recommendation can be found on the CERT website.

References

Wiki Markup
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.20.4, "Communication with the environment"
\[[Open Group 04|AA. C References#Open Group 04]\] Chapter 8, "Environment Variables", [strdup|http://www.opengroup.org/onlinepubs/009695399/functions/strdup.html]
\[[Viega 03|AA. C References#Viega 03]\] Section 3.6, "Using Environment Variables Securely"