#! /usr/bin/perl
use strict;
use warnings;

my @args = ();
my $debug = 0;

if (defined($ENV{'DEB_BUILD_HARDENING'}) && $ENV{'DEB_BUILD_HARDENING'}!='0') {
    # Set up defaults, based on OS and CPU
    my %default;
    $default{'DEB_BUILD_HARDENING_DEBUG'}=0;

    # #OS# #CPU#
    $default{'DEB_BUILD_HARDENING_STACKPROTECTOR'}=1;
    $default{'DEB_BUILD_HARDENING_FORTIFY'}=1;
    $default{'DEB_BUILD_HARDENING_FORMAT'}=1;
    $default{'DEB_BUILD_HARDENING_PIE'}=1;

    # Scan arguments
    my $force_stack =   defined($ENV{'DEB_BUILD_HARDENING_STACKPROTECTOR'}) ?
                            $ENV{'DEB_BUILD_HARDENING_STACKPROTECTOR'} : 
                            $default{'DEB_BUILD_HARDENING_STACKPROTECTOR'};
    my $force_format =  defined($ENV{'DEB_BUILD_HARDENING_FORMAT'}) ?
                            $ENV{'DEB_BUILD_HARDENING_FORMAT'} :
                            $default{'DEB_BUILD_HARDENING_FORMAT'};
    my $force_fPIE =    defined($ENV{'DEB_BUILD_HARDENING_PIE'}) ?
                            $ENV{'DEB_BUILD_HARDENING_PIE'} :
                            $default{'DEB_BUILD_HARDENING_PIE'};
    my $force_pie =     defined($ENV{'DEB_BUILD_HARDENING_PIE'}) ?
                            $ENV{'DEB_BUILD_HARDENING_PIE'} :
                            $default{'DEB_BUILD_HARDENING_PIE'};
    my $force_fortify = defined($ENV{'DEB_BUILD_HARDENING_FORTIFY'}) ?
                            $ENV{'DEB_BUILD_HARDENING_FORTIFY'} :
                            $default{'DEB_BUILD_HARDENING_FORTIFY'};
    $debug =            defined($ENV{'DEB_BUILD_HARDENING_DEBUG'}) ?
                            $ENV{'DEB_BUILD_HARDENING_DEBUG'} :
                            $default{'DEB_BUILD_HARDENING_DEBUG'};

    my $linking = 1;
    foreach my $arg (@ARGV) {
        if ($arg eq "-fno-PIC" ||
            $arg eq "-fno-pic" ||
            $arg eq "-fno-PIE" ||
            $arg eq "-fno-pie" ||
            $arg eq "-nopie" ||
            $arg eq "-static" ||
            $arg eq "-shared" ||
            $arg eq "-D__KERNEL__" ||
            $arg eq "-nostdlib" ||
            $arg eq "-nostartfiles")
        {
            # If any PIC or PIE things are explicitly disabled,
            # disable all our PIE flags.
            $force_fPIE = 0;
            $force_pie = 0;
        }
        if ($arg eq "-fPIC" ||
            $arg eq "-fpic")
        {
            # fPIC is a stricter version of fPIE, so don't use fPIE when
            # we encounter fPIC.  However, the inclusion of -fPIC does
            # not mean we need to block the use of "-pie", which is still
            # possible with fPIC.
            $force_fPIE = 0;
        }
        if ($arg eq "-c") {
            $linking = 0;
        }
        if ($arg =~ /^-D_FORTIFY_SOURCE(=|$)/) {
            $force_fortify = 0;
        }
    }

    # Enable SSP by default
    if ($force_stack) {
        push(@args,'-fstack-protector');
    }

    # Enable -fPIE by default
    if ($force_fPIE) {
        push(@args, '-fPIE');
    }
    if ($force_pie) {
        if ($linking) {
            # "-pie" is really only meaningful when calling the linker
            push(@args, '-pie');
        }
    }

    # Enable glibc protections by default (-02 should already be defined...)
    # (disable with -D_FORTIFY_SOURCE=0)
    if ($force_fortify) {
        push(@args,'-D_FORTIFY_SOURCE=2');
    }

    # Enable format string checking
    if ($force_format) {
        push(@args,'-Wformat','-Wformat-security');
    }
}

my $self = "\Qhardened-cc\E";
my $link = "";
my $tool = $0;
if ($tool =~ /$self$/) {
    $tool = "/usr/bin/cc";
}
while (-l $tool && ($link = readlink($tool)) !~ /$self$/) {
    $tool = $link;
}
if (-x "$tool.real") {
    $tool = "$tool.real";
}
my @target = ($tool, @args, @ARGV);

print STDERR join(" ",@target),"\n" if ($debug);

exec @target or die "Unable to exec $target[0]: $!\n";
