# CONSTANTS/VARIABLES
# Regex to catch compiler commands.
-my $cc_regex = qr/(?:x86_64-linux-gnu-)?(?:(?<!\.)cc|gcc|g\+\+|c\+\+)(?:-[\d.]+)?/;
+my $cc_regex = qr/(?:[a-z0-9_]+-(?:linux|kfreebsd)-gnu(?:eabi|eabihf)?-)?
+ (?:(?<!\.)cc|gcc|g\+\+|c\+\+)
+ (?:-[\d.]+)?/x;
# Regex to catch (GCC) compiler warnings.
my $warning_regex = qr/^(.+?):([0-9]+):[0-9]+: warning: (.+?) \[(.+?)\]$/;
my ($line, $next_line, $skip_ref) = @_;
if (not ($line =~ /^checking if you want to see long compiling messages\.\.\. no/
- or $line =~ /^\s*\[?(?:CC|CCLD|LD)\]?\s+(.+?)$/
+ or $line =~ /^\s*\[?(?:CC|CCLD|CXX|CXXLD|LD)\]?\s+(.+?)$/
or $line =~ /^\s*(?:C|c)ompiling\s+(.+?)(?:\.\.\.)?$/
or $line =~ /^\s*(?:B|b)uilding (?:program|shared library)\s+(.+?)$/
or $line =~ /^\s*\[[\d ]+%\] Building (?:C|CXX) object (.+?)$/)) {
my $option_version = 0;
my $option_all = 0;
my $option_arch = undef;
+my $option_buildd = 0;
if (not Getopt::Long::GetOptions(
'help|h|?' => \$option_help,
'version' => \$option_version,
'all' => \$option_all,
# Misc.
'arch' => \$option_arch,
+ 'buildd' => \$option_buildd,
)) {
require Pod::Usage;
Pod::Usage::pod2usage(2);
my $continuation = 0;
my $complete_line = undef;
while (my $line = <>) {
+ # 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 to prevent false
# positives.
$start = 1 if $line =~ /^dpkg-buildpackage:/;
# Also strip '\0xf' (delete previous character), used by Elink's 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);
#
# `./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*$/
+ next if $line =~ /^\s*(?:C\s+)?
+ (?:C|c)ompiler[\s.]*:\s+
+ $cc_regex
+ (?:\s-std=[a-z0-9:+]+)?\s*$
+ /x
or $line =~ /^\s*(?:- )?(?: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;
}
--bindnow force +bindbow check
--all force +all (+pie, +bindnow) check
--arch set architecture (autodetected)
+ --buildd parser mode for buildds
=head1 DESCRIPTION
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