From the main function:
#include <stdio.h>
void main(int argc, char* argv[], char* envp[]) {
int i = 0;
while (envp[i] != NULL) {
printf("%s\n", envp[i++]);
}
}
Using the global variable:
#include <stdio.h>
extern char** environ;
void main(int argc, char* argv[], char* envp[]) {
int i = 0;
while (environ[i] != NULL) {
printf("%s\n", environ[i++]);
}
}
environ
is more reliable.Programs can also use:
getenv(var_name)
: find value of environment variableputenv()
: add value to environment variablesetenv()
: modify value of an environment variableunset()
: delete environment variablefork()
: child process inherits parent's environment variablesexecve()
: memory space is overwritten, old environment variables are lost; can be invoked to pass environment variables.execve()
and Environment Variables/usr/bin/env
to print environment variables.newenv
is constructed and used as the 3rd argument.execve()
Example$ a.out 1 // Passing NULL
$ a.out 2 // Passing newenv()
AAA=aaa
BBB=bbb
$ a.out 3 // Passing environ
SSH_AGENT_PID=...
GPG_AGENT_INFO=...
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=...
WINDOWID=...
OLDPWD=...
main()
is invoked, three blocks of data are pushed onto the stack:main()
function.envp
and environ
point to the same place initially.envp
is accessible inside main()
, while environ
is global.environ
will change (but envp
does not).unset
will not appear as environment variables in the child process.env
in shell prompt creates a child process.LOGNAME
and LOGNAME3
get into the child process, but not LOGNAME2
. This is because only exported variables and those inherited from the environment are passed to child processes./proc
File Systemenviron
, containing the environment of the process./proc/932/environ
contains the environment variables of process 932.strings /proc//environ
prints the environment variables of the current process (shell replaces
with its PID).env
program is invoked in a bash shell, it runs in a child process. Therefore, it prints the environment variables of the shell's child process, not its own.printf()
) in shared libraries.main()
ldd
command to see shared libraries a program depends on.libc
library (e.g., printf()
, sleep()
).main()
.LD_PRELOAD
: List of shared libraries searched first by the linker.LD_LIBRARY_PATH
: If not all functions are found in LD_PRELOAD
, the linker searches folders specified by LD_LIBRARY_PATH
.sleep()
function, which is dynamically linked.sleep()
function.LD_PRELOAD
environment variable.LD_PRELOAD
and LD_LIBRARY_PATH
when EUID and RUID differ.env
program and make it Set-UID.LD_LIBRARY_PATH
and LD_PRELOAD
and run both programs.env
program will execute normally.env
program will not use the preloaded library due to the countermeasure.exec()
family of functions (calls execve()
): runs the program directly.system()
: calls execl()
, which eventually calls execve()
to run /bin/sh
; the shell program then runs the program.PATH
variable.PATH
variable to locate the command.PATH
variable.execve()
's attack surface is smaller compared to system()
.execve()
does not invoke shell and is not affected by environment variables.execve()
.gettext()
and catopen()
in the libc
library.LANG
, LANGUAGE
, NLSPATH
, LOCPATH
, LC_ALL
, LC_MESSAGES
printf()
function.NSLPATH
).getenv()
to get its current directory from the PWD
environment variable.PWD
comes from the shell program.getenv()
, such as secure_getenv()
.getenv()
searches the environment variable list and returns a pointer to the string found.secure_getenv()
returns NULL
when “secure execution” is required.