Package: dpkg Version: 1.16.1.2 Severity: normal Tags: patch Hi,
In working through the requirements for adding hardening build checks to lintian[1], it has become clear that there needs to be a way to ask dpkg-buildflags what its expected features area for a given situation. This patch adds that ability, and lets the environment correctly adjust it: $ dpkg-buildflags --features hardening -bindnow,+format,+fortify,-pie,+relro,+stackprotector $ DEB_HOST_ARCH=ia64 dpkg-buildflags --features hardening -bindnow,+format,+fortify,-pie,-relro,-stackprotector I'm obviously open to changing how this works, what the output looks like, etc. I'm just interested in the behavior to query expected hardening features. Hopefully I can deprecate hardening-wrapper and hardening-includes to just use dpkg-buildflags directly, as well as hook it up to lintian. Thanks! -Kees [1] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=650536 -- Kees Cook @debian.org
>From 8a8a1414ad6cac4d22ca732eaa9e14f802e82e29 Mon Sep 17 00:00:00 2001 From: Kees Cook <k...@debian.org> Date: Thu, 8 Dec 2011 15:53:14 -0800 Subject: [PATCH] dpkg-buildflags: provide feature query ability Since the logic for having a hardening flag enabled or disabled depends on the architecture, and since the flags may change over time for each hardening feature, there needs to be a way to externally query the state of the hardening features. Specifically, lintian needs this to be able to figure out if a binary package is missing expected hardening features. Instead of maintaining multiple hard-coded lists of expected hardening features, this makes dpkg-buildflags the canonical location of the information, which can be queried externally. (See bug 650536.) Signed-off-by: Kees Cook <k...@debian.org> --- man/dpkg-buildflags.1 | 5 +++++ scripts/Dpkg/BuildFlags.pm | 24 ++++++++++++++++++++++++ scripts/Dpkg/Vendor/Debian.pm | 22 ++++++++++++++++++++++ scripts/dpkg-buildflags.pl | 20 +++++++++++++++++++- 4 files changed, 70 insertions(+), 1 deletions(-) diff --git a/man/dpkg-buildflags.1 b/man/dpkg-buildflags.1 index a018edb..dad6be6 100644 --- a/man/dpkg-buildflags.1 +++ b/man/dpkg-buildflags.1 @@ -87,6 +87,11 @@ the flag is set/modified by a user-specific configuration; the flag is set/modified by an environment-specific configuration. .RE .TP +.BI \-\-features " area" +Print the features enabled for a given area. The only currently recognized +area is \fBhardening\fP. Exits with 0 if the area is known otherwise exits +with 1. +.TP .B \-\-help Show the usage message and exit. .TP diff --git a/scripts/Dpkg/BuildFlags.pm b/scripts/Dpkg/BuildFlags.pm index 6112a9f..261e649 100644 --- a/scripts/Dpkg/BuildFlags.pm +++ b/scripts/Dpkg/BuildFlags.pm @@ -68,6 +68,7 @@ sub load_vendor_defaults { my ($self) = @_; $self->{'options'} = {}; $self->{'source'} = {}; + $self->{'features'} = {}; my $build_opts = Dpkg::BuildOptions->new(); my $default_flags = $build_opts->has("noopt") ? "-g -O0" : "-g -O2"; $self->{flags} = { @@ -306,6 +307,17 @@ sub get { return $self->{'flags'}{$key}; } +=item $bf->get_features($area) + +Return the list of features enabled for the given area. + +=cut + +sub get_features { + my ($self, $key) = @_; + return $self->{'features'}{$key}; +} + =item $bf->get_origin($flag) Return the origin associated to the flag. It might be undef if the @@ -318,6 +330,18 @@ sub get_origin { return $self->{'origin'}{$key}; } +=item $bf->features($area) + +Returns a list of enabled features for a given area. Currently the +only recognized area is "hardening". + +=cut + +sub features { + my ($self, $key) = @_; + return exists $self->{'features'}{$key}; +} + =item $bf->has($option) Returns a boolean indicating whether the flags exists in the object. diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm index e824d0e..8106c47 100644 --- a/scripts/Dpkg/Vendor/Debian.pm +++ b/scripts/Dpkg/Vendor/Debian.pm @@ -122,6 +122,10 @@ sub add_hardening_flags { $flags->append("CFLAGS", "-fPIE"); $flags->append("CXXFLAGS", "-fPIE"); $flags->append("LDFLAGS", "-fPIE -pie"); + $flags->{'features'}{'hardening'}{'pie'} = 1; + } + else { + $flags->{'features'}{'hardening'}{'pie'} = 0; } # Stack protector if ($use_feature{"stackprotector"} and @@ -132,26 +136,44 @@ sub add_hardening_flags { # compiler supports it incorrectly (leads to SEGV) $flags->append("CFLAGS", "-fstack-protector --param=ssp-buffer-size=4"); $flags->append("CXXFLAGS", "-fstack-protector --param=ssp-buffer-size=4"); + $flags->{'features'}{'hardening'}{'stackprotector'} = 1; + } + else { + $flags->{'features'}{'hardening'}{'stackprotector'} = 0; } # Fortify if ($use_feature{"fortify"}) { $flags->append("CPPFLAGS", "-D_FORTIFY_SOURCE=2"); + $flags->{'features'}{'hardening'}{'fortify'} = 1; + } + else { + $flags->{'features'}{'hardening'}{'fortify'} = 0; } # Format if ($use_feature{"format"}) { $flags->append("CFLAGS", "-Wformat -Wformat-security -Werror=format-security"); $flags->append("CXXFLAGS", "-Wformat -Wformat-security -Werror=format-security"); + $flags->{'features'}{'hardening'}{'format'} = 1; + } + else { + $flags->{'features'}{'hardening'}{'format'} = 0; } # Relro if ($use_feature{"relro"} and $cpu !~ /^(ia64|hppa|avr32)$/) { $flags->append("LDFLAGS", "-Wl,-z,relro"); + $flags->{'features'}{'hardening'}{'relro'} = 1; } else { # Disable full relro if relro is not enabled. $use_feature{"bindnow"} = 0; + $flags->{'features'}{'hardening'}{'relro'} = 0; } # Bindnow if ($use_feature{"bindnow"}) { $flags->append("LDFLAGS", "-Wl,-z,now"); + $flags->{'features'}{'hardening'}{'bindnow'} = 1; + } + else { + $flags->{'features'}{'hardening'}{'bindnow'} = 0; } } diff --git a/scripts/dpkg-buildflags.pl b/scripts/dpkg-buildflags.pl index ee33961..29ab48d 100755 --- a/scripts/dpkg-buildflags.pl +++ b/scripts/dpkg-buildflags.pl @@ -47,6 +47,7 @@ Actions: --get <flag> output the requested flag to stdout. --origin <flag> output the origin of the flag to stdout: value is one of vendor, system, user, env. + --features <area> output the enabled features for the given area. --list output a list of the flags supported by the current vendor. --export=(sh|make|configure) output something convenient to import the @@ -62,7 +63,7 @@ my ($param, $action); while (@ARGV) { $_ = shift(@ARGV); - if (m/^--(get|origin)$/) { + if (m/^--(get|origin|features)$/) { usageerr(_g("two commands specified: --%s and --%s"), $1, $action) if defined($action); $action = $1; @@ -115,6 +116,23 @@ if ($action eq "get") { print $build_flags->get_origin($param) . "\n"; exit(0); } +} elsif ($action eq "features") { + if ($build_flags->features($param)) { + my $features = $build_flags->get_features($param); + my @report; + foreach my $feature (sort keys %{$features}) { + my $item = $feature; + if ($features->{$feature} == 1) { + $item = "+$item"; + } + else { + $item = "-$item"; + } + push(@report, $item); + } + print join(",", @report), "\n"; + exit(0); + } } elsif ($action =~ m/^export-(.*)$/) { my $export_type = $1; foreach my $flag ($build_flags->list()) { -- 1.7.5.4