From ef74e9d6103be37e4f4a43fb4c8b948789346b7c Mon Sep 17 00:00:00 2001 From: Sona Sarmadi Date: Thu, 14 Dec 2017 13:17:04 +0100 Subject: DPKG: Fix and test case for CVE-2017-8283 Directory Traversal Vulnerability References: https://nvd.nist.gov/vuln/detail/CVE-2017-8283 http://www.securityfocus.com/bid/98064/info Signed-off-by: Sona Sarmadi Signed-off-by: Adrian Dudau --- recipes-devtools/dpkg/dpkg/CVE-2017-8283.patch | 190 +++++++++++++++++++++ .../dpkg/dpkg/test-case-for-CVE-2017-8283.patch | 83 +++++++++ recipes-devtools/dpkg/dpkg_%.bbappend | 6 + 3 files changed, 279 insertions(+) create mode 100644 recipes-devtools/dpkg/dpkg/CVE-2017-8283.patch create mode 100644 recipes-devtools/dpkg/dpkg/test-case-for-CVE-2017-8283.patch create mode 100644 recipes-devtools/dpkg/dpkg_%.bbappend diff --git a/recipes-devtools/dpkg/dpkg/CVE-2017-8283.patch b/recipes-devtools/dpkg/dpkg/CVE-2017-8283.patch new file mode 100644 index 0000000..b4c8df1 --- /dev/null +++ b/recipes-devtools/dpkg/dpkg/CVE-2017-8283.patch @@ -0,0 +1,190 @@ +From 67f2bc55ec79926f3334eb2956a62719f824e85b Mon Sep 17 00:00:00 2001 +From: Sona Sarmadi +Date: Thu, 14 Dec 2017 10:21:01 +0100 +Subject: [PATCH] build: Detect the required GNU patch + +This makes sure the perl module is using a directory traversal resistant +patch implementation, currently that's only GNU patch. + +CVE: CVE-2017-8283 +Upstream-Status: Backport [remotes/origin/1.18.x: 8ba04d41c839318b5a024f6c5298848d3b54c723] + +Signed-off-by: Sona Sarmadi +--- + configure.ac | 1 + + debian/changelog | 5 +++++ + m4/dpkg-progs.m4 | 15 +++++++++++++++ + scripts/Dpkg.pm | 13 ++++++++++++- + scripts/Dpkg/Source/Patch.pm | 9 +++++---- + scripts/Makefile.am | 4 +++- + 6 files changed, 41 insertions(+), 6 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 3123d0c..0112d4d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -61,6 +61,7 @@ AC_PROG_CC + DPKG_C_C99 + AC_PROG_CXX + DPKG_CXX_CXX11 ++DPKG_PROG_PATCH + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + AC_CHECK_PROG([HAVE_DOT], [dot], [YES], [NO]) + DPKG_PROG_PO4A +diff --git a/debian/changelog b/debian/changelog +index 695c55d..4b5b36b 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,8 @@ ++ - Check that the detected patch is a GNU patch, so that we get a directory ++ traversal resistant patch implementation. This fixes CVE-2017-8283 by ++ delegating those checks to patch(1), so that we trap blank-indented ++ diff hunks trying to escape from the source tree. ++ + dpkg (1.18.10) unstable; urgency=medium + + [ Guillem Jover ] +diff --git a/m4/dpkg-progs.m4 b/m4/dpkg-progs.m4 +index c59f595..577d50d 100644 +--- a/m4/dpkg-progs.m4 ++++ b/m4/dpkg-progs.m4 +@@ -49,3 +49,18 @@ AC_ARG_VAR([TAR], [GNU tar program]) + AC_CHECK_PROGS([TAR], [gnutar gtar tar], [tar]) + AC_DEFINE_UNQUOTED([TAR], ["$TAR"], [GNU tar program]) + ])# DPKG_DEB_PROG_TAR ++ ++# DPKG_PROG_PATCH ++# --------------- ++# Specify GNU patch program name to use by dpkg-source. On GNU systems this ++# is usually simply patch, on BSD systems this is usually gpatch. ++# Even though most invocations would work with other patch implementations, ++# currently only GNU patch is directory traversal resistant. ++AC_DEFUN([DPKG_PROG_PATCH], [ ++ AC_ARG_VAR([PATCH], [GNU patch program]) ++ AC_CHECK_PROGS([PATCH], [gpatch patch], [patch]) ++ AS_IF([! $PATCH --version 2>/dev/null | grep -q '^GNU patch'], [ ++ AC_MSG_ERROR([cannot find a GNU patch program]) ++ ]) ++ AC_DEFINE_UNQUOTED([PATCH], ["$PATCH"], [GNU patch program]) ++])# DPKG_PROG_PATCH +diff --git a/scripts/Dpkg.pm b/scripts/Dpkg.pm +index deecfb3..4905ab8 100644 +--- a/scripts/Dpkg.pm ++++ b/scripts/Dpkg.pm +@@ -29,10 +29,11 @@ this system installation. + use strict; + use warnings; + +-our $VERSION = '1.01'; ++our $VERSION = '1.03'; + our @EXPORT_OK = qw( + $PROGNAME + $PROGVERSION ++ $PROGPATCH + $CONFDIR + $ADMINDIR + $LIBDIR +@@ -60,6 +61,11 @@ Contains the name of the current program. + + Contains the version of the dpkg suite. + ++=item $Dpkg::PROGPATCH ++ ++Contains the name of the system GNU patch program (or another implementation ++that is directory traversal resistant). ++ + =item $Dpkg::CONFDIR + + Contains the path to the dpkg system configuration directory. +@@ -84,6 +90,7 @@ our ($PROGNAME) = $0 =~ m{(?:.*/)?([^/]*)}; + + # The following lines are automatically fixed at install time + our $PROGVERSION = '1.18.x'; ++our $PROGPATCH = $ENV{DPKG_PROGPATCH} // 'patch'; + our $CONFDIR = '/etc/dpkg'; + our $ADMINDIR = '/var/lib/dpkg'; + our $LIBDIR = '.'; +@@ -100,6 +107,10 @@ our $pkgdatadir = $DATADIR; + + =head1 CHANGES + ++=head2 Version 1.03 (dpkg 1.18.10) ++ ++New variable: $PROGPATCH. ++ + =head2 Version 1.01 (dpkg 1.17.0) + + New variables: $PROGNAME, $PROGVERSION, $CONFDIR, $ADMINDIR, $LIBDIR and +diff --git a/scripts/Dpkg/Source/Patch.pm b/scripts/Dpkg/Source/Patch.pm +index ee5e114..22e9d21 100644 +--- a/scripts/Dpkg/Source/Patch.pm ++++ b/scripts/Dpkg/Source/Patch.pm +@@ -30,6 +30,7 @@ use File::Compare; + use Fcntl ':mode'; + use Time::HiRes qw(stat); + ++use Dpkg; + use Dpkg::Gettext; + use Dpkg::ErrorHandling; + use Dpkg::IPC; +@@ -582,7 +583,7 @@ sub apply { + $self->ensure_open('r'); + my ($stdout, $stderr) = ('', ''); + spawn( +- exec => [ 'patch', @{$opts{options}} ], ++ exec => [ $Dpkg::PROGPATCH, @{$opts{options}} ], + chdir => $destdir, + env => { LC_ALL => 'C', LANG => 'C', PATCH_GET => '0' }, + delete_env => [ 'POSIXLY_CORRECT' ], # ensure expected patch behaviour +@@ -595,7 +596,7 @@ sub apply { + if ($?) { + print { *STDOUT } $stdout; + print { *STDERR } $stderr; +- subprocerr('LC_ALL=C patch ' . join(' ', @{$opts{options}}) . ++ subprocerr("LC_ALL=C $Dpkg::PROGPATCH " . join(' ', @{$opts{options}}) . + ' < ' . $self->get_filename()); + } + $self->close(); +@@ -632,7 +633,7 @@ sub check_apply { + # Apply the patch + $self->ensure_open('r'); + my $patch_pid = spawn( +- exec => [ 'patch', @{$opts{options}} ], ++ exec => [ $Dpkg::PROGPATCH, @{$opts{options}} ], + chdir => $destdir, + env => { LC_ALL => 'C', LANG => 'C', PATCH_GET => '0' }, + delete_env => [ 'POSIXLY_CORRECT' ], # ensure expected patch behaviour +@@ -642,7 +643,7 @@ sub check_apply { + ); + wait_child($patch_pid, nocheck => 1); + my $exit = WEXITSTATUS($?); +- subprocerr('patch --dry-run') unless WIFEXITED($?); ++ subprocerr("$Dpkg::PROGPATCH --dry-run") unless WIFEXITED($?); + $self->close(); + return ($exit == 0); + } +diff --git a/scripts/Makefile.am b/scripts/Makefile.am +index 7b1ac36..84059c1 100644 +--- a/scripts/Makefile.am ++++ b/scripts/Makefile.am +@@ -127,6 +127,7 @@ do_perl_subst = $(AM_V_GEN) \ + -e "s:\$$ADMINDIR[[:space:]]*=[[:space:]]*['\"][^'\"]*['\"]:\$$ADMINDIR='$(admindir)':" \ + -e "s:\$$LIBDIR[[:space:]]*=[[:space:]]*['\"][^'\"]*['\"]:\$$LIBDIR='$(pkglibdir)':" \ + -e "s:\$$DATADIR[[:space:]]*=[[:space:]]*['\"][^'\"]*['\"]:\$$DATADIR='$(pkgdatadir)':" \ ++ -e "s:our \$$PROGPATCH = .*;:our \$$PROGPATCH = '$(PATCH)';:" \ + -e "s:\$$PROGVERSION[[:space:]]*=[[:space:]]*['\"][^'\"]*[\"']:\$$PROGVERSION='$(PACKAGE_VERSION)':" + + do_shell_subst = $(AM_V_GEN) \ +@@ -187,7 +188,8 @@ coverage-clean: + rm -rf cover_db + + TEST_ENV_VARS = \ +- DPKG_DATADIR=$(srcdir)/.. \ ++ DPKG_PROGPATCH=$(PATCH) \ ++ DPKG_DATADIR=$(srcdir)/.. \ + DPKG_ORIGINS_DIR=$(srcdir)/t/origins + TEST_COVERAGE = $(PERL_COVERAGE) + +-- +1.9.1 + diff --git a/recipes-devtools/dpkg/dpkg/test-case-for-CVE-2017-8283.patch b/recipes-devtools/dpkg/dpkg/test-case-for-CVE-2017-8283.patch new file mode 100644 index 0000000..5632d8f --- /dev/null +++ b/recipes-devtools/dpkg/dpkg/test-case-for-CVE-2017-8283.patch @@ -0,0 +1,83 @@ +From 57a3daba4d3dee1c33571e84f160aa1c67aece4c Mon Sep 17 00:00:00 2001 +From: Sona Sarmadi +Date: Thu, 14 Dec 2017 10:40:42 +0100 +Subject: [PATCH] Dpkg::Source::Patch: Indented patch test-case + +POSIX specifies that a diff hunk can be indented by spaces or tabs +(while the original patch(1) by Larry Wall also accepts 'X'), as long +as the amount of spaces is consistent for all subsequent lines. And as +we are not checking for this condition at all, any such indented hunk +can avoid the sanity checks performed by Dpkg::Source::Patch. + +On systems using GNU patch >= 2.7.5, this should, in principle, not be +a problem anymore, as that implementation protects against directory +traversal issue. But on other systems where the patch implementation +does not perform such checks (such as the BSDs) this is an issue, so +check for this in the test-suite. + +Those are arguably all security issues in these various patch +implementations, but given that we are performing sanity checks and that +those implementations are currently very lax, it seems prudent to do the +heavy lifting ourselves and also take the possible blame too. + +Ref: test-case for CVE-2017-8283 +Upstream-Status: Backport + +Signed-off-by: Sona Sarmadi +--- + debian/changelog | 3 +++ + scripts/Makefile.am | 1 + + scripts/t/Dpkg_Source_Patch.t | 6 +++++- + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/debian/changelog b/debian/changelog +index 4b5b36b..596a59e 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -2,6 +2,9 @@ + traversal resistant patch implementation. This fixes CVE-2017-8283 by + delegating those checks to patch(1), so that we trap blank-indented + diff hunks trying to escape from the source tree. ++ * Test suite: ++ - Add a test case for blank-indented patches which were the cause for ++ CVE-2017-8283. + + dpkg (1.18.10) unstable; urgency=medium + +diff --git a/scripts/Makefile.am b/scripts/Makefile.am +index 84059c1..6ce0ad6 100644 +--- a/scripts/Makefile.am ++++ b/scripts/Makefile.am +@@ -275,6 +275,7 @@ test_data = \ + t/Dpkg_Shlibs/spacesyms-o-map.pl \ + t/Dpkg_Source_Patch/c-style.patch \ + t/Dpkg_Source_Patch/ghost-hunk.patch \ ++ t/Dpkg_Source_Patch/indent-header.patch \ + t/Dpkg_Source_Patch/index-+++.patch \ + t/Dpkg_Source_Patch/index-alone.patch \ + t/Dpkg_Source_Patch/index-inert.patch \ +diff --git a/scripts/t/Dpkg_Source_Patch.t b/scripts/t/Dpkg_Source_Patch.t +index 258a9aa..30be77a 100644 +--- a/scripts/t/Dpkg_Source_Patch.t ++++ b/scripts/t/Dpkg_Source_Patch.t +@@ -16,7 +16,7 @@ + use strict; + use warnings; + +-use Test::More tests => 9; ++use Test::More tests => 10; + + use File::Path qw(make_path); + +@@ -67,4 +67,8 @@ test_patch_escape('partial', 'symlink', 'partial.patch', + test_patch_escape('ghost-hunk', 'symlink', 'ghost-hunk.patch', + 'Patch cannot escape using a disabling hunk'); + ++# This is CVE-2017-8283 ++test_patch_escape('indent-header', 'symlink', 'indent-header.patch', ++ 'Patch cannot escape indented hunks'); ++ + 1; +-- +1.9.1 + diff --git a/recipes-devtools/dpkg/dpkg_%.bbappend b/recipes-devtools/dpkg/dpkg_%.bbappend new file mode 100644 index 0000000..65d380e --- /dev/null +++ b/recipes-devtools/dpkg/dpkg_%.bbappend @@ -0,0 +1,6 @@ +# look for files in the layer first +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://CVE-2017-8283.patch \ + file://test-case-for-CVE-2017-8283.patch \ + " -- cgit v1.2.3-54-g00ecf