develooper Front page | perl.perl5.porters | Postings from September 2011

Re: [perl #98934] set{u,g}id doesn't clear $! on success

Thread Next
From:
Chris Adams
Date:
September 13, 2011 04:49
Subject:
Re: [perl #98934] set{u,g}id doesn't clear $! on success
Message ID:
20110912195014.GD18269@hiwaay.net
Once upon a time, Leon Timmermans via RT <perlbug-followup@perl.org> said:
> On Mon Sep 12 09:39:58 2011, cmadams@hiwaay.net wrote:
> > [Please enter your report here]
> > Setting a user/group ID by assigning to the perl special variables
> >    does
> > not clear $!, so confusing errors can occur.  This test program fails
> >    on
> > 5.8.8 (RHEL 5) and 5.12.4 (Fedora Linux 15):
> > 
> > ########################################################################
> > #!/usr/bin/perl
> > 
> > use warnings;
> > use strict;
> > 
> > my @foo = stat ("/does/not/exist");
> > my $gid = $( + 0;
> > $( = $gid;
> > die "setgid($gid): $!\n" if ($!);
> > ########################################################################
> > 
> > I get "setgid(1000): No such file or directory".  If I take out the
> > stat() or add a "$! = undef" after the stat(), the script runs as
> > expected.
> 
> First of all, that is exactly what you should expect. Succeeding system
> calls do not set errno, only failing ones do. If you want to check for
> an error by using $!, you should set it to 0 before setting $(.

The problem is that is not what the documentation says.  The docs say
"require a check to $! to detect any possible errors", not "you must
clear $! first, make your change, then check the results".

The underlying problem is that the perl source code doesn't check or
save the return code from the setregid() call.  Since library calls can
have unexpected side-effects, perl should handle this internally.

For example, my actual code that shows the problem fails after a
getpwnam() for some users (and not others).  getpwnam() uses the NSS
library for its lookups, and some users are local (/etc/passwd) while
most are from the network (LDAP).  The NSS library tries a couple of
locations to load libnss_ldap.so.2, and errno doesn't get cleared after
the first location returns ENOENT.

This is highly confusing, and there's really no reason to push this off
on the people writing perl code.  At a minimum, perl internally could do
something like:

    if (setregid(gid,-1) == 0)
        errno = 0;

(and that goes for all the setuid/setgid family of functions).

> Secondly, what you're doing is completely wrong. You're setting the real
> GID but not the effective GID, thus not dropping privileges at all. Try
> POSIX' setuid/setgid, or better yet something like Unix::SetUser or
> Proc::UID.

No, I only want to set the real GID here (I'm dropping privs temporarily
for a check).  Also, the above is just a short-and-simple example of the
problem, not my full code.
-- 
Chris Adams <cmadams@hiwaay.net>
Systems and Network Administrator - HiWAAY Internet Services
I don't speak for anybody but myself - that's enough trouble.

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About