[dpkg] Fixes for CVE-2010-1679 CVE-2011-0402 (#668923)

topdog topdog at fedoraproject.org
Wed Jan 12 08:36:37 UTC 2011


commit 974a9c1590bb8ab1dc5f66774b20f042760b3f04
Author: Andrew Colin Kissa <andrew at topdog.za.net>
Date:   Wed Jan 12 10:27:28 2011 +0200

    Fixes for CVE-2010-1679 CVE-2011-0402 (#668923)

 .gitignore                                   |    1 +
 dpkg.spec                                    |    8 +-
 fedora-fix-CVE-2010-1679_CVE-2011-0402.patch |  176 ++++++++++++++++++++++++++
 3 files changed, 184 insertions(+), 1 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index c2fffab..0d52732 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 dpkg_1.15.5.6.tar.bz2
+/dpkg_1.15.5.6.tar.bz2
diff --git a/dpkg.spec b/dpkg.spec
index 91ceff0..c233462 100644
--- a/dpkg.spec
+++ b/dpkg.spec
@@ -1,6 +1,6 @@
 Name:           dpkg
 Version:        1.15.5.6
-Release:        5%{?dist}
+Release:        6%{?dist}
 Summary:        Package maintenance system for Debian Linux
 Group:          System Environment/Base
 # The entire source code is GPLv2+ with exception of the following
@@ -21,6 +21,7 @@ Patch1:         dpkg-change-libdir-path.patch
 Patch2:		fedora-fix-CVE-2010-0396-00.patch
 Patch3:		fedora-fix-CVE-2010-0396-01.patch
 Patch4:     fedora-bug642160-empty-argv.patch
+Patch5:		fedora-fix-CVE-2010-1679_CVE-2011-0402.patch
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires:  zlib-devel, bzip2-devel, libselinux-devel, gettext, ncurses-devel
 
@@ -65,6 +66,7 @@ dselect is a high-level interface for the installation/removal of debs .
 %patch2 -p1
 %patch3 -p1
 %patch4 -p1
+%patch5 -p1
 
 # Filter unwanted Requires:
 cat << \EOF > %{name}-req
@@ -203,6 +205,10 @@ rm -rf $RPM_BUILD_ROOT
 
 
 %changelog
+* Wed Jan 12 2011 Andrew Colin Kissa <andrew at topdog.za.net> - 1.15.5.6-6
+- Fix CVE-2010-1679
+- Fix CVE-2011-0402
+
 * Sun Oct 17 2010 Jeroen van Meeuwen <kanarip at kanarip.com> - 1.15.5.6-5
 - Apply minimal fix for rhbz #642160
 
diff --git a/fedora-fix-CVE-2010-1679_CVE-2011-0402.patch b/fedora-fix-CVE-2010-1679_CVE-2011-0402.patch
new file mode 100644
index 0000000..26ce08d
--- /dev/null
+++ b/fedora-fix-CVE-2010-1679_CVE-2011-0402.patch
@@ -0,0 +1,176 @@
+diff -ruN dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Archive.pm dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Archive.pm
+--- dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Archive.pm	2010-04-15 13:38:58.000000000 +0200
++++ dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Archive.pm	2011-01-06 21:08:30.000000000 +0200
+@@ -119,7 +119,7 @@
+     # Call tar extraction process
+     $fork_opts{"delete_env"} = [ "TAR_OPTIONS" ];
+     $fork_opts{'exec'} = [ 'tar', '--no-same-owner', '--no-same-permissions',
+-                           @{$opts{"options"}}, '-xkf', '-' ];
++                           @{$opts{"options"}}, '-xf', '-' ];
+     fork_and_exec(%fork_opts);
+     $self->cleanup_after_open();
+ 
+@@ -142,7 +142,7 @@
+     closedir(D);
+     my $done = 0;
+     erasedir($dest);
+-    if (scalar(@entries) == 1 && -d "$tmp/$entries[0]") {
++    if (scalar(@entries) == 1 && ! -l "$tmp/$entries[0]" && -d _) {
+ 	rename("$tmp/$entries[0]", $dest) ||
+ 		syserr(_g("Unable to rename %s to %s"),
+ 		       "$tmp/$entries[0]", $dest);
+diff -ruN dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Package/V2.pm dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Package/V2.pm
+--- dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Package/V2.pm	2010-04-15 13:38:58.000000000 +0200
++++ dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Package/V2.pm	2011-01-06 21:08:30.000000000 +0200
+@@ -115,7 +115,12 @@
+     # Extract main tarball
+     info(_g("unpacking %s"), $tarfile);
+     my $tar = Dpkg::Source::Archive->new(filename => "$dscdir$tarfile");
+-    $tar->extract($newdirectory, no_fixperms => 1);
++    $tar->extract($newdirectory, no_fixperms => 1,
++                  options => [ "--anchored", "--no-wildcards-match-slash",
++                               "--exclude", "*/.pc", "--exclude", ".pc" ]);
++    # The .pc exclusion is only needed for 3.0 (quilt) and to avoid
++    # having an upstream tarball provide a directory with symlinks
++    # that would be blindly followed when applying the patches
+ 
+     # Extract additional orig tarballs
+     foreach my $subdir (keys %origtar) {
+diff -ruN dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Patch.pm dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Patch.pm
+--- dpkg-1.15.5.6ubuntu4/scripts/Dpkg/Source/Patch.pm	2010-04-15 13:38:58.000000000 +0200
++++ dpkg-1.15.5.6ubuntu4.5//scripts/Dpkg/Source/Patch.pm	2011-01-06 21:08:30.000000000 +0200
+@@ -313,11 +313,42 @@
+         $header =~ s/\s.*// unless ($header =~ s/\t.*//);
+         return $header;
+     }
++
++    sub intuit_file_patched {
++	my ($old, $new) = @_;
++	return $new unless defined $old;
++	return $old unless defined $new;
++	return $new if -e $new and not -e $old;
++	return $old if -e $old and not -e $new;
++	# We don't consider the case where both files are non-existent and
++	# where patch picks the one with the fewest directories to create
++	# since dpkg-source will pre-create the required directories
++	#
++	# Precalculate metrics used by patch
++	my ($tmp_o, $tmp_n) = ($old, $new);
++	my ($len_o, $len_n) = (length($old), length($new));
++	$tmp_o =~ s{[/\\]+}{/}g;
++	$tmp_n =~ s{[/\\]+}{/}g;
++	my $nb_comp_o = ($tmp_o =~ tr{/}{/});
++	my $nb_comp_n = ($tmp_n =~ tr{/}{/});
++	$tmp_o =~ s{^.*/}{};
++	$tmp_n =~ s{^.*/}{};
++	my ($blen_o, $blen_n) = (length($tmp_o), length($tmp_n));
++	# Decide like patch would
++	if ($nb_comp_o != $nb_comp_n) {
++	    return ($nb_comp_o < $nb_comp_n) ? $old : $new;
++	} elsif ($blen_o != $blen_n) {
++	    return ($blen_o < $blen_n) ? $old : $new;
++	} elsif ($len_o != $len_n) {
++	    return ($len_o < $len_n) ? $old : $new;
++	}
++	return $old;
++    }
+     $_ = getline($diff_handle);
+ 
+   HUNK:
+     while (defined($_) || not eof($diff_handle)) {
+-	my ($fn, $fn2);
++	my (%path, %fn);
+ 	# skip comments leading up to patch (if any)
+ 	until (/^--- /) {
+ 	    last HUNK if not defined($_ = getline($diff_handle));
+@@ -327,11 +358,8 @@
+ 	unless(s/^--- //) {
+ 	    error(_g("expected ^--- in line %d of diff `%s'"), $., $diff);
+ 	}
+-        $_ = strip_ts($_);
+-        if ($_ eq '/dev/null' or s{^[^/]+/}{$destdir/}) {
+-            $fn = $_;
+-	    error(_g("%s contains an insecure path: %s"), $diff, $_) if m{/\.\./};
+-        }
++        $path{'old'} = $_ = strip_ts($_);
++	$fn{'old'} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
+ 	if (/\.dpkg-orig$/) {
+ 	    error(_g("diff `%s' patches file with name ending .dpkg-orig"), $diff);
+ 	}
+@@ -342,46 +370,47 @@
+ 	unless (s/^\+\+\+ //) {
+ 	    error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.);
+ 	}
+-        $_ = strip_ts($_);
+-        if ($_ eq '/dev/null' or s{^[^/]+/}{$destdir/}) {
+-            $fn2 = $_;
+-	    error(_g("%s contains an insecure path: %s"), $diff, $_) if m{/\.\./};
+-        } else {
+-            unless (defined $fn) {
+-                error(_g("none of the filenames in ---/+++ are relative in diff `%s' (line %d)"),
+-                      $diff, $.);
+-            }
+-        }
++        $path{'new'} = $_ = strip_ts($_);
++	$fn{'new'} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
++
++	unless (defined $fn{'old'} or defined $fn{'new'}) {
++	    error(_g("none of the filenames in ---/+++ are valid in diff '%s' (line %d)"),
++		  $diff, $.);
++	}
+ 
+-        if (defined($fn) and $fn eq '/dev/null') {
++	# Safety checks on both filenames that patch could use
++	foreach my $key ("old", "new") {
++	    next unless defined $fn{$key};
++	    if ($path{$key} =~ m{/\.\./}) {
++		error(_g("%s contains an insecure path: %s"), $diff, $path{$key});
++	    }
++	    my $path = $fn{$key};
++	    while (1) {
++		if (-l $path) {
++		    error(_g("diff %s modifies file %s through a symlink: %s"),
++			  $diff, $fn{$key}, $path);
++		}
++		last unless $path =~ s{/+[^/]*$}{};
++		last if length($path) <= length($destdir); # $destdir is assumed safe
++	    }
++	}
++
++        if ($path{'old'} eq '/dev/null' and $path{'new'} eq '/dev/null') {
+             error(_g("original and modified files are /dev/null in diff `%s' (line %d)"),
+-                  $diff, $.) if (defined($fn2) and $fn2 eq '/dev/null');
+-            $fn = $fn2;
+-        } elsif (defined($fn2) and $fn2 ne '/dev/null') {
+-            $fn = $fn2 unless defined $fn;
+-            $fn = $fn2 if ((not -e $fn) and -e $fn2);
+-        } elsif (defined($fn2) and $fn2 eq '/dev/null') {
++                  $diff, $.);
++        } elsif ($path{'new'} eq '/dev/null') {
+             error(_g("file removal without proper filename in diff `%s' (line %d)"),
+-                  $diff, $. - 1) unless defined $fn;
++                  $diff, $. - 1) unless defined $fn{'old'};
+             warning(_g("diff %s removes a non-existing file %s (line %d)"),
+-                    $diff, $fn, $.) unless -e $fn;
++                    $diff, $fn{'old'}, $.) unless -e $fn{'old'};
+         }
++	my $fn = intuit_file_patched($fn{'old'}, $fn{'new'});
+ 
+ 	my $dirname = $fn;
+ 	if ($dirname =~ s{/[^/]+$}{} && not -d $dirname) {
+ 	    $dirtocreate{$dirname} = 1;
+ 	}
+ 
+-	# Sanity check, refuse to patch through a symlink
+-	$dirname = $fn;
+-	while (1) {
+-	    if (-l $dirname) {
+-		error(_g("diff %s modifies file %s through a symlink: %s"),
+-		      $diff, $fn, $dirname);
+-	    }
+-	    last unless $dirname =~ s{/[^/]+$}{};
+-	}
+-
+ 	if (-e $fn and not -f _) {
+ 	    error(_g("diff `%s' patches something which is not a plain file"), $diff);
+ 	}


More information about the scm-commits mailing list