]> ruderich.org/simon Gitweb - blhc/blhc.git/blobdiff - bin/blhc
Support architectures which can't use all hardening flags.
[blhc/blhc.git] / bin / blhc
index d53c7d7b849a01b62610263e851dde695f26dd41..d2e5df761c09e45e5943cc7ba328cd8f34f3746f 100755 (executable)
--- a/bin/blhc
+++ b/bin/blhc
@@ -34,36 +34,41 @@ my $cc_regex = qr/(?:x86_64-linux-gnu-)?(?:(?<!\.)cc|gcc|g\+\+|c\+\+)(?:-[\d.]+)
 # Regex to catch (GCC) compiler warnings.
 my $warning_regex = qr/^(.+?):([0-9]+):[0-9]+: warning: (.+?) \[(.+?)\]$/;
 
-# Expected hardening flags. All flags are used as regexps.
+# Expected (hardening) flags. All flags are used as regexps.
 my @cflags = (
     '-g',
     '-O2',
-    '-fstack-protector',
-    '--param=ssp-buffer-size=4',
+);
+my @cflags_format = (
     '-Wformat',
     '-Wformat-security',
     '-Werror=format-security',
 );
+my @cflags_fortify = (
+    # fortify needs at least -O1, but -O2 is recommended anyway
+);
+my @cflags_stack = (
+    '-fstack-protector',
+    '--param=ssp-buffer-size=4',
+);
 my @cflags_pie = (
     '-fPIE',
 );
