From cad4b15dabaffc7b404bd1bd533dc19267b29b11 Mon Sep 17 00:00:00 2001 From: Ole Tange Date: Thu, 14 May 2015 17:17:02 +0200 Subject: [PATCH] parallel: Fixed security issue with -S + --fifo/--cat. --- src/parallel | 55 +++++++++++-------- testsuite/tests-to-run/parallel-local-ssh2.sh | 4 +- testsuite/tests-to-run/parallel-local22.sh | 4 +- testsuite/wanted-results/parallel-local-ssh2 | 38 ++++++------- testsuite/wanted-results/parallel-local22 | 38 ++++++------- testsuite/wanted-results/parallel-tutorial | 3 +- 6 files changed, 77 insertions(+), 65 deletions(-) diff --git a/src/parallel b/src/parallel index 771890fb..741ec1dd 100755 --- a/src/parallel +++ b/src/parallel @@ -6263,24 +6263,29 @@ sub wrapped { } } if($opt::cat) { - # Prepend 'cat > {};' - # Append 'unlink {} without affecting $?' +# Append 'unlink {} without affecting $?' $command = $self->{'commandline'}->replace_placeholders(["cat > \257<\257>; "], 0, 0). $command.";". postpone_exit_and_cleanup(). - $self->{'commandline'}->replace_placeholders(["\257<\257>"], 0, 0); + '$PARALLEL_TMP'; } elsif($opt::fifo) { # Prepend 'mkfifo {}; (' # Append ') & _PID=$!; cat > {}; wait $_PID; ' # (This makes it fail in csh, but give the correct exit code in bash) # Append 'unlink {} without affecting $?' + # Set $ENV{PARALLEL_TMP} when starting a job + # Set $ENV{PARALLEL_TMP} in the remote wrapper + # mkfifo $PARALLEL_TMP; + # {} = $PARALLEL_TMP; + # (...) & + # cat > $PARALLEL_TMP; wait \$_PID; cleanup $PARALLEL_TMP + # perl -e 'open($fifo,">",shift); while(read){print FIFO};unlink $fifo;waitpid($pid,0);exit $?' $! $PARALLEL_FIFO $command = - $self->{'commandline'}->replace_placeholders(["mkfifo \257<\257>;\n ("], 0, 0). + "mkfifo \$PARALLEL_TMP\n (". $command.";". - $self->{'commandline'}->replace_placeholders([") & _PID=\$!; cat > \257<\257>; ", - "wait \$_PID; "]). + ') & _PID=$!; cat > $PARALLEL_TMP; wait $_PID; '. postpone_exit_and_cleanup(). - $self->{'commandline'}->replace_placeholders(["\257<\257>"], 0, 0); + '$PARALLEL_TMP'; } # Wrap with ssh + tranferring of files $command = $self->sshlogin_wrap($command); @@ -6401,7 +6406,13 @@ sub sshlogin_wrap { $monitor_parent_sshd_script = # This will be packed in ', so only use " ::spacefree(0,'$shell = "'.($ENV{'PARALLEL_SHELL'} || '$ENV{SHELL}').'";'. - q{ + '$tmpdir = "'.::perl_quote_scalar($ENV{'TMPDIR'}).'";'. + q{ + # Set $PARALLEL_TMP to a non-existent file name in $TMPDIR + do { + $ENV{PARALLEL_TMP} = $tmpdir."/par". + join"", map { (0..9,"a".."z","A".."Z")[rand(62)] } (1..5); + } while(-e $ENV{PARALLEL_TMP}); $SIG{CHLD} = sub { $done = 1; }; $pid = fork; unless($pid) { @@ -6828,6 +6839,7 @@ sub start { } $ENV{'PARALLEL_SEQ'} = $job->seq(); $ENV{'PARALLEL_PID'} = $$; + $ENV{'PARALLEL_TMP'} = ::tmpname("par"); ::debug("run", $Global::total_running, " processes . Starting (", $job->seq(), "): $command\n"); if($opt::pipe) { @@ -6936,12 +6948,8 @@ sub print_dryrun_and_verbose { my $self = shift; my $actual_command = shift; # Temporary file name. Used for fifo to communicate exit val - my ($fh, $tmpfifo) = ::tmpfile(SUFFIX => ".tmx"); - $Global::unlink{$tmpfifo} = 1; - close $fh; - unlink $tmpfifo; -# # FIFO for communicating exit val -# my $tmpfifo = ::tmpfifo(); + my $tmpfifo=::tmpname("tmx"); + if(length($tmpfifo) >=100) { ::error("tmux does not support sockets with path > 100\n"); ::wait_and_exit(255); @@ -6959,12 +6967,13 @@ sub print_dryrun_and_verbose { my $l_act = length($actual_command); my $l_tit = length($title); + my $l_fifo = length($tmpfifo); # The line to run contains a 118 chars extra code + the title 2x - my $l_tot = 2 * $l_tit + $l_act + 30; + my $l_tot = 2 * $l_tit + $l_act + $l_fifo; while($l_tit < 1000 and ( - (900 < $l_tot and $l_tot < 1300) + (890 < $l_tot and $l_tot < 1350) or (9250 < $l_tot and $l_tot < 9800) )) { @@ -6977,7 +6986,7 @@ sub print_dryrun_and_verbose { # 9331 < (title + whole command) < 9636 $title = $title.('\ 'x75); $l_tit = length($title); - $l_tot = 2 * $l_tit + $l_act + 30; + $l_tot = 2 * $l_tit + $l_act + $l_fifo; } my $tmux; @@ -6994,7 +7003,7 @@ sub print_dryrun_and_verbose { $Limits::Command::line_max_len, " tot ", $l_tot, "\n"); - return "mkfifo $tmpfifo; $tmux ". + return "mkfifo $tmpfifo && $tmux ". # Run in tmux ::shell_quote_scalar ( @@ -7567,14 +7576,14 @@ sub populate { my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length(); if($opt::cat) { - # Generate a tempfile name that will be used as {} + # $PARALLEL_TMP will point to a tempfile that will be used as {} $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}-> - unget([Arg->new(::tmpname("cat"))]); + unget([Arg->new('$PARALLEL_TMP')]); } if($opt::fifo) { - # Generate a tempfile name that will be used as {} + # $PARALLEL_TMP will point to a tempfile that will be used as {} $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}-> - unget([Arg->new(::tmpname("fif"))]); + unget([Arg->new('$PARALLEL_TMP')]); } while (not $self->{'arg_queue'}->empty()) { $next_arg = $self->{'arg_queue'}->get(); @@ -7868,6 +7877,8 @@ sub replaced { if(not defined $self->{'replaced'}) { # Don't quote arguments if the input is the full command line my $quote_arg = $Global::noquote ? 0 : not $Global::quoting; + # or if ($opt::cat or $opt::pipe) as they use $PARALLEL_TMP + $quote_arg = ($opt::cat || $opt::fifo) ? 0 : $quote_arg; $self->{'replaced'} = $self-> replace_placeholders($self->{'command'},$Global::quoting, $quote_arg); diff --git a/testsuite/tests-to-run/parallel-local-ssh2.sh b/testsuite/tests-to-run/parallel-local-ssh2.sh index ec173d53..dba5d98c 100644 --- a/testsuite/tests-to-run/parallel-local-ssh2.sh +++ b/testsuite/tests-to-run/parallel-local-ssh2.sh @@ -45,8 +45,8 @@ echo '2bug #43358: shellshock breaks exporting functions using --env' echo '### bug #42999: --pipepart with remote does not work' seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; - parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+fif)\S+:${1}XXXXX:' ; - parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+cat)\S+:${1}XXXXX:' ; + parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; + parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; rm /tmp/bug42999 echo '### --cat gives incorrect exit value in csh' diff --git a/testsuite/tests-to-run/parallel-local22.sh b/testsuite/tests-to-run/parallel-local22.sh index 5dc67ddd..9333b355 100755 --- a/testsuite/tests-to-run/parallel-local22.sh +++ b/testsuite/tests-to-run/parallel-local22.sh @@ -46,8 +46,8 @@ echo '### bug #42041: Implement $PARALLEL_JOBSLOT' echo '### bug #42363: --pipepart and --fifo/--cat does not work' seq 100 > /tmp/bug42363; - parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+fif).....:${1}XXXXX:'; - parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+cat).....:${1}XXXXX:'; + parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; + parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; rm /tmp/bug42363 echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile' diff --git a/testsuite/wanted-results/parallel-local-ssh2 b/testsuite/wanted-results/parallel-local-ssh2 index a739c98e..0ce9bd78 100644 --- a/testsuite/wanted-results/parallel-local-ssh2 +++ b/testsuite/wanted-results/parallel-local-ssh2 @@ -44,7 +44,7 @@ shellshock-hardened to non-shellshock-hardened Function non-shellshock-hardened echo '### bug #42999: --pipepart with remote does not work' ### bug #42999: --pipepart with remote does not work - seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+fif)\S+:${1}XXXXX:' ; parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+cat)\S+:${1}XXXXX:' ; rm /tmp/bug42999 + seq 100 > /tmp/bug42999; chmod 600 /tmp/bug42999; parallel --sshdelay 0.3 --pipepart --block 31 -a /tmp/bug42999 -k -S parallel@lo wc; parallel --sshdelay 0.2 --pipepart --block 31 -a /tmp/bug42999 -k --fifo -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; parallel --sshdelay 0.1 --pipepart --block 31 -a /tmp/bug42999 -k --cat -S parallel@lo wc | perl -pe 's:(/tmp\S+par)\S+:${1}XXXXX:' ; rm /tmp/bug42999 14 14 33 11 11 33 11 11 33 @@ -54,24 +54,24 @@ echo '### bug #42999: --pipepart with remote does not work' 11 11 33 11 11 33 9 9 28 - 14 14 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 11 11 33 /tmp/parallel-local-ssh2/fifXXXXX - 9 9 28 /tmp/parallel-local-ssh2/fifXXXXX -14 14 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX -11 11 33 /tmp/parallel-local-ssh2/catXXXXX - 9 9 28 /tmp/parallel-local-ssh2/catXXXXX + 14 14 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 9 9 28 /tmp/parallel-local-ssh2/parXXXXX +14 14 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX +11 11 33 /tmp/parallel-local-ssh2/parXXXXX + 9 9 28 /tmp/parallel-local-ssh2/parXXXXX echo '### --cat gives incorrect exit value in csh' ### --cat gives incorrect exit value in csh echo false | parallel --pipe --cat -Scsh@lo 'cat {}; false' ; echo $?; echo false | parallel --pipe --cat -Stcsh@lo 'cat {}; false' ; echo $?; echo true | parallel --pipe --cat -Scsh@lo 'cat {}; true' ; echo $?; echo true | parallel --pipe --cat -Stcsh@lo 'cat {}; true' ; echo $?; echo '### --cat and --fifo exit value in bash' diff --git a/testsuite/wanted-results/parallel-local22 b/testsuite/wanted-results/parallel-local22 index d6a5d841..f6294cbf 100644 --- a/testsuite/wanted-results/parallel-local22 +++ b/testsuite/wanted-results/parallel-local22 @@ -43,25 +43,25 @@ echo '### bug #42041: Implement $PARALLEL_JOBSLOT' 2 echo '### bug #42363: --pipepart and --fifo/--cat does not work' ### bug #42363: --pipepart and --fifo/--cat does not work - seq 100 > /tmp/bug42363; parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+fif).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+cat).....:${1}XXXXX:'; rm /tmp/bug42363 - 14 14 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 11 11 33 /tmp/parallel-local22/fifXXXXX - 9 9 28 /tmp/parallel-local22/fifXXXXX -14 14 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX -11 11 33 /tmp/parallel-local22/catXXXXX - 9 9 28 /tmp/parallel-local22/catXXXXX + seq 100 > /tmp/bug42363; parallel --pipepart --block 31 -a /tmp/bug42363 -k --fifo wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; parallel --pipepart --block 31 -a /tmp/bug42363 -k --cat wc | perl -pe 's:(/tmp\S+par).....:${1}XXXXX:'; rm /tmp/bug42363 + 14 14 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 11 11 33 /tmp/parallel-local22/parXXXXX + 9 9 28 /tmp/parallel-local22/parXXXXX +14 14 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX +11 11 33 /tmp/parallel-local22/parXXXXX + 9 9 28 /tmp/parallel-local22/parXXXXX echo '### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile' ### bug #42055: --pipepart -a bigfile should not require sequential reading of bigfile parallel --pipepart -a /etc/passwd -L 1 should not be run diff --git a/testsuite/wanted-results/parallel-tutorial b/testsuite/wanted-results/parallel-tutorial index d6c1c5b3..c77c923c 100644 --- a/testsuite/wanted-results/parallel-tutorial +++ b/testsuite/wanted-results/parallel-tutorial @@ -637,6 +637,7 @@ ORACLE_SID PARALLEL PARALLEL_PID PARALLEL_SEQ +PARALLEL_TMP PATH PERL_MB_OPT PERL_MM_OPT @@ -691,7 +692,7 @@ _ /bin/bash: my_func2: command not found parallel -vv -S $SERVER1 echo ::: bar -ssh parallel@lo exec perl\ -e\ \\\$ENV\\\{\\\"PARALLEL_PID\\\"\\\}=\\\"000000\\\"\\\;\\\$ENV\\\{\\\"PARALLEL_SEQ\\\"\\\}=\\\"1\\\"\\\;\\\$bashfunc\\\ =\\\ \\\"\\\"\\\;@ARGV=\\\"echo\\\ bar\\\"\\\;\\\$shell=\\\"\\\$ENV\\\{SHELL\\\}\\\"\\\;\\\$SIG\\\{CHLD\\\}=sub\\\{\\\$done=1\\\;\\\}\\\;\\\$pid=fork\\\;unless\\\(\\\$pid\\\)\\\{setpgrp\\\;exec\\\$shell,\\\"-c\\\",\\\(\\\$bashfunc.\\\"@ARGV\\\"\\\)\\\;die\\\"exec:\\\$\\\!\\\\n\\\"\\\;\\\}do\\\{\\\$s=\\\$s\\\<1\\\?0.001+\\\$s\\\*1.03:\\\$s\\\;select\\\(undef,undef,undef,\\\$s\\\)\\\;\\\}until\\\(\\\$done\\\|\\\|getppid==1\\\)\\\;kill\\\(SIGHUP,-\\\$\\\{pid\\\}\\\)unless\\\$done\\\;wait\\\;exit\\\(\\\$\\\?\\\&127\\\?128+\\\(\\\$\\\?\\\&127\\\):1+\\\$\\\?\\\>\\\>8\\\); +ssh parallel@lo exec perl\ -e\ \\\$ENV\\\{\\\"PARALLEL_PID\\\"\\\}=\\\"000000\\\"\\\;\\\$ENV\\\{\\\"PARALLEL_SEQ\\\"\\\}=\\\"1\\\"\\\;\\\$bashfunc\\\ =\\\ \\\"\\\"\\\;@ARGV=\\\"echo\\\ bar\\\"\\\;\\\$shell=\\\"\\\$ENV\\\{SHELL\\\}\\\"\\\;\\\$tmpdir=\\\"/tmp/parallel-tutorial\\\"\\\;do\\\{\\\$ENV\\\{PARALLEL_TMP\\\}=\\\$tmpdir.\\\"/par\\\".join\\\"\\\",map\\\{\\\(0..9,\\\"a\\\"..\\\"z\\\",\\\"A\\\"..\\\"Z\\\"\\\)\\\[rand\\\(62\\\)\\\]\\\}\\\(1..5\\\)\\\;\\\}while\\\(-e\\\$ENV\\\{PARALLEL_TMP\\\}\\\)\\\;\\\$SIG\\\{CHLD\\\}=sub\\\{\\\$done=1\\\;\\\}\\\;\\\$pid=fork\\\;unless\\\(\\\$pid\\\)\\\{setpgrp\\\;exec\\\$shell,\\\"-c\\\",\\\(\\\$bashfunc.\\\"@ARGV\\\"\\\)\\\;die\\\"exec:\\\$\\\!\\\\n\\\"\\\;\\\}do\\\{\\\$s=\\\$s\\\<1\\\?0.001+\\\$s\\\*1.03:\\\$s\\\;select\\\(undef,undef,undef,\\\$s\\\)\\\;\\\}until\\\(\\\$done\\\|\\\|getppid==1\\\)\\\;kill\\\(SIGHUP,-\\\$\\\{pid\\\}\\\)unless\\\$done\\\;wait\\\;exit\\\(\\\$\\\?\\\&127\\\?128+\\\(\\\$\\\?\\\&127\\\):1+\\\$\\\?\\\>\\\>8\\\); bar my_func3() { echo in my_func $1 > $1.out