http://www.perlmonks.org?node_id=1219211

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

We have a number of Perl scripts running setuid that invoke system() calls. (No flames please). In our migration from Solaris 10 to Solaris 11, we've found that /bin/sh won't respect the setuid credentials unless there is a '-p' included on the /bin/sh command. It looks like system() invokes /bin/sh -c ... . Would there be a way to include the '-p' in system()'s call to sh? I've tried several and none have been successful. Thanks, Mark

Replies are listed 'Best First'.
Re: setuid system() calls on Solaris 11
by dave_the_m (Monsignor) on Jul 25, 2018 at 08:16 UTC
    system() only invokes the shell if it has a single arg containing metachars (so it's relying on the shell to parse the command line). If you do that processing yourself, perl will execute the command directly. For example, change this first line to the second line:
    system "foo -x 'a b' -y bar"; system "foo", "-x", "a b", "-y", "bar";

    Dave.

      See also The problem of "the" default shell for the interactions of system and its friends with the default shell.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: setuid system() calls on Solaris 11
by hippo (Chancellor) on Jul 25, 2018 at 08:11 UTC
    I've tried several

    Did those you tried include prepending the precise shell and args to the command list? eg.

    my $shellfile = 'foo.sh'; my @cmd = ('/bin/sh', '-p', $shellfile); my $res = system (@cmd);

    Note that I have no access to Solaris 11 so this is untested and is just a suggestion.

Re: setuid system() calls on Solaris 11
by baataboom (Initiate) on Jul 25, 2018 at 15:11 UTC
    So replacing something like this:
    if (system ( "/usr/bin/cp -f $version/$obj $dest 2> /dev/null")) {
    with
    if (system ( '/usr/bin/cp', '-f', "$version/$obj", $dest '2>', '/dev/null')) {
    would work? And maybe this would be more of a drop in replacement, i.e. keep /bin/sh in the call to avoid behavior diffs from changing to a no-shell execution?
    if (system ( /bin/sh', '-p', '-c', '/usr/bin/cp', '-f', "$version/$obj", $dest '2>', '/dev/null')) {
      system ( "/usr/bin/cp -f $version/$obj $dest 2> /dev/null")

      The 2> /dev/null is a shell construct for redirecting FD 2 so you would need a shell to handle that. However, why would you want to redirect FD 2 to /dev/null anyway? Surely you want to log the details of any failure?

      Furthermore, why fork out to cp when we have File::Copy in core?

      I'm not sure if the replacement you showed would work on your shell due to the redirection. What I would try first is this:

      system('/bin/sh', '-p', '-c', '-e', "/usr/bin/cp -f $version/$obj $dest 2> /dev/null" )==0 or die "system: \$?=$?";

      I've added some error checking. Note that this suffers from potential security issues if those variables contain any unchecked user input! (And potential quoting issues.) I wrote more on that topic, and how to run external commands using modules, here.

        Using
        system( '/bin/sh', '-pc', "cmd string w/optional stderr and stdout red +irection" );
        worked! Excellent. What we had experienced in migrating to the newer OS (Solaris 11) was that some of our system() calls were honoring setuid/setgid and some were not. Yet they were all quite similar (i.e. system( "single param string")). And the Perl docs were not clear (to me) regarding the nuances:
        If there are no shell metacharacters in the argument, it is split into words and passed directly to "execvp", ...
        Anynow, I'm off to make many changes, replacing system() calls and backticks with calls to a ssystem() wrapper function. Thanks all! Mark