Capturing caller id

Jeff Uphoff (juphoff@tarsier.cv.nrao.edu)
Tue, 7 Nov 1995 23:57:50 +0100


"GD" == Gert Doering <gert@greenie.muc.de> writes:

GD> How secure *is* perl? I'd never do something like that in /bin/sh, but
GD> perl is rumored to be quite secure...

It is.  With the -T option (or when running setuid or setgid), "taint"
checks are turned on.  This prevents a programmer from using his/her
copious amounts of stupidity unless said programmer is *really* intent
upon it.

Here's the perlsec(1) manual page for Perl v5, just for kicks:



PERLSEC(1)                                             PERLSEC(1)


NAME
       perlsec - Perl security

DESCRIPTION
       Perl is designed to make it easy to write secure setuid
       and setgid scripts.  Unlike shells, which are based on
       multiple substitution passes on each line of the script,
       Perl uses a more conventional evaluation scheme with fewer
       hidden "gotchas".  Additionally, since the language has
       more built-in functionality, it has to rely less upon
       external (and possibly untrustworthy) programs to
       accomplish its purposes.

       Beyond the obvious problems that stem from giving special
       privileges to such flexible systems as scripts, on many
       operating systems, setuid scripts are inherently insecure
       right from the start.  This is because that between the
       time that the kernel opens up the file to see what to run,
       and when the now setuid interpreter it ran turns around
       and reopens the file so it can interpret it, things may
       have changed, especially if you have symbolic links on
       your system.

       Fortunately, sometimes this kernel "feature" can be
       disabled.  Unfortunately, there are two ways to disable
       it.  The system can simply outlaw scripts with the setuid
       bit set, which doesn't help much.  Alternately, it can
       simply ignore the setuid bit on scripts.  If the latter is
       true, Perl can emulate the setuid and setgid mechanism
       when it notices the otherwise useless setuid/gid bits on
       Perl scripts.  It does this via a special executable
       called suidperl that is automatically invoked for you if
       it's needed.

       If, however, the kernel setuid script feature isn't
       disabled, Perl will complain loudly that your setuid
       script is insecure.  You'll need to either disable the
       kernel setuid script feature, or put a C wrapper around
       the script.  See the program wrapsuid in the eg directory
       of your Perl distribution for how to go about doing this.

       There are some systems on which setuid scripts are free of
       this inherent security bug.  For example, recent releases
       of Solaris are like this.  On such systems, when the
       kernel passes the name of the setuid script to open to the
       interpreter, rather than using a pathname subject to
       mettling, it instead passes /dev/fd/3.  This is a special
       file already opened on the script, so that there can be no
       race condition for evil scripts to exploit.  On these
       systems, Perl should be compiled with
       -DSETUID_SCRIPTS_ARE_SECURE_NOW.  The Configure program
       that builds Perl tries to figure this out for itself.

       When Perl is executing a setuid script, it takes special



                    Release 5.0 Patchlevel 01                   1





PERLSEC(1)                                             PERLSEC(1)


       precautions to prevent you from falling into any obvious
       traps.  (In some ways, a Perl script is more secure than
       the corresponding C program.)  Any command line argument,
       environment variable, or input is marked as "tainted", and
       may not be used, directly or indirectly, in any command
       that invokes a subshell, or in any command that modifies
       files, directories, or processes.  Any variable that is
       set within an expression that has previously referenced a
       tainted value also becomes tainted (even if it is
       logically impossible for the tainted value to influence
       the variable).  For example:

           $foo = shift;               # $foo is tainted
           $bar = $foo,'bar';          # $bar is also tainted
           $xxx = <>;                  # Tainted
           $path = $ENV{'PATH'};       # Tainted, but see below
           $abc = 'abc';               # Not tainted

           system "echo $foo";         # Insecure
           system "/bin/echo", $foo;   # Secure (doesn't use sh)
           system "echo $bar";         # Insecure
           system "echo $abc";         # Insecure until PATH set

           $ENV{'PATH'} = '/bin:/usr/bin';
           $ENV{'IFS'} = '' if $ENV{'IFS'} ne '';

           $path = $ENV{'PATH'};       # Not tainted
           system "echo $abc";         # Is secure now!

           open(FOO,"$foo");           # OK
           open(FOO,">$foo");          # Not OK

           open(FOO,"echo $foo|");     # Not OK, but...
           open(FOO,"-|") || exec 'echo', $foo;        # OK

           $zzz = `echo $foo`;         # Insecure, zzz tainted

           unlink $abc,$foo;           # Insecure
           umask $foo;                 # Insecure

           exec "echo $foo";           # Insecure
           exec "echo", $foo;          # Secure (doesn't use sh)
           exec "sh", '-c', $foo;      # Considered secure, alas

       The taintedness is associated with each scalar value, so
       some elements of an array can be tainted, and others not.

       If you try to do something insecure, you will get a fatal
       error saying something like "Insecure dependency" or
       "Insecure PATH".  Note that you can still write an
       insecure system call or exec, but only by explicitly doing
       something like the last example above.  You can also
       bypass the tainting mechanism by referencing
       subpatterns--Perl presumes that if you reference a



                    Release 5.0 Patchlevel 01                   2





PERLSEC(1)                                             PERLSEC(1)


       substring using $1, $2, etc, you knew what you were doing
       when you wrote the pattern:

           $ARGV[0] =~ /^-P(\w+)$/;
           $printer = $1;              # Not tainted

       This is fairly secure since \w+ doesn't match shell
       metacharacters.  Use of /.+/ would have been insecure, but
       Perl doesn't check for that, so you must be careful with
       your patterns.  This is the ONLY mechanism for untainting
       user supplied filenames if you want to do file operations
       on them (unless you make $> equal to $< ).

       For "Insecure $ENV{PATH}" messages, you need to set
       $ENV{'PATH'} to a known value, and each directory in the
       path must be non-writable by the world.  A frequently
       voiced gripe is that you can get this message even if the
       pathname to an executable is fully qualified.  But Perl
       can't know that the executable in question isn't going to
       execute some other program depending on the PATH.

       It's also possible to get into trouble with other
       operations that don't care whether they use tainted
       values.  Make judicious use of the file tests in dealing
       with any user-supplied filenames.  When possible, do opens
       and such after setting $> = $<.  (Remember group IDs,
       too!) Perl doesn't prevent you from opening tainted
       filenames for reading, so be careful what you print out.
       The tainting mechanism is intended to prevent stupid
       mistakes, not to remove the need for thought.



























                    Release 5.0 Patchlevel 01                   3