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 optionalenvp
argument 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
main
andwmain
is a "frozen" copy of the current environment. If you subsequently change the environment via a call toputenv
or_wputenv
, the current environment (as returned bygetenv
/_wgetenv
and the_environ
/_wenviron
variable) will change, but the block pointed to byenvp
will 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()
...