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