Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure with ($>, $<) = ($<, $>) on linux. #12047

Open
p5pRT opened this issue Apr 10, 2012 · 6 comments
Open

Failure with ($>, $<) = ($<, $>) on linux. #12047

p5pRT opened this issue Apr 10, 2012 · 6 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 10, 2012

Migrated from rt.perl.org#112374 (status was 'open')

Searchable as RT112374$

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2012

From david.Ingamells@mapscape.eu

Created by David.ingamells@mapscape.eu

This bug was first reported to the Ubuntu team as bug number 576984 a long time ago
and I have been supporting a patched version (as described below) at our site ever since. They clearly didn't care :(
I hope that you do :)

The following perl (from perl-base) script fails in the new LTS Ubuntu 10.04, it works in LTS version 8.04.

It tests the perl statement

  ($&gt;, $&lt;) = ($&lt;, $&gt;)

which is documented in perl's perlvar maunal page, also in version 5.14.1.
I have tested this with perl 5.10.1 and 5.12 but not with 5.14.

The output expected is in the script's header comments.

Under Ubuntu 10.04 (perl 5.10.1) it results in​:

Testing perl version 5.010001
Initially UID = 1000, EUID = 1001
After swap UID = 1001, EUID = 1001
EUID (1001) should be 1000 at /tmp/swap_uid.pl line 16.
ERROR​: Test failed.

Notice how the 2 uids are the same after the attempt to swap.

<b>Note to demonstrate this bug the script needs to perform sudo commands.</b> Therefore
  1) check the script first for unsafe behaviour
  2) to run it you will be prompted for your sudo password. Don't run it if you don't have sudo rights

Notes​:
1) In the early days of Ubuntu 8.04 there was a similar problem that was fixed at some time.
2) I've now also tested Ubuntu 9.10 (with perl 5.10.0) and it has the same bug.
3) There is possibly a security issue here as a script that assumes that it has swapped the
  UIDs back will actually be running under a different UID than intended. However
  this is too slight to mark it as a security bug. Please feel free to escalate if you feel differently.
4) This script does not use the suid-perl package that is now deprecated - it is a bug in the core perl program.

Kind regards,
David.

<---begin script--->
#!/usr/bin/perl

# this program should give output like​:
#
# Testing perl version 5.008008
# Initially UID = 1020, EUID = 1021
# After swap UID = 1021, EUID = 1020
# After double swap UID = 1020, EUID = 1021
#

use warnings;
use strict;

# This program creates a perl_script​:

my $perl_script = "/tmp/swap_uid.pl";

# and a C program that runs this perl script​:

my $c_source = "/tmp/run_me.c";
my $c_program = "/tmp/run_me";

# This program is given a different owner ID

my $other_uid = $&lt; + 1;

sub my_system($)
{
  my $command = shift;
  my $result = system $command;
  $result /= 256;

  return $result;
}

sub create_perl_script($)
{
  my $file_name = shift;

  my $script = '#!/usr/bin/perl

use warnings;
use strict;

my $real_uid = $&lt;;
my $eff_uid = $&gt;;

die "Effective UID ($eff_uid) is same as own UID" if ($real_uid == $eff_uid);
print "Testing perl version $]\n";
print "Initially UID = $&lt;, EUID = $&gt;\n";
($&lt;, $&gt;) = ($&gt;, $&lt;);
print "After swap UID = $&lt;, EUID = $&gt;\n";
die "Effective UID ($eff_uid) is same as own UID" if ($real_uid == $eff_uid);
die "UID ($<) should be $eff_uid" if ($&lt; != $eff_uid);
die "EUID ($>) should be $real_uid" if ($&gt; != $real_uid);
($&lt;, $&gt;) = ($&gt;, $&lt;);
print "After double swap UID = $&lt;, EUID = $&gt;\n";
die "Effective UID ($eff_uid) is same as own UID" if ($real_uid == $eff_uid);
die "UID ($<) should be $real_uid" if ($&lt; != $real_uid);
die "EUID ($>) should be $eff_uid" if ($&gt; != $eff_uid);
exit 0;
';

  open my $FH, '>', $file_name or die "Could not open script file";
  print $FH $script or die "Could not print script file";
  close $FH or die "Could not close script file";
  my_system "sudo chmod ug+rx $file_name" and die "Could not set suid bit of program";
}

