The following commit has been merged in the master branch:
commit 8994a516a52f1e5927d1ce7f31f854a7ccf872d8
Author: Kees Cook <[email protected]>
Date:   Thu Dec 8 15:53:14 2011 -0800

    dpkg-buildflags: new --query-features command
    
    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 by externally. (See bug 650536.)
    
    Signed-off-by: Kees Cook <[email protected]>
    Signed-off-by: Raphaël Hertzog <[email protected]>

diff --git a/debian/changelog b/debian/changelog
index fff5158..fc5fde6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -70,6 +70,8 @@ dpkg (1.16.2) UNRELEASED; urgency=low
     is given with a relative filename. Closes: #652414
   * Further clarify in dpkg-source(1) the conditions under which it's possible
     to pass an explicit patch file to dpkg-source --commit.
+  * Add new --query-features command to dpkg-buildflags. Thanks to Kees Cook
+    for the patch. Closes: #651481
 
   [ Jonathan Nieder ]
   * Bump po4a version in Build-Depends to 0.41, since earlier versions do
diff --git a/man/dpkg-buildflags.1 b/man/dpkg-buildflags.1
index b86ae0d..2b5fb2e 100644
--- a/man/dpkg-buildflags.1
+++ b/man/dpkg-buildflags.1
@@ -87,6 +87,22 @@ the flag is set/modified by a user-specific configuration;
 the flag is set/modified by an environment-specific configuration.
 .RE
 .TP
+.BI \-\-query\-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.
+.IP
+The output format is RFC822 header-style, with one section per feature.
+For example:
+.IP
+.nf
+  Feature: pie
+  Enabled: no
+
+  Feature: stackprotector
+  Enabled: yes
+.fi
+.TP
 .B \-\-help
 Show the usage message and exit.
 .TP
diff --git a/scripts/Dpkg/BuildFlags.pm b/scripts/Dpkg/BuildFlags.pm
index 6112a9f..b114335 100644
--- a/scripts/Dpkg/BuildFlags.pm
+++ b/scripts/Dpkg/BuildFlags.pm
@@ -18,7 +18,7 @@ package Dpkg::BuildFlags;
 use strict;
 use warnings;
 
-our $VERSION = "1.01";
+our $VERSION = "1.02";
 
 use Dpkg::Gettext;
 use Dpkg::BuildOptions;
@@ -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} = {
@@ -202,6 +203,19 @@ sub set {
     $self->{origin}->{$flag} = $src if defined $src;
 }
 
+=item $bf->set_feature($area, $feature, $enabled)
+
+Update the boolean state of whether a specific feature within a known
+feature area has been enabled. The only currently known feature area is
+"hardening".
+
+=cut
+
+sub set_feature {
+    my ($self, $area, $feature, $enabled) = @_;
+    $self->{'features'}{$area}{$feature} = $enabled;
+}
+
 =item $bf->strip($flag, $value, $source)
 
 Update the build flag $flag by stripping the flags listed in $value and
@@ -306,6 +320,18 @@ sub get {
     return $self->{'flags'}{$key};
 }
 
+=item $bf->get_features($area)
+
+Return, for the given area, a hash with keys as feature names, and values
+as booleans indicating whether the feature is enabled or not.
+
+=cut
+
+sub get_features {
+    my ($self, $area) = @_;
+    return %{$self->{'features'}{$area}};
+}
+
 =item $bf->get_origin($flag)
 
 Return the origin associated to the flag. It might be undef if the
@@ -318,6 +344,18 @@ sub get_origin {
     return $self->{'origin'}{$key};
 }
 
+=item $bf->has_features($area)
+
+Returns true if the given area of features is known, and false otherwise.
+The only currently recognized area is "hardening".
+
+=cut
+
+sub has_features {
+    my ($self, $area) = @_;
+    return exists $self->{'features'}{$area};
+}
+
 =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 f363fee..537293f 100644
--- a/scripts/Dpkg/Vendor/Debian.pm
+++ b/scripts/Dpkg/Vendor/Debian.pm
@@ -174,6 +174,11 @@ sub add_hardening_flags {
     if ($use_feature{"bindnow"}) {
        $flags->append("LDFLAGS", "-Wl,-z,now");
     }
+
+    # Store the feature usage.
+    while (my ($feature, $enabled) = each %use_feature) {
+       $flags->set_feature("hardening", $feature, $enabled);
+    }
 }
 
 1;
diff --git a/scripts/dpkg-buildflags.pl b/scripts/dpkg-buildflags.pl
index ee33961..8f4b7f0 100755
--- a/scripts/dpkg-buildflags.pl
+++ b/scripts/dpkg-buildflags.pl
@@ -47,6 +47,8 @@ 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.
+  --query-features <area>
+                     output the status of 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 +64,7 @@ my ($param, $action);
 
 while (@ARGV) {
     $_ = shift(@ARGV);
-    if (m/^--(get|origin)$/) {
+    if (m/^--(get|origin|query-features)$/) {
         usageerr(_g("two commands specified: --%s and --%s"), $1, $action)
             if defined($action);
         $action = $1;
@@ -115,6 +117,17 @@ if ($action eq "get") {
        print $build_flags->get_origin($param) . "\n";
        exit(0);
     }
+} elsif ($action eq "query-features") {
+    if ($build_flags->has_features($param)) {
+       my %features = $build_flags->get_features($param);
+       my $para_shown = 0;
+       foreach my $feature (sort keys %features) {
+           print $para_shown++ ? "\n" : "";
+           printf "Feature: %s\n", $feature;
+           printf "Enabled: %s\n", $features{$feature} ? "yes" : "no";
+       }
+       exit(0);
+    }
 } elsif ($action =~ m/^export-(.*)$/) {
     my $export_type = $1;
     foreach my $flag ($build_flags->list()) {

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to