diff -Nru dpkg-1.16.1.2ubuntu7.5/debian/changelog dpkg-1.16.1.2ubuntu7.6/debian/changelog --- dpkg-1.16.1.2ubuntu7.5/debian/changelog 2014-06-09 17:00:47.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/debian/changelog 2015-04-09 14:40:43.000000000 +0000 @@ -1,3 +1,14 @@ +dpkg (1.16.1.2ubuntu7.6) precise-security; urgency=medium + + * SECURITY UPDATE: OpenPGP Armor Header Line parsing issue + - scripts/Dpkg/Control/{Hash,Package}.pm: adjust parsing logic. + - scripts/Makefile.*, scripts/t/700_Dpkg_Control.t, + scripts/t/700_Dpkg_Control/*: added bunch of tests. + - Patch thanks to Guillem Jover + - CVE-2015-0840 + + -- Marc Deslauriers Thu, 09 Apr 2015 09:22:25 -0400 + dpkg (1.16.1.2ubuntu7.5) precise-security; urgency=medium * SECURITY UPDATE: arbitrary file modification via dpkg-source diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/Dpkg/Control/Hash.pm dpkg-1.16.1.2ubuntu7.6/scripts/Dpkg/Control/Hash.pm --- dpkg-1.16.1.2ubuntu7.5/scripts/Dpkg/Control/Hash.pm 2011-04-06 11:34:39.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/Dpkg/Control/Hash.pm 2015-04-09 14:03:12.000000000 +0000 @@ -105,6 +105,7 @@ my $self = \{ 'in_order' => [], 'out_order' => [], + 'is_pgp_signed' => 0, 'allow_pgp' => 0, 'allow_duplicate' => 0, 'drop_empty' => 0, @@ -159,21 +160,29 @@ my ($self, $fh, $desc) = @_; my $paraborder = 1; + my $parabody = 0; my $cf; # Current field my $expect_pgp_sig = 0; + while (<$fh>) { - s/\s*\n$//; - next if (m/^$/ and $paraborder); + chomp; + next if m/^\s*$/ and $paraborder; next if (m/^#/); $paraborder = 0; if (m/^(\S+?)\s*:\s*(.*)$/) { - if (exists $self->{$1}) { + $parabody = 1; + if ($1 =~ m/^-/) { + syntaxerror($desc, _g('field cannot start with a hyphen')); + } + my ($name, $value) = ($1, $2); + if (exists $self->{$name}) { unless ($$self->{'allow_duplicate'}) { - syntaxerr($desc, sprintf(_g("duplicate field %s found"), $1)); + syntaxerr($desc, sprintf(_g("duplicate field %s found"), $name)); } } - $self->{$1} = $2; - $cf = $1; + $value =~ s/\s*$//; + $self->{$name} = $value; + $cf = $name; } elsif (m/^\s(\s*\S.*)$/) { my $line = $1; unless (defined($cf)) { @@ -182,36 +191,43 @@ if ($line =~ /^\.+$/) { $line = substr $line, 1; } + $line =~ s/\s*$//; $self->{$cf} .= "\n$line"; - } elsif (m/^-----BEGIN PGP SIGNED MESSAGE/) { + } elsif (m/^-----BEGIN PGP SIGNED MESSAGE-----[\r\t ]*$/) { $expect_pgp_sig = 1; - if ($$self->{'allow_pgp'}) { + if ($$self->{'allow_pgp'} and not $parabody) { # Skip PGP headers while (<$fh>) { - last if m/^$/; + last if m/^\s*$/; } } else { syntaxerr($desc, _g("PGP signature not allowed here")); } - } elsif (m/^$/ || ($expect_pgp_sig && m/^-----BEGIN PGP SIGNATURE/)) { + } elsif (m/^\s*$/ || + ($expect_pgp_sig && m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/)) { if ($expect_pgp_sig) { # Skip empty lines $_ = <$fh> while defined($_) && $_ =~ /^\s*$/; - length($_) || + unless (length $_) { syntaxerr($desc, _g("expected PGP signature, found EOF " . "after blank line")); - s/\n$//; - unless (m/^-----BEGIN PGP SIGNATURE/) { + } + chomp; + unless (m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/) { syntaxerr($desc, sprintf(_g("expected PGP signature, " . "found something else \`%s'"), $_)); } # Skip PGP signature while (<$fh>) { - last if m/^-----END PGP SIGNATURE/; + chomp; + last if m/^-----END PGP SIGNATURE-----[\r\t ]*$/; } unless (defined($_)) { syntaxerr($desc, _g("unfinished PGP signature")); } + # This does not mean the signature is correct, that needs to + # be verified by gnupg. + $$self->{'is_pgp_signed'} = 1; } last; # Finished parsing one block } else { @@ -219,6 +235,11 @@ _g("line with unknown format (not field-colon-value)")); } } + + if ($expect_pgp_sig and not $$self->{'is_pgp_signed'}) { + syntaxerror($desc, _g('unfinished PGP signature')); + } + return defined($cf); } diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/Dpkg/Source/Package.pm dpkg-1.16.1.2ubuntu7.6/scripts/Dpkg/Source/Package.pm --- dpkg-1.16.1.2ubuntu7.5/scripts/Dpkg/Source/Package.pm 2011-10-14 10:26:48.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/Dpkg/Source/Package.pm 2015-04-09 14:39:59.000000000 +0000 @@ -194,7 +194,7 @@ $self->{'is_signed'} = 0; while () { next if /^\s*$/o; - $self->{'is_signed'} = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----$/o; + $self->{'is_signed'} = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----\s*$/o; last; } close(DSC); diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/Makefile.am dpkg-1.16.1.2ubuntu7.6/scripts/Makefile.am --- dpkg-1.16.1.2ubuntu7.5/scripts/Makefile.am 2011-10-14 10:26:48.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/Makefile.am 2015-04-09 14:29:25.000000000 +0000 @@ -224,6 +224,14 @@ t/600_Dpkg_Changelog/regressions \ t/600_Dpkg_Changelog/shadow \ t/700_Dpkg_Control/control-1 \ + t/700_Dpkg_Control/bogus-unsigned.dsc \ + t/700_Dpkg_Control/bogus-armor-double.dsc \ + t/700_Dpkg_Control/bogus-armor-formfeed.dsc \ + t/700_Dpkg_Control/bogus-armor-no-sig.dsc \ + t/700_Dpkg_Control/bogus-armor-trail.dsc \ + t/700_Dpkg_Control/bogus-armor-inline.dsc \ + t/700_Dpkg_Control/bogus-armor-nested.dsc \ + t/700_Dpkg_Control/bogus-armor-spaces.dsc \ t/750_Dpkg_Substvars/substvars1 \ t/910_merge_changelogs/ch-old \ t/910_merge_changelogs/ch-a \ diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/Makefile.in dpkg-1.16.1.2ubuntu7.6/scripts/Makefile.in --- dpkg-1.16.1.2ubuntu7.5/scripts/Makefile.in 2011-10-14 10:26:48.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/Makefile.in 2015-04-09 14:30:22.000000000 +0000 @@ -461,6 +461,14 @@ t/600_Dpkg_Changelog/regressions \ t/600_Dpkg_Changelog/shadow \ t/700_Dpkg_Control/control-1 \ + t/700_Dpkg_Control/bogus-unsigned.dsc \ + t/700_Dpkg_Control/bogus-armor-double.dsc \ + t/700_Dpkg_Control/bogus-armor-formfeed.dsc \ + t/700_Dpkg_Control/bogus-armor-no-sig.dsc \ + t/700_Dpkg_Control/bogus-armor-trail.dsc \ + t/700_Dpkg_Control/bogus-armor-inline.dsc \ + t/700_Dpkg_Control/bogus-armor-nested.dsc \ + t/700_Dpkg_Control/bogus-armor-spaces.dsc \ t/750_Dpkg_Substvars/substvars1 \ t/910_merge_changelogs/ch-old \ t/910_merge_changelogs/ch-a \ diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-double.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-double.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-double.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-double.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,13 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: pass + +-----BEGIN PGP SIGNATURE----- + +Valid signature here. +-----END PGP SIGNATURE----- +-----BEGIN PGP SIGNATURE----- + +Fake signature here. +-----END PGP SIGNATURE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-formfeed.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-formfeed.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-formfeed.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-formfeed.dsc 2015-04-09 13:22:37.000000000 +0000 @@ -0,0 +1,19 @@ +-----BEGIN PGP SIGNED MESSAGE----- + +Source: fail + +-----BEGIN PGP SIGNATURE----- +Version: vim v7.3.547 (GNU/Linux) + +Fake signature here. +-----END PGP SIGNATURE----- +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: pass + +-----BEGIN PGP SIGNATURE +Version: GnuPG v1.4.12 (GNU/Linux) + +Valid signature here. +-----END PGP SIGNATURE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-inline.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-inline.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-inline.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-inline.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,9 @@ +Source: fail +-----BEGIN PGP SIGNED MESSAGE----- + +Binary: pass + +-----BEGIN PGP SIGNATURE----- + +Valid signature here. +-----END PGP SIGNATURE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-nested.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-nested.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-nested.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-nested.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,15 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: pass + +-----BEGIN PGP SIGNATURE----- +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: fail + +-----BEGIN PGP SIGNATURE----- + +Valid signature here. +-----END PGP SIGNATURE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-no-sig.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-no-sig.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-no-sig.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-no-sig.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,4 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: pass diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-spaces.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-spaces.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-spaces.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-spaces.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,18 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Source: pass + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.12 (GNU/Linux) + +Valid signature here. +-----END PGP SIGNATURE----- + +Source: fail + +-----BEGIN PGP SIGNATURE +Version: vim v7.3.547 (GNU/Linux) + +Fake signature here. +-----END PGP SIGNATURE diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-trail.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-trail.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-armor-trail.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-armor-trail.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNED MESSAGE + +Source: fail + +-----BEGIN PGP SIGNATURE +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Source: pass + +-----BEGIN PGP SIGNATURE----- + +Valid signature here. +-----END PGP SIGNATURE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-unsigned.dsc dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-unsigned.dsc --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control/bogus-unsigned.dsc 1970-01-01 00:00:00.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control/bogus-unsigned.dsc 2013-10-20 03:53:28.000000000 +0000 @@ -0,0 +1,5 @@ +-----BEGIN PGP MESSAGE----- + +Source: fail + +-----END PGP MESSAGE----- diff -Nru dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control.t dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control.t --- dpkg-1.16.1.2ubuntu7.5/scripts/t/700_Dpkg_Control.t 2011-10-14 10:26:48.000000000 +0000 +++ dpkg-1.16.1.2ubuntu7.6/scripts/t/700_Dpkg_Control.t 2015-04-09 13:49:46.000000000 +0000 @@ -13,17 +13,32 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -use Test::More tests => 11; +use Test::More tests => 23; use strict; use warnings; use IO::String; -use_ok('Dpkg::Control::Info'); +BEGIN { + use_ok('Dpkg::Control'); + use_ok('Dpkg::Control::Info'); +} my $srcdir = $ENV{srcdir} || '.'; my $datadir = $srcdir . '/t/700_Dpkg_Control'; +sub parse_dsc { + my ($path) = @_; + + my $dsc = Dpkg::Control->new(type => CTRL_PKG_SRC); + eval { + $dsc->load($path); + 1; + } or return; + + return $dsc; +} + my $c = Dpkg::Control::Info->new("$datadir/control-1"); my $io = IO::String->new(); @@ -86,3 +101,34 @@ Architecture: all Depends: hello ', "Dump of second binary package of $datadir/control-1"); + +# Check OpenPGP armored signatures in source control files + +my $dsc; + +$dsc = parse_dsc("$datadir/bogus-unsigned.dsc"); +is($dsc, undef, 'Unsigned .dsc w/ OpenPGP armor'); + +$dsc = parse_dsc("$datadir/bogus-armor-no-sig.dsc"); +is($dsc, undef, 'Signed .dsc w/ OpenPGP armor missing signature'); + +$dsc = parse_dsc("$datadir/bogus-armor-trail.dsc"); +is($dsc, undef, 'Signed .dsc w/ bogus OpenPGP armor trailer'); + +$dsc = parse_dsc("$datadir/bogus-armor-inline.dsc"); +is($dsc, undef, 'Signed .dsc w/ bogus OpenPGP inline armor'); + +$dsc = parse_dsc("$datadir/bogus-armor-formfeed.dsc"); +is($dsc, undef, 'Signed .dsc w/ bogus OpenPGP armor line'); + +$dsc = parse_dsc("$datadir/bogus-armor-double.dsc"); +ok(defined $dsc, 'Signed .dsc w/ two OpenPGP armor signatures'); +is($dsc->{Source}, 'pass', 'Signed spaced .dsc package name'); + +$dsc = parse_dsc("$datadir/bogus-armor-spaces.dsc"); +ok(defined $dsc, 'Signed .dsc w/ spaced OpenPGP armor'); +is($dsc->{Source}, 'pass', 'Signed spaced .dsc package name'); + +$dsc = parse_dsc("$datadir/bogus-armor-nested.dsc"); +ok(defined $dsc, 'Signed .dsc w/ nested OpenPGP armor'); +is($dsc->{Source}, 'pass', 'Signed nested .dsc package name');