sub create_program($$$$)
{
  my $source_file = shift;
  my $executable = shift;
  my $exec_owner = shift;
  my $script = shift;

  # See perlsec where this code is presented.
  my $source = '#define REAL_PATH "'. $script . '"
  main(int ac, char **av)
  {
  execv(REAL_PATH, av);
  }
';

  open my $FH, '>', $source_file or die "Could not open source file";
  print $FH $source or die "Could not print source file";
  close $FH or die "Could not close source file";

  my_system "gcc -o $executable $source_file" and die "Could not compile C program";
  my_system "sudo chown $exec_owner $executable" and die "Could not change ownership of program";
  my_system "sudo chmod ug+s $executable" and die "Could not set suid bit of program";
}

sub run_test($)
{
  my $executable = shift;
  my_system("$executable") and print "ERROR​: Test failed.\n";
}

sub cleanup
{

  foreach my $f (@​_)
  {
  system "sudo chown $< $f";
  unlink $f;
  }
}

create_perl_script($perl_script);
create_program($c_source, $c_program, $other_uid, $perl_script);
run_test($c_program);
cleanup($c_source, $c_program, $perl_script);
<---- end script ---->

The following code change fixes the problem with perl 5.10 .1. The above script now gives this output​:

Testing perl version 5.010001
Initially UID = 1020, EUID = 1021

After swap UID = 1021, EUID = 1020

After double swap UID = 1020, EUID = 1021

PLEASE FIX THE DISTRIBUTED VERSION IN UBUNTU 10.4.

In mg.c use setresuid by preference if it is available and set the saved uid (3rd argument) to the other value so that
both values (real and effective) are always present among the 3 values the system knows (real, effective and saved).

  case '<'​:
  PL_uid = SvIV(sv);
  if (PL_delaymagic)
  {
  PL_delaymagic |= DM_RUID;
  break; /* don't do magic till later */
  }

#ifdef HAS_SETRESUID
  {
  Uid_t Curr_uid = getuid();
  Uid_t Curr_euid = geteuid();
  Uid_t saved_Uid = (Curr_uid != (Uid_t)PL_uid) ? Curr_uid : Curr_euid;
  (void)setresuid((Uid_t)PL_uid, (Uid_t)-1, saved_Uid);
  }
#else
#ifdef HAS_SETRUID
  (void)setruid((Uid_t)PL_uid);
#else
#ifdef HAS_SETREUID
  (void)setreuid((Uid_t)PL_uid, (Uid_t)-1);
#else
  if (PL_uid == PL_euid)
  { /* special case $&lt; = $&gt; */
#ifdef PERL_DARWIN
  /* workaround for Darwin's setuid peculiarity, cf [perl #24122] */
  if (PL_uid != 0 && PerlProc_getuid() == 0)
  {
  (void)PerlProc_setuid(0);
  }
#endif
  (void)PerlProc_setuid(PL_uid);
  }
  else
  {
  PL_uid = PerlProc_getuid();
  Perl_croak(aTHX_ "setruid() not implemented");
  }
#endif
#endif
#endif
  PL_uid = PerlProc_getuid();
  PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
  break;
  case '>'​:
  PL_euid = SvIV(sv);
  if (PL_delaymagic)
  {
  PL_delaymagic |= DM_EUID;
  break; /* don't do magic till later */
  }
#ifdef HAS_SETRESUID
  {
  Uid_t Curr_uid = getuid();
  Uid_t Curr_euid = geteuid();
  Uid_t saved_Uid = (Curr_euid != (Uid_t)PL_euid) ? Curr_euid : Curr_uid;
  (void)setresuid((Uid_t)-1, (Uid_t)PL_euid, saved_Uid);
  }
#else
#ifdef HAS_SETEUID
  (void)seteuid((Uid_t)PL_euid);
#else
#ifdef HAS_SETREUID
  (void)setreuid((Uid_t)-1, (Uid_t)PL_euid);
#else
  if (PL_euid == PL_uid) /* special case $&gt; = $&lt; */
  {
  PerlProc_setuid(PL_euid);
  }
  else
  {
  PL_euid = PerlProc_geteuid();
  Perl_croak(aTHX_ "seteuid() not implemented");
  }
#endif
#endif
#endif

Perl Info

Flags:
    category=core
    severity=high

Site configuration information for perl 5.10.1:

