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

At work, I help maintain a number of products from a 3rd party software vendor. While these apps are all J2EE web applications, they ship with a set of utility scripts for various administrative tasks, written in Perl. Because the applications are installed under a privileged production user id (on Sun boxes), I am trying to put together a setuid wrapper script that allows certain users to execute certain utilities. The wrapper script is not the problem. I am getting bitten by Perl's reluctance to accept alternate library paths in taint mode, and my need to specify them.

The vendor ships their products with their own perl binary (5.6.1), core packages and some of their own modules, which are all placed within each product's directory structure. The Perl utilities are then executed by invoking one "dispatcher" shell script. This script checks the platform, sets a number of environment variables and then exec's the utility with something like the following:

exec ${PATH_TO_VENDORS_PERL} -w -I "some/lib/path" -I "/some/other/lib +" "$@"
... where $@ of course specifies the script file and any extra arguments.

When my setuid wrapper script is executed, it runs the dispatcher which then attempts to execute the Perl script as shown above. But as soon as Perl detects that the effective user != real user, it goes into taint mode which causes the script to fail with a No -I allowed while running setuid.

So this is my question: How can I specify library paths for these scripts? Please note that the obvious answer of modifying each of the scripts and explicitly adding to @INC is not an option for me. These scripts are all part of an out-of-the-box solution we try to modify as little as possible. I can justify touching the dispatcher script. But tracking changes to ten to 15 files, across multiple products, environments and through upgrades is not feasible. I hope this makes sense.

With this in mind, I see two ways to approach the problem:

  1. Find a way to turn off taint mode.
    • A thorough reading of perlrun and perlsec turned up the -U option, which stands for "unsafe". I bravely replaced the -w with -U in the dispatching script's hand-off to Perl, but the scripts continued to run in taint mode. perlrun states that one of the unsafe operations -U allows is running setuid programs with fatal taint checks turned into warnings, but I suppose some taint checks are more fatal than others. I had hoped -U would be synonymous with "turn taint off", but that's not the case.

      Is there a way to completely disable taint mode on setuid scripts?

    • As an outside, drastic solution I have though about just compiling Perl again, but modifying the source to disable taint mode completely (if that's even possible). The benefits (I only have to modify one file!) are severely outweighed by the risk of making such a major change.

  2. Try to specify library paths through alternate methods.
    • Without much hope, I attempted to specify the library paths through the PERL5LIB and PERLLIB environment variables. A dump of @INC confirmed that Perl ignored those, as perlsec explains all taint-mode scripts do.

    • I also had a thought to place symlinks from the default library paths found in @INC to the appropriate locations. Unfortunately, the vendor compiled their perl with unsuitable dummy default search paths. They literally look something like /vendor/please/use/-I/option. I don't think my admins would want to create a symlink in /, besides which - it would be a maintenance issue.

    • My next idea was to create a small wrapper program that would feed the script to perl through STDIN, allowing me to prepend the library paths I needed as a BEGIN block at the top (as in push @INC, 'my/path/here';). I found out that perl won't read its program from STDIN when in taint mode. In retrospect, this makes a lot of sense and I feel a little foolish for having tried it.

    • Building on this, I am thinking about an even less subtle approach: Having the wrapper program create a temporary file made up of a BEGIN block to set the library search paths, followed by the script I want to execute. Then this file could (hopefully) be executed, and deleted on exit. This is, I believe, my last resort. Besides being very clumsy, I would have to worry about an unsafe race condition, where a user could modify the file between its writing to disk and its execution. But unless some monks enlighten me here, I think this is the road I have to go down.

This is a low-priority project. I've been coming back to it off and on for weeks, hoping to get a fresh perspective and fresh ideas, but I've run out. Can anybody point out an approach I might have missed? Am I not seeing the forest for all the trees, and is there some other way to get these scripts to run? I appreciate any help you can give me - Thanks!

Replies are listed 'Best First'.
Re: Specifying library paths for taint-mode / setuid scripts
by Tanktalus (Canon) on Jun 14, 2005 at 18:09 UTC

    This really sounds like you should get, install, and train users to use, sudo. Or, you should get, install, and write your wrappers (non-suid) to call, sudo.

Re: Specifying library paths for taint-mode / setuid scripts
by Zaxo (Archbishop) on Jun 14, 2005 at 17:57 UTC

    You've stated all the pieces of what you need to do - just not matched them up.

    You consider recompiling perl, but for the wrong reason. When you run ./Configure before building perl, you get the opportunity to add vendor library locations to @INC. Rebuilding perl with the actual library path will solve your path problem.

    I try to avoid suid scripts if I can. Try to find a way of doing what you can do with a special group and group permissions on the objects you need to modify.

    If you still need suid, that's all the more reason to run in taint mode. Don't choose a solution that steps around that.

    I would be nervous of a product whose installation permitted a non-default location without adjusting its internals to match.

    After Compline,
    Zaxo

Re: Specifying library paths for taint-mode / setuid scripts
by mhearse (Chaplain) on Jun 14, 2005 at 19:07 UTC
    Since these are Sun boxes, you could also use rbac to solve your suid situation. It has been around since Solaris 8. To be honest, it's not as easy to work with as sudo, but it comes ready to go and is more powerful (I think). You can set things up using smc or the command line.