From affd2ba7dcef980b10553894e0aa40ac1c7dd14e Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 30 Apr 2012 16:28:12 +0200 Subject: [PATCH] Add --ignore-arch-flag and --ignore-arch-line. --- MANIFEST | 1 + bin/blhc | 91 ++++++++++++++++++++++++---- t/logs/arch-amd64 | 11 ++++ t/tests.t | 150 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 242 insertions(+), 11 deletions(-) create mode 100644 t/logs/arch-amd64 diff --git a/MANIFEST b/MANIFEST index 032a880..91fcec6 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6,6 +6,7 @@ META.json META.yml NEWS README +t/logs/arch-amd64 t/logs/arch-avr32 t/logs/arch-i386 t/logs/arch-ia64 diff --git a/bin/blhc b/bin/blhc index a51c860..97e8571 100755 --- a/bin/blhc +++ b/bin/blhc @@ -396,6 +396,21 @@ sub is_non_verbose_build { return 1; } +sub remove_flags { + my ($flag_refs_ref, $flag_renames_ref, @flags) = @_; + + my %removes = map { $_ => 1 } @flags; + foreach my $flags (@{$flag_refs_ref}) { + @{$flags} = grep { + # Flag found as string. + not exists $removes{$_} + # Flag found as string representation of regexp. + and (not defined $flag_renames_ref->{$_} + or not exists $removes{$flag_renames_ref->{$_}}) + } @{$flags}; + } +} + sub compile_flag_regexp { my ($flag_renames_ref, @flags) = @_; @@ -437,7 +452,9 @@ my $option_pie = 0; my $option_bindnow = 0; my @option_ignore_arch = (); my @option_ignore_flag = (); +my @option_ignore_arch_flag = (); my @option_ignore_line = (); +my @option_ignore_arch_line = (); my $option_all = 0; my $option_arch = undef; my $option_buildd = 0; @@ -452,7 +469,9 @@ if (not Getopt::Long::GetOptions( # Ignore. 'ignore-arch=s' => \@option_ignore_arch, 'ignore-flag=s' => \@option_ignore_flag, + 'ignore-arch-flag=s' => \@option_ignore_arch_flag, 'ignore-line=s' => \@option_ignore_line, + 'ignore-arch-line=s' => \@option_ignore_arch_line, # Misc. 'color' => \$option_color, 'arch=s' => \$option_arch, @@ -501,17 +520,27 @@ if ($option_all) { $option_bindnow = 1; } +# Precompiled ignores for faster lookup. +my %option_ignore_arch_flag = (); +my %option_ignore_arch_line = (); + # 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}; + remove_flags(\@flag_refs, \%flag_renames, @option_ignore_flag); +} +# Same for arch specific ignore flags, but only prepare here. +if (scalar @option_ignore_arch_flag > 0) { + foreach my $ignore (@option_ignore_arch_flag) { + my ($ignore_arch, $ignore_flag) = split ':', $ignore, 2; + + if (not $ignore_arch or not $ignore_flag) { + printf STDERR 'Value "%s" invalid for option ignore-arch-flag ' + . '("arch:flag" expected)' . "\n", $ignore; + require Pod::Usage; + Pod::Usage::pod2usage(2); + } + + push @{$option_ignore_arch_flag{$ignore_arch}}, $ignore_flag; } } @@ -525,6 +554,21 @@ foreach my $flags (@flag_refs_all) { foreach my $ignore (@option_ignore_line) { $ignore = qr/^$ignore$/; } +# Same for arch specific ignore lines. +if (scalar @option_ignore_arch_line > 0) { + foreach my $ignore (@option_ignore_arch_line) { + my ($ignore_arch, $ignore_line) = split ':', $ignore, 2; + + if (not $ignore_arch or not $ignore_line) { + printf STDERR 'Value "%s" invalid for option ignore-arch-line ' + . '("arch:line" expected)' . "\n", $ignore; + require Pod::Usage; + Pod::Usage::pod2usage(2); + } + + push @{$option_ignore_arch_line{$ignore_arch}}, qr/^$ignore_line$/; + } +} # Final exit code. my $exit = 0; @@ -788,12 +832,27 @@ foreach my $file (@ARGV) { @ldflags = (@ldflags, @def_ldflags_bindnow); } + # Ignore flags for this arch if requested. + if ($arch and exists $option_ignore_arch_flag{$arch}) { + my @flag_refs = (\@cflags, \@cxxflags, \@cppflags, \@ldflags); + + remove_flags(\@flag_refs, + \%flag_renames, + @{$option_ignore_arch_flag{$arch}}); + } + + my @ignore_line = @option_ignore_line; + # Ignore lines for this arch if requested. + if ($arch and exists $option_ignore_arch_line{$arch}) { + @ignore_line = (@ignore_line, @{$option_ignore_arch_line{$arch}}); + } + LINE: for (my $i = 0; $i < scalar @input; $i++) { my $line = $input[$i]; # Ignore line if requested. - foreach my $ignore (@option_ignore_line) { + foreach my $ignore (@ignore_line) { next LINE if $line =~ /$ignore/; } @@ -1059,6 +1118,14 @@ Ignore build logs from architectures matching I. I is a string. Used to prevent false positives. This option can be specified multiple times. +=item B<--ignore-arch-flag> I:I + +Like B<--ignore-flag>, but only ignore flag on I. + +=item B<--ignore-arch-line> I:I + +Like B<--ignore-line>, but only ignore line on I. + =item B<--ignore-flag> I Don't print an error when the specific flag is missing in a compiler line. @@ -1108,6 +1175,10 @@ Don't treat missing C<-g> as error: blhc --ignore-flag -g path/to/log/file +Don't treat missing C<-pie> on kfreebsd-amd64 as error: + + blhc --ignore-arch-flag kfreebsd-amd64:-pie path/to/log/file + Ignore lines consisting exactly of C<./script gcc file> which would cause a false positive. diff --git a/t/logs/arch-amd64 b/t/logs/arch-amd64 new file mode 100644 index 0000000..744b4b4 --- /dev/null +++ b/t/logs/arch-amd64 @@ -0,0 +1,11 @@ +dpkg-buildpackage: source package test +dpkg-buildpackage: host architecture amd64 + +# all hardening options + +gcc -D_FORTIFY_SOURCE=2 -g -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -Wall -c test.c +gcc -fPIE -pie -Wl,-z,relro -Wl,-z,now -o test test.o + +# missing flags +gcc -D_FORTIFY_SOURCE=2 -g -O2 -fPIE --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -Wall -c test.c +gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o diff --git a/t/tests.t b/t/tests.t index 3ef7cd1..0641e45 100644 --- a/t/tests.t +++ b/t/tests.t @@ -19,7 +19,7 @@ use strict; use warnings; -use Test::More tests => 140; +use Test::More tests => 182; sub is_blhc { @@ -100,6 +100,52 @@ is_blhc 'ignore-flag', '--ignore-flag -g --ignore-flag -O2', 0, is_blhc 'ignore-flag-ldflags', '--ignore-flag -fPIE', 0, ''; +# Ignore missing compiler flags for specific architectures. + +# Invalid option. +is_blhc 'ignore-flag', '--ignore-arch-flag -g', 2, + 'Value "-g" invalid for option ignore-arch-flag ("arch:flag" expected) +Usage: + blhc [*options*] *..* + +'; +is_blhc 'ignore-flag', '--ignore-arch-flag -g:', 2, + 'Value "-g:" invalid for option ignore-arch-flag ("arch:flag" expected) +Usage: + blhc [*options*] *..* + +'; + +# Wrong architecture. +is_blhc 'ignore-flag', '--ignore-arch-flag amd64:-g', 8, + 'CFLAGS missing (-g): gcc -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-b.c +CFLAGS missing (-O2): gcc -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-c.c +'; + +is_blhc 'arch-i386', '--ignore-arch-flag i386:-fstack-protector', 8, + 'LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-flag i386:-pie', 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 +'; +is_blhc 'arch-i386', '--ignore-arch-flag i386:-fstack-protector --ignore-arch-flag i386:-pie', 0, + ''; + +# Wrong architecture. +is_blhc 'arch-i386', '--ignore-arch-flag amd64:-fstack-protector', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-flag amd64:-pie', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-flag amd64:-fstack-protector --ignore-arch-flag amd64:-pie', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; + + # Ignore certain lines. is_blhc 'ignore-line', '--ignore-line "\./prepare-script gcc test-[a-z]\.c"', 8, @@ -111,6 +157,67 @@ LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-a.c test-b.c test- is_blhc 'ignore-line', '--ignore-line "\./prepare-script gcc test-[a-z]\.c" --ignore-line "\s*\./prepare-script gcc test-[a-z]\.c .+"', 0, ''; +# Ignore certain lines for specific architectures. + +# Invalid option. +is_blhc 'ignore-line', '--ignore-arch-line .+', 2, + 'Value ".+" invalid for option ignore-arch-line ("arch:line" expected) +Usage: + blhc [*options*] *..* + +'; +is_blhc 'ignore-line', '--ignore-arch-line .+:', 2, + 'Value ".+:" invalid for option ignore-arch-line ("arch:line" expected) +Usage: + blhc [*options*] *..* + +'; + +# Wrong architecture. +is_blhc 'ignore-line', '--ignore-arch-line "amd64:.+"', 8, + 'CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-a.c test-b.c test-c.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-a.c test-b.c test-c.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-a.c test-b.c test-c.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-a.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-a.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-a.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-b.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-b.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-b.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-c.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-c.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-c.c +'; + +# Line regex anchored at beginning/end of the line. +is_blhc 'arch-i386', '--ignore-arch-line "i386:-fPIE --param=ssp-buffer-size=4"', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; + +is_blhc 'arch-i386', '--ignore-arch-line "i386:gcc .+ -fPIE --param=ssp-buffer-size=4 .+ test\.c"', 8, + 'LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-line "i386:gcc .+ -Wl,-z,relro -Wl,-z,now .+"', 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 +'; +is_blhc 'arch-i386', '--ignore-arch-line "i386:gcc .+ -fPIE --param=ssp-buffer-size=4 .+ test\.c" --ignore-arch-line "i386:gcc .+ -Wl,-z,relro -Wl,-z,now .+"', 0, + ''; + +# Wrong architecture. +is_blhc 'arch-i386', '--ignore-arch-line "amd64:gcc .+ -fPIE --param=ssp-buffer-size=4 .+ test\.c"', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-line "amd64:gcc .+ -Wl,-z,relro -Wl,-z,now .+"', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; +is_blhc 'arch-i386', '--ignore-arch-line "amd64:gcc .+ -fPIE --param=ssp-buffer-size=4 .+ test\.c" --ignore-arch-line "amd64:gcc .+ -Wl,-z,relro -Wl,-z,now .+"', 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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +'; + # Correct build logs. @@ -774,3 +881,44 @@ is_blhc ['bad-ldflags', 'empty', 'arch-avr32', 'debian-hardening-wrapper'], '', . "checking './t/logs/debian-hardening-wrapper'...\n" . $debian_hardening_wrapper ; + +# Ignore works correctly with multiple architectures. +is_blhc ['arch-i386', 'arch-amd64', 'arch-avr32', 'ignore-flag'], + '--ignore-arch-flag i386:-fstack-protector --ignore-arch-flag mipsel:-Werror=format-security', 8, + "checking './t/logs/arch-i386'... +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +checking './t/logs/arch-amd64'... +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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +checking './t/logs/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 +checking './t/logs/ignore-flag'... +CFLAGS missing (-g): gcc -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-b.c +CFLAGS missing (-O2): gcc -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -c test-c.c +" + ; + +is_blhc ['arch-i386', 'arch-amd64', 'arch-avr32', 'ignore-line'], + '--ignore-arch-line "i386:gcc .+ -fPIE --param=ssp-buffer-size=4 .+" --ignore-arch-line "mipsel:gcc .+ -Wl,-z,relro -Wl,-z,now .+"', 8, + "checking './t/logs/arch-i386'... +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +checking './t/logs/arch-amd64'... +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 +LDFLAGS missing (-pie): gcc -fPIE -Wl,-z,relro -Wl,-z,now -o test test.o +checking './t/logs/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 +checking './t/logs/ignore-line'... +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-a.c test-b.c test-c.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-a.c test-b.c test-c.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-a.c test-b.c test-c.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-a.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-a.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-a.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-b.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-b.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-b.c +CFLAGS missing (-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security): ./prepare-script gcc test-c.c +CPPFLAGS missing (-D_FORTIFY_SOURCE=2): ./prepare-script gcc test-c.c +LDFLAGS missing (-Wl,-z,relro): ./prepare-script gcc test-c.c +" + ; -- 2.43.2