X-Git-Url: https://ruderich.org/simon/gitweb/?p=blhc%2Fblhc.git;a=blobdiff_plain;f=bin%2Fblhc;h=87a798810773fda45e7404de658b2a2ddbb4fe22;hp=829d78252e90548278ee5ca5d12278f9e6b5a41c;hb=a98be1bc5f253c876681cb133896d72d527fff1c;hpb=2ab1d3168798b8826c78ad7b76f8175d2ef07022 diff --git a/bin/blhc b/bin/blhc index 829d782..87a7988 100755 --- a/bin/blhc +++ b/bin/blhc @@ -22,7 +22,6 @@ use strict; use warnings; use Getopt::Long (); -use Term::ANSIColor (); use Text::ParseWords (); our $VERSION = '0.01'; @@ -49,7 +48,7 @@ my @source_preprocess_compile_cpp = ( # C++ qw( cc cp cxx cpp CPP c++ C ), # Objective-C++ - qw( mm Mr), + qw( mm M ), ); my @source_preprocess_compile = ( # C @@ -63,7 +62,7 @@ my @source_preprocess_compile = ( ); my @source_preprocess_no_compile = ( # Assembly - qw( s ), + qw( S sx ), ); my @source_preprocess = ( @source_preprocess_compile, @@ -88,7 +87,7 @@ my @source_no_preprocess_compile = ( ); my @source_no_preprocess_no_compile = ( # Assembly - qw( S sx ), + qw( s ), ); my @source_no_preprocess = ( @source_no_preprocess_compile, @@ -189,6 +188,26 @@ my @def_ldflags_pic = ( '-fpic', '-shared', ); +# References to all flags checked by the parser. +my @flag_refs = ( + \@def_cflags, + \@def_cflags_format, + \@def_cflags_fortify, + \@def_cflags_stack, + \@def_cflags_pie, + \@def_cxxflags, + \@def_cppflags, + \@def_cppflags_fortify, + \@def_ldflags, + \@def_ldflags_relro, + \@def_ldflags_bindnow, +); +# References to all used flags. +my @flag_refs_all = ( + @flag_refs, + \@def_ldflags_pie, + \@def_ldflags_pic, +); # Renaming rules for the output so the regex parts are not visible. Also # stores string values of flag regexps above, see compile_flag_regexp(). my %flag_renames = ( @@ -407,6 +426,8 @@ my $option_help = 0; my $option_version = 0; my $option_pie = 0; my $option_bindnow = 0; +my @option_ignore_flag = (); +my @option_ignore_line = (); my $option_all = 0; my $option_arch = undef; my $option_buildd = 0; @@ -418,11 +439,15 @@ if (not Getopt::Long::GetOptions( 'pie' => \$option_pie, 'bindnow' => \$option_bindnow, 'all' => \$option_all, + # Ignore. + 'ignore-flag=s' => \@option_ignore_flag, + 'ignore-line=s' => \@option_ignore_line, # Misc. 'color' => \$option_color, 'arch=s' => \$option_arch, 'buildd' => \$option_buildd, - )) { + ) + or scalar @ARGV == 0) { require Pod::Usage; Pod::Usage::pod2usage(2); } @@ -449,31 +474,47 @@ along with this program. If not, see . exit 0; } +# Don't load Term::ANSIColor in buildd mode because Term::ANSIColor is not +# installed on Debian's buildds. +if (not $option_buildd) { + require Term::ANSIColor; +} + if ($option_all) { $option_pie = 1; $option_bindnow = 1; } +# Strip flags which should be ignored. +if (scalar @option_ignore_flag > 0) { + my %ignores = map { $_ => 1 } @option_ignore_flag; + foreach my $flags (@flag_refs) { + @{$flags} = grep { + # Flag found as string. + not exists $ignores{$_} + # Flag found as string representation of regexp. + and (not defined $flag_renames{$_} + or not exists $ignores{$flag_renames{$_}}) + } @{$flags}; + } +} + # Precompile all flag regexps. any_flags_used(), all_flags_used() get a lot # faster with this. -@def_cflags = compile_flag_regexp(\%flag_renames, @def_cflags); -@def_cflags_format = compile_flag_regexp(\%flag_renames, @def_cflags_format); -@def_cflags_fortify = compile_flag_regexp(\%flag_renames, @def_cflags_fortify); -@def_cflags_stack = compile_flag_regexp(\%flag_renames, @def_cflags_stack); -@def_cflags_pie = compile_flag_regexp(\%flag_renames, @def_cflags_pie); -@def_cxxflags = compile_flag_regexp(\%flag_renames, @def_cxxflags); -@def_cppflags = compile_flag_regexp(\%flag_renames, @def_cppflags); -@def_cppflags_fortify = compile_flag_regexp(\%flag_renames, @def_cppflags_fortify); -@def_ldflags = compile_flag_regexp(\%flag_renames, @def_ldflags); -@def_ldflags_relro = compile_flag_regexp(\%flag_renames, @def_ldflags_relro); -@def_ldflags_bindnow = compile_flag_regexp(\%flag_renames, @def_ldflags_bindnow); -@def_ldflags_pie = compile_flag_regexp(\%flag_renames, @def_ldflags_pie); -@def_ldflags_pic = compile_flag_regexp(\%flag_renames, @def_ldflags_pic); +foreach my $flags (@flag_refs_all) { + @{$flags} = compile_flag_regexp(\%flag_renames, @{$flags}); +} + +# Precompile ignore line regexps, also anchor at beginning and end of line. +foreach my $ignore (@option_ignore_line) { + $ignore = qr/^$ignore$/; +} # Final exit code. my $exit = 0; -FILE: foreach my $file (@ARGV) { +FILE: +foreach my $file (@ARGV) { print "checking '$file'...\n" if scalar @ARGV > 1; open my $fh, '<', $file or die "$!: $file"; @@ -563,7 +604,7 @@ FILE: foreach my $file (@ARGV) { # Ignore compiler warnings for now. next if $line =~ /$warning_regex/o; - if ($line =~ /\033/) { # esc + if (not $option_buildd and $line =~ /\033/) { # esc # Remove all ANSI color sequences which are sometimes used in # non-verbose builds. $line = Term::ANSIColor::colorstrip($line); @@ -607,40 +648,38 @@ FILE: foreach my $file (@ARGV) { next; } - if (not $continuation) { - # Use the complete line if a line continuation occurred. - if (defined $complete_line) { - $line = $complete_line; - $complete_line = undef; - } - - # Ignore lines with no compiler commands. - next if not $non_verbose - and not $line =~ /\b$cc_regex(?:\s|\\)/o; - # Ignore lines with no filenames with extensions. May miss - # some non-verbose builds (e.g. "gcc -o test" [sic!]), but - # shouldn't be a problem as the log will most likely contain - # other non-verbose commands which are detected. - next if not $non_verbose - and not $line =~ /$file_extension_regex/o; - - # Ignore false positives. - # - # `./configure` output. - next if not $non_verbose - and $line =~ /^(?:checking|(?:C|c)onfigure:) /; - next if $line =~ /^\s*(?:Host\s+)?(?:C(?:\+\+)?\s+)? - (?:C|c)ompiler[\s.]*:?\s+ - /xo; - next if $line =~ /^\s*(?:- )?(?:HOST_)?(?:CC|CXX)\s*=\s*$cc_regex_full\s*$/o; - - # 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, @def_cflags_pie, @def_ldflags_pie); - $harden_bindnow = 1 if any_flags_used($line, @def_ldflags_bindnow); - - push @input, $line; + # Use the complete line if a line continuation occurred. + if (defined $complete_line) { + $line = $complete_line; + $complete_line = undef; } + + # Ignore lines with no compiler commands. + next if not $non_verbose + and not $line =~ /\b$cc_regex(?:\s|\\)/o; + # Ignore lines with no filenames with extensions. May miss some + # non-verbose builds (e.g. "gcc -o test" [sic!]), but shouldn't be + # a problem as the log will most likely contain other non-verbose + # commands which are detected. + next if not $non_verbose + and not $line =~ /$file_extension_regex/o; + + # Ignore false positives. + # + # `./configure` output. + next if not $non_verbose + and $line =~ /^(?:checking|(?:C|c)onfigure:) /; + next if $line =~ /^\s*(?:Host\s+)?(?:C(?:\+\+)?\s+)? + (?:C|c)ompiler[\s.]*:?\s+ + /xo; + next if $line =~ /^\s*(?:- )?(?:HOST_)?(?:CC|CXX)\s*=\s*$cc_regex_full\s*$/o; + + # 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, @def_cflags_pie, @def_ldflags_pie); + $harden_bindnow = 1 if any_flags_used($line, @def_ldflags_bindnow); + + push @input, $line; } } @@ -712,9 +751,15 @@ FILE: foreach my $file (@ARGV) { @ldflags = (@ldflags, @def_ldflags_bindnow); } +LINE: for (my $i = 0; $i < scalar @input; $i++) { my $line = $input[$i]; + # Ignore line if requested. + foreach my $ignore (@option_ignore_line) { + next LINE if $line =~ /$ignore/; + } + my $skip = 0; if (is_non_verbose_build($line, $input[$i + 1], \$skip)) { if (not $option_buildd) { @@ -949,15 +994,41 @@ changes are in effect: =item +Print tags instead of normal warnings, see README file for a list of possible +tags. + +=item + Don't check hardening flags in old log files (if dpkg-dev << 1.16.1 is detected). +=item + +Don't require Term::ANSIColor. + =back =item B<--color> Use colored (ANSI) output for warning messages. +=item B<--ignore-flag> I + +Don't print an error when the specific flag is missing in a compiler line. +I is a string. + +Used to prevent false positives. This option can be specified multiple times. + +=item B<--ignore-line> I + +Ignore lines matching the given Perl regex. I is automatically anchored +at the beginning and end of the line to prevent false negatives. + +B: Not the input lines are checked, but the lines which are displayed in +warnings (which have line continuation resolved). + +Used to prevent false positives. This option can be specified multiple times. + =item B<--pie> Force check for all +pie hardening flags. By default it's auto detected.