The getenv()
function searches an environment list, provided by the host environment, for a string that matches a specified name. The getenv()
function returns a pointer to a string associated with the matched list member. It is best not to store this pointer as it may be overwritten by a subsequent call to the getenv()
function [[ISO/IEC 9899:1999]] 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.
According to C99 [[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.
This allows an implementation, for example, to copy the environmental variable to an internal static buffer and return a pointer to that buffer.
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) { 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.
char *tmpvar; char *tempvar; size_t requiredSize; getenv_s(&requiredSize, NULL, 0, "TMP"); tmpvar = (char *)malloc(requiredSize * sizeof(char)); if (!tmpvar) { /* handle error condition */ } 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 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"); } free(tmpvar); tmpvar = NULL; free(tempvar); tempvar = NULL;
Compliant Solution (Windows)
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].
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()
.
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) { puts("TMP and TEMP are the same.\n"); } else { puts("TMP and TEMP are NOT the same.\n"); } free(tmpvar); tmpvar = NULL; free(tempvar); tempvar = NULL;
Compliant Solution (POSIX)
The following compliant solution depends on the POSIX strdup()
function to make a copy of the environment variable string. 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 condition */ } } else { return -1; } temp = getenv("TEMP"); if (temp != NULL) { tempvar = strdup(temp); if (tempvar == NULL) { free(tmpvar); tmpvar = NULL; /* handle error condition */ } } else { free(tmpvar); tmpvar = NULL; 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); tmpvar = NULL; free(tempvar); tempvar = NULL;
Compliant Solution
This compliant solution is fully portable.
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 condition */ } } 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 condition */ } } else { free(tmpvar); tmpvar = NULL; 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); 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]]
[[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