Some environments provide environment pointers that are valid when main() is called, but may be invalided by operations that modify the environment.
According to C99 Section J.5.1 of the C standard [ISO/IEC 9899:19992011] states:
In a hosted environment, the main function receives a third argument,
char *envp[], that points to a null-terminated array of pointers tochar, each of which points to a string that provides information about the environment for this execution of the program.
Consequently, under a hosted environment it is possible to access the environment through a modified form of main():
| Code Block |
|---|
main(int argc, char *argv[], char *envp[])
|
...
For example, when compiled with GCC version 3.4.6 and run on a 32-bit Intel GNU/Linux machine, the following code
| Code Block |
|---|
extern char **environ;
/* ... */
int main(int argc, const char *argv[], const char *envp[]) {
printf("environ: %p\n", environ);
printf("envp: %p\n", envp);
setenv("MY_NEW_VAR", "new_value", 1);
puts("--Added MY_NEW_VAR--");
printf("environ: %p\n", environ);
printf("envp: %p\n", envp);
}
|
yields
| Code Block |
|---|
% ./envp-environ
environ: 0xbf8656ec
envp: 0xbf8656ec
--Added MY_NEW_VAR--
environ: 0x804a008
envp: 0xbf8656ec
|
...
After a call to the POSIX setenv() function, or another function that modifies the environment, the envp pointer may no longer reference the environment. POSIX states that [Open Group 2004]
Unanticipated unanticipated results may occur if
setenv()changes the external variableenviron. In particular, if the optionalenvpargument tomain()is present, it is not changed, and as a result may point to an obsolete copy of the environment (as may any other copy ofenviron).
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
int main(int argc, const char *argv[], const char *envp[]) {
size_t i;
if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {
/* Handle error */
}
if (envp != NULL) {
for (i = 0; envp[i] != NULL; i++) {
if (puts(envp[i]) == EOF) {
/* Handle error */
}
}
}
return 0;
}
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
extern char **environ;
/* ... */
int main(int argc, const char *argv[]) {
size_t i;
if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {
/* Handle error */
}
if (environ != NULL) {
for (i = 0; environ[i] != NULL; i++) {
if (puts(environ[i]) == EOF) {
/* Handle error */
}
}
}
return 0;
}
|
...
According to the Visual C++ reference [MSDN],
The environment block passed to
mainandwmainis a "frozen" copy of the current environment. If you subsequently change the environment via a call toputenvor_wputenv, the current environment (as returned bygetenv/_wgetenvand the_environ/_wenvironvariable) will change, but the block pointed to byenvpwill not change.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
int main(int argc, const char *argv[], const char *envp[]) {
size_t i;
if (_putenv_s("MY_NEW_VAR", "new_value") != 0) {
/* Handle error */
}
if (envp != NULL) {
for (i = 0; envp[i] != NULL; i++) {
if (puts(envp[i]) == EOF) {
/* Handle error */
}
}
}
return 0;
}
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
_CRTIMP extern char **_environ;
/* ... */
int main(int argc, const char *argv[]) {
size_t i;
if (_putenv_s("MY_NEW_VAR", "new_value") != 0) {
/* Handle error */
}
if (_environ != NULL) {
for (i = 0; _environ[i] != NULL; i++) {
if (puts(_environ[i]) == EOF) {
/* Handle error */
}
}
}
return 0;
}
|
...
If you have a great deal of unsafe envp code, you can save time in your remediation by replacing
| Code Block |
|---|
int main(int argc, char *argv[], char *envp[]) {
/* ... */
}
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#if defined (_POSIX_) || defined (__USE_POSIX)
extern char **environ;
#define envp environ
#else
_CRTIMP extern char **_environ;
#define envp _environ
#endif
int main(int argc, char *argv[]) {
/* ... */
}
|
...
Tool | Version | Checker | Description | |
|---|---|---|---|---|
| Section | Compass/ROSE |
|
|
|
Related Vulnerabilities
...
CERT C++ Secure Coding Standard: ENV31-CPP. Do not rely on an environment pointer following an operation that may invalidate it
ISO/IEC 9899:1999 Section 2011 Section J.5.1, "Environment Argumentsarguments"
Bibliography
[MSDN] getenv, _wgetenv, _environ, _wenviron, _putenv_s, _wputenv_s
[Open Group 2004] setenv()
...