Bug 5510 - [review] some tests fail to run as root due to file ownership in t/log
Summary: [review] some tests fail to run as root due to file ownership in t/log
Status: RESOLVED FIXED
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: Building & Packaging (show other bugs)
Version: SVN Trunk (Latest Devel Version)
Hardware: Other Linux
: P1 major
Target Milestone: 3.1.10
Assignee: SpamAssassin Developer Mailing List
URL:
Whiteboard: go
Keywords:
: 5525 5550 (view as bug list)
Depends on:
Blocks: 5518
  Show dependency tree
 
Reported: 2007-06-12 05:41 UTC by Daniel J McDonald
Modified: 2007-07-23 02:41 UTC (History)
2 users (show)



Attachment Type Modified Status Actions Submitter/CLA Status
fix patch None Justin Mason [HasCLA]
same patch against 3.1 branch patch None Sidney Markowitz [HasCLA]

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel J McDonald 2007-06-12 05:41:45 UTC
The spamd_optC, spamc_optL, spamd_allow_user_rules, and spamd_plugin tests all
attempt to drop privileges during the "test" phase, but with no user to fall
back on, are unable to create temporary files necessary to complete the tests:

e.g:
[27488] warn: spamd: still running as root: user not specified with -u, not
found, or set to root, falling back to nobody
[27488] warn: spamd: bayes: locker: safe_lock: cannot create tmp lockfile
./log/user_state/bayes.lock.ldap.austin-energy.net.27488 for
./log/user_state/bayes.lock: Permission denied
Comment 1 Justin Mason 2007-06-12 05:54:33 UTC
just to clarify -- this issue happens when the tests are run as root.  the test
script should be ensuring that its temp and output dirs are writable by
"nobody", since now part of the spamd tests will run as "nobody" instead of
"root". (in previous versions, there was a security hole whereby they didn't
drop privs when running as root.)
Comment 2 Justin Mason 2007-06-14 11:13:11 UTC
this breaks the "sudo cpan Mail::SpamAssassin" style of installation, so is
pretty important :(
Comment 3 Theo Van Dinter 2007-06-14 11:15:54 UTC
an easy option may be, btw, to skip certain tests if running as root.
Comment 4 Daniel J McDonald 2007-06-14 11:20:51 UTC
Another solution is to chmod the directories to world writable before dropping
privs.
Comment 5 Daryl C. W. O'Shea 2007-06-14 13:45:23 UTC
I think we need to fix this and cut a release soon.  If we aim for Wednesday it
leaves the weekend for anyone who feels like playing whack-a-bug.
Comment 6 Justin Mason 2007-06-14 14:22:18 UTC
I think I may have a fix nearly ready...
Comment 7 Justin Mason 2007-06-14 14:35:47 UTC
Created attachment 3989 [details]
fix

I think this may do it... give it a try.
Comment 8 Daniel J McDonald 2007-06-14 16:06:42 UTC
Works on Mandriva Corporate server 4:
t/spamc_optC................ok                                               
t/spamc_optL................ok                                               
t/spamc_y...................ok                                               
t/spamc_z...................ok                                               
t/spamd.....................ok                                               
t/spamd_allow_user_rules....ok           

It will take another 10 minutes or so to finish compiling, but this is where it
always broke before.

I'd give it +1, but I don't count.
Comment 9 Sidney Markowitz 2007-06-14 18:37:54 UTC
This doesn't work for me in MacOS 10.4.9, but the bug may be something in spamd
that I didn't notice before. This error happens when you try as root to run

  spamd --virtual-config-dir=somepath -u nobody

which is what t/spamd_allow_user_rules.t tries to do

[16061] info: spamd: server started on port 48825/tcp (running version
3.2.2-r547235)
[16061] info: spamd: server pid: 16061
[16061] info: spamd: server successfully spawned child process, pid 16065
[16061] dbg: prefork: child 16065: entering state 0
[16061] dbg: prefork: new lowest idle kid: none
[16061] info: spamd: server successfully spawned child process, pid 16066
[16061] dbg: prefork: child 16066: entering state 0
[16061] dbg: prefork: new lowest idle kid: none
[16065] error: setrgid() not implemented at ../spamd/spamd.raw line 1041.
setrgid() not implemented at ../spamd/spamd.raw line 1041.
[16066] error: setrgid() not implemented at ../spamd/spamd.raw line 1041.
setrgid() not implemented at ../spamd/spamd.raw line 1041.
[16061] dbg: prefork: child closed connection
Comment 10 Sidney Markowitz 2007-06-14 19:38:42 UTC
Doing some digging I fond this mentioned as a long-time problem with trying to
run spamd as nobody on MacOS X. Both the uid and gid of 'nobody' on the Mac are
-2 and that seems to confuse things as the spamd sees $ugid as having a value of
4294967294 and then $( = $ugid produces the misleading error message that
setrgid is not implemented.

  spamd --virtual-config-dir=somepath -u www

for example executes the $( = $ugid; with no error.
Comment 11 Sidney Markowitz 2007-06-14 19:49:59 UTC
getpwnam('nobody') returns the 4294967294 values instead of -2. If at that point
I  force the values of $uuid and $ugid to be -2 then everything seems to work
correctly.

I see some code that appears to recognize the possibility of something like this

      if ( $> != $uuid and $> != ( $uuid - 2**32 ) ) {
        die "spamd: setuid to uid $uuid failed\n";
      }

but I don't really know what is going on with the various tests and workarounds
for BSD-specific behavior so I don't know just how to fix this.
Comment 12 Sidney Markowitz 2007-06-14 21:13:24 UTC
More digging: The underlying variables in the C library are unsigned ints. So
getpwnam returns what is there which looks like 4294967294 even though Apple
puts a -2 in /etc/passwd. Assignments to $< and $> are fine with either
4294967294 or -2, doing the same thing in either case. It is only assignments to
$( and $) that flake out if the number is bigger than the maximum positive 32
bit signed int.

However, POSIX::setgid() works fine to set both the real and effective gid with
one call and it accepts 4294967294.

So I suggest that we replace

   $) = "$ugid $ugid";    # effective gid
   $( = $ugid;            # real gid

with
    setgid($ugid);

I'm not expert in this stuff... Does anyone see any problem with using
POSIX::setgid here on other platforms?
Comment 13 Justin Mason 2007-06-15 03:04:34 UTC
(In reply to comment #12)
> More digging: The underlying variables in the C library are unsigned ints. So
> getpwnam returns what is there which looks like 4294967294 even though Apple
> puts a -2 in /etc/passwd. Assignments to $< and $> are fine with either
> 4294967294 or -2, doing the same thing in either case. It is only assignments to
> $( and $) that flake out if the number is bigger than the maximum positive 32
> bit signed int.

this sounds like a perl bug on MacOS X (another one!! what are they doing over
there?)

> However, POSIX::setgid() works fine to set both the real and effective gid with
> one call and it accepts 4294967294.
> 
> So I suggest that we replace
> 
>    $) = "$ugid $ugid";    # effective gid
>    $( = $ugid;            # real gid
> 
> with
>     setgid($ugid);
> 
> I'm not expert in this stuff... Does anyone see any problem with using
> POSIX::setgid here on other platforms?

it may not be implemented, for one, which would cause a die().  We'd have
to protect it with an eval ' ... ' block.

you'd probably have to do sth like this:

  - run the $) / $( assignments in an eval '...' block
  - capture errors
  - if error =~ /setrgid\(\) not implemented/, then
    - run POSIX::setgid(...)
    - die if that failed too

however would it be simpler to just do (pseudocode)

  if (platform eq MacOS && ($uid = getpwnam($user)) == 4294967294) { $uid = -2; }

if that works, that would be better than attempting to use another syscall
entirely, IMO.

Also I suggest that should be opened as a totally separate bug; it's not caused
by this one, it's just being _exposed_ by the fix.
Comment 14 Justin Mason 2007-06-15 05:22:18 UTC
btw, I've added "t/root_spamd_virtual.t" as a test case for this.  Sidney, could
you verify that fails for you?
Comment 15 Justin Mason 2007-06-15 05:22:56 UTC
doh.  that was for bug 5518!
Comment 16 Justin Mason 2007-06-15 05:27:41 UTC
anyway, I've applied patch 3989 to SVN trunk:

: jm 247...; svn commit -m "bug 5510: fix test suite to support running as root,
now that spamd will automatically fall back to 'nobody' privs"
Sending        t/SATest.pm
Sending        t/spamd_allow_user_rules.t
Sending        t/spamd_plugin.t
Transmitting file data ...
Committed revision 547650.
Comment 17 Justin Mason 2007-06-15 05:29:03 UTC
setting this to review state; please vote for inclusion in 3.2.x.
Comment 18 Mark Martinec 2007-06-15 08:09:21 UTC
(In reply to comment #13)
Assignments to $< and $> are fine with either 4294967294 or -2
[...] assignments to $( and $) that flake out if the number
is bigger than the maximum positive 32 bit signed int.
> 
> this sounds like a perl bug on MacOS X

> However, POSIX::setgid() works fine to set both the real
> and effective gid with

> you'd probably have to do sth like this:
>   - run the $) / $( assignments in an eval '...' block
>   - capture errors
>   - if error =~ /setrgid\(\) not implemented/, then
>     - run POSIX::setgid(...)
>     - die if that failed too

If POSIX::setgid and POSIX::setuid are available (and I can't think
why they wouldn't be), by all means, use ONLY these, to avoid
all the $<, $>, $( and $) perl crap, which is causing all kinds
of inconsistencies on various platforms.  The Net::Server (which
is used by amavisd-new) had a series of problem-reports until
it finally switched to POSIX::setgid and POSIX::setuid.

For illustration (not that I claim it is best), this is what
currently stands in Net::Server::Daemonize.pm:

sub set_uid {
  my $uid = get_uid( shift() );
  POSIX::setuid($uid);
  if ($< != $uid || $> != $uid) { # check $> also (rt #21262)
    $< = $> = $uid; # try again-needed by some 5.8.0 linux systems (rt #13450)
    if ($< != $uid) {
      die "Couldn't become uid \"$uid\": $!\n";
    }
  }
  return 1;
}

sub set_gid {
  my $gids = get_gid( @_ );
  my $gid  = (split /\s+/, $gids)[0];
  eval { $) = $gids }; # store all the gids - this is really sort of optional
  POSIX::setgid($gid);
  if (! grep {$gid == $_} split /\s+/, $() { # look for any valid id in list
    die "Couldn't become gid \"$gid\": $!\n";
  }
  return 1;
}
Comment 19 Sidney Markowitz 2007-06-15 08:14:53 UTC
> If POSIX::setgid and POSIX::setuid are available (and I can't think
> why they wouldn't be), by all means, use ONLY these, to avoid

Martin, I'm going to copy your comment over to bug 5518 where we are continuing
this discussion, and I'll respond there.

As for the proposed patch for this bug that is up for review
I vote +1
Comment 20 Daryl C. W. O'Shea 2007-06-17 20:10:04 UTC
+1
Comment 21 Justin Mason 2007-06-18 09:19:44 UTC
ok, checked in on 3.2.x:

: jm 142...; svn commit -m "bug 5110: fix test suite to support running as root,
now that spamd will automatically fall back to 'nobody' privs; this was breaking
CPAN installation" t/spamd_allow_user_rules.t t/spamd_plugin.t t/SATest.pm
Sending        t/SATest.pm
Sending        t/spamd_allow_user_rules.t
Sending        t/spamd_plugin.t
Transmitting file data ...
Committed revision 548391.
Comment 22 Daryl C. W. O'Shea 2007-06-18 11:50:15 UTC
*** Bug 5525 has been marked as a duplicate of this bug. ***
Comment 23 Theo Van Dinter 2007-07-08 18:46:51 UTC
*** Bug 5550 has been marked as a duplicate of this bug. ***
Comment 24 Sidney Markowitz 2007-07-17 05:44:14 UTC
Created attachment 4050 [details]
same patch against 3.1 branch

Here is the same fix in the form of a patch against the 3.1 branch
Comment 25 Sidney Markowitz 2007-07-17 05:46:13 UTC
Reopen to target to 3.1.10

Here's my +1 to apply it

Comment 26 Justin Mason 2007-07-18 06:36:02 UTC
+1
Comment 27 Daryl C. W. O'Shea 2007-07-23 01:36:55 UTC
+1
Comment 28 Sidney Markowitz 2007-07-23 02:41:47 UTC
Committed to branch 3.1 revision 558675.