You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2007/09/11 02:49:35 UTC
svn commit: r574417 - /spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm
Author: mmartinec
Date: Mon Sep 10 17:49:35 2007
New Revision: 574417
URL: http://svn.apache.org/viewvc?rev=574417&view=rev
Log:
Util::helper_app_pipe_open_unix : contain a failing exec with
an eval to prevent additional cases of process cloning. The exec
could fail this way when given tainted arguments. While at it,
also eval-protect an open($fh,'-|'), which need eval-trapping
when implied fork fails due to system resource quotas exceeded.
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm?rev=574417&r1=574416&r2=574417&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm Mon Sep 10 17:49:35 2007
@@ -1378,7 +1378,8 @@
# note use of eval { } scope in logging -- paranoia to ensure that a broken
# $SIG{__WARN__} implementation will not interfere with the flow of control
# here, where we *have* to die.
- eval { warn $msg; };
+ eval { warn $msg }; # hmm, STDERR may no longer be open
+ eval { dbg("util: force_die: $msg") };
POSIX::_exit(1); # avoid END and destructor processing
kill('KILL',$$); # still kicking? die!
@@ -1387,11 +1388,17 @@
sub helper_app_pipe_open_unix {
my ($fh, $stdinfile, $duperr2out, @cmdline) = @_;
+ my $pid;
# do a fork-open, so we can setuid() back
- my $pid = open ($fh, '-|');
+ eval {
+ $pid = open ($fh, '-|'); 1;
+ } or do {
+ my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
+ die "util: cannot fork: $eval_stat";
+ };
if (!defined $pid) {
# acceptable to die() here, calling code catches it
- die "util: cannot fork: $!";
+ die "util: cannot open a pipe to a forked process: $!";
}
if ($pid != 0) {
@@ -1399,75 +1406,77 @@
}
# else, child process.
- # from now on, we cannot die(), as a parent-process eval { } scope
- # could intercept it! use force_die() instead (bug 4370, cmt 2)
- # go setuid...
- setuid_to_euid();
- dbg("util: setuid: ruid=$< euid=$>");
-
- # now set up the fds. due to some wierdness, we may have to ensure that we
- # *really* close the correct fd number, since some other code may have
- # redirected the meaning of STDOUT/STDIN/STDERR it seems... (bug 3649). use
- # POSIX::close() for that. it's safe to call close() and POSIX::close() on
- # the same fd; the latter is a no-op in that case.
-
- if (!$stdinfile) { # < $tmpfile
- # ensure we have *some* kind of fd 0.
- $stdinfile = "/dev/null";
- }
+ # from now on, we cannot die(), it could create a cloned process
+ # use force_die() instead (bug 4370, cmt 2)
+ eval {
+ # go setuid...
+ setuid_to_euid();
+ dbg("util: setuid: ruid=$< euid=$>");
+
+ # now set up the fds. due to some wierdness, we may have to ensure that
+ # we *really* close the correct fd number, since some other code may have
+ # redirected the meaning of STDOUT/STDIN/STDERR it seems... (bug 3649).
+ # use POSIX::close() for that. it's safe to call close() and POSIX::close()
+ # on the same fd; the latter is a no-op in that case.
+
+ if (!$stdinfile) { # < $tmpfile
+ # ensure we have *some* kind of fd 0.
+ $stdinfile = "/dev/null";
+ }
- my $f = fileno(STDIN);
- close STDIN;
+ my $f = fileno(STDIN);
+ close STDIN;
- # sanity: was that the *real* STDIN? if not, close that one too ;)
- if ($f != 0) {
- POSIX::close(0);
- }
-
- open (STDIN, "<$stdinfile") or force_die "util: cannot open $stdinfile: $!";
+ # sanity: was that the *real* STDIN? if not, close that one too ;)
+ if ($f != 0) {
+ POSIX::close(0);
+ }
- # this should be impossible; if we just closed fd 0, UNIX
- # fd behaviour dictates that the next fd opened (the new STDIN)
- # will be the lowest unused fd number, which should be 0.
- # so die with a useful error if this somehow isn't the case.
- if (fileno(STDIN) != 0) {
- force_die "util: setuid: oops: fileno(STDIN) [".fileno(STDIN)."] != 0";
- }
+ open (STDIN, "<$stdinfile") or die "cannot open $stdinfile: $!";
- # ensure STDOUT is open. since we just created a pipe to ensure this, it has
- # to be open to that pipe, and if it isn't, something's seriously screwy.
- # Update: actually, this fails! see bug 3649 comment 37. For some reason,
- # fileno(STDOUT) can be 0; possibly because open("-|") didn't change the fh
- # named STDOUT, instead changing fileno(1) directly. So this is now
- # commented.
- # if (fileno(STDOUT) != 1) {
- # die "setuid: oops: fileno(STDOUT) [".fileno(STDOUT)."] != 1";
- # }
-
- if ($duperr2out) { # 2>&1
- my $f = fileno(STDERR);
- close STDERR;
-
- # sanity: was that the *real* STDERR? if not, close that one too ;)
- if ($f != 2) {
- POSIX::close(2);
+ # this should be impossible; if we just closed fd 0, UNIX
+ # fd behaviour dictates that the next fd opened (the new STDIN)
+ # will be the lowest unused fd number, which should be 0.
+ # so die with a useful error if this somehow isn't the case.
+ if (fileno(STDIN) != 0) {
+ die "oops: fileno(STDIN) [".fileno(STDIN)."] != 0";
}
- open (STDERR, ">&STDOUT") or force_die "util: dup STDOUT failed: $!";
-
- # STDERR must be fd 2 to be useful to subprocesses! (bug 3649)
- if (fileno(STDERR) != 2) {
- force_die "util: oops: fileno(STDERR) [".fileno(STDERR)."] != 2";
+ # Ensure STDOUT is open. As we just created a pipe to ensure this, it has
+ # to be open to that pipe, and if it isn't, something's seriously screwy.
+ # Update: actually, this fails! see bug 3649 comment 37. For some reason,
+ # fileno(STDOUT) can be 0; possibly because open("-|") didn't change the fh
+ # named STDOUT, instead changing fileno(1) directly. So this is now
+ # commented.
+ # if (fileno(STDOUT) != 1) {
+ # die "setuid: oops: fileno(STDOUT) [".fileno(STDOUT)."] != 1";
+ # }
+
+ if ($duperr2out) { # 2>&1
+ my $f = fileno(STDERR);
+ close STDERR;
+
+ # sanity: was that the *real* STDERR? if not, close that one too ;)
+ if ($f != 2) {
+ POSIX::close(2);
+ }
+
+ open (STDERR, ">&STDOUT") or die "dup STDOUT failed: $!";
+
+ # STDERR must be fd 2 to be useful to subprocesses! (bug 3649)
+ if (fileno(STDERR) != 2) {
+ die "oops: fileno(STDERR) [".fileno(STDERR)."] != 2";
+ }
}
- }
- exec @cmdline;
- warn "util: exec failed: $!";
+ exec @cmdline;
+ die "exec failed: $!";
+ };
+ my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
# bug 4370: we really have to exit here; break any eval traps
- POSIX::_exit(1); # avoid END and destructor processing
- kill('KILL',$$); # still kicking? die!
+ force_die("util: failed to spawn a process: $eval_stat");
die; # must be a die() otherwise -w will complain
}