Package: dpkg
Version: 1.17.13
Severity: wishlist
Tags: patch

Hi,

I'm working on a new port, hardened-amd64 [1]. The attached patches adds
the new port and enables ASAN and UBSAN through the hardening flags.
The flags are disabled on other architectures by default even when using
hardening=all, since ASAN causes significant slowdown and UBSAN will
probably reveal a lot of issues in many packages.

Dpkg for example builds fine with ASAN (with fixed #760690), but UBSAN
makes it FTBFS due to the following issue:
.../dpkg.git$ DEB_BUILD_MAINT_OPTIONS=hardening=all,+asan,+ubsan
dpkg-buildpackage
...

PATH="../src:../scripts:../utils:/usr/lib/ccache:/home/rbalint/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
\
  LC_ALL=C \
   \
  srcdir=../../src builddir=. \
  PERL_DL_NONLAZY=1 \
  PERL5OPT= \
  /usr/bin/perl -MTAP::Harness -e ' my $harness = TAP::Harness->new({
lib => [ "../../scripts" ], color => 1, verbosity => 0, failures => 1,
}); my $aggregate = $harness->runtests(@ARGV); die "FAIL: test suite has
errors\n" if $aggregate->has_errors;' \
     ../../src/t/dpkg_divert.t
../../src/t/dpkg_divert.t .. 1/257
not ok 62 - --list stderr

#   Failed test '--list stderr'
#   at ../../src/t/dpkg_divert.t line 106.
#          got: '../../src/filesdb.c:581:21: runtime error: signed
integer overflow: 313137907 * 1787 cannot be represented in type 'int'
# '
#     expected: ''
not ok 65 - --list * stderr

The third patch fixes the issue.

Please consired accepting the patches despite the fact that
hardened-amd64 is not an official port yet. It would help the
bootstrapping efforts and patch 2 would make it easier to experiment
with ASAN and UBSAN for others.

Cheers,
Balint

[1]
http://balintreczey.hu/blog/proposing-amd64-hardened-architecture-for-debian/
>From 8364086c0e499802d37d7a52ed295cf8c3014eb8 Mon Sep 17 00:00:00 2001
From: Balint Reczey <[email protected]>
Date: Tue, 22 Apr 2014 20:58:00 +0200
Subject: [PATCH 1/3] Add hardened-amd64 architecture

Use the new GNU name linux-gnuhardened for the hardened-amd64 arch.
Also extend tests to cover the new arch
---
 lib/dpkg/test/t-arch.c |  3 ++-
 ostable                |  1 +
 scripts/t/Dpkg_Arch.t  | 15 ++++++++++++++-
 triplettable           |  1 +
 4 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/lib/dpkg/test/t-arch.c b/lib/dpkg/test/t-arch.c
index 6078be4..3326c40 100644
--- a/lib/dpkg/test/t-arch.c
+++ b/lib/dpkg/test/t-arch.c
@@ -44,6 +44,7 @@ test_dpkg_arch_name_is_illegal(void)
 	/* Test valid architecture names. */
 	test_pass(dpkg_arch_name_is_illegal("i386") == NULL);
 	test_pass(dpkg_arch_name_is_illegal("amd64") == NULL);
+	test_pass(dpkg_arch_name_is_illegal("hardened-amd64") == NULL);
 	test_pass(dpkg_arch_name_is_illegal("hurd-i386") == NULL);
 	test_pass(dpkg_arch_name_is_illegal("kfreebsd-i386") == NULL);
 	test_pass(dpkg_arch_name_is_illegal("kfreebsd-amd64") == NULL);
