Safe execution of system() or exec() using environment variables
I have two strings, both of which can be set by the user, eg
char *command = "vim $VAR";
char *myVar = "/tmp/something";
I want to use *myVar
to perform *command
for $VAR
.
I tried concatenating them as environment variables (e.g. (pseudocode) system("VAR="+*myVar+"; "+ *command),
but the user controls myVar
so it would be very insecure and wrong.
I considered marking spaces to replace $var
directly and passing the result to exec(),
but was worried that it would be too awkward to mark shell command arguments correctly.
I
think the solution is by doing something like exec(“sh”, “-c”, command, “–argument”, “VAR", myVar),
but I don’t see anything in the sh/dash/bash man page that allows environment variables to be set this way.
EDIT: I just saw execvpe(), which has a parameter to set the environment variable from the key=value string. Is it safe to enter with untrusted values?
How do I do this safely?
Solution
You can perform some string substitution on the value of myVar
—put it inside single quotes, and replace all single quote (character ‘) strings ‘\
‘'
with four characters. If you don’t make implementation mistakes, it’s cumbersome but safe. If possible, use a library that does it for you
If your program is single-threaded, I recommend a different solution that doesn’t involve tedious references. You talked about setting environment variables… Well, let’s do it: set VAR
as an environment variable.
setenv("VAR", myVar, 1);
system(command);
unsetenv("VAR")
I
omitted the error checking, and I’m assuming VAR
isn’t needed elsewhere in the program (this solution becomes more tedious if needed because you need to remember the old values).
If you want fine-grained control over the environment in which commands run, you can do so in fork
, execve (or execvpe
) and waitpid
, or in posix_spawn
(or
posix_spawnp
) and > above waitpid
. This requires more effort, but you can get Spirit Active.
Note that with the exception of string substitution for "vim $VAR
” in the C program, the command needs to be vim “$VAR” and not vim $VAR
regardless of your solution. This is because in shell syntax, $VAR only means “the value of the variable VAR” when it is inside double quotes—
otherwise,
$VAR
means “take the value of VAR, split it into words,
and expand each word into a filename wildcard pattern"
.