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

I'm confused about status of running setuid script with perl 5.16

I see in 5.12 delta
suidperl is no longer part of Perl. It used to provide a mechanism to emulate setuid permission bits on systems that don't support it properly.

I read this as systems that properly support setuid bits should not be affected, but my experience does not match.

Summary
-------
God awful old RedHat 8.0 perl 5.8.8 setting setuid on script works as expected. New Centos 7 perl 5.16 setting setuid on script does not work as expected.

example
-------
On Centos 7 Perl 5.16

sudo -i cat > /tmp/setuid.pl #!/usr/bin/perl use English; print "UID:$UID EUID:$EUID\n"; ctrl D chmod a+rx /tmp/setuid.pl chmod u+s /tmp/setuid.pl exit /tmp/setuid.pl UID:1334 EUID:1334

On RedHat 8.0 perl 5.8.8

sudo -s cat > /tmp/setuid.pl #!/usr/bin/perl use English; print "UID:$UID EUID:$EUID\n"; ctrl D chmod a+rx /tmp/setuid.pl chmod u+s /tmp/setuid.pl exit /tmp/setuid.pl UID:1334 EUID:0

Have I overlooked something on Centos 7 setup to allow setuid?
Or did all setuid functionality get killed in 5.12?

Replies are listed 'Best First'.
Re: perl 5.16 setuid
by afoken (Chancellor) on Oct 13, 2016 at 21:13 UTC

    The clean way to execute perl code setuid is to compile a wrapper from six lines of C code. See Security Bugs in perlsec.

    Update:

    This is the code from perlsec:

    #define REAL_PATH "/path/to/script" main(ac, av) char **av; { execv(REAL_PATH, av); }

    It is K&R style, quick and dirty, but it works.

    If you prefer modern code that compiles cleanly even with gcc -Wall -pedantic, and that reports an error when executing the script fails, try this:

    #include <unistd.h> /* for execv() */ #include <stdio.h> /* for perror() */ #define REAL_PATH "/path/to/script" int main(int argc, char ** argv) { execv(REAL_PATH, argv); perror("Can't execute main script"); return 126; }

    Note that the wrapper is setuid, not the script. The script inherits the setuid from the wrapper.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      This change from K&R to C89 has now found its way into Perl at 245c138e. Thanks to you and mauke for putting in the hard work.

      There is a problem with this method. If the 'C' wrapper is used the script it points to must be secured with 750 or 755 and owned by root or the user it is switching to. Otherwise, you have a real problem with someone being able to write anything they want to the script since the SUID tamper security is only on the wrapper and not on the script. Also, make sure to still use the following header in the script so it will complain about unsafe code. And finally monitor all your scripts called from wrappers for changes with something like inotifywait/inotifywatch or other file monitoring tool.

      #!/usr/bin/perl -T

      Hope this helps someone.

        The world-writable checks (on every path directory as well as the file itself) are understood and a good security practice, certainly. But could you please elaborate on the inotify suggestion? How would one read the inotify events, and perform an execve() at the same time without any race conditions arising?