You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 42 Next »

C99 defines getenv() to have the following behavior: [[ISO/IEC 9899:1999]]

The getenv function returns a pointer to a string associated with the matched list member. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to the getenv function.

Consequently, it is best not to store this pointer as 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, or copied so that the copy may be referenced safely at a later time.

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

Non-Compliant Code 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 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.

char *tmpvar;
char *tempvar;

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

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

Compliant Solution (Windows)

Windows provides the getenv_s() and _wgetenv_s() functions for getting a value from the current environment [[MSDN]].

char *tmpvar;
char *tempvar;
size_t requiredSize;

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

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

if (strcmp(tmpvar, tempvar) == 0) {
  if (puts("TMP and TEMP are the same.\n") == EOF) {
    /* Handle Error */
  }
}
else {
  if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
    /* Handle Error */
  }
}
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().

It is the calling program's responsibility to free any allocated buffers returned by these functions.

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);
  tmpvar = NULL;
  return -1;
}

if (strcmp(tmpvar, tempvar) == 0) {
  if (puts("TMP and TEMP are the same.\n") == EOF) {
    /* Handle Error */
  }
}
else {
  if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
    /* Handle Error */
  }
}
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 [[Open Group 04]]. The strdup() function is also included in ISO/IEC PDTR 24731-2 [[ISO/IEC PDTR 24731-2]].

char *tmpvar;
char *tempvar;

char *temp = getenv("TMP");
if (temp != NULL) {
  tmpvar = strdup(temp);
  if (tmpvar == NULL) {
    /* Handle Error */
  }
}
else {
  return -1;
}

temp = getenv("TEMP");
if (temp != NULL) {
  tempvar = strdup(temp);
  if (tempvar == NULL) {
    free(tmpvar);
    tmpvar = NULL;
    /* Handle Error */
  }
}
else {
  free(tmpvar);
  tmpvar = NULL;
  return -1;
}

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

Compliant Solution

This compliant solution uses only the C99 malloc() and strcpy() functions to copy the string returned by getenv() into a dynamically allocated buffer.

char *tmpvar;
char *tempvar;

char *temp = getenv("TMP");
if (temp != NULL) {
  tmpvar = (char *)malloc(strlen(temp)+1);
  if (tmpvar != NULL) {
    strcpy(tmpvar, temp);
  }
  else {
    /* Handle Error */
  }
}
else {
  return -1;
}

temp = getenv("TEMP");
if (temp != NULL) {
  tempvar = (char *)malloc(strlen(temp)+1);
  if (tempvar != NULL) {
    strcpy(tempvar, temp);
  }
  else {
    free(tmpvar);
    tmpvar = NULL;
    /* Handle Error */
  }
}
else {
  free(tmpvar);
  tmpvar = NULL;
  return -1;
}

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

Risk Assessment

Storing the pointer to the string returned by getenv() can result in overwritten environmental data.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

ENV00-A

low

probable

medium

P4

L3

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

[[ISO/IEC 9899:1999]] Section 7.20.4, "Communication with the environment"
[[ISO/IEC PDTR 24731-2]]
[[MSDN]] _dupenv_s() and _wdupenv_s(), getenv_s(), _wgetenv_s()
[[Open Group 04]] Chapter 8, "Environment Variables", strdup
[[Viega 03]] Section 3.6, "Using Environment Variables Securely"


10. Environment (ENV)      10. Environment (ENV)       ENV01-A. Do not make assumptions about the size of an environment variable

  • No labels