Configured by Debian Project at Fri Apr 22 18:53:20 UTC 2011.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=2.6.24-28-server, archname=x86_64-linux-gnu-thread-multi
    uname='linux allspice 2.6.24-28-server #1 smp wed aug 18 21:17:51 utc 2010 x86_64 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.10.1 -Dsitearch=/usr/local/lib/perl/5.10.1 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib -Dlibperl=libperl.so.5.10.1 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.3', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.11.1.so, so=so, useshrplib=true, libperl=libperl.so.5.10.1
    gnulibc_version='2.11.1'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib -fstack-protector'

Locally applied patches:
    


@INC for perl 5.10.1:
    /etc/perl
    /usr/local/lib/perl/5.10.1
    /usr/local/share/perl/5.10.1
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.10
    /usr/share/perl/5.10
    /usr/local/lib/site_perl
    .


Environment for perl 5.10.1:
    HOME=/data/users/david.ingamells
    LANG (unset)
    LANGUAGE=
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=.:/data/users/david.ingamells/bin:/data/id/release/MScms/Environment_latest:/data/ops/bin:.:~/bin:/data/id/release/MScms/Environment_latest:/data/ops/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2012

From @Leont

On Tue, Apr 10, 2012 at 8​:09 AM, david.Ingamells@​mapscape.eu
<perlbug-followup@​perl.org> wrote​:

This bug was first reported to the Ubuntu team as bug number 576984 a long time ago
and I have been supporting a patched version (as described below) at our site ever since. They clearly didn't care :(
I hope that you do :)

The following perl (from perl-base) script fails in the new LTS Ubuntu 10.04, it works in LTS version 8.04.

It tests the perl statement

   ($&gt;, $&lt;) = ($&lt;, $&gt;)

which is documented in perl's perlvar maunal page, also in version 5.14.1.
I have tested this with perl 5.10.1 and 5.12 but not with 5.14.

Why are you doing this in the first place? In particular, why are you
setting the real user id? This trick was only necessary on BSD before
it supported saved userids (1994). You either want to change only the
effective id, or all ids.

BTW I can reproduce this is 5.12 but not in 5.14 (don't have 5.10 at
hand). Sounds like a bisect is in order.

In mg.c use setresuid by preference if it is available and set the saved uid (3rd argument) to the other value so that
both values (real and effective) are always present among the 3 values the system knows (real, effective and saved).

That codepath should not be used in this case, it should use delayed
assignment. This solution seems way too brittle, then again I've
proposed removing this entire idiom since it's no longer of use in
this millennium.

Leon

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 11, 2012

From david.Ingamells@mapscape.eu

On 10/04/12 12​:25, Leon Timmermans via RT wrote​:

On Tue, Apr 10, 2012 at 8​:09 AM, david.Ingamells@​mapscape.eu
<perlbug-followup@​perl.org> wrote​:

This bug was first reported to the Ubuntu team as bug number 576984 a long time ago
and I have been supporting a patched version (as described below) at our site ever since. They clearly didn't care :(
I hope that you do :)

The following perl (from perl-base) script fails in the new LTS Ubuntu 10.04, it works in LTS version 8.04.

It tests the perl statement

\($>\, $\<\) = \($\<\, $>\)

which is documented in perl's perlvar maunal page, also in version 5.14.1.
I have tested this with perl 5.10.1 and 5.12 but not with 5.14.
Why are you doing this in the first place? In particular, why are you
setting the real user id? This trick was only necessary on BSD before
it supported saved userids (1994). You either want to change only the
effective id, or all ids.

Leon,
Thanks for the quick response.

The action isn't SET but SWAP. An executable with the sticky bit set
gets 2 user IDs available to it​: the real ID and the effective ID. The
real ID is the ID of the user who runs the executable and the effective
ID is the owner of the executable.
This is a known and well documented Unix practice, e.g. for a number of
Unix/GNU Linux commands where the effective ID is root, although in my
case the effective ID is not a privileged user. A very easy to
understand example is the unix command "passwd" which needs to be able
to store the user's new password without allowing the user to get at
the store directly.

