#!perl ... my $cmd = "btrfs subvolume snapshot -r '$subvolume' '$destination/$name'"; my $status = system $cmd;
The above command does route through the shell, and does have a few problems. Spoiler: avoid routing through the shell via something like:
my $status = system qw(btrfs subvolume snapshot -r), $subvolume, "$destination/$name";
This avoids word-splitting problems the POSIX shell is plagued with,
sh is (probably) not involved, and also avoids various
security issues like what if untrusted users supply whatever is in those
variables, or even if the variables somehow contain something that makes
the shell go derp, e.g. a variable with a password that has (for
"security" reasons) various fancy characters that the shell then turns
into something wrong wrong wrong. (I had to explain all this to some
folks at a Computer Science department, once. Sigh.) Also, it saves us a
fork, as Perl should directly run
btrfs not first
sh and that then
btrfs. But (almost) nobody cares about Wirth's Law.
Incoherent Internet Ramblings (IIR) should not be trusted; therefore,
with a simpler command (the fact that I do not have anything with
btrfs is also relevant)
#!/usr/bin/env perl my $variable = shift; system "printf '%s\n' '$variable'";
we can get down to testing variable inputs. (It's single quoted, what could possibly go wrong here, one might ask.)
% < file #!/usr/bin/env perl my $variable = shift; system "printf '%s\n' '$variable'"; % perl file "goodbye cruel world" goodbye cruel world
All well and good. Unless...
% perl file "';who am i;echo '" jmates ttys007 Aug 4 11:54 %
Whoops, shell injection. Let's try that with the
not-through-the-blasted-sh version of the
#!/usr/bin/env perl my $variable = shift; system printf => '%s\n', $variable;
which now results in:
% < file #!/usr/bin/env perl my $variable = shift; system printf => '%s\n', $variable; % perl file "';who am i;echo '" ';who am i;echo '
By the way I'm using ZSH here; other shells might have trouble with the
< file form and may need to use something like
cat file or
some other such barbarism. And yes, my shell prompt is only
One might wish to know where or if
sh is being routed through; process
tracing such as
ktrace (OpenBSD) or
strace (Linux) or so forth
depending on the flavor of unix is a good way to reveal this, especially
if you are really trying to prevent things from every going needlessly
through the shell.
File brand X
# ktrace -id perl file foo foo # kdump -f ktrace.out | grep /bin 16273 ktrace NAMI "/bin/perl" 16273 ktrace NAMI "/usr/bin/perl" "#!/usr/bin/env perl 27736 perl NAMI "/bin/printf" 27736 perl NAMI "/usr/bin/printf"
File brand Y
# ktrace -id perl file foo foo # kdump -f ktrace.out | grep /bin 12316 ktrace NAMI "/bin/perl" 12316 ktrace NAMI "/usr/bin/perl" "#!/usr/bin/env perl 82307 perl NAMI "/bin/sh" 82307 sh NAMI "/bin/printf" 82307 sh NAMI "/usr/bin/printf" 82307 sh NAMI "/usr/bin/printf" 29518 sh NAMI "/usr/bin/printf"
Which of these files do you think used the dangerous
'%s\n' '$variable'"; form?
This will be pretty similar for
strace or whatever. The major hurdle
is figuring out what command flags you need to perform the trace, and
then how to extract the information you want from the resulting output.
Anyways, eliminate the shell where you can. It is usually more efficient to do so, and helps avoid fun things like shell injection attacks.