19.6. Executing Commands Without Shell EscapesProblem
You need to use a user's input as part of a command, but you don't want to allow the user to make the shell run other commands or look at other files. If you just blindly call the Solution
Unlike its single-argument version, the list form of the system("command $input @files"); # UNSAFE Write it this way instead: system("command", $input, @files); # safer DiscussionBecause 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 It's safe to use backticks in a CGI script only if the arguments you give the program are purely 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
Similar circumlocutions are needed when using 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: $pid = open(KID_TO_WRITE, "|-"); die "cannot fork: $!" unless defined($pid = open(KID_TO_WRITE, "|-")); $SIG{ALRM} = 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: $!"; }
At the point where the comment in the code says
All this doesn't help you, of course, if your See Also
The |
|