Here are some of the GNU/Linux executables that have the "s" bit set -
from Ubuntu 10.04 released in 2010, well into the 21st century - which
AFIK is part of the /current/ millennium ;-)
$ ls -l /usr/bin | egrep "^...s"
-rwsr-sr-x 1 root root 10536 Jan 18 19​:49 X
-rwsr-xr-x 1 root root 14720 Mar 12 2010 arping
-rwsr-sr-x 1 daemon daemon 52032 Jan 15 2011 at
-rwsr-xr-x 1 root root 41864 Feb 14 2011 chfn
-rwsr-xr-x 1 root root 37128 Feb 14 2011 chsh
-rwsr-xr-x 1 root root 11214 Oct 22 2010 fileshareset
-rwsr-xr-x 1 root root 59752 Feb 14 2011 gpasswd
-rwsr-xr-x 1 root root 10480 Oct 22 2010 kgrantpty
-rwsr-xr-x 1 root root 10536 Oct 22 2010 kpac_dhcp_helper
-rwsr-xr-- 1 root dialout 644872 Apr 16 2011 kppp
-rwsr-xr-x 1 root root 47968 Oct 11 21​:14 ksu
-rwsr-xr-x 1 root lpadmin 14256 Sep 12 2011 lppasswd
-rwsr-xr-x 1 root root 32416 Feb 14 2011 newgrp
-rwsr-xr-x 1 root root 42856 Feb 14 2011 passwd
-rwsr-xr-x 1 root root 19112 Apr 19 2011 pkexec
-rwsr-xr-x 1 root root 73216 Apr 22 2011 sperl5.10.1
-rwsr-xr-x 1 root root 10528 Oct 22 2010 start_kdeinit
-rwsr-xr-x 2 root root 148024 Jan 19 2011 sudo
-rwsr-xr-x 2 root root 148024 Jan 19 2011 sudoedit
-rwsr-xr-x 1 root root 18928 Mar 12 2010 traceroute6.iputils

This feature is also documented in the core Perl documentation.
My code needs to SWAP the real and effective IDs, create/modify a file
with the effective ID as owner (so that the user whose ID is the
effective ID can manage the file) and SWAP back to the real user ID to
create some other files for the user.

BTW I can reproduce this is 5.12 but not in 5.14 (don't have 5.10 at
hand). Sounds like a bisect is in order.

It seems then that someone else has discovered the bug and it has been
fixed since 5.12.

We will soon be upgrading from the current long-term-support Ubuntu
version 10.04 (which uses perl 5.10.1)
to the next LTS support Ubuntu version 12.04 once it gets rolled out
(very soon). I was using Ubuntu 11.10 as preparation for this.
I have not yet been able to get my hands on a machine running Ubuntu
12.04, but the web site says that it uses Perl 5.14.2. If that is the
case and it works in Ubuntu 12.04,
as looks to be the case from your tests, I myself won't need 5.12.x to
be fixed and I will be happy if something
like the test I supplied gets added to the test suite to prevent future
regressions (if this hasn't yet been done when the bug got fixed in or
before 5.14).

In mg.c use setresuid by preference if it is available and set the saved uid (3rd argument) to the other value so that
both values (real and effective) are always present among the 3 values the system knows (real, effective and saved).
That codepath should not be used in this case, it should use delayed
assignment. This solution seems way too brittle, then again I've
proposed removing this entire idiom since it's no longer of use in
this millennium.

Leon

The update I applied and supplied here worked and was the minimal
change in perl 5.10 for our needs​: it fixed the codepath that the Perl
developers implemented. It doesn't matter to me how the "($&gt;, $&lt;) = ($<,
$>)" idiom (which is, I presume, the idiom you are referring to) is
implemented provided it works :)
I, for one, will be very upset if that idiom is removed. It will turn a
trivial implementation in my code into a major headache.

--

*David*<http​://www.mapscape.eu/>

@p5pRT
Copy link
Author

p5pRT commented Apr 11, 2012

From @Leont

On Tue, Apr 10, 2012 at 2​:17 PM, David Ingamells
<david.ingamells@​mapscape.eu> wrote​:

The action isn't SET but SWAP. An executable with the sticky bit set gets 2
user IDs available to it​: the real ID and the effective ID. The real ID is
the ID of the user who runs the executable and the  effective ID is the
owner of the executable.

You're forgetting about the saved id (which you confusingly did
mention in your patch). This saved ID was introduced exactly for this
kind of scenario​: temporarily dropping privileges. On exec*, it's set
to the new effective id, so that when you change the effective id to
the real one, you can still change it back. Setting any id other than
the effective one is rarely necessary, and even then you probably want
to set the saved id. See Proc​::UID on CPAN for a nice implementation
of this.

