X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=bin%2Fblhc;h=e183027e22886699b7e4c66639ad77c12555034e;hb=d9bd7570d07a93026a3147971c8e34be6c1c6c86;hp=d089931fa04de504f151fdda83a87c4cf7352f60;hpb=30a4fb78518a579a6725725a4647740aa8241987;p=blhc%2Fblhc.git diff --git a/bin/blhc b/bin/blhc index d089931..e183027 100755 --- a/bin/blhc +++ b/bin/blhc @@ -23,6 +23,7 @@ use warnings; use Getopt::Long (); use Term::ANSIColor (); +use Text::ParseWords (); our $VERSION = '0.01'; @@ -30,10 +31,87 @@ our $VERSION = '0.01'; # CONSTANTS/VARIABLES # Regex to catch compiler commands. -my $cc_regex = qr/(?:x86_64-linux-gnu-)?(?:(? \$option_help, 'version' => \$option_version, @@ -226,6 +303,7 @@ if (not Getopt::Long::GetOptions( 'all' => \$option_all, # Misc. 'arch' => \$option_arch, + 'buildd' => \$option_buildd, )) { require Pod::Usage; Pod::Usage::pod2usage(2); @@ -268,8 +346,28 @@ my $start = 0; my $continuation = 0; my $complete_line = undef; while (my $line = <>) { - # We skip over unimportant lines at the beginning to prevent false - # positives. + # 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. + # + # Packages which were built before 1.16.1 but used their own hardening + # flags are not checked. + if ($option_buildd and not $start + and $line =~ /^Toolchain package versions: /) { + require Dpkg::Version; + if ($line !~ /dpkg-dev_(\S+)/ + or Dpkg::Version::version_compare($1, '1.16.1') < 0) { + $harden_format = 0; + $harden_fortify = 0; + $harden_stack = 0; + $harden_relro = 0; + $harden_bindnow = 0; + $harden_pie = 0; + } + } + + # We skip over unimportant lines at the beginning of the log to prevent + # false positives. $start = 1 if $line =~ /^dpkg-buildpackage:/; next if not $start; @@ -282,12 +380,24 @@ while (my $line = <>) { # Ignore compiler warnings for now. next if $line =~ /$warning_regex/; + # Remove all ANSI color sequences which are sometimes used in non-verbose + # builds. + $line = Term::ANSIColor::colorstrip($line); + # Also strip '\0xf' (delete previous character), used by Elinks' build + # system. + $line =~ s/\x0f//g; + # And "ESC(B" which seems to be used on armhf and hurd (not sure what it + # does). + $line =~ s/\033\(B//g; + # Check if this line indicates a non verbose build. my $non_verbose = is_non_verbose_build($line); # One line may contain multiple commands (";"). Treat each one as single - # line. - my @line = split /(?) { # # `./configure` output. next if not $non_verbose and $line =~ /^checking /; - next if $line =~ /^\s*(?:C|c)ompiler[\s.]*:\s+$cc_regex(?:\s-std=[a-z0-9:+]+)?\s*$/ - or $line =~ /^\s*- (?:CC|CXX)\s*=\s*$cc_regex\s*$/ + next if $line =~ /^\s*(?:Host\s+)?(?:C\s+)? + (?:C|c)ompiler[\s.]*:?\s+ + $cc_regex + (?:\s-std=[a-z0-9:+]+)?\s*$ + /x + or $line =~ /^\s*(?:- )?(?:HOST_)?(?:CC|CXX)\s*=\s*$cc_regex\s*$/ or $line =~ /^\s*-- Check for working (?:C|CXX) compiler: / or $line =~ /^\s*(?:echo )?Using [A-Z_]+\s*=\s*/; + # Debian buildd output. + next if $line =~ /^\s*Depends: .*?$cc_regex.*?$/ + and $line !~ /\s-./; # option, prevent false negatives + push @input, $line; } @@ -403,46 +521,60 @@ for (my $i = 0; $i < scalar @input; $i++) { # Even if it's a verbose build, we might have to skip this line. next if $skip; + # Skip unnecessary tests when only preprocessing. + my $flag_preprocess = 0; + + my $preprocess = 0; + my $compile = 0; + my $link = 0; + + # Preprocess, compile, assemble. + if ($line =~ /$cc_regex.*?\s(-E|-S|-c)\b/) { + $preprocess = 1; + $flag_preprocess = 1 if $1 eq '-E'; + $compile = 1 if $1 eq '-S' or $1 eq '-c'; + # Otherwise assume we are linking. + } else { + $link = 1; + } - # Is this a compiler or linker command? - my $compiler = 1; - my $linker = 0; - - # Linker commands. - if ($line =~ m{\s-o # -o - [\s\\]*\s+ # possible line continuation - (?:[/.A-Za-z0-9~_-]+/)? # path to file - [A-Za-z0-9~_-]+ # binary name (no dots!) - (?:[0-9.]*\.so[0-9.]*[a-z]? # library (including version) - |\.la)? - (?:\s|\\|$) # end of file name - }x - or $line =~ /^libtool: link: / - or $line =~ m{\s*/bin/bash .+?libtool\s+(.+?\s+)?--mode=(re)?link}) { - $compiler = 0; - $linker = 1; + # These file types don't require preprocessing. + if ($line =~ /$file_no_preprocess_regex/) { + $preprocess = 0; + } + # These file types require preprocessing. + if ($line =~ /$file_preprocess_regex/) { + $preprocess = 1; } # If there are source files then it's compiling/linking in one step and we - # must check both. - if ($line =~ /\.(?:c|cc|cpp)\b/) { - $compiler = 1; + # must check both. We only check for source files here, because header + # files cause too many false positives. + if (not $flag_preprocess and $line =~ /$file_compile_link_regex/) { + # Assembly files don't need CFLAGS. + if (not $line =~ /$file_compile_regex/ + and $line =~ /$file_no_compile_regex/) { + $compile = 0; + # But the rest does. + } else { + $compile = 1; + } } # Check hardening flags. my @missing; - if ($compiler and not all_flags_used($line, \@missing, @cflags) + 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)) { error_flags('CFLAGS missing', \@missing, \%flag_renames, $line); $exit |= 1 << 3; } - if ($compiler and not all_flags_used($line, \@missing, @cppflags)) { + if ($preprocess and not all_flags_used($line, \@missing, @cppflags)) { error_flags('CPPFLAGS missing', \@missing, \%flag_renames, $line); $exit |= 1 << 3; } - if ($linker and not all_flags_used($line, \@missing, @ldflags) + 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)) { error_flags('LDFLAGS missing', \@missing, \%flag_renames, $line); @@ -471,6 +603,7 @@ B [--pie] [--bindnow] [--all] --bindnow force +bindbow check --all force +all (+pie, +bindnow) check --arch set architecture (autodetected) + --buildd parser mode for buildds =head1 DESCRIPTION @@ -508,10 +641,25 @@ 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. +=item B<--buildd> + +Special mode for buildds when automatically parsing log files. The following +changes are in effect: + +=over 2 + +=item + +Don't check hardening flags in old log files (if dpkg-dev << 1.16.1 is +detected). + +=back + =back -Auto detection only works if at least one command uses the required hardening -flag (e.g. -fPIE). Then it's required for all other commands as well. +Auto detection for B<--pie> and B<--bindnow> only works if at least one +command uses the required hardening flag (e.g. -fPIE). Then it's required for +all other commands as well. =head1 EXIT STATUS