Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 52935 Details for
Bug 79685
dev-lang/perl: File::Path::rmtree still vulnerable to a race condition
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
rmtree.patch
rmtree.patch (text/plain), 7.49 KB, created by
Thierry Carrez (RETIRED)
on 2005-03-08 05:56:25 UTC
(
hide
)
Description:
rmtree.patch
Filename:
MIME Type:
Creator:
Thierry Carrez (RETIRED)
Created:
2005-03-08 05:56:25 UTC
Size:
7.49 KB
patch
obsolete
>--- perl-5.8.4.orig/lib/File/Path.pm >+++ perl-5.8.4/lib/File/Path.pm >@@ -72,27 +72,17 @@ > > =item * > >-a boolean value, which if TRUE will cause C<rmtree> to >-skip any files to which you do not have delete access >-(if running under VMS) or write access (if running >-under another OS). This will change in the future when >-a criterion for 'delete permission' under OSs other >-than VMS is settled. (defaults to FALSE) >+a boolean value, which if FALSE (the default for non-root users) will >+cause C<rmtree> to adjust the mode of directories (if required) prior >+to attempting to remove the contents. Note that on interruption or >+failure of C<rmtree>, directories may be left with more permissive >+modes for the owner. > > =back > > It returns the number of files successfully deleted. Symlinks are > simply deleted and not followed. > >-B<NOTE:> If the third parameter is not TRUE, C<rmtree> is B<unsecure> >-in the face of failure or interruption. Files and directories which >-were not deleted may be left with permissions reset to allow world >-read and write access. Note also that the occurrence of errors in >-rmtree can be determined I<only> by trapping diagnostic messages >-using C<$SIG{__WARN__}>; it is not apparent from the return value. >-Therefore, you must be extremely careful about using C<rmtree($foo,$bar,0)> >-in situations where security is an issue. >- > =head1 DIAGNOSTICS > > =over 4 >@@ -118,6 +108,7 @@ > use Exporter (); > use strict; > use warnings; >+use Cwd 'getcwd'; > > our $VERSION = "1.06"; > our @ISA = qw( Exporter ); >@@ -166,111 +157,133 @@ > @created; > } > >-sub rmtree { >- my($roots, $verbose, $safe) = @_; >- my(@files); >- my($count) = 0; >- $verbose ||= 0; >- $safe ||= 0; >- >- if ( defined($roots) && length($roots) ) { >- $roots = [$roots] unless ref $roots; >- } >- else { >- carp "No root path(s) specified\n"; >- return 0; >- } >- >- my($root); >- foreach $root (@{$roots}) { >- if ($Is_MacOS) { >- $root = ":$root" if $root !~ /:/; >- $root =~ s#([^:])\z#$1:#; >- } else { >- $root =~ s#/\z##; >+sub _rmtree; >+sub _rmtree >+{ >+ my ($path, $prefix, $up, $up_dev, $up_ino, $verbose, $safe) = @_; >+ >+ my ($dev, $ino) = lstat $path or do { >+ carp "Can't stat $prefix$path ($!)" unless $!{ENOENT}; >+ return 0; >+ }; >+ >+ unless (-d _) >+ { >+ print "unlink $prefix$path\n" if $verbose; >+ unless (unlink $path) >+ { >+ carp "Can't remove file $prefix$path ($!)"; >+ return 0; > } >- (undef, undef, my $rp) = lstat $root or next; >- $rp &= 07777; # don't forget setuid, setgid, sticky bits >- if ( -d _ ) { >- # notabene: 0777 is for making readable in the first place, >- # it's also intended to change it to writable in case we have >- # to recurse in which case we are better than rm -rf for >- # subtrees with strange permissions >- chmod(0777, ($Is_VMS ? VMS::Filespec::fileify($root) : $root)) >- or carp "Can't make directory $root read+writeable: $!" >- unless $safe; >- >- if (opendir my $d, $root) { >- no strict 'refs'; >- if (!defined ${"\cTAINT"} or ${"\cTAINT"}) { >- # Blindly untaint dir names >- @files = map { /^(.*)$/s ; $1 } readdir $d; >- } else { >- @files = readdir $d; >- } >- closedir $d; >- } >- else { >- carp "Can't read $root: $!"; >- @files = (); >- } > >- # Deleting large numbers of files from VMS Files-11 filesystems >- # is faster if done in reverse ASCIIbetical order >- @files = reverse @files if $Is_VMS; >- ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS; >- if ($Is_MacOS) { >- @files = map("$root$_", @files); >- } else { >- @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files); >- } >- $count += rmtree(\@files,$verbose,$safe); >- if ($safe && >- ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) { >- print "skipped $root\n" if $verbose; >- next; >- } >- chmod 0777, $root >- or carp "Can't make directory $root writeable: $!" >- if $force_writeable; >- print "rmdir $root\n" if $verbose; >- if (rmdir $root) { >- ++$count; >- } >- else { >- carp "Can't remove directory $root: $!"; >- chmod($rp, ($Is_VMS ? VMS::Filespec::fileify($root) : $root)) >- or carp("and can't restore permissions to " >- . sprintf("0%o",$rp) . "\n"); >- } >- } >- else { >- if ($safe && >- ($Is_VMS ? !&VMS::Filespec::candelete($root) >- : !(-l $root || -w $root))) >- { >- print "skipped $root\n" if $verbose; >- next; >- } >- chmod 0666, $root >- or carp "Can't make file $root writeable: $!" >- if $force_writeable; >- print "unlink $root\n" if $verbose; >- # delete all versions under VMS >- for (;;) { >- unless (unlink $root) { >- carp "Can't unlink file $root: $!"; >- if ($force_writeable) { >- chmod $rp, $root >- or carp("and can't restore permissions to " >- . sprintf("0%o",$rp) . "\n"); >- } >- last; >- } >- ++$count; >- last unless $Is_VMS && lstat $root; >- } >+ return 1; >+ } >+ >+ unless (chdir $path) >+ { >+ carp "Can't chdir to $prefix$path ($!)"; >+ return 0; >+ } >+ >+ # avoid a race condition where a directory may be replaced by a >+ # symlink between the lstat and the chdir >+ my ($new_dev, $new_ino, $perm) = stat '.'; >+ unless ("$new_dev:$new_ino" eq "$dev:$ino") >+ { >+ croak "Directory $prefix$path changed before chdir, aborting"; >+ } >+ >+ $perm &= 07777; >+ my $nperm = $perm | 0700; >+ unless ($safe or $nperm == $perm or chmod $nperm, '.') >+ { >+ carp "Can't make directory $prefix$path read+writeable ($!)"; >+ $nperm = $perm; >+ } >+ >+ my $count = 0; >+ if (opendir my $dir, '.') >+ { >+ my $entry; >+ while (defined ($entry = readdir $dir)) >+ { >+ next if $entry =~ /^\.\.?$/; >+ $entry =~ /^(.*)$/s; $entry = $1; # untaint >+ $count += _rmtree $entry, "$prefix$path/", '..', $dev, $ino, >+ $verbose, $safe; > } >+ >+ closedir $dir; >+ } >+ >+ # restore directory permissions if required (in case the rmdir >+ # below fails) now, while we're still in the directory and may do >+ # so without a race via '.' >+ unless ($nperm == $perm or chmod $perm, '.') >+ { >+ carp "Can't restore permissions on directory $prefix$path ($!)"; >+ } >+ >+ # don't leave the caller in an unexpected directory >+ unless (chdir $up) >+ { >+ croak "Can't return to $up from $prefix$path ($!)"; >+ } >+ >+ # ensure that a chdir .. didn't take us somewhere other than >+ # where we expected (see CVE-2002-0435) >+ unless (($new_dev, $new_ino) = stat '.' >+ and "$new_dev:$new_ino" eq "$up_dev:$up_ino") >+ { >+ croak "Previous directory $up changed since entering $prefix$path"; >+ } >+ >+ print "rmdir $prefix$path\n" if $verbose; >+ if (rmdir $path) >+ { >+ $count++; >+ } >+ else >+ { >+ carp "Can't remove directory $prefix$path ($!)"; >+ } >+ >+ return $count; >+} >+ >+sub rmtree >+{ >+ my ($p, $verbose, $safe) = @_; >+ $p = [] unless defined $p and length $p; >+ $p = [ $p ] unless ref $p; >+ my @paths = grep defined && length, @$p; >+ >+ # default to "unsafe" for non-root (will chmod dirs) >+ $safe = $> ? 0 : 1 unless defined $safe; >+ >+ unless (@paths) >+ { >+ carp "No root path(s) specified"; >+ return; >+ } >+ >+ my $oldpwd = getcwd or do { >+ carp "Can't fetch initial working directory"; >+ return; >+ }; >+ >+ my ($dev, $ino) = stat '.' or do { >+ carp "Can't stat initial working directory"; >+ return; >+ }; >+ >+ # untaint >+ for ($oldpwd) { /^(.*)$/s; $_ = $1 } >+ >+ my $count = 0; >+ for my $path (@paths) >+ { >+ $count += _rmtree $path, '', $oldpwd, $dev, $ino, $verbose, $safe; > } > > $count;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 79685
: 52935