This is a known and well documented Unix practice, e.g. for a number of
Unix/GNU Linux commands where the effective ID is root, although in my case
the effective ID is not a privileged user. A very easy to understand example
is the unix command "passwd" which needs to be able to store  the  user's
new password without allowing the user to get at the store directly.

Here are some of the GNU/Linux executables  that have the "s" bit set - from
Ubuntu 10.04 released in 2010, well into the 21st century - which AFIK is
part of the current millennium ;-)
$ ls -l /usr/bin | egrep "^...s"
-rwsr-sr-x 1 root   root      10536 Jan 18 19​:49 X
-rwsr-xr-x 1 root   root      14720 Mar 12  2010 arping
-rwsr-sr-x 1 daemon daemon    52032 Jan 15  2011 at
-rwsr-xr-x 1 root   root      41864 Feb 14  2011 chfn
-rwsr-xr-x 1 root   root      37128 Feb 14  2011 chsh
-rwsr-xr-x 1 root   root      11214 Oct 22  2010 fileshareset
-rwsr-xr-x 1 root   root      59752 Feb 14  2011 gpasswd
-rwsr-xr-x 1 root   root      10480 Oct 22  2010 kgrantpty
-rwsr-xr-x 1 root   root      10536 Oct 22  2010 kpac_dhcp_helper
-rwsr-xr-- 1 root   dialout  644872 Apr 16  2011 kppp
-rwsr-xr-x 1 root   root      47968 Oct 11 21​:14 ksu
-rwsr-xr-x 1 root   lpadmin   14256 Sep 12  2011 lppasswd
-rwsr-xr-x 1 root   root      32416 Feb 14  2011 newgrp
-rwsr-xr-x 1 root   root      42856 Feb 14  2011 passwd
-rwsr-xr-x 1 root   root      19112 Apr 19  2011 pkexec
-rwsr-xr-x 1 root   root      73216 Apr 22  2011 sperl5.10.1
-rwsr-xr-x 1 root   root      10528 Oct 22  2010 start_kdeinit
-rwsr-xr-x 2 root   root     148024 Jan 19  2011 sudo
-rwsr-xr-x 2 root   root     148024 Jan 19  2011 sudoedit
-rwsr-xr-x 1 root   root      18928 Mar 12  2010 traceroute6.iputils

This feature is also documented in the core Perl documentation.

It would be pleasant if you would assume I have a clue of what I'm
talking about while I'm helping you with a bug. If you don't
understand my question, can you ask for a clarification instead of
assuming I'm incompetent?

My code needs to SWAP the real and effective IDs, create/modify a file with
the effective ID as owner (so that the user whose ID is the effective ID can
manage the file) and SWAP back to the real user ID to create some other
files for the user.

That's all I needed to know. You just want to reversibly set the
effective user id. You don't really need to swap it with the real user
id to achieve that.

It seems then that someone else has discovered the bug and it has been fixed
since 5.12.

I'm not seeing any obvious changes that would explain that in the
history. Until last February, the code directly involved hadn't been
touched majorly since 2003. This looks to me like it's either an
action at a distance, debian/ubuntu patching perl in weird ways, or
both.

I, for one, will be very upset if that idiom is removed. It will turn a
trivial implementation in my code into a major headache.

Quite to the contrary. It would make everyone's code easier​: yours and ours.

Leon

@p5pRT
Copy link
Author

p5pRT commented Apr 12, 2012

From @Leont

On Tue, Apr 10, 2012 at 2​:17 PM, David Ingamells
<david.ingamells@​mapscape.eu> wrote​:

This feature is also documented in the core Perl documentation.
My code needs to SWAP the real and effective IDs, create/modify a file with
the effective ID as owner (so that the user whose ID is the effective ID can
manage the file) and SWAP back to the real user ID to create some other
files for the user.

You're talking about this swapping as if it's a purpose in itself, it
isn't. All you want is to reversibly set the effective user id.
Because of the saved user id, you do not need to swap it with the real
user id like people did 20 years ago. Let me explain this with a
little piece of code​:

# setuid, so [res]uids at start are (self, other, other)
{
  local $&gt; = $&lt;;
  do_something(); # [res]uids are now (self, self, other)
}
# setuid, so [res]uids are (self, other, other) again.

Leon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants