Patchwork [1/2] Dpkg::Source::Patch: Correctly parse C-style diff filenames

login
register
mail settings
Submitter wenzong.fan@windriver.com
Date June 16, 2014, 5:20 a.m.
Message ID <0c9ae168604c96d3333810b5fc0ae70af832ff88.1402895653.git.wenzong.fan@windriver.com>
Download mbox | patch
Permalink /patch/73827/
State New
Headers show

Comments

wenzong.fan@windriver.com - June 16, 2014, 5:20 a.m.
From: Guillem Jover <guillem@debian.org>

based on: commit a82651188476841d190c58693f95827d61959b51

We need to strip the surrounding quotes, and unescape any escape
sequence, so that we check the same files that the patch program will
be using, otherwise a malicious package could overpass those checks,
and perform directory traversal attacks on source package unpacking.

Fixes: CVE-2014-0471

Reported-by: Jakub Wilk <jwilk@debian.org>
[drop the text for debian/changelog,because it's not suitable
 for the veriosn]
Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
Signed-off-by: Wenzong Fan <wenzong.fan@windriver.com>
---
 .../dpkg/dpkg/dpkg-1.17.4-CVE-2014-0471.patch      |   83 ++++++++++++++++++++
 meta/recipes-devtools/dpkg/dpkg_1.17.4.bb          |    1 +
 2 files changed, 84 insertions(+)
 create mode 100644 meta/recipes-devtools/dpkg/dpkg/dpkg-1.17.4-CVE-2014-0471.patch

Patch

diff --git a/meta/recipes-devtools/dpkg/dpkg/dpkg-1.17.4-CVE-2014-0471.patch b/meta/recipes-devtools/dpkg/dpkg/dpkg-1.17.4-CVE-2014-0471.patch
new file mode 100644
index 0000000..f5a023a
--- /dev/null
+++ b/meta/recipes-devtools/dpkg/dpkg/dpkg-1.17.4-CVE-2014-0471.patch
@@ -0,0 +1,83 @@ 
+diff -uarN dpkg-1.17.1-org/scripts/Dpkg/Source/Patch.pm dpkg-1.17.1/scripts/Dpkg/Source/Patch.pm
+--- dpkg-1.17.1-org/scripts/Dpkg/Source/Patch.pm	2014-06-05 15:24:07.422446284 +0800
++++ dpkg-1.17.1/scripts/Dpkg/Source/Patch.pm	2014-06-05 15:41:37.746446314 +0800
+@@ -324,14 +324,53 @@
+     return $line;
+ }
+ 
+-# Strip timestamp
+-sub _strip_ts {
+-    my $header = shift;
+-
+-    # Tab is the official separator, it's always used when
+-    # filename contain spaces. Try it first, otherwise strip on space
+-    # if there's no tab
+-    $header =~ s/\s.*// unless ($header =~ s/\t.*//);
++my %ESCAPE = ((
++    'a' => "\a",
++    'b' => "\b",
++    'f' => "\f",
++    'n' => "\n",
++    'r' => "\r",
++    't' => "\t",
++    'v' => "\cK",
++    '\\' => '\\',
++    '"' => '"',
++), (
++    map { sprintf('%03o', $_) => chr($_) } (0..255)
++));
++
++sub _unescape {
++    my ($diff, $str) = @_;
++
++    if (exists $ESCAPE{$str}) {
++        return $ESCAPE{$str};
++    } else {
++        error(_g('diff %s patches file with unknown escape sequence \\%s'),
++              $diff, $str);
++    }
++}
++
++# Fetch the header filename ignoring the optional timestamp
++sub _fetch_filename {
++    my ($diff, $header) = @_;
++
++    # Strip any leading spaces.
++    $header =~ s/^\s+//;
++
++    # Is it a C-style string?
++    if ($header =~ m/^"/) {
++        $header =~ m/^"((?:[^\\"]|\\.)*)"/;
++        error(_g('diff %s patches file with unbalanced quote'), $diff)
++            unless defined $1;
++
++        $header = $1;
++        $header =~ s/\\([0-3][0-7]{2}|.)/_unescape($diff, $1)/eg;
++    } else {
++        # Tab is the official separator, it's always used when
++        # filename contain spaces. Try it first, otherwise strip on space
++        # if there's no tab
++        $header =~ s/\s.*// unless $header =~ s/\t.*//;
++    }
++
+     return $header;
+ }
+ 
+@@ -400,7 +439,7 @@
+ 	unless(s/^--- //) {
+ 	    error(_g("expected ^--- in line %d of diff `%s'"), $., $diff);
+ 	}
+-        $path{old} = $_ = _strip_ts($_);
++	$path{old} = $_ = _fetch_filename($diff, $_);
+ 	$fn{old} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
+ 	if (/\.dpkg-orig$/) {
+ 	    error(_g("diff `%s' patches file with name ending .dpkg-orig"), $diff);
+@@ -412,7 +451,7 @@
+ 	unless (s/^\+\+\+ //) {
+ 	    error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.);
+ 	}
+-        $path{new} = $_ = _strip_ts($_);
++	$path{new} = $_ = _fetch_filename($diff, $_);
+ 	$fn{new} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
+ 
+ 	unless (defined $fn{old} or defined $fn{new}) {
diff --git a/meta/recipes-devtools/dpkg/dpkg_1.17.4.bb b/meta/recipes-devtools/dpkg/dpkg_1.17.4.bb
index 5507352..48e1394 100644
--- a/meta/recipes-devtools/dpkg/dpkg_1.17.4.bb
+++ b/meta/recipes-devtools/dpkg/dpkg_1.17.4.bb
@@ -12,6 +12,7 @@  SRC_URI += "file://noman.patch \
             file://dpkg-configure.service \
             file://glibc2.5-sync_file_range.patch \
             file://no-vla-warning.patch \
+            file://dpkg-1.17.4-CVE-2014-0471.patch \
            "
 
 SRC_URI[md5sum] = "cc25086e1e3bd9512a95f14cfe9002e1"