summaryrefslogtreecommitdiffstats
path: root/upstream/debian-bookworm/man1/perlsec.1
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/debian-bookworm/man1/perlsec.1
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/debian-bookworm/man1/perlsec.1')
-rw-r--r--upstream/debian-bookworm/man1/perlsec.1690
1 files changed, 690 insertions, 0 deletions
diff --git a/upstream/debian-bookworm/man1/perlsec.1 b/upstream/debian-bookworm/man1/perlsec.1
new file mode 100644
index 00000000..bc9370b1
--- /dev/null
+++ b/upstream/debian-bookworm/man1/perlsec.1
@@ -0,0 +1,690 @@
+.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "PERLSEC 1"
+.TH PERLSEC 1 "2023-11-25" "perl v5.36.0" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+perlsec \- Perl security
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+Perl is designed to make it easy to program securely even when running
+with extra privileges, like setuid or setgid programs. Unlike most
+command line shells, which are based on multiple substitution passes on
+each line of the script, Perl uses a more conventional evaluation scheme
+with fewer hidden snags. Additionally, because the language has more
+builtin functionality, it can rely less upon external (and possibly
+untrustworthy) programs to accomplish its purposes.
+.SH "SECURITY VULNERABILITY CONTACT INFORMATION"
+.IX Header "SECURITY VULNERABILITY CONTACT INFORMATION"
+If you believe you have found a security vulnerability in the Perl
+interpreter or modules maintained in the core Perl codebase,
+email the details to
+perl\-security@perl.org <mailto:perl-security@perl.org>.
+This address is a closed membership mailing list monitored by the Perl
+security team.
+.PP
+See perlsecpolicy for additional information.
+.SH "SECURITY MECHANISMS AND CONCERNS"
+.IX Header "SECURITY MECHANISMS AND CONCERNS"
+.SS "Taint mode"
+.IX Subsection "Taint mode"
+By default,
+Perl automatically enables a set of special security checks, called \fItaint
+mode\fR, when it detects its program running with differing real and effective
+user or group IDs. The setuid bit in Unix permissions is mode 04000, the
+setgid bit mode 02000; either or both may be set. You can also enable taint
+mode explicitly by using the \fB\-T\fR command line flag. This flag is
+\&\fIstrongly\fR suggested for server programs and any program run on behalf of
+someone else, such as a \s-1CGI\s0 script. Once taint mode is on, it's on for
+the remainder of your script.
+.PP
+While in this mode, Perl takes special precautions called \fItaint
+checks\fR to prevent both obvious and subtle traps. Some of these checks
+are reasonably simple, such as verifying that path directories aren't
+writable by others; careful programmers have always used checks like
+these. Other checks, however, are best supported by the language itself,
+and it is these checks especially that contribute to making a set-id Perl
+program more secure than the corresponding C program.
+.PP
+You may not use data derived from outside your program to affect
+something else outside your program\*(--at least, not by accident. All
+command line arguments, environment variables, locale information (see
+perllocale), results of certain system calls (\f(CW\*(C`readdir()\*(C'\fR,
+\&\f(CW\*(C`readlink()\*(C'\fR, the variable of \f(CW\*(C`shmread()\*(C'\fR, the messages returned by
+\&\f(CW\*(C`msgrcv()\*(C'\fR, the password, gcos and shell fields returned by the
+\&\f(CW\*(C`getpwxxx()\*(C'\fR calls), and all file input are marked as \*(L"tainted\*(R".
+Tainted data may not be used directly or indirectly in any command
+that invokes a sub-shell, nor in any command that modifies files,
+directories, or processes, \fBwith the following exceptions\fR:
+.PP
+Support for taint checks adds an overhead to all Perl programs,
+whether or not you're using the taint features.
+Perl 5.18 introduced C preprocessor symbols that can
+be used to disable the taint features.
+.IP "\(bu" 4
+Arguments to \f(CW\*(C`print\*(C'\fR and \f(CW\*(C`syswrite\*(C'\fR are \fBnot\fR checked for taintedness.
+.IP "\(bu" 4
+Symbolic methods
+.Sp
+.Vb 1
+\& $obj\->$method(@args);
+.Ve
+.Sp
+and symbolic sub references
+.Sp
+.Vb 2
+\& &{$foo}(@args);
+\& $foo\->(@args);
+.Ve
+.Sp
+are not checked for taintedness. This requires extra carefulness
+unless you want external data to affect your control flow. Unless
+you carefully limit what these symbolic values are, people are able
+to call functions \fBoutside\fR your Perl code, such as POSIX::system,
+in which case they are able to run arbitrary external code.
+.IP "\(bu" 4
+Hash keys are \fBnever\fR tainted.
+.PP
+For efficiency reasons, Perl takes a conservative view of
+whether data is tainted. If an expression contains tainted data,
+any subexpression may be considered tainted, even if the value
+of the subexpression is not itself affected by the tainted data.
+.PP
+Because taintedness is associated with each scalar value, some
+elements of an array or hash can be tainted and others not.
+The keys of a hash are \fBnever\fR tainted.
+.PP
+For example:
+.PP
+.Vb 8
+\& $arg = shift; # $arg is tainted
+\& $hid = $arg . \*(Aqbar\*(Aq; # $hid is also tainted
+\& $line = <>; # Tainted
+\& $line = <STDIN>; # Also tainted
+\& open FOO, "/home/me/bar" or die $!;
+\& $line = <FOO>; # Still tainted
+\& $path = $ENV{\*(AqPATH\*(Aq}; # Tainted, but see below
+\& $data = \*(Aqabc\*(Aq; # Not tainted
+\&
+\& system "echo $arg"; # Insecure
+\& system "/bin/echo", $arg; # Considered insecure
+\& # (Perl doesn\*(Aqt know about /bin/echo)
+\& system "echo $hid"; # Insecure
+\& system "echo $data"; # Insecure until PATH set
+\&
+\& $path = $ENV{\*(AqPATH\*(Aq}; # $path now tainted
+\&
+\& $ENV{\*(AqPATH\*(Aq} = \*(Aq/bin:/usr/bin\*(Aq;
+\& delete @ENV{\*(AqIFS\*(Aq, \*(AqCDPATH\*(Aq, \*(AqENV\*(Aq, \*(AqBASH_ENV\*(Aq};
+\&
+\& $path = $ENV{\*(AqPATH\*(Aq}; # $path now NOT tainted
+\& system "echo $data"; # Is secure now!
+\&
+\& open(FOO, "< $arg"); # OK \- read\-only file
+\& open(FOO, "> $arg"); # Not OK \- trying to write
+\&
+\& open(FOO,"echo $arg|"); # Not OK
+\& open(FOO,"\-|")
+\& or exec \*(Aqecho\*(Aq, $arg; # Also not OK
+\&
+\& $shout = \`echo $arg\`; # Insecure, $shout now tainted
+\&
+\& unlink $data, $arg; # Insecure
+\& umask $arg; # Insecure
+\&
+\& exec "echo $arg"; # Insecure
+\& exec "echo", $arg; # Insecure
+\& exec "sh", \*(Aq\-c\*(Aq, $arg; # Very insecure!
+\&
+\& @files = <*.c>; # insecure (uses readdir() or similar)
+\& @files = glob(\*(Aq*.c\*(Aq); # insecure (uses readdir() or similar)
+\&
+\& # In either case, the results of glob are tainted, since the list of
+\& # filenames comes from outside of the program.
+\&
+\& $bad = ($arg, 23); # $bad will be tainted
+\& $arg, \`true\`; # Insecure (although it isn\*(Aqt really)
+.Ve
+.PP
+If you try to do something insecure, you will get a fatal error saying
+something like \*(L"Insecure dependency\*(R" or \*(L"Insecure \f(CW$ENV\fR{\s-1PATH\s0}\*(R".
+.PP
+The exception to the principle of \*(L"one tainted value taints the whole
+expression\*(R" is with the ternary conditional operator \f(CW\*(C`?:\*(C'\fR. Since code
+with a ternary conditional
+.PP
+.Vb 1
+\& $result = $tainted_value ? "Untainted" : "Also untainted";
+.Ve
+.PP
+is effectively
+.PP
+.Vb 5
+\& if ( $tainted_value ) {
+\& $result = "Untainted";
+\& } else {
+\& $result = "Also untainted";
+\& }
+.Ve
+.PP
+it doesn't make sense for \f(CW$result\fR to be tainted.
+.SS "Laundering and Detecting Tainted Data"
+.IX Subsection "Laundering and Detecting Tainted Data"
+To test whether a variable contains tainted data, and whose use would
+thus trigger an \*(L"Insecure dependency\*(R" message, you can use the
+\&\f(CW\*(C`tainted()\*(C'\fR function of the Scalar::Util module, available in your
+nearby \s-1CPAN\s0 mirror, and included in Perl starting from the release 5.8.0.
+Or you may be able to use the following \f(CW\*(C`is_tainted()\*(C'\fR function.
+.PP
+.Vb 4
+\& sub is_tainted {
+\& local $@; # Don\*(Aqt pollute caller\*(Aqs value.
+\& return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
+\& }
+.Ve
+.PP
+This function makes use of the fact that the presence of tainted data
+anywhere within an expression renders the entire expression tainted. It
+would be inefficient for every operator to test every argument for
+taintedness. Instead, the slightly more efficient and conservative
+approach is used that if any tainted value has been accessed within the
+same expression, the whole expression is considered tainted.
+.PP
+But testing for taintedness gets you only so far. Sometimes you have just
+to clear your data's taintedness. Values may be untainted by using them
+as keys in a hash; otherwise the only way to bypass the tainting
+mechanism is by referencing subpatterns from a regular expression match.
+Perl presumes that if you reference a substring using \f(CW$1\fR, \f(CW$2\fR, etc. in a
+non-tainting pattern, that
+you knew what you were doing when you wrote that pattern. That means using
+a bit of thought\*(--don't just blindly untaint anything, or you defeat the
+entire mechanism. It's better to verify that the variable has only good
+characters (for certain values of \*(L"good\*(R") rather than checking whether it
+has any bad characters. That's because it's far too easy to miss bad
+characters that you never thought of.
+.PP
+Here's a test to make sure that the data contains nothing but \*(L"word\*(R"
+characters (alphabetics, numerics, and underscores), a hyphen, an at sign,
+or a dot.
+.PP
+.Vb 5
+\& if ($data =~ /^([\-\e@\ew.]+)$/) {
+\& $data = $1; # $data now untainted
+\& } else {
+\& die "Bad data in \*(Aq$data\*(Aq"; # log this somewhere
+\& }
+.Ve
+.PP
+This is fairly secure because \f(CW\*(C`/\ew+/\*(C'\fR doesn't normally match shell
+metacharacters, nor are dot, dash, or at going to mean something special
+to the shell. Use of \f(CW\*(C`/.+/\*(C'\fR would have been insecure in theory because
+it lets everything through, but Perl doesn't check for that. The lesson
+is that when untainting, you must be exceedingly careful with your patterns.
+Laundering data using regular expression is the \fIonly\fR mechanism for
+untainting dirty data, unless you use the strategy detailed below to fork
+a child of lesser privilege.
+.PP
+The example does not untaint \f(CW$data\fR if \f(CW\*(C`use locale\*(C'\fR is in effect,
+because the characters matched by \f(CW\*(C`\ew\*(C'\fR are determined by the locale.
+Perl considers that locale definitions are untrustworthy because they
+contain data from outside the program. If you are writing a
+locale-aware program, and want to launder data with a regular expression
+containing \f(CW\*(C`\ew\*(C'\fR, put \f(CW\*(C`no locale\*(C'\fR ahead of the expression in the same
+block. See \*(L"\s-1SECURITY\*(R"\s0 in perllocale for further discussion and examples.
+.ie n .SS "Switches On the ""#!"" Line"
+.el .SS "Switches On the ``#!'' Line"
+.IX Subsection "Switches On the #! Line"
+When you make a script executable, in order to make it usable as a
+command, the system will pass switches to perl from the script's #!
+line. Perl checks that any command line switches given to a setuid
+(or setgid) script actually match the ones set on the #! line. Some
+Unix and Unix-like environments impose a one-switch limit on the #!
+line, so you may need to use something like \f(CW\*(C`\-wU\*(C'\fR instead of \f(CW\*(C`\-w \-U\*(C'\fR
+under such systems. (This issue should arise only in Unix or
+Unix-like environments that support #! and setuid or setgid scripts.)
+.ie n .SS "Taint mode and @INC"
+.el .SS "Taint mode and \f(CW@INC\fP"
+.IX Subsection "Taint mode and @INC"
++When the taint mode (\f(CW\*(C`\-T\*(C'\fR) is in effect, the environment variables
++\f(CW\*(C`PERL5LIB\*(C'\fR, \f(CW\*(C`PERLLIB\*(C'\fR, and \f(CW\*(C`PERL_USE_UNSAFE_INC\*(C'\fR
+are ignored by Perl. You can still adjust \f(CW@INC\fR from outside the
+program by using the \f(CW\*(C`\-I\*(C'\fR command line option as explained in
+perlrun. The two environment variables are
+ignored because they are obscured, and a user running a program could
+be unaware that they are set, whereas the \f(CW\*(C`\-I\*(C'\fR option is clearly
+visible and therefore permitted.
+.PP
+Another way to modify \f(CW@INC\fR without modifying the program, is to use
+the \f(CW\*(C`lib\*(C'\fR pragma, e.g.:
+.PP
+.Vb 1
+\& perl \-Mlib=/foo program
+.Ve
+.PP
+The benefit of using \f(CW\*(C`\-Mlib=/foo\*(C'\fR over \f(CW\*(C`\-I/foo\*(C'\fR, is that the former
+will automagically remove any duplicated directories, while the latter
+will not.
+.PP
+Note that if a tainted string is added to \f(CW@INC\fR, the following
+problem will be reported:
+.PP
+.Vb 1
+\& Insecure dependency in require while running with \-T switch
+.Ve
+.PP
+On versions of Perl before 5.26, activating taint mode will also remove
+the current directory (\*(L".\*(R") from the default value of \f(CW@INC\fR. Since
+version 5.26, the current directory isn't included in \f(CW@INC\fR by
+default.
+.SS "Cleaning Up Your Path"
+.IX Subsection "Cleaning Up Your Path"
+For "Insecure \f(CW$ENV{PATH}\fR" messages, you need to set \f(CW$ENV{\*(AqPATH\*(Aq}\fR to
+a known value, and each directory in the path must be absolute and
+non-writable by others than its owner and group. You may be surprised to
+get this message even if the pathname to your executable is fully
+qualified. This is \fInot\fR generated because you didn't supply a full path
+to the program; instead, it's generated because you never set your \s-1PATH\s0
+environment variable, or you didn't set it to something that was safe.
+Because Perl can't guarantee that the executable in question isn't itself
+going to turn around and execute some other program that is dependent on
+your \s-1PATH,\s0 it makes sure you set the \s-1PATH.\s0
+.PP
+The \s-1PATH\s0 isn't the only environment variable which can cause problems.
+Because some shells may use the variables \s-1IFS, CDPATH, ENV,\s0 and
+\&\s-1BASH_ENV,\s0 Perl checks that those are either empty or untainted when
+starting subprocesses. You may wish to add something like this to your
+setid and taint-checking scripts.
+.PP
+.Vb 1
+\& delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer
+.Ve
+.PP
+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 \fBafter\fR properly dropping any special user (or group!)
+privileges. 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.
+.PP
+Perl does not call the shell to expand wild cards when you pass \f(CW\*(C`system\*(C'\fR
+and \f(CW\*(C`exec\*(C'\fR explicit parameter lists instead of strings with possible shell
+wildcards in them. Unfortunately, the \f(CW\*(C`open\*(C'\fR, \f(CW\*(C`glob\*(C'\fR, and
+backtick functions provide no such alternate calling convention, so more
+subterfuge will be required.
+.PP
+Perl provides a reasonably safe way to open a file or pipe from a setuid
+or setgid program: just create a child process with reduced privilege who
+does the dirty work for you. First, fork a child using the special
+\&\f(CW\*(C`open\*(C'\fR syntax that connects the parent and child by a pipe. Now the
+child resets its \s-1ID\s0 set and any other per-process attributes, like
+environment variables, umasks, current working directories, back to the
+originals or known safe values. Then the child process, which no longer
+has any special permissions, does the \f(CW\*(C`open\*(C'\fR or other system call.
+Finally, the child passes the data it managed to access back to the
+parent. Because the file or pipe was opened in the child while running
+under less privilege than the parent, it's not apt to be tricked into
+doing something it shouldn't.
+.PP
+Here's a way to do backticks reasonably safely. Notice how the \f(CW\*(C`exec\*(C'\fR is
+not called with a string that the shell could expand. This is by far the
+best way to call something that might be subjected to shell escapes: just
+never call the shell at all.
+.PP
+.Vb 10
+\& use English;
+\& die "Can\*(Aqt fork: $!" unless defined($pid = open(KID, "\-|"));
+\& if ($pid) { # parent
+\& while (<KID>) {
+\& # do something
+\& }
+\& close KID;
+\& } else {
+\& my @temp = ($EUID, $EGID);
+\& my $orig_uid = $UID;
+\& my $orig_gid = $GID;
+\& $EUID = $UID;
+\& $EGID = $GID;
+\& # Drop privileges
+\& $UID = $orig_uid;
+\& $GID = $orig_gid;
+\& # Make sure privs are really gone
+\& ($EUID, $EGID) = @temp;
+\& die "Can\*(Aqt drop privileges"
+\& unless $UID == $EUID && $GID eq $EGID;
+\& $ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH.
+\& # Consider sanitizing the environment even more.
+\& exec \*(Aqmyprog\*(Aq, \*(Aqarg1\*(Aq, \*(Aqarg2\*(Aq
+\& or die "can\*(Aqt exec myprog: $!";
+\& }
+.Ve
+.PP
+A similar strategy would work for wildcard expansion via \f(CW\*(C`glob\*(C'\fR, although
+you can use \f(CW\*(C`readdir\*(C'\fR instead.
+.PP
+Taint checking is most useful when although you trust yourself not to have
+written a program to give away the farm, you don't necessarily trust those
+who end up using it not to try to trick it into doing something bad. This
+is the kind of security checking that's useful for set-id programs and
+programs launched on someone else's behalf, like \s-1CGI\s0 programs.
+.PP
+This is quite different, however, from not even trusting the writer of the
+code not to try to do something evil. That's the kind of trust needed
+when someone hands you a program you've never seen before and says, \*(L"Here,
+run this.\*(R" For that kind of safety, you might want to check out the Safe
+module, included standard in the Perl distribution. This module allows the
+programmer to set up special compartments in which all system operations
+are trapped and namespace access is carefully controlled. Safe should
+not be considered bullet-proof, though: it will not prevent the foreign
+code to set up infinite loops, allocate gigabytes of memory, or even
+abusing perl bugs to make the host interpreter crash or behave in
+unpredictable ways. In any case it's better avoided completely if you're
+really concerned about security.
+.SS "Shebang Race Condition"
+.IX Subsection "Shebang Race Condition"
+Beyond the obvious problems that stem from giving special privileges to
+systems as flexible as scripts, on many versions of Unix, set-id scripts
+are inherently insecure right from the start. The problem is a race
+condition in the kernel. Between the time the kernel opens the file to
+see which interpreter to run and when the (now-set-id) interpreter turns
+around and reopens the file to interpret it, the file in question may have
+changed, especially if you have symbolic links on your system.
+.PP
+Some Unixes, especially more recent ones, are free of this
+inherent security bug. On such systems, when the kernel passes the name
+of the set-id script to open to the interpreter, rather than using a
+pathname subject to meddling, it instead passes \fI/dev/fd/3\fR. 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 \f(CW\*(C`\-DSETUID_SCRIPTS_ARE_SECURE_NOW\*(C'\fR. The \fIConfigure\fR
+program that builds Perl tries to figure this out for itself, so you
+should never have to specify this yourself. Most modern releases of
+SysVr4 and \s-1BSD 4.4\s0 use this approach to avoid the kernel race condition.
+.PP
+If you don't have the safe version of set-id scripts, all is not lost.
+Sometimes this kernel \*(L"feature\*(R" can be disabled, so that the kernel
+either doesn't run set-id scripts with the set-id or doesn't run them
+at all. Either way avoids the exploitability of the race condition,
+but doesn't help in actually running scripts set-id.
+.PP
+If the kernel set-id script feature isn't disabled, then any set-id
+script provides an exploitable vulnerability. Perl can't avoid being
+exploitable, but will point out vulnerable scripts where it can. If Perl
+detects that it is being applied to a set-id script then it will complain
+loudly that your set-id script is insecure, and won't run it. When Perl
+complains, you need to remove the set-id bit from the script to eliminate
+the vulnerability. Refusing to run the script doesn't in itself close
+the vulnerability; it is just Perl's way of encouraging you to do this.
+.PP
+To actually run a script set-id, if you don't have the safe version of
+set-id scripts, you'll need to put a C wrapper around
+the script. A C wrapper is just a compiled program that does nothing
+except call your Perl program. Compiled programs are not subject to the
+kernel bug that plagues set-id scripts. Here's a simple wrapper, written
+in C:
+.PP
+.Vb 4
+\& #include <unistd.h>
+\& #include <stdio.h>
+\& #include <string.h>
+\& #include <errno.h>
+\&
+\& #define REAL_PATH "/path/to/script"
+\&
+\& int main(int argc, char **argv)
+\& {
+\& execv(REAL_PATH, argv);
+\& fprintf(stderr, "%s: %s: %s\en",
+\& argv[0], REAL_PATH, strerror(errno));
+\& return 127;
+\& }
+.Ve
+.PP
+Compile this wrapper into a binary executable and then make \fIit\fR rather
+than your script setuid or setgid. Note that this wrapper isn't doing
+anything to sanitise the execution environment other than ensuring
+that a safe path to the script is used. It only avoids the shebang
+race condition. It relies on Perl's own features, and on the script
+itself being careful, to make it safe enough to run the script set-id.
+.SS "Protecting Your Programs"
+.IX Subsection "Protecting Your Programs"
+There are a number of ways to hide the source to your Perl programs,
+with varying levels of \*(L"security\*(R".
+.PP
+First of all, however, you \fIcan't\fR take away read permission, because
+the source code has to be readable in order to be compiled and
+interpreted. (That doesn't mean that a \s-1CGI\s0 script's source is
+readable by people on the web, though.) So you have to leave the
+permissions at the socially friendly 0755 level. This lets
+people on your local system only see your source.
+.PP
+Some people mistakenly regard this as a security problem. If your program does
+insecure things, and relies on people not knowing how to exploit those
+insecurities, it is not secure. It is often possible for someone to
+determine the insecure things and exploit them without viewing the
+source. Security through obscurity, the name for hiding your bugs
+instead of fixing them, is little security indeed.
+.PP
+You can try using encryption via source filters (Filter::* from \s-1CPAN,\s0
+or Filter::Util::Call and Filter::Simple since Perl 5.8).
+But crackers might be able to decrypt it. You can try using the byte
+code compiler and interpreter described below, but crackers might be
+able to de-compile it. You can try using the native-code compiler
+described below, but crackers might be able to disassemble it. These
+pose varying degrees of difficulty to people wanting to get at your
+code, but none can definitively conceal it (this is true of every
+language, not just Perl).
+.PP
+If you're concerned about people profiting from your code, then the
+bottom line is that nothing but a restrictive license will give you
+legal security. License your software and pepper it with threatening
+statements like \*(L"This is unpublished proprietary software of \s-1XYZ\s0 Corp.
+Your access to it does not give you permission to use it blah blah
+blah.\*(R" You should see a lawyer to be sure your license's wording will
+stand up in court.
+.SS "Unicode"
+.IX Subsection "Unicode"
+Unicode is a new and complex technology and one may easily overlook
+certain security pitfalls. See perluniintro for an overview and
+perlunicode for details, and \*(L"Security Implications
+of Unicode\*(R" in perlunicode for security implications in particular.
+.SS "Algorithmic Complexity Attacks"
+.IX Subsection "Algorithmic Complexity Attacks"
+Certain internal algorithms used in the implementation of Perl can
+be attacked by choosing the input carefully to consume large amounts
+of either time or space or both. This can lead into the so-called
+\&\fIDenial of Service\fR (DoS) attacks.
+.IP "\(bu" 4
+Hash Algorithm \- Hash algorithms like the one used in Perl are well
+known to be vulnerable to collision attacks on their hash function.
+Such attacks involve constructing a set of keys which collide into
+the same bucket producing inefficient behavior. Such attacks often
+depend on discovering the seed of the hash function used to map the
+keys to buckets. That seed is then used to brute-force a key set which
+can be used to mount a denial of service attack. In Perl 5.8.1 changes
+were introduced to harden Perl to such attacks, and then later in
+Perl 5.18.0 these features were enhanced and additional protections
+added.
+.Sp
+At the time of this writing, Perl 5.18.0 is considered to be
+well-hardened against algorithmic complexity attacks on its hash
+implementation. This is largely owed to the following measures
+mitigate attacks:
+.RS 4
+.IP "Hash Seed Randomization" 4
+.IX Item "Hash Seed Randomization"
+In order to make it impossible to know what seed to generate an attack
+key set for, this seed is randomly initialized at process start. This
+may be overridden by using the \s-1PERL_HASH_SEED\s0 environment variable, see
+\&\*(L"\s-1PERL_HASH_SEED\*(R"\s0 in perlrun. This environment variable controls how
+items are actually stored, not how they are presented via
+\&\f(CW\*(C`keys\*(C'\fR, \f(CW\*(C`values\*(C'\fR and \f(CW\*(C`each\*(C'\fR.
+.IP "Hash Traversal Randomization" 4
+.IX Item "Hash Traversal Randomization"
+Independent of which seed is used in the hash function, \f(CW\*(C`keys\*(C'\fR,
+\&\f(CW\*(C`values\*(C'\fR, and \f(CW\*(C`each\*(C'\fR return items in a per-hash randomized order.
+Modifying a hash by insertion will change the iteration order of that hash.
+This behavior can be overridden by using \f(CW\*(C`hash_traversal_mask()\*(C'\fR from
+Hash::Util or by using the \s-1PERL_PERTURB_KEYS\s0 environment variable,
+see \*(L"\s-1PERL_PERTURB_KEYS\*(R"\s0 in perlrun. Note that this feature controls the
+\&\*(L"visible\*(R" order of the keys, and not the actual order they are stored in.
+.IP "Bucket Order Perturbance" 4
+.IX Item "Bucket Order Perturbance"
+When items collide into a given hash bucket the order they are stored in
+the chain is no longer predictable in Perl 5.18. This
+has the intention to make it harder to observe a
+collision. This behavior can be overridden by using
+the \s-1PERL_PERTURB_KEYS\s0 environment variable, see \*(L"\s-1PERL_PERTURB_KEYS\*(R"\s0 in perlrun.
+.IP "New Default Hash Function" 4
+.IX Item "New Default Hash Function"
+The default hash function has been modified with the intention of making
+it harder to infer the hash seed.
+.IP "Alternative Hash Functions" 4
+.IX Item "Alternative Hash Functions"
+The source code includes multiple hash algorithms to choose from. While we
+believe that the default perl hash is robust to attack, we have included the
+hash function Siphash as a fall-back option. At the time of release of
+Perl 5.18.0 Siphash is believed to be of cryptographic strength. This is
+not the default as it is much slower than the default hash.
+.RE
+.RS 4
+.Sp
+Without compiling a special Perl, there is no way to get the exact same
+behavior of any versions prior to Perl 5.18.0. The closest one can get
+is by setting \s-1PERL_PERTURB_KEYS\s0 to 0 and setting the \s-1PERL_HASH_SEED\s0
+to a known value. We do not advise those settings for production use
+due to the above security considerations.
+.Sp
+\&\fBPerl has never guaranteed any ordering of the hash keys\fR, and
+the ordering has already changed several times during the lifetime of
+Perl 5. Also, the ordering of hash keys has always been, and continues
+to be, affected by the insertion order and the history of changes made
+to the hash over its lifetime.
+.Sp
+Also note that while the order of the hash elements might be
+randomized, this \*(L"pseudo-ordering\*(R" should \fBnot\fR be used for
+applications like shuffling a list randomly (use \f(CW\*(C`List::Util::shuffle()\*(C'\fR
+for that, see List::Util, a standard core module since Perl 5.8.0;
+or the \s-1CPAN\s0 module \f(CW\*(C`Algorithm::Numerical::Shuffle\*(C'\fR), or for generating
+permutations (use e.g. the \s-1CPAN\s0 modules \f(CW\*(C`Algorithm::Permute\*(C'\fR or
+\&\f(CW\*(C`Algorithm::FastPermute\*(C'\fR), or for any cryptographic applications.
+.Sp
+Tied hashes may have their own ordering and algorithmic complexity
+attacks.
+.RE
+.IP "\(bu" 4
+Regular expressions \- Perl's regular expression engine is so called \s-1NFA\s0
+(Non-deterministic Finite Automaton), which among other things means that
+it can rather easily consume large amounts of both time and space if the
+regular expression may match in several ways. Careful crafting of the
+regular expressions can help but quite often there really isn't much
+one can do (the book \*(L"Mastering Regular Expressions\*(R" is required
+reading, see perlfaq2). Running out of space manifests itself by
+Perl running out of memory.
+.IP "\(bu" 4
+Sorting \- the quicksort algorithm used in Perls before 5.8.0 to
+implement the \fBsort()\fR function was very easy to trick into misbehaving
+so that it consumes a lot of time. Starting from Perl 5.8.0 a different
+sorting algorithm, mergesort, is used by default. Mergesort cannot
+misbehave on any input.
+.PP
+See <https://www.usenix.org/legacy/events/sec03/tech/full_papers/crosby/crosby.pdf> for more information,
+and any computer science textbook on algorithmic complexity.
+.SS "Using Sudo"
+.IX Subsection "Using Sudo"
+The popular tool \f(CW\*(C`sudo\*(C'\fR provides a controlled way for users to be able
+to run programs as other users. It sanitises the execution environment
+to some extent, and will avoid the shebang race condition. If you don't have the safe version of set-id scripts,
+then \f(CW\*(C`sudo\*(C'\fR may be a more convenient way of executing a script as
+another user than writing a C wrapper would be.
+.PP
+However, \f(CW\*(C`sudo\*(C'\fR sets the real user or group \s-1ID\s0 to that of the target
+identity, not just the effective \s-1ID\s0 as set-id bits do. As a result, Perl
+can't detect that it is running under \f(CW\*(C`sudo\*(C'\fR, and so won't automatically
+take its own security precautions such as turning on taint mode. Where
+\&\f(CW\*(C`sudo\*(C'\fR configuration dictates exactly which command can be run, the
+approved command may include a \f(CW\*(C`\-T\*(C'\fR option to perl to enable taint mode.
+.PP
+In general, it is necessary to evaluate the suitability of a script to
+run under \f(CW\*(C`sudo\*(C'\fR specifically with that kind of execution environment
+in mind. It is neither necessary nor sufficient for the same script to
+be suitable to run in a traditional set-id arrangement, though many of
+the issues overlap.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\*(L"\s-1ENVIRONMENT\*(R"\s0 in perlrun for its description of cleaning up environment
+variables.