@@ -212,7 +213,7 @@ test_dpkg_arch_describe(void)
 void
 test(void)
 {
-	test_plan(60);
+	test_plan(61);
 
 	test_dpkg_arch_name_is_illegal();
 	test_dpkg_arch_get_list();
diff --git a/ostable b/ostable
index 9f559bf..c3f5500 100644
--- a/ostable
+++ b/ostable
@@ -24,6 +24,7 @@ gnuspe-linux		linux-gnuspe		linux[^-]*-gnuspe
 gnux32-linux		linux-gnux32		linux[^-]*-gnux32
 gnulp-linux		linux-gnulp		linux[^-]*-gnulp
 gnu-linux		linux-gnu		linux[^-]*(-gnu.*)?
+gnuhardened-linux	linux-gnuhardened	linux[^-]*(-gnu.*)?
 gnu-kfreebsd		kfreebsd-gnu		kfreebsd[^-]*(-gnu.*)?
 gnu-knetbsd		knetbsd-gnu		knetbsd[^-]*(-gnu.*)?
 gnu-kopensolaris	kopensolaris-gnu	kopensolaris[^-]*(-gnu.*)?
diff --git a/scripts/t/Dpkg_Arch.t b/scripts/t/Dpkg_Arch.t
index 91759ec..dc15966 100644
--- a/scripts/t/Dpkg_Arch.t
+++ b/scripts/t/Dpkg_Arch.t
@@ -13,7 +13,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-use Test::More tests => 42;
+use Test::More tests => 54;
 
 use strict;
 use warnings;
@@ -41,11 +41,17 @@ is(debarch_to_multiarch('i386'), 'i386-linux-gnu',
    'normalized i386 multiarch triplet');
 is(debarch_to_multiarch('amd64'), 'x86_64-linux-gnu',
    'normalized amd64 multiarch triplet');
+is(debarch_to_multiarch('hardened-amd64'), 'x86_64-linux-gnuhardened',
+   'normalized hardened-amd64 multiarch triplet');
 
 ok(!debarch_eq('amd64', 'i386'), 'no match, simple arch');
+ok(!debarch_eq('hardened-amd64', 'i386'), 'no match, simple arch');
 ok(!debarch_eq('', 'amd64'), 'no match, empty first arch');
+ok(!debarch_eq('', 'hardened-amd64'), 'no match, empty first arch');
 ok(!debarch_eq('amd64', ''), 'no match, empty second arch');
+ok(!debarch_eq('hardened-amd64', ''), 'no match, empty second arch');
 ok(!debarch_eq('amd64', 'unknown'), 'no match, with first unknown arch');
+ok(!debarch_eq('hardened-amd64', 'unknown'), 'no match, with first unknown arch');
 ok(!debarch_eq('unknown', 'i386'), 'no match, second unknown arch');
 ok(debarch_eq('unknown', 'unknown'), 'match equal unknown arch');
 ok(debarch_eq('amd64', 'amd64'), 'match equal known arch');
@@ -54,11 +60,16 @@ ok(debarch_eq('amd64', 'linux-amd64'), 'match implicit linux arch');
 ok(!debarch_is('unknown', 'linux-any'), 'no match unknown on wildcard cpu');
 ok(!debarch_is('unknown', 'any-amd64'), 'no match unknown on wildcard os');
 ok(!debarch_is('amd64', 'unknown'), 'no match amd64 on unknown wildcard');
+ok(!debarch_is('hardened-amd64', 'unknown'), 'no match amd64 on unknown wildcard');
 ok(!debarch_is('amd64', 'unknown-any'), 'no match amd64 on unknown wildcard');
+ok(!debarch_is('hardened-amd64', 'unknown-any'), 'no match amd64 on unknown wildcard');
 ok(!debarch_is('amd64', 'any-unknown'), 'no match amd64 on unknown wildcard');
+ok(!debarch_is('hardened-amd64', 'any-unknown'), 'no match amd64 on unknown wildcard');
 ok(debarch_is('unknown', 'any'), 'match unknown on global wildcard');
 ok(debarch_is('amd64', 'linux-any'), 'match amd64 on wildcard cpu');
 ok(debarch_is('amd64', 'any-amd64'), 'match amd64 on wildcard os');
+ok(debarch_is('hardened-amd64', 'linux-any'), 'match hardened-amd64 on wildcard cpu');
+ok(debarch_is('hardened-amd64', 'any-amd64'), 'match hardened-amd64 on wildcard os');
 ok(debarch_is('x32', 'any-amd64'), 'match x32 on amd64 wildcard os');
 ok(debarch_is('i386', 'any-i386'), 'match i386 on i386 wildcard os');
 ok(debarch_is('arm', 'any-arm'), 'match arm on arm wildcard os');
@@ -66,6 +77,7 @@ ok(debarch_is('armel', 'any-arm'), 'match armel on arm wildcard os');
 ok(debarch_is('armhf', 'any-arm'), 'match armhf on arm wildcard os');
 
 ok(debarch_is('amd64', 'gnu-any-any'), 'match amd64 on abi wildcard');
+ok(debarch_is('hardened-amd64', 'gnuhardened-any-any'), 'match hardened-amd64 on abi wildcard');
 ok(debarch_is('linux-amd64', 'gnu-any-any'),
    'match linux-amd64 on abi wildcard');
 ok(debarch_is('kfreebsd-amd64', 'gnu-any-any'),
@@ -74,6 +86,7 @@ ok(debarch_is('kfreebsd-amd64', 'gnu-any-any'),
 ok(!debarch_is_wildcard('unknown'), 'unknown is not a wildcard');
 ok(!debarch_is_wildcard('all'), 'all is not a wildcard');
 ok(!debarch_is_wildcard('amd64'), '<arch> is not a wildcard');
+ok(!debarch_is_wildcard('hardened-amd64'), '<arch> is not a wildcard');
 ok(debarch_is_wildcard('any'), '<any> is a global wildcard');
 ok(debarch_is_wildcard('any-any'), '<any>-<any> is a wildcard');
 ok(debarch_is_wildcard('any-any-any'), '<any>-<any>-<any> is a wildcard');
diff --git a/triplettable b/triplettable
index a741fcf..efadc36 100644
--- a/triplettable
+++ b/triplettable
@@ -17,6 +17,7 @@ gnuspe-linux-powerpc	powerpcspe
 gnux32-linux-amd64	x32
 gnulp-linux-i386	lpia
 gnu-linux-<cpu>		<cpu>
+gnuhardened-linux-amd64	hardened-amd64
 gnu-kfreebsd-<cpu>	kfreebsd-<cpu>
 gnu-knetbsd-<cpu>	knetbsd-<cpu>
 gnu-kopensolaris-<cpu>	kopensolaris-<cpu>
-- 
2.1.0

>From 04260a09eedbd3b28ea00809e9bb5c1ad3e3611a Mon Sep 17 00:00:00 2001
From: Balint Reczey <[email protected]>
Date: Sat, 6 Sep 2014 13:23:14 +0200
Subject: [PATCH 2/3] Set ASAN and UBSAN for hardened-amd64 builds by default

Also let maintainers enable/disable them on other architectures
---
 scripts/Dpkg/Vendor/Debian.pm | 50 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm
index 775f3ac..b57a965 100644
--- a/scripts/Dpkg/Vendor/Debian.pm
+++ b/scripts/Dpkg/Vendor/Debian.pm
@@ -74,7 +74,7 @@ sub run_hook {
 }
 
 sub _parse_feature_area {
-    my ($self, $area, $use_feature) = @_;
+    my ($self, $area, $use_feature, $use_feature_extra) = @_;
 
     # Adjust features based on Maintainer's desires.
     my $opts = Dpkg::BuildOptions->new(envvar => 'DEB_BUILD_MAINT_OPTIONS');
@@ -87,6 +87,8 @@ sub _parse_feature_area {
 	    } else {
 		if (exists $use_feature->{$feature}) {
 		    $use_feature->{$feature} = $value;
+		} elsif (exists $use_feature_extra->{$feature}) {
+		    $use_feature_extra->{$feature} = $value;
 		} else {
 		    warning(_g('unknown %s feature: %s'), $area, $feature);
 		}
@@ -119,8 +121,23 @@ sub add_hardening_flags {
 	bindnow => 0,
     );
 
+    # Extra features disabled by default for all builds.
+    # They are not enabled by using 'all', but can be enabled on-by-one.
+    # They may migrate to %use_feature in the future.
+    my %use_feature_extra = (
+	asan => 0,
+	ubsan => 0,
+    );
+
+    if ($arch =~ /^(?:hardened-amd64)$/) {
+	# Address and undefined sanitizers are enabled for one arch for now
+	# by default.
+	$use_feature_extra{asan} = 1;
+	$use_feature_extra{ubsan} = 1;
+    }
+
     # Adjust features based on Maintainer's desires.
-    $self->_parse_feature_area('hardening', \%use_feature);
+    $self->_parse_feature_area('hardening', \%use_feature, \%use_feature_extra);
 
     # Mask features that are not available on certain architectures.
     if ($os !~ /^(?:linux|knetbsd|hurd)$/ or
@@ -141,6 +158,10 @@ sub add_hardening_flags {
 	# relro not implemented on ia64, hppa, avr32.
 	$use_feature{relro} = 0;
     }
+    if ($cpu !~ /^(?:amd64|i386|arm)$/) {
+	# ASAN is available only for a few architectures
+	$use_feature_extra{asan} = 0;
+    }
 
     # Mask features that might be influenced by other flags.
     if ($flags->{build_options}->has('noopt')) {
@@ -217,10 +238,35 @@ sub add_hardening_flags {
 	$flags->append('LDFLAGS', '-Wl,-z,now');
     }
 
+    # ASAN
+    if ($use_feature_extra{asan}) {
+	my $flag = '-fsanitize=address';
+	$flags->append('CFLAGS', $flag);
+	$flags->append('OBJCFLAGS', $flag);
+	$flags->append('OBJCXXFLAGS', $flag);
+	$flags->append('FFLAGS', $flag);
+	$flags->append('FCFLAGS', $flag);
+	$flags->append('CXXFLAGS', $flag);
+	$flags->append('LDFLAGS', $flag);
+    }
+
+    # UBSAN
+    if ($use_feature_extra{ubsan}) {
+	my $flag = '-fsanitize=undefined';
+	$flags->append('CFLAGS', $flag);
+	$flags->append('OBJCFLAGS', $flag);
+	$flags->append('OBJCXXFLAGS', $flag);
+	$flags->append('CXXFLAGS', $flag);
+	$flags->append('LDFLAGS', $flag);
+    }
+
     # Store the feature usage.
     while (my ($feature, $enabled) = each %use_feature) {
 	$flags->set_feature('hardening', $feature, $enabled);
     }
+    while (my ($feature, $enabled) = each %use_feature_extra) {
+	$flags->set_feature('hardening', $feature, $enabled);
+    }
 }
 
 1;
-- 
2.1.0

>From 55f7dabe2ea5fde7dd5a14e350c67f9b4ca7d22a Mon Sep 17 00:00:00 2001
From: Balint Reczey <[email protected]>
Date: Sun, 7 Sep 2014 14:55:04 +0200
Subject: [PATCH 3/3] Fix signed overflow in hash()

---
 src/filesdb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/filesdb.c b/src/filesdb.c
index af1e466..91004fc 100644
--- a/src/filesdb.c
+++ b/src/filesdb.c
@@ -577,7 +577,7 @@ void filesdbinit(void) {
 }
 
 static int hash(const char *name) {
-  int v= 0;
+  unsigned int v= 0;
   while (*name) { v *= 1787; v += *name; name++; }
   return v;
 }
-- 
2.1.0

Reply via email to