Executing Commands Without Shell Escapes (Perl Cookbook, 2nd Edition)

## 19.5. Executing Commands Without Shell Escapes

### 19.5.1. Problem

You need to use a user's input as part of a command, but you don't want to allow the user to trick the shell into running other commands or looking at other files. If you just blindly call the `system` function or backticks on a single string containing a command line derived from untested user input, the shell might be used to run the command. This would be unsafe.

### 19.5.2. Solution

Unlike its single-argument version, the list form of the `system` function is safe from shell escapes. When the command's arguments involve user input from a form, never use this:

>     system("command $input @files");            # UNSAFE

Write it this way instead:

>     system("command", $input, @files);          # safer

### 19.5.3. Discussion

Because Perl was designed as a glue language, it's easy to use it to call other programs—too easy, in some cases.

If you're merely trying to run a shell command but don't need to capture its output, it's easy enough to call `system` using its multiple argument form. But what happens if you're using the command in backticks or as part of a piped open? Now you have a real problem, because those don't permit the multiple argument form that `system` does. The solution (prior to v5.8; see later in this Discussion) is to manually `fork` and `exec` the child processes on your own. It's more work, but at least stray shell escapes won't be ruining your day.

It's safe to use backticks in a CGI script only if the arguments you give the program are internally generated, as in:

>     chomp($now = `date`);

But if the command within the backticks contains user-supplied input, perhaps like this:

>     @output = `grep $input @files`;

you have to be much more careful.

>     die "cannot fork: $!" unless defined ($pid = open(SAFE_KID, "-|"));
>     if ($pid =  = 0) {
>         exec('grep', $input, @files) or die "can't exec grep: $!";
>     } else {
>         @output = <SAFE_KID>;
>         close SAFE_KID;                 # $? contains status
>     }

This works because `exec`, like `system`, permits a calling convention that's immune to shell escapes. When passed a list, no shell is called, and so no escapes can occur.

Similar circumlocutions are needed when using `open` to start up a command. Here's a safe backtick or piped open for read. Instead of using this unsafe code:

>     open(KID_TO_READ, "$program @options @args |");    # UNSAFE

use this more complicated but safer code:

>     # add error processing as above
>     die "cannot fork: $!" unless defined($pid = open(KID_TO_READ, "-|"));

>     if ($pid) {   # parent
>        while (<KID_TO_READ>) {
>            # do something interesting
>        }
>        close(KID_TO_READ)               or warn "kid exited $?";

>     } else {      # child
>        # reconfigure, then
>        exec($program, @options, @args)  or die "can't exec program: $!";
>     }

Here's a safe piped open for writing. Instead of using this unsafe code:

>     open(KID_TO_WRITE, "|$program $options @args");   # UNSAFE

use this more complicated but safer code:

>     die "cannot fork: $!" unless defined($pid = open(KID_TO_WRITE, "-|"));
>     $SIG{PIPE} = sub { die "whoops, $program pipe broke" };

>     if ($pid) {  # parent
>        for (@data) { print KID_TO_WRITE $_ }
>        close(KID_TO_WRITE)              or warn "kid exited $?";

>     } else {     # child
>        # reconfigure, then
>        exec($program, @options, @args)  or die "can't exec program: $!";
>     }

Put any extra security measures you'd like where the comment in the code says `reconfigure`. You can change environment variables, reset temporary user or group ID values, change directories or umasks, etc. You're in the child process now, where changes won't propagate back to the parent.

If you don't have any reconfiguration to do in the child process, and you're running at least the v5.8 release of Perl, `open` supports a list of separate parameters that works as `system` and `exec` do when passed a list; that is, it avoids the shell altogether. Those two calls would be:

>     open(KID_TO_READ, "-|", $program, @options, @args)
>         || die "can't run $program: $!";

and:

>     open(KID_TO_WRITE, "|-", $program, $options, @args)
>           || die "can't run $program: $!";

This doesn't help you, of course, if you run a setuid program that can be exploited with the data you give it. The mail program sendmail is a setuid program commonly run from CGI scripts. Know the risks before you call sendmail or any other setuid program.

### 19.5.4. See Also

The `system`, `exec`, and `open` functions in Chapter 29 of Programming Perl and in perlfunc(1); the section on "Talking to Yourself" in Chapter 16 of Programming Perl; the section on "Accessing Commands and Files Under Reduced Privilege" in Chapter 23 of Programming Perl; perlsec(1); Recipe 16.1; Recipe 16.2; Recipe 16.3

Copyright © 2003 O'Reilly & Associates. All rights reserved.