1#! /usr/bin/perl 2use strict; 3use warnings; 4use File::Spec qw(rel2abs); 5use File::Basename; 6 7my @args = (); 8my $enabled = 0; 9my $debug = 0; 10my $debug_symlinks = 0; 11my $debug_fd = *STDERR; 12 13# Set up defaults 14my %default; 15$default{'DEB_BUILD_HARDENING'}=0; 16$default{'DEB_BUILD_HARDENING_DEBUG'}=0; 17$default{'DEB_BUILD_HARDENING_DEBUG_SYMLINKS'}=0; 18 19# Architecture settings 20# #OS# #ARCH# 21$default{'DEB_BUILD_HARDENING_STACKPROTECTOR'}=1; 22$default{'DEB_BUILD_HARDENING_FORTIFY'}=1; 23$default{'DEB_BUILD_HARDENING_FORMAT'}=1; 24$default{'DEB_BUILD_HARDENING_PIE'}=1; 25 26# System settings 27my $system_conf = '/etc/hardening-wrapper.conf'; 28if (-r $system_conf) { 29 open(CONF,$system_conf) || warn "Cannot read $system_conf\n"; 30 while (my $line = <CONF>) { 31 if ($line =~ /^\s*(DEB_BUILD_HARDENING[_A-Z]*)\s*=\s*(\d)$/) { 32 $default{$1}=$2+0; 33 } 34 } 35 close(CONF); 36} 37 38# Environment settings 39$enabled = defined($ENV{'DEB_BUILD_HARDENING'}) ? 40 $ENV{'DEB_BUILD_HARDENING'} : 41 $default{'DEB_BUILD_HARDENING'}; 42$debug = defined($ENV{'DEB_BUILD_HARDENING_DEBUG'}) ? 43 $ENV{'DEB_BUILD_HARDENING_DEBUG'} : 44 $default{'DEB_BUILD_HARDENING_DEBUG'}; 45$debug_symlinks = defined($ENV{'DEB_BUILD_HARDENING_DEBUG_SYMLINKS'}) ? 46 $ENV{'DEB_BUILD_HARDENING_DEBUG_SYMLINKS'} : 47 $default{'DEB_BUILD_HARDENING_DEBUG_SYMLINKS'}; 48my $force_stack = defined($ENV{'DEB_BUILD_HARDENING_STACKPROTECTOR'}) ? 49 $ENV{'DEB_BUILD_HARDENING_STACKPROTECTOR'} : 50 $default{'DEB_BUILD_HARDENING_STACKPROTECTOR'}; 51my $force_fortify = defined($ENV{'DEB_BUILD_HARDENING_FORTIFY'}) ? 52 $ENV{'DEB_BUILD_HARDENING_FORTIFY'} : 53 $default{'DEB_BUILD_HARDENING_FORTIFY'}; 54my $force_format = defined($ENV{'DEB_BUILD_HARDENING_FORMAT'}) ? 55 $ENV{'DEB_BUILD_HARDENING_FORMAT'} : 56 $default{'DEB_BUILD_HARDENING_FORMAT'}; 57my $force_pie = defined($ENV{'DEB_BUILD_HARDENING_PIE'}) ? 58 $ENV{'DEB_BUILD_HARDENING_PIE'} : 59 $default{'DEB_BUILD_HARDENING_PIE'}; 60my $force_fPIE = defined($ENV{'DEB_BUILD_HARDENING_PIE'}) ? 61 $ENV{'DEB_BUILD_HARDENING_PIE'} : 62 $default{'DEB_BUILD_HARDENING_PIE'}; 63if (defined($ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'})) { 64 $debug_fd = undef; 65 if (!open($debug_fd, ">>$ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'}")) { 66 die "Cannot open $ENV{'DEB_BUILD_HARDENING_DEBUG_OUTPUT'}: $!\n"; 67 } 68} 69 70# Figure out which tool we were called as. 71my $self = "\Qhardened-cc\E"; 72my $link = ""; 73my $arg0 = File::Spec->rel2abs(basename($0),dirname($0)); 74my $tool = $arg0; 75if ($tool =~ /$self$/) { 76 $tool = "/usr/bin/cc"; 77} 78 79sub resolve_link($) 80{ 81 my $origin = $_[0]; 82 my $link = readlink($origin); 83 return File::Spec->rel2abs($link,dirname($origin)); 84} 85 86while (-l $tool && ($link = resolve_link($tool)) !~ /$self$/) { 87 print $debug_fd "$tool -> $link\n" if ($debug_symlinks); 88 $tool = $link; 89} 90if (-x "$tool.real") { 91 print $debug_fd "$tool -real> $tool.real\n" if ($debug_symlinks); 92 $tool = "$tool.real"; 93} 94# Abort if we ended up on a circular symlink resolution 95if ($tool eq $arg0) { 96 my $short = $tool; 97 $short =~ s/.*\///g; 98 print STDERR "$tool: not found (maybe $short is not installed?)\n"; 99 exit(127); 100} 101 102# Set per-tool flags. 103my $ssp_strong = 1; 104my $gcc_version = basename($tool); 105# Disable stack-protector-strong on pre-4.9 GCC. 106if ($gcc_version =~ /4\.[2345678]($|\D)/) { 107 $ssp_strong = 0; 108} 109 110if ($enabled) { 111 # Scan arguments 112 my $linking = 1; 113 foreach my $arg (@ARGV) { 114 if ($arg eq "-fno-PIC" || 115 $arg eq "-fno-pic" || 116 $arg eq "-fno-PIE" || 117 $arg eq "-fno-pie" || 118 $arg eq "-nopie" || 119 $arg eq "-static" || 120 $arg eq "-shared" || 121 $arg eq "-D__KERNEL__" || 122 $arg eq "-nostdlib" || 123 $arg eq "-nostartfiles") 124 { 125 # If any PIC or PIE things are explicitly disabled, 126 # disable all our PIE flags. 127 $force_fPIE = 0; 128 $force_pie = 0; 129 } 130 if ($arg eq "-fPIC" || 131 $arg eq "-fpic") 132 { 133 # fPIC is a stricter version of fPIE, so don't use fPIE when 134 # we encounter fPIC. However, the inclusion of -fPIC does 135 # not mean we need to block the use of "-pie", which is still 136 # possible with fPIC. 137 $force_fPIE = 0; 138 } 139 if ($arg eq "-c") { 140 $linking = 0; 141 } 142 if ($arg =~ /^-D_FORTIFY_SOURCE(=|$)/) { 143 $force_fortify = 0; 144 } 145 if ($arg eq "-nostdlib" || 146 $arg eq "-ffreestanding") { 147 $force_stack = 0; 148 } 149 } 150 151 # Enable SSP by default 152 if ($force_stack) { 153 if ($ssp_strong) { 154 push(@args,'-fstack-protector-strong'); 155 } else { 156 push(@args,'-fstack-protector','--param=ssp-buffer-size=4'); 157 } 158 } 159 160 # Enable -fPIE by default 161 if ($force_fPIE) { 162 push(@args, '-fPIE'); 163 } 164 if ($force_pie) { 165 if ($linking) { 166 # "-pie" is really only meaningful when calling the linker 167 push(@args, '-pie'); 168 } 169 } 170 171 # Enable glibc protections by default (-02 should already be defined...) 172 # (disable with -D_FORTIFY_SOURCE=0) 173 if ($force_fortify) { 174 push(@args,'-D_FORTIFY_SOURCE=2'); 175 } 176 177 # Enable format string checking 178 if ($force_format) { 179 push(@args,'-Wformat','-Wformat-security','-Werror=format-security'); 180 } 181} 182 183my @target = ($tool, @args, @ARGV); 184 185print $debug_fd join(" ",@target),"\n" if ($debug); 186 187exec @target or die "Unable to exec $target[0]: $!\n"; 188