From 48f6d8ed0c3c7ae59c3a55c9d2e9dd6c8aa5f052 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 26 Mar 2012 03:15:10 +0200 Subject: [PATCH] Support multiple log files as arguments. Not really useful at the momemnt because the parser output is not separated between the files. --- bin/blhc | 105 ++++++++++++++++++++++++++++++------------------------ t/tests.t | 40 +++++++++++++++++---- 2 files changed, 93 insertions(+), 52 deletions(-) diff --git a/bin/blhc b/bin/blhc index 618fa76..8b21c8f 100755 --- a/bin/blhc +++ b/bin/blhc @@ -145,42 +145,42 @@ my $file_extension_regex = qr/ /x; # Expected (hardening) flags. All flags are used as regexps. -my @cflags = ( +my @def_cflags = ( '-g', '-O(?:2|3)', ); -my @cflags_format = ( +my @def_cflags_format = ( '-Wformat', '-Wformat-security', '-Werror=format-security', ); -my @cflags_fortify = ( +my @def_cflags_fortify = ( # fortify needs at least -O1, but -O2 is recommended anyway ); -my @cflags_stack = ( +my @def_cflags_stack = ( '-fstack-protector', '--param=ssp-buffer-size=4', ); -my @cflags_pie = ( +my @def_cflags_pie = ( '-fPIE', ); -my @cxxflags = ( +my @def_cxxflags = ( '-g', '-O(?:2|3)', ); -# @cxxflags_* is the same as @cflags_*. -my @cppflags = (); -my @cppflags_fortify = ( +# @def_cxxflags_* is the same as @def_cflags_*. +my @def_cppflags = (); +my @def_cppflags_fortify = ( '-D_FORTIFY_SOURCE=2', ); -my @ldflags = (); -my @ldflags_relro = ( +my @def_ldflags = (); +my @def_ldflags_relro = ( '-Wl,(-z,)?relro', ); -my @ldflags_bindnow = ( +my @def_ldflags_bindnow = ( '-Wl,(-z,)?now', ); -my @ldflags_pie = ( +my @def_ldflags_pie = ( '-fPIE', '-pie', ); @@ -338,17 +338,11 @@ sub extension_found { # MAIN -# 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_help = 0; my $option_version = 0; +my $option_pie = 0; +my $option_bindnow = 0; my $option_all = 0; my $option_arch = undef; my $option_buildd = 0; @@ -357,8 +351,8 @@ if (not Getopt::Long::GetOptions( 'help|h|?' => \$option_help, 'version' => \$option_version, # Hardening options. - 'pie' => \$harden_pie, - 'bindnow' => \$harden_bindnow, + 'pie' => \$option_pie, + 'bindnow' => \$option_bindnow, 'all' => \$option_all, # Misc. 'color' => \$option_color, @@ -392,20 +386,31 @@ along with this program. If not, see . } if ($option_all) { - $harden_pie = 1; - $harden_bindnow = 1; + $option_pie = 1; + $option_bindnow = 1; } # Final exit code. my $exit = 0; +FILE: foreach my $file (@ARGV) { +open my $fh, '<', $file or die "$!: $file"; + +# 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 = $option_bindnow; # defaults to 0 +my $harden_pie = $option_pie; # defaults to 0 + # Input lines, contain only the lines with compiler commands. my @input = (); my $start = 0; my $continuation = 0; my $complete_line = undef; -while (my $line = <>) { +while (my $line = <$fh>) { # dpkg-buildflags only provides hardening flags since 1.16.1, don't check # for hardening flags in buildd mode if an older dpkg-dev is used. Default # flags (-g -O2) are still checked. @@ -431,7 +436,7 @@ while (my $line = <>) { if (not $start and $line =~ /^Build-Depends: .*\bhardening-wrapper\b/) { error_hardening_wrapper(); $exit |= 1 << 4; - exit $exit; + next FILE; } # We skip over unimportant lines at the beginning of the log to prevent @@ -524,18 +529,20 @@ while (my $line = <>) { # Check if additional hardening options were used. Used to ensure # they are used for the complete build. - $harden_pie = 1 if any_flags_used($line, @cflags_pie, @ldflags_pie); - $harden_bindnow = 1 if any_flags_used($line, @ldflags_bindnow); + $harden_pie = 1 if any_flags_used($line, @def_cflags_pie, @def_ldflags_pie); + $harden_bindnow = 1 if any_flags_used($line, @def_ldflags_bindnow); push @input, $line; } } } +close $fh; + if (scalar @input == 0) { print "No compiler commands!\n"; $exit |= 1; - exit $exit; + next FILE; } # Option or auto detected. @@ -559,30 +566,35 @@ if ($option_arch) { } } +# Default values. +my @cflags = @def_cflags; +my @cxxflags = @def_cxxflags; +my @cppflags = @def_cppflags; +my @ldflags = @def_ldflags; # Check the specified hardening options, same order as dpkg-buildflags. if ($harden_pie) { - @cflags = (@cflags, @cflags_pie); - @cxxflags = (@cxxflags, @cflags_pie); - @ldflags = (@ldflags, @ldflags_pie); + @cflags = (@cflags, @def_cflags_pie); + @cxxflags = (@cxxflags, @def_cflags_pie); + @ldflags = (@ldflags, @def_ldflags_pie); } if ($harden_stack) { - @cflags = (@cflags, @cflags_stack); - @cxxflags = (@cxxflags, @cflags_stack); + @cflags = (@cflags, @def_cflags_stack); + @cxxflags = (@cxxflags, @def_cflags_stack); } if ($harden_fortify) { - @cflags = (@cflags, @cflags_fortify); - @cxxflags = (@cxxflags, @cflags_fortify); - @cppflags = (@cppflags, @cppflags_fortify); + @cflags = (@cflags, @def_cflags_fortify); + @cxxflags = (@cxxflags, @def_cflags_fortify); + @cppflags = (@cppflags, @def_cppflags_fortify); } if ($harden_format) { - @cflags = (@cflags, @cflags_format); - @cxxflags = (@cxxflags, @cflags_format); + @cflags = (@cflags, @def_cflags_format); + @cxxflags = (@cxxflags, @def_cflags_format); } if ($harden_relro) { - @ldflags = (@ldflags, @ldflags_relro); + @ldflags = (@ldflags, @def_ldflags_relro); } if ($harden_bindnow) { - @ldflags = (@ldflags, @ldflags_bindnow); + @ldflags = (@ldflags, @def_ldflags_bindnow); } for (my $i = 0; $i < scalar @input; $i++) { @@ -661,7 +673,7 @@ for (my $i = 0; $i < scalar @input; $i++) { if ($compile 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, $harden_pie, \@missing, @cflags_pie) + and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie) # Assume dpkg-buildflags returns the correct flags. and not $line =~ /`dpkg-buildflags --get CFLAGS`/) { error_flags('CFLAGS missing', \@missing, \%flag_renames, $input[$i]); @@ -669,7 +681,7 @@ for (my $i = 0; $i < scalar @input; $i++) { } elsif ($compile_cpp 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, $harden_pie, \@missing, @cflags_pie) + and not pic_pie_conflict($line, $harden_pie, \@missing, @def_cflags_pie) # Assume dpkg-buildflags returns the correct flags. and not $line =~ /`dpkg-buildflags --get CXXFLAGS`/) { error_flags('CXXFLAGS missing', \@missing, \%flag_renames, $input[$i]); @@ -683,13 +695,14 @@ for (my $i = 0; $i < scalar @input; $i++) { } if ($link and not all_flags_used($line, \@missing, @ldflags) # Same here, -fPIC conflicts with -fPIE. - and not pic_pie_conflict($line, $harden_pie, \@missing, @ldflags_pie) + and not pic_pie_conflict($line, $harden_pie, \@missing, @def_ldflags_pie) # Assume dpkg-buildflags returns the correct flags. and not $line =~ /`dpkg-buildflags --get LDFLAGS`/) { error_flags('LDFLAGS missing', \@missing, \%flag_renames, $input[$i]); $exit |= 1 << 3; } } +} exit $exit; @@ -702,7 +715,7 @@ blhc - build log hardening check, checks build logs for missing hardening flags =head1 SYNOPSIS -B [options] +B [options] .. --all force +all (+pie, +bindnow) check --arch set architecture (autodetected) diff --git a/t/tests.t b/t/tests.t index 3260213..e3acca2 100644 --- a/t/tests.t +++ b/t/tests.t @@ -19,12 +19,18 @@ use strict; use warnings; -use Test::More tests => 92; +use Test::More tests => 98; sub is_blhc { my ($file, $options, $exit, $expected) = @_; + # Multiple files as array references. + if (ref $file eq 'ARRAY') { + local $" = ' ./t/logs/'; + $file = "@{$file}"; + } + my $output = `./bin/blhc $options ./t/logs/$file 2>&1`; if ($options) { @@ -40,7 +46,7 @@ sub is_blhc { is_blhc 'empty', '--invalid', 2, 'Unknown option: invalid Usage: - blhc [options] + blhc [options] .. --all force +all (+pie, +bindnow) check --arch set architecture (autodetected) @@ -56,8 +62,9 @@ Usage: # No compiler commands found. +my $empty = "No compiler commands!\n"; is_blhc 'empty', '', 1, - "No compiler commands!\n"; + $empty; # Correct build logs. @@ -277,9 +284,11 @@ CPPFLAGS missing (-D_FORTIFY_SOURCE=2): gcc -fPIC -g -O2 -fstack-protector --par CPPFLAGS missing (-D_FORTIFY_SOURCE=2): g++ -o test -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security test-a.cxx test-b.o test-c.o -Wl,-z,relro '; -is_blhc 'bad-ldflags', '', 8, +my $bad_ldflags = 'LDFLAGS missing (-Wl,-z,relro): gcc -o test test-a.o test-b.o test-c.o -ltest '; +is_blhc 'bad-ldflags', '', 8, + $bad_ldflags; is_blhc 'bad-ldflags', '--pie', 8, 'CFLAGS missing (-fPIE): gcc -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-a.c CFLAGS missing (-fPIE): gcc -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-b.c @@ -513,9 +522,11 @@ LDFLAGS missing (-fPIE -pie -Wl,-z,now): /bin/bash ../libtool --tag=CC --mode= # different architectures -is_blhc 'arch-avr32', '', 8, +my $arch_avr32 = 'CFLAGS missing (--param=ssp-buffer-size=4): gcc -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector -Wformat -Wformat-security -Werror=format-security -Wall -c test.c '; +is_blhc 'arch-avr32', '', 8, + $arch_avr32; is_blhc 'arch-i386', '', 8, 'CFLAGS missing (-fstack-protector): gcc -D_FORTIFY_SOURCE=2 -g -O2 -fPIE --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -Wall -c test.c @@ -551,9 +562,11 @@ CPPFLAGS missing (-D_FORTIFY_SOURCE=2): gcc -c `dpkg-buildflags --get LDFLAGS` t LDFLAGS missing (-Wl,-z,relro): gcc -o test test.o `dpkg-buildflags --get CFLAGS` '; -is_blhc 'debian-hardening-wrapper', '', 16, +my $debian_hardening_wrapper = 'HARDENING WRAPPER: no checks possible, aborting '; +is_blhc 'debian-hardening-wrapper', '', 16, + $debian_hardening_wrapper; # buildd support @@ -583,3 +596,18 @@ is_blhc 'buildd-dpkg-dev-old', '--buildd', 8, CFLAGS missing (-O2): gcc -g -c test-b.c CFLAGS missing (-O2): gcc -g -c test-c.c '; + +# multiple files + +is_blhc ['good', 'good-pie', 'good-bindnow', 'good-all', 'good-multiline', 'good-library'], '', 0, + ''; +is_blhc ['good-all', 'good-library'], '--all', 0, + ''; + +# No exit when multiple files are specified. +is_blhc ['bad-ldflags', 'empty', 'arch-avr32', 'debian-hardening-wrapper'], '', 25, + $bad_ldflags + . $empty + . $arch_avr32 + . $debian_hardening_wrapper + ; -- 2.43.2