From: ram@eiffel.com (Raphael Manfredi)
Newsgroups: comp.lang.perl
Subject: Official patch for perload script
Summary: perload forgot about taintperl
Keywords: autoloading, dataloading, taintperl, bug
Date: 14 Aug 92 17:00:48 GMT
Organization: Interactive Software Engineering, Santa Barbara CA

Laurence Yaffe <lgy@landau.phys.washington.edu> was kind enough to
bring to my attention the fact that perload did not consider setuid
scripts.

Actually, there seems to be a severe bug in taintperl which causes it
to loop when eval'ing a tainted variable, but this bug does not manifest
at once. It is a latent one, the most dangerous kind :-)

What happens with perl 4.0 PL35 is that perl reports the following
message:

	Warning: something's wrong at utest.dl line 374.

instead of the expected:

	Insecure dependency in eval at utest.dl line 374.

Ok... Here is the patch which solves this problem by forcing an untainting
of the loaded function body before eval'ing it. You need to use the new -t
option of perload to force those checks. They introduce some slight overhead,
which is why they are made optional (but unless you have CPU cycles to waste,
the -t option is useless if you do not expect your script to be run as
setuid -- or setgid, I presume).

Thanks again Laurence for letting me know about this problem.
--
Raphael Manfredi <ram@eiffel.com>
Interactive Software Engineering Inc.
270 Storke Road, Suite #7                      / Tel +1 (805) 685-1006 \
Goleta, California 93117, USA                  \ Fax +1 (805) 685-6869 /

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Following is the patch for perload. To apply, simply run

	patch -N < this_article

where "this_article" is a saved copy of this article.

*** perload.old	Fri Aug 14 09:53:38 1992
--- perload	Fri Aug 14 09:53:08 1992
***************
*** 8,14 ****
  # This perl script is its own manual page [generated by wrapman]
  #
  
! # $Id: perload,v 2.9.1.1 92/08/02 16:25:43 ram Exp Locker: ram $
  #
  #  Copyright (c) 1992, Raphael Manfredi
  #
--- 8,14 ----
  # This perl script is its own manual page [generated by wrapman]
  #
  
! # $Id: perload,v 2.9.1.2 92/08/12 21:36:54 ram Exp Locker: ram $
  #
  #  Copyright (c) 1992, Raphael Manfredi
  #
***************
*** 16,21 ****
--- 16,26 ----
  #  Licence as specified in the README file that comes with dist.
  #
  # $Log:	perload,v $
+ # Revision 2.9.1.2  92/08/12  21:36:54  ram
+ # patch6: new -o option which optimizes dataloading by building an offset table
+ # patch6: loading routines now avoid unnecessary strings operations
+ # patch6: previous changes contributed by Wayne Scott <wscott@ecn.purdue.edu>
+ # 
  # Revision 2.9.1.1  92/08/02  16:25:43  ram
  # patch2: dataloading routines now fully operate in perload package
  # 
***************
*** 154,160 ****
  }
  
  @auto = keys %Auto;
! print &q(<<'EOC') if @auto > 0;
  :# Load the calling function from file and call it. This function is called
  :# only once per file to be loaded.
  :sub main'autoload {
--- 159,166 ----
  }
  
  @auto = keys %Auto;
! if (@auto > 0) {
! 	print &q(<<'EOC');
  :# Load the calling function from file and call it. This function is called
  :# only once per file to be loaded.
  :sub main'autoload {
***************
*** 191,197 ****
--- 197,216 ----
  :		$body .= $_;
  :	}
  :	close FILE;
+ EOC
+ 	if ($opt_t) {
+ 		print &q(<<'EOC');
+ :	# Untaint body when running setuid
+ :	$body =~ /^([^\0]*)/;
+ :	# No need to untaint $load, as it was built using trusted variables
+ :	eval $1 . $load;
+ EOC
+ 	} else {
+ 		print &q(<<'EOC');
  :	eval $body . $load;
+ EOC
+ 	}
+ 	print &q(<<'EOC');
  :	chop($@) && die "$@, while parsing code of $file.\n";
  :}
  :
***************
*** 220,227 ****
  :}
  :
  EOC
  
