in reply to Not understanding the code to drop privileges in perlsec
I have found a bug with this script, and I am looking forward to whether people consider this a bug in Perl or a bug in the script. Anyway, before going into the details I would like to state my Perl version: 5.32.1
I have amended the original script with print statements. The following is the same script as in my first post, but with those statements included and with the last two lines removed:
#!/usr/bin/perl use English; my @temp = ($EUID, $EGID); my $orig_uid = $UID; my $orig_gid = $GID; print('$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: '.$UID.", ".$GI +D.", ".$EUID.", ".$EGID.", ".$orig_uid.", ".$orig_gid."\n"); print('@temp: '.$temp[0].", ".$temp[1]."\n\n"); $EUID = $UID; $EGID = $GID; print('$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: '.$UID.", ".$GI +D.", ".$EUID.", ".$EGID.", ".$orig_uid.", ".$orig_gid."\n"); print('@temp: '.$temp[0].", ".$temp[1]."\n\n"); # Drop privileges $UID = $orig_uid; $GID = $orig_gid; print('$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: '.$UID.", ".$GI +D.", ".$EUID.", ".$EGID.", ".$orig_uid.", ".$orig_gid."\n"); print('@temp: '.$temp[0].", ".$temp[1]."\n\n"); # Make sure privs are really gone ($EUID, $EGID) = @temp; print('$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: '.$UID.", ".$GI +D.", ".$EUID.", ".$EGID.", ".$orig_uid.", ".$orig_gid."\n"); print('@temp: '.$temp[0].", ".$temp[1]."\n\n");
Then I have setup the following test scenario: I set the script suid to the user with id 1015, log in as root and let the script run. This is quite unusual I guess, but since we are testing, this case must be included. The script produces the following output:
$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 1015, 1001 0, +0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 0, 0 0, 0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 0, 0 0, 0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 1015, 0 0, 0, +0 0 @temp: 1015, 1001 0
Please note the last block of the output. We see clearly that the assignment ($EUID, $EGID) = @temp; fails, although we are still root at this moment. Perl has changed only $EUID, not $EGID.
There are two possible conclusions: Either it is generally wrong to assign UID, EUID, GID or EGID in list context (then the bug would be in the script), or Perl should handle that situation correctly (then the bug would be in Perl).
The script works correctly if I replace
by($EUID, $EGID) = @temp;
$EGID = $temp[1]; $EUID = $temp[0];
The script then produces this output:
$UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 1015, 1001 0, +0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 0, 0 0, 0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 0, 0 0, 0, 0 0 @temp: 1015, 1001 0 $UID, $GID, $EUID, $EGID, $orig_UID, $orig_GID: 0, 0 0, 1015, 1001 0, +0, 0 0 @temp: 1015, 1001 0
The last block of output shows that Perl now has changed $EUID as well as $EGID.
I have read somewhere that we always should change $EGID before $EUID; maybe that's the problem with the assignment in list context. However, I also have replaced @temp = ($EUID, $EGID) by @temp = ($EGID, $EUID) at the begin of the script and ($EUID, $EGID) = @temp; by ($EGID, $EUID) = @temp; at the end of the script. This didn't effect anything; Perl still changed only $EUID, not $EGID.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Not understanding the code to drop privileges in perlsec
by Anonymous Monk on Feb 24, 2024 at 00:18 UTC | |
by Nocturnus (Scribe) on Feb 24, 2024 at 20:10 UTC | |
by hv (Prior) on Feb 24, 2024 at 23:20 UTC | |
by hv (Prior) on Feb 24, 2024 at 00:20 UTC |