http://qs321.pair.com?node_id=833950

saintmike has asked for the wisdom of the Perl Monks concerning the following question:

Pop quiz: What's wrong with dropping privileges of a process, started as root, to "nobody", like this?
my $uid = getpwnam("nobody"); $< = $uid;
Answer: It's easy to regain root privileges afterwards by simply assigning 0 to $<.

Why is that? Turns out that assigning a uid to $< (or the effective uid $> for that matter) isn't using setuid(), at least not on Linux. Instead, it uses setreuid32() which allows the unprivileged user to switch back to the "saved set-user-ID". You can see what's going on in a perl script like

$< = $uid; $> = $uid; $> = 0; $< = 0;
by looking at the strace output:
$ sudo strace ./switchback 2>&1 | grep '^set' setreuid32(99, -1) = 0 setresuid32(-1, 99, -1) = 0 setresuid32(-1, 0, -1) = 0 setreuid32(0, -1) = 0
The last two calls successfully restore root privileges (uid and euid) while running as an unprivileged user.

Question: What's the best way to drop privileges, then? POSIX:setuid( $uid ) seems to work, is that the best practice?

Replies are listed 'Best First'.
Re: $< and setuid: quite different animals?
by almut (Canon) on Apr 10, 2010 at 06:52 UTC

    Try it the other way round (first effective, then real):

    $> = $uid; $< = $uid; ...
    $ sudo strace ./switchback.pl 2>&1 | grep '^setr' setresuid(-1, 65534, -1) = 0 setreuid(65534, 4294967295) = 0 setresuid(-1, 0, -1) = -1 EPERM (Operation not perm +itted) setreuid(0, 4294967295) = -1 EPERM (Operation not perm +itted)