You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by jm...@apache.org on 2004/10/03 23:30:33 UTC
svn commit: rev 51851 - spamassassin/branches/3.0/lib/Mail/SpamAssassin
Author: jm
Date: Sun Oct 3 14:30:32 2004
New Revision: 51851
Modified:
spamassassin/branches/3.0/lib/Mail/SpamAssassin/Util.pm
Log:
bug 3649: helper_app_pipe_open doesn't do the right thing if STD{IN,OUT,ERR} filehandles != {0,1,2} fds
Modified: spamassassin/branches/3.0/lib/Mail/SpamAssassin/Util.pm
==============================================================================
--- spamassassin/branches/3.0/lib/Mail/SpamAssassin/Util.pm (original)
+++ spamassassin/branches/3.0/lib/Mail/SpamAssassin/Util.pm Sun Oct 3 14:30:32 2004
@@ -41,6 +41,7 @@
use Time::Local;
use Sys::Hostname (); # don't import hostname() into this namespace!
use Fcntl;
+use POSIX (); # don't import anything unless we ask explicitly!
###########################################################################
@@ -1016,14 +1017,58 @@
setuid_to_euid();
dbg ("setuid: helper proc $$: ruid=$< euid=$>");
- if ($stdinfile) { # < $tmpfile
- close STDIN;
- open (STDIN, "<$stdinfile") or die "cannot open $stdinfile: $!";
- }
+ # 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;
+
+ # sanity: was that the *real* STDIN? if not, close that one too ;)
+ if ($f != 0) {
+ POSIX::close(0);
+ }
+ open STDIN, "<$stdinfile" or die "cannot open $stdinfile: $!";
+
+ # 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 "setuid: oops: fileno(STDIN) [".fileno(STDIN)."] != 0";
+ }
+
+ # 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);
+ }
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 "setuid: oops: fileno(STDERR) [".fileno(STDERR)."] != 2";
+ }
}
exec @cmdline;