Quote:>A while back I read somewhere that when you write a C program to
>function as a set-uid wrapper around a command, you should use
>execl() rather than system(). Apparently there is some security
>risk inherent in the use of system().
>Could someone elaborate on just what this is? My reason isn't
>to try and exploit any such hole, but to be able to explain
>to my colleage why I'm using execl() rather than system() when
>system() is actually easier to implement (because it allows
>me to do more than one thing in the program without having
>to fork(), etc.. i.e. with system() I could just have a
>series of system() calls to do the things I want to do.
I saw a reply to this that didn't answer anything at all, so I'll do that
here.
The first and biggest problem with system() is that it executes a shell
for you. It uses the SHELL environment variable to do that. It's
therefore possible for the user to change their variable and point it
to a shell script that starts with "#!" and their script would be running
with setid authority (they would ignore any/all parameters passed to them,
of course).
The second problem is for programs that run multiple jobs at once. The
system() call uses wait() to wait for the fork()ed process to complete.
If there is already another child running, the wait() will return and the
system() call will either (a) return the exit status of the wrong child,
or (b) loop until the correct child terminates, meaning that you cannot
retrieve the exit status of the prior child(ren). (The choice of methods,
(a) or (b), is made by the author of the library call and is not
necessarily consistent across library implementations.)
Quote:>Thanks in advance.
>Bill
The general rule is to not use system() at all. There are too many
variables which can cause the code to execute incorrectly at best, and
unsecurely at worst.
Even simple, non-intrusive, "obvious" code can fail in mysterious ways.
For instance, the following won't work if the SHELL variable contains
/bin/csh (or some other shell which doesn't understand Bourne syntax).
system("if [ -r filename ]; then echo Yes; else echo No; fi");
However, there are numerous cases where it is extremely convenient for the
shell to do wildcards and I/O redirection for you. In this case, a more
appropriate call would be:
pid_t pid;
int stat;
switch (pid = fork()) {
case -1 : /* error */
break;
case 0 : /* child */
execl("/bin/sh", "sh", "-c", "PATH=/usr/bin:/sbin ...");
perror("execl");
exit(1);
default : /* parent */
if (waitpid(pid, &stat, 0) != pid)
/* error */
}
Obviously, there's more to flesh out in this example. See the W. Richard
Stevens book, _Advanced Programming in the Unix Environment_ for more
details.
--
Frank "Crash" Edwards Edwards & Edwards Consulting
Voice: 813/786-3675 Unix/AIX-Sun-HP: Training, Programming, and SysAdmin
Outside FL: 500/HI-CRASH (this is NOT toll-free, but is auto-forwarded to me)
"The beast of Tenagra. Rozauni; his army. Chaka; when the walls fell."