! print &q(<<'EOC') if @Data > 0;
  :# Load the calling function from DATA segment and call it. This function is
  :# called only once per routine to be loaded.
  :sub main'dataload {
--- 239,248 ----
  :}
  :
  EOC
+ }
  
! if (@Data > 0) {
! 	print &q(<<'EOC');
  :# Load the calling function from DATA segment and call it. This function is
  :# called only once per routine to be loaded.
  :sub main'dataload {
***************
*** 253,265 ****
  :	local($body) = scalar(<main'DATA>);
  :	local($*) = 1;
  :	die "End of file found while loading $_[0].\n" unless $body =~ /^\}$/;
  :	eval $body;		# Load function into perl space
  :	chop($@) && die "$@, while parsing code of $_[0].\n";
  :}
  :
  EOC
- 
- if (@Data > 0) {
  	print &q(<<'EOC') unless $opt_o;
  :# Parse text after the END token and record defined loadable functions (i.e.
  :# those whose name starts with load_) into the %Datapos array. Such function
--- 274,297 ----
  :	local($body) = scalar(<main'DATA>);
  :	local($*) = 1;
  :	die "End of file found while loading $_[0].\n" unless $body =~ /^\}$/;
+ EOC
+ 	if ($opt_t) {
+ 		print &q(<<'EOC')
+ :	# Untaint body when running setuid
+ :	$body =~ /^([^\0]*)/;
+ :	# Now we may safely eval it without getting an insecure dependency
+ :	eval $1;		# Load function into perl space
+ EOC
+ 	} else {
+ 		print &q(<<'EOC');
  :	eval $body;		# Load function into perl space
+ EOC
+ 	}
+ 	print &q(<<'EOC');
  :	chop($@) && die "$@, while parsing code of $_[0].\n";
  :}
  :
  EOC
  	print &q(<<'EOC') unless $opt_o;
  :# Parse text after the END token and record defined loadable functions (i.e.
  :# those whose name starts with load_) into the %Datapos array. Such function
***************
*** 453,459 ****
  perload \- builds up autoloaded and dataloaded perl scripts
  .SH SYNOPSIS
  .B perload
! [ \fB\-o\fR ]
  [ \fIfile\fR ]
  .SH DESCRIPTION
  .I Perload
--- 485,491 ----
  perload \- builds up autoloaded and dataloaded perl scripts
  .SH SYNOPSIS
  .B perload
! [ \fB\-ot\fR ]
  [ \fIfile\fR ]
  .SH DESCRIPTION
  .I Perload
***************
*** 550,557 ****
  directive (the inmost one). This does not turn off the \fIperload\fR processing
  though. The \fIpath\fR name is optional here (in fact, it has only a comment
  value).
! .SH OPTION
! Perload accepts only one option, \fB\-o\fR, which is meaningful only when
  dataloading is used. It outputs an offset table which lists the relative
  offset of the dataloaded functions within the data section. This will spare
  perl the run-time parsing needed to locate the function, and results in an good
--- 582,589 ----
  directive (the inmost one). This does not turn off the \fIperload\fR processing
  though. The \fIpath\fR name is optional here (in fact, it has only a comment
  value).
! .SH OPTIONS
! Perload accepts only two options. Using \fB\-o\fR is meaningful only when
  dataloading is used. It outputs an offset table which lists the relative
  offset of the dataloaded functions within the data section. This will spare
  perl the run-time parsing needed to locate the function, and results in an good
***************
*** 564,569 ****
--- 596,607 ----
  section is necessary for whatever reason. When \fB\-o\fR is used, any
  change in the dataloaded function must be committed by re-running perload
  on the original script.
+ .PP
+ The other option \fB\-t\fR is to be used when producing a script which is
+ going to run setuid. The body of the loaded function is untainted before being
+ fed to eval, which slightly slows down loading (the first time the function is
+ called), but avoids either an insecure dependency report or weird warnings from
+ taintperl stating something is wrong (which is the behaviour with 4.0 PL35).
  .SH FILES
  .TP 10
  auto

### End of patch ###
Newsgroups: comp.lang.perl