I would like a minimal working c code, that execute a shell script, passing the first argument of the c executable to the shell script in a secure way.
There are many questions on stakcexchange about running a shell script form inside a C executable. Many of them suggest to use the system
call.
Actually I'm using this solution:
#include <unistd.h>
#include <errno.h>
main( int argc, char ** argv, char ** envp )
{
char *command;
int size = asprintf(&command, "/path/to/script.sh %s", argv[1]);
envp = 0; /* blocks IFS attack on non-bash shells */
system( command );
//perror( argv[0] );
return errno;
}
derived from How to enable suidperl in Debian wheezy?.
I know that this solution is subject to code-injection. A possible solution is described "in principle" in the @basile-starynkevitch answer to this question
How can I modify the above example .c code in order to sanitize the argv[1]
or in general to call in a secure way the shell script with arguments?
system()
At All#include <unistd.h>
#include <errno.h>
main(int argc, char **argv) {
int retval;
execl("/path/to/sctcipt.sh", "/path/to/sctcipt.sh", argv[1], NULL);
_exit(1); /* if we got here, the fork() failed */
}
Because all we're doing is wrapping another program, we can just pass direct control off to it with an execv
-family syscall; there's no need to even fork()
first.
Here, the code passed to system()
is a constant you've audited yourself; replacements are performed only after the shell is started, by the shell, after it's already finished with the syntax-parsing phase.
#include <unistd.h>
#include <errno.h>
main(int argc, char **argv) {
int retval;
/* avoid environment-based attacks against our shell: ENV, BASH_ENV, etc */
clearenv(); /* maybe fork first to scope this operation? */
/* Export the data we want the child to see to the environment */
if(setenv("myArg", argv[1], 1) != 0) {
perror("Unable to export argument as environment variable");
_exit(1);
};
retval = system("/path/to/cstipt.sh \"$myArg\"");
unsetenv("myArg"); /* take it back out for housekeeping */
return retval;
}