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

This is a firewall script I run from my apache cgi-bin. Apache is run with user nobody (uid 99), so all scripts it runs are with uid 99. I need root access for one specific script. I tried to chmod +s it while being root, but after that the script runs with user nobody.
Somebody told me to search for suidperl - an interpreter designed for this purpose. But when I google for it I get only 'suidperl vulnerability','suidperl overflow' and such answers.
How can I run that script with root?

Fixed. I'm using SUDO now, and it fits well ;)

Replies are listed 'Best First'.
Re: Perl script needs root privilegies
by tirwhan (Abbot) on Dec 26, 2005 at 11:32 UTC

    A much better option than suid-ing a script IMO is to use sudo to give your user exactly the capabilities he needs. For example, if you put this in your /etc/sudoers file:

    nobody: ALL=(ALL) NOPASSWD:/sbin/iptables

    Your user nobody will be able to call sudo iptables and it will execute as root without the need to enter a password. Personally this would not be quite paranoid enough for me, I'd prefer to write separate shell scripts which execute exactly the iptables command I want the user to be able to execute and specify these explicitly in sudoers, but YMMV.


    A computer is a state machine. Threads are for people who can't program state machines. -- Alan Cox
      SUDO would be nice if I had only iptables. But this script uses a whole bunch of programs, not only iptables. I can't write them all down to /etc/sudoers ;)
      I thought there is some generic perl way to change uid?
        I can't write them all down to /etc/sudoers

        Umm, why not? This is an extremely flexible and comfortable way of granting minimum necessary privileges (you can even give users the ability to run commands as other users, not root, or use one sudoers file for several systems, specifying which capabilities are allowed on which systems). Why would you not want to do this the most secure way possible (given that what you're trying to do is risky at best anyway)?

        I thought there is some generic perl way to change uid?

        Sorry, I'm not in the business of promoting bad practices (and I consider suidperl to be a bad practice :-).

        If you're calling lots of external commands, the best thing would be to condense these into one or several shell scripts (taking care to make the scripts do as little as possible, be as unambiguous as possible and require as few passed parameters as possible) and then make the script callable by sudo.


        A computer is a state machine. Threads are for people who can't program state machines. -- Alan Cox

        You can change your uid in Perl by using POSIX::setuid, but setting your userid only works if you are already on uid 0. Also, using setuid programs or scripts is a dangerous practice, so I would try to limit what needs to be done by root as much as possible.

      nobody: ALL=(ALL) NOPASSWD:/sbin/iptables

      Eek! Now all of the CGI scripts, mod_perl code and everything else that runs anonymously under the web server, PLUS everything else that runs under user nobody on the system, including things like a font server, will be able to run this command!

      The best approach in my opinion is to combine both:

      1. Script is setuid to a dedicated user that runs only that script, and
      2. That dedicated user is only allowed to run a couple of key commands via sudo.

      But if I had to choose and use only one approach, I'd pick the OP's.

      Now as to how to make the script setuid in the first place, that depends. If you have an operating system like Solaris that has secure setuid scripts, it will work directly. Otherwise you have the suidperl can of worms. As an alternative, the web server might make use of suExec and you may be able to get that to cause your script to run under the correct user ID.

      In any case, don't forget to turn on taint checks if they're not turned on automatically for whatever invocation style you end up using (they are turned on automatically for true setuid scripts.

        You missed out my following statement "I'd prefer to write separate shell scripts which execute exactly the iptables command I want the user to be able to execute" :-). Which would you rather have, /sbin/iptables that is setuid and user-executable (which nobody advocated, for good reason) or my line in sudoers? Same thing goes for scripts you write yourself.


        A computer is a state machine. Threads are for people who can't program state machines. -- Alan Cox
      A much better option than suid-ing a script IMO is to use sudo to give your user exactly the capabilities he needs. For example, if you put this in your /etc/sudoers file:

      And another option would be to have another program with appropriate permissions running as a separate process and do the critical jobs: this would require some form of IPC, but may even be done asyinchronously if such an option is suitable for the actual application.

      For example the firewall script may add entries to a file (which may also happen to be a named pipe) and another script may process them running the necessary programs requiring root privileges.

Re: Perl script needs root privilegies
by jhourcle (Prior) on Dec 26, 2005 at 12:31 UTC

    I'd personally use the sudo approach that ivanatora recommended, but there are other ways of achieving the same result.

    • Have a daemon running with the correct permissions, that the CGI script can connect to, and signal to run the necessary commands.
    • If immediate timing isn't necessary, write a message to a directory, and have a cronjob check for messages and finish processing them as root.
    • You can also kick off a single script w/ sudo, which then runs all of the other commands.

    Each one of these suggestions has additional problems -- the first one, some other process might connect; the second has a directory writable by 'nobody', which means all scripts on the webserver; the third one will need the script protected so no one modifies it.

    You can mitigate some of the concerns by using suEXEC or CGIwrap on the webserver. (both of which allow cgis to be run as someone other than the webserver's default user)

Re: Perl script needs root privilegies
by Corion (Patriarch) on Dec 26, 2005 at 11:35 UTC

    suidperl is a dangerous way of doing setuid Perl scripts. Over the time, there were many vulnerabilities found in suidperl, which is why people are discouraged from pursuing solutions with it. If you want to trigger functionality from Apache which needs root privileges, consider a two-fold approach. Your trigger script writes the information to a file, and the cron for root kicks off a script every minute which looks for that data and then updates the firewall.

    If you want to pull the information in the other direction, it's even easier - have your firewall script run every minute and dump the data somewhere where your Apache script can read it.