X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=bin%2Fblhc;h=0c9360b360788163294b89e94b9832091c05b98c;hb=80aa6479d0057222eadb9a01a6fde08f4a9f10c7;hp=2ea54d4e8f35bf2e0bd60dafd96ab078e44b2b93;hpb=c2874d0d8e4579450add73e804f400fdd7f2f456;p=blhc%2Fblhc.git diff --git a/bin/blhc b/bin/blhc index 2ea54d4..0c9360b 100755 --- a/bin/blhc +++ b/bin/blhc @@ -2,7 +2,7 @@ # Build log hardening check, checks build logs for missing hardening flags. -# Copyright (C) 2012-2020 Simon Ruderich +# Copyright (C) 2012-2021 Simon Ruderich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -341,18 +341,24 @@ my $option_color; # FUNCTIONS -# Only works for single-level arrays with no undef values. Thanks to perlfaq4. -sub array_equal { - my ($first_ref, $second_ref) = @_; +sub split_line { + my ($line) = @_; - return 0 if scalar @{$first_ref} != scalar @{$second_ref}; - - my $length = scalar @{$first_ref}; - for (my $i = 0; $i < $length; $i++) { - return 0 if $first_ref->[$i] ne $second_ref->[$i]; + my @work = ($line); + foreach my $delim (';', '&&', '||') { + my @x; + foreach (@work) { + push @x, Text::ParseWords::parse_line(qr/\Q$delim\E/, 1, $_); + } + @work = @x; } - return 1; + return map { + # Ensure newline at the line end - necessary for + # correct parsing later. + $_ =~ s/\s+$//; + $_ .= "\n"; + } @work; } sub error_flags { @@ -610,7 +616,7 @@ sub compile_flag_regexp { my @result = (); foreach my $flag (@flags) { # Compile flag regexp for faster execution. - my $regex = qr/\s$flag(?:\s|\\)/; + my $regex = qr/\s(['"]?)$flag\1(?:\s|\\)/; # Store flag name in replacement string for correct flags in messages # with qr//ed flag regexps. @@ -684,7 +690,7 @@ if ($option_help) { } if ($option_version) { print <<"EOF"; -blhc $VERSION Copyright (C) 2012-2020 Simon Ruderich +blhc $VERSION Copyright (C) 2012-2021 Simon Ruderich This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -985,16 +991,12 @@ foreach my $file (@ARGV) { $non_verbose |= is_non_verbose_build($line, \$skip); next if $skip; - # One line may contain multiple commands (";"). Treat each one as - # single line. parse_line() is slow, only use it when necessary. - my @line = (index($line, ';') == -1) + # Treat each command as a single line so we don't ignore valid + # commands when handling false positives. split_line() is slow, only + # use it when necessary. + my @line = ($line !~ /(?:;|&&|\|\|)/) ? ($line) - : map { - # Ensure newline at the line end - necessary for - # correct parsing later. - $_ =~ s/\s+$//; - $_ .= "\n"; - } Text::ParseWords::parse_line(';', 1, $line); + : split_line($line); foreach my $line (@line) { if ($continuation) { $continuation = 0; @@ -1020,9 +1022,29 @@ foreach my $file (@ARGV) { $complete_line = undef; } + my $noenv = $line; + # Strip (basic) environment variables for compiler detection. This + # prevents false positives when environment variables contain + # compiler binaries. Nested quotes, command substitution, etc. is + # not supported. + $noenv =~ s/^ + \s* + (?: + [a-zA-Z_]+ # environment variable name + = + (?: + [^\s"'\$`\\]+ # non-quoted string + | + '[^"'\$`\\]*' # single-quoted string + | + "[^"'\$`\\]*" # double-quoted string + ) + \s+ + )* + //x; # Ignore lines with no compiler commands. next if not $non_verbose - and not $line =~ /$cc_regex_normal/o; + and not $noenv =~ /$cc_regex_normal/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 @@ -1043,6 +1065,11 @@ foreach my $file (@ARGV) { # optional compiler options, don't allow # "everything" here to prevent false negatives \s*(?:\s-\S+)*\s*$}xo; + # `echo` is never a compiler command + next if $line =~ /^\s*echo\s/; + # Ignore calls to `make` because they can contain environment + # variables which look like compiler commands, e.g. CC=). + next if $line =~ /^\s*make\s/; # `moc-qt4`/`moc-qt5` contain '-I.../linux-g++' in their command # line (or similar for other architectures) which gets recognized # as a compiler line, but `moc-qt*` is only a preprocessor for Qt @@ -1080,6 +1107,8 @@ foreach my $file (@ARGV) { next if $line =~ /^C\+\+ linker for the host machine: /; # Embedded `gcc -print-*` commands next if $line =~ /`$cc_regex_normal\s*[^`]*-print-\S+`/; + # cmake checking for compiler flags without setting CPPFLAGS + next if $line =~ m{^\s*/usr/(bin|lib)/(ccache/)?c\+\+ -dM -E -c /usr/share/cmake-\S+/Modules/CMakeCXXCompilerABI\.cpp}; # Check if additional hardening options were used. Used to ensure # they are used for the complete build. @@ -1543,6 +1572,9 @@ you find false positives which affect more packages please report a bug. To generate this string simply use echo in C; make sure to use @ to suppress the echo command itself as it could also trigger a false positive. +If the build process takes a long time edit the C<.build> file in place and +tweak the ignore string until B no longer +reports any false positives. =head1 OPTIONS