-my @cppflags = (
+my @cppflags = ();
+my @cppflags_fortify = (
     '-D_FORTIFY_SOURCE=2',
 );
-my @ldflags = (
+my @ldflags = ();
+my @ldflags_relro = (
     '-Wl,(-z,)?relro',
 );
+my @ldflags_bindnow = (
+    '-Wl,(-z,)?now',
+);
 my @ldflags_pie = (
     '-fPIE',
     '-pie',
 );
-my @ldflags_bindnow = (
-    '-Wl,(-z,)?now',
-);
-# All (hardening) flags.
-my @flags = (@cflags, @cflags_pie,
-             @cppflags,
-             @ldflags, @ldflags_pie, @ldflags_bindnow);
 # Renaming rules for the output so the regex parts are not visible.
 my %flag_renames = (
     '-Wl,(-z,)?relro' => '-Wl,-z,relro',
@@ -198,20 +203,28 @@ sub is_non_verbose_build {
 
 # MAIN
 
-# Additional hardening options.
-my $pie     = 0;
-my $bindnow = 0;
+# Hardening options. Not all architectures support all hardening options.
+my $harden_format  = 1;
+my $harden_fortify = 1;
+my $harden_stack   = 1;
+my $harden_relro   = 1;
+my $harden_bindnow = 0;
+my $harden_pie     = 0;
 
 # Parse command line arguments.
-my $option_all     = 0;
 my $option_help    = 0;
 my $option_version = 0;
+my $option_all     = 0;
+my $option_arch    = undef;
 if (not Getopt::Long::GetOptions(
             'help|h|?' => \$option_help,
             'version'  => \$option_version,
-            'pie'      => \$pie,
-            'bindnow'  => \$bindnow,
+            # Hardening options.
+            'pie'      => \$harden_pie,
+            'bindnow'  => \$harden_bindnow,
             'all'      => \$option_all,
+            # Misc.
+            'arch'     => \$option_arch,
         )) {
     require Pod::Usage;
     Pod::Usage::pod2usage(2);
@@ -240,8 +253,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 }
 
 if ($option_all) {
-    $pie     = 1;
-    $bindnow = 1;
+    $harden_pie     = 1;
+    $harden_bindnow = 1;
 }
 
 # Final exit code.
@@ -258,6 +271,12 @@ while (my $line = <>) {
     $start = 1 if $line =~ /^dpkg-buildpackage:/;
     next if not $start;
 
+    # Detect architecture automatically unless overridden.
+    if (not $option_arch
+            and $line =~ /^dpkg-buildpackage: host architecture (.+)$/) {
+        $option_arch = $1;
+    }
+
     # Ignore compiler warnings for now.
     next if $line =~ /$warning_regex/;
 
@@ -305,18 +324,53 @@ if (scalar @input == 0) {
     exit $exit;
 }
 
+# Option or auto detected.
+if ($option_arch) {
+    # The following was partially copied from dpkg-dev 1.16.1.2
+    # (/usr/share/perl5/Dpkg/Vendor/Debian.pm, add_hardening_flags()),
+    # copyright RaphaĆ«l Hertzog <hertzog@debian.org>, Kees Cook
+    # <kees@debian.org>, Canonical, Ltd. licensed under GPL version 2 or
+    # later. Keep it in sync.
+
+    require Dpkg::Arch;
+    my ($abi, $os, $cpu) = Dpkg::Arch::debarch_to_debtriplet($option_arch);
+
+    # Disable unsupported hardening options.
+    if ($cpu =~ /^(ia64|alpha|mips|mipsel|hppa)$/ or $option_arch eq 'arm') {
+        $harden_stack = 0;
+    }
+    if ($cpu =~ /^(ia64|hppa|avr32)$/) {
+        $harden_relro   = 0;
+        $harden_bindnow = 0;
+    }
+}
+
 # Check if additional hardening options were used. Used to ensure they are
 # used for the complete build.
 foreach my $line (@input) {
-    $pie     = 1 if any_flags_used($line, @cflags_pie, @ldflags_pie);
-    $bindnow = 1 if any_flags_used($line, @ldflags_bindnow);
+    $harden_pie     = 1 if any_flags_used($line, @cflags_pie, @ldflags_pie);
+    $harden_bindnow = 1 if any_flags_used($line, @ldflags_bindnow);
 }
 
-if ($pie) {
+# Check the specified hardening options, same order as dpkg-buildflags.
+if ($harden_pie) {
     @cflags  = (@cflags,  @cflags_pie);
     @ldflags = (@ldflags, @ldflags_pie);
 }
-if ($bindnow) {
+if ($harden_stack) {
+    @cflags = (@cflags, @cflags_stack);
+}
+if ($harden_fortify) {
+    @cflags   = (@cflags,   @cflags_fortify);
+    @cppflags = (@cppflags, @cppflags_fortify);
+}
+if ($harden_format) {
+    @cflags = (@cflags, @cflags_format);
+}
+if ($harden_relro) {
+    @ldflags = (@ldflags, @ldflags_relro);
+}
+if ($harden_bindnow) {
     @ldflags = (@ldflags, @ldflags_bindnow);
 }
 
@@ -369,7 +423,7 @@ for (my $i = 0; $i < scalar @input; $i++) {
     if ($compiler and not all_flags_used($line, \@missing, @cflags)
             # Libraries linked with -fPIC don't have to (and can't) be linked
             # with -fPIE as well. It's no error if only PIE flags are missing.
-            and not pic_pie_conflict($line, $pie, \@missing, @cflags_pie)) {
+            and not pic_pie_conflict($line, $harden_pie, \@missing, @cflags_pie)) {
         error_flags('CFLAGS missing', \@missing, \%flag_renames, $line);
         $exit |= 1 << 3;
     }
@@ -379,7 +433,7 @@ for (my $i = 0; $i < scalar @input; $i++) {
     }
     if ($linker and not all_flags_used($line, \@missing, @ldflags)
             # Same here, -fPIC conflicts with -fPIE.
-            and not pic_pie_conflict($line, $pie, \@missing, @ldflags_pie)) {
+            and not pic_pie_conflict($line, $harden_pie, \@missing, @ldflags_pie)) {
         error_flags('LDFLAGS missing', \@missing, \%flag_renames, $line);
         $exit |= 1 << 3;
     }
@@ -405,6 +459,7 @@ B<blhc> [--pie] [--bindnow] [--all]
     --pie                   force +pie check
     --bindnow               force +bindbow check
     --all                   force +all (+pie, +bindnow) check
+    --arch                  set architecture (autodetected)
 
 =head1 DESCRIPTION
 
@@ -436,6 +491,12 @@ Force check for all +bindnow hardening flags. By default it's auto detected.
 Force check for all +all (+pie, +bindnow) hardening flags. By default it's
 auto detected.
 
+=item B<--arch>
+
+Set the specific architecture (e.g. amd64, armel, etc.), automatically
+disables hardening flags not available on this architecture. Is detected
+automatically if dpkg-buildpackage is used.
+
 =back
 
 Auto detection only works if at least one command uses the required hardening