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 could 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.
If you do not immediately use and discard this string, make a copy of the referenced string returned by getenv()
so that this copy may be safely referenced 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.
Implementation Details
According to the Microsoft Visual Studio 2005/.NET Framework 2.0 help pages:
The
getenv
function searches the list of environment variables forvarname
.getenv
is not case sensitive in the Windows operating system.getenv
and_putenv
use the copy of the environment pointed to by the global variable_environ
to access the environment.getenv
operates only on the data structures accessible to the run-time library and not on the environment "segment" created for the process by the operating system. Therefore, programs that use theenvp
argument tomain
orwmain
may retrieve invalid information.
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 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= 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)
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); 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.
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"); }
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]]
Compliant Solution
This compliant solution is fully portable.
char *tmpvar; char *tempvar; char *temp; if ( (temp = getenv("TMP")) != NULL) { tmpvar= malloc(strlen(temp)+1); if (tmpvar != NULL) { strcpy(tmpvar, temp); } else { /* handle error condition */ } } else { return -1; } if ( (temp = getenv("TEMP")) != NULL) { tempvar= malloc(strlen(temp)+1); if (tempvar != NULL) { strcpy(tempvar, temp); } 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
Storing the pointer to the string returned by getenv()
can result in overwritten environmental data.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
ENV00-A |
1 (low) |
1 (unlikely) |
2 (medium) |
P2 |
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"
[[Open Group 04]] Chapter 8, "Environment Variables", strdup
[[Viega 03]] Section 3.6, "Using Environment Variables Securely"