summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'dev-lang/perl/files/perl-5.8.8-CAN-2005-0448-rmtree-2.patch')
-rw-r--r--dev-lang/perl/files/perl-5.8.8-CAN-2005-0448-rmtree-2.patch280
1 files changed, 280 insertions, 0 deletions
diff --git a/dev-lang/perl/files/perl-5.8.8-CAN-2005-0448-rmtree-2.patch b/dev-lang/perl/files/perl-5.8.8-CAN-2005-0448-rmtree-2.patch
new file mode 100644
index 000000000..d29fc2522
--- /dev/null
+++ b/dev-lang/perl/files/perl-5.8.8-CAN-2005-0448-rmtree-2.patch
@@ -0,0 +1,280 @@
+SECURITY [CAN-2005-0448]:
+
+Rewrite File::Path::rmtree to avoid race condition which allows an
+attacker with write permission on directories in the tree being
+removed to make files setuid or to remove arbitrary files (see
+http://bugs.debian.org/286905 and http://bugs.debian.org/286922).
+
+Revised for 5.8.8-7etch6 to avoid failure when rmtree removes the
+current directory.
+
+diff --git a/lib/File/Path.pm b/lib/File/Path.pm
+index 2e41ff3..fd32b96 100644
+--- a/lib/File/Path.pm
++++ b/lib/File/Path.pm
+@@ -72,33 +72,17 @@ or C<unlink> to remove it, or that it's skipping it.
+
+ =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:> There are race conditions internal to the implementation of
+-C<rmtree> making it unsafe to use on directory trees which may be
+-altered or moved while C<rmtree> is running, and in particular on any
+-directory trees with any path components or subdirectories potentially
+-writable by untrusted users.
+-
+-Additionally, if the third parameter is not TRUE and C<rmtree> is
+-interrupted, it may leave files and directories with permissions altered
+-to allow deletion (and older versions of this module would even set
+-files and directories to world-read/writable!)
+-
+-Note also that the occurrence of errors in C<rmtree> can be determined I<only>
+-by trapping diagnostic messages using C<$SIG{__WARN__}>; it is not apparent
+-from the return value.
+-
+ =head1 DIAGNOSTICS
+
+ =over 4
+@@ -172,111 +156,127 @@ sub mkpath {
+ @created;
+ }
+
+-sub rmtree {
+- my($roots, $verbose, $safe) = @_;
+- my(@files);
+- my($count) = 0;
+- $verbose ||= 0;
+- $safe ||= 0;
++sub _rmtree;
++sub _rmtree
++{
++ my ($path, $prefix, $up, $up_dev, $up_ino, $verbose, $safe) = @_;
++ my $up_name = $up eq '..' ? 'parent' : 'initial';
++
++ my ($dev, $ino) = lstat $path or return 0;
++ unless (-d _)
++ {
++ print "unlink $prefix$path\n" if $verbose;
++ unless (unlink $path)
++ {
++ carp "Can't remove file $prefix$path ($!)";
++ return 0;
++ }
+
+- if ( defined($roots) && length($roots) ) {
+- $roots = [$roots] unless ref $roots;
++ return 1;
+ }
+- else {
+- carp "No root path(s) specified\n";
+- return 0;
++
++ unless (chdir $path)
++ {
++ carp "Can't chdir to $prefix$path ($!)";
++ return 0;
+ }
+
+- my($root);
+- foreach $root (@{$roots}) {
+- if ($Is_MacOS) {
+- $root = ":$root" if $root !~ /:/;
+- $root =~ s#([^:])\z#$1:#;
+- } else {
+- $root =~ s#/\z##;
+- }
+- (undef, undef, my $rp) = lstat $root or next;
+- $rp &= 07777; # don't forget setuid, setgid, sticky bits
+- if ( -d _ ) {
+- # notabene: 0700 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($rp | 0700, ($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 = ();
+- }
++ # 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";
++ }
+
+- # 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 $rp | 0700, $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 $rp | 0600, $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;
+- }
++ $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_name directory 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 "\u$up_name directory 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;
++ }
++
++ opendir my $oldpwd, '.' or do {
++ carp "Can't fetch initial working directory";
++ return;
++ };
++
++ my ($dev, $ino) = stat '.' or do {
++ carp "Can't stat initial working directory";
++ return;
++ };
++
++ my $count = 0;
++ for my $path (@paths)
++ {
++ $count += _rmtree $path, '', $oldpwd, $dev, $ino, $verbose, $safe;
+ }
+
+ $count;