19.6. Executing Commands Without Shell EscapesProblemYou 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 SolutionUnlike its single-argument version, the list form of the system("command $input @files"); # UNSAFEWrite it this way instead: system("command", $input, @files); # saferDiscussionBecause 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 AlsoThe |