Skip to content

Commit

Permalink
dpkg-buildflags: Add support for stack-clash / cf-protection
Browse files Browse the repository at this point in the history
Currently this is disabled by default for Debian but enabled for Ubuntu.
Since cf-protection is specific to Intel x86 architectures this will be
force disabled on all other architectures. Similar, stack-clash-protection
is only able to be enabled on architectures which are known to support it.
  • Loading branch information
alexmurray committed Jun 30, 2020
1 parent 33b5bf0 commit 8109c09
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 4 deletions.
20 changes: 20 additions & 0 deletions man/dpkg-buildflags.pod
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,26 @@ Disabling B<stackprotector> will also disable this setting.
This feature has the same requirements as B<stackprotector>, and in
addition also requires gcc 4.9 and later.

=item B<stackclashprotection>

This setting adds
B<-fstack-clash-protection>
to B<CFLAGS>, B<CXXFLAGS>, B<OBJCFLAGS> and B<OBJCXXFLAGS>. This adds
extra instructions around variable length stack memory allocations (via
B<alloca> or variable length arrays) to probe each page of memory at
allocation time. This mitigates stack-clash attacks by ensuring all stack
memory allocations are valid (or by raising a segmentation fault if they
are not, and hence turning a possible code-execution attack into a denial
of service).

=item B<cfprotection>

This setting adds
B<-fcf-protection>
to B<CFLAGS>, B<CXXFLAGS>, B<OBJCFLAGS> and B<OBJCXXFLAGS>. This instructs
the compiler to generate additional instructions to support Intel's
Control-flow Enforcement Technology (CET).

=item B<relro>

This setting (enabled by default) adds
Expand Down
30 changes: 30 additions & 0 deletions scripts/Dpkg/Vendor/Debian.pm
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ sub _add_build_flags {
format => 1,
relro => 1,
bindnow => 0,
stackclashprotection => 0,
cfprotection => 0,
},
);

Expand Down Expand Up @@ -350,6 +352,16 @@ sub _add_build_flags {
# relro not implemented on ia64, hppa, avr32.
$use_feature{hardening}{relro} = 0;
}
if ($cpu !~ /^(?:amd64|arm64|i386|ppc64|ppc64el|s390x|x32)$/) {
# Stack clash protection only enabled on amd64, arm64, i386, ppc64,
# ppc64el, s390x, x32
$use_feature{hardening}{stackclashprotection} = 0;
}
if ($cpu !~ /^(?:amd64|i386|x32)$/) {
# Control flow protection is Intel only so only enabled on amd64,
# i386, and x32
$use_feature{hardening}{cfprotection} = 0;
}

# Mask features that might be influenced by other flags.
if ($opts_build->has('noopt')) {
Expand Down Expand Up @@ -440,6 +452,24 @@ sub _add_build_flags {
$flags->append('LDFLAGS', '-Wl,-z,now');
}

# Stack clash protection
if ($use_feature{hardening}{stackclashprotection}) {
my $flag = '-fstack-clash-protection';
$flags->append('CFLAGS', $flag);
$flags->append('CXXFLAGS', $flag);
$flags->append('OBJCFLAGS', $flag);
$flags->append('OBJCXXFLAGS', $flag);
}

# Control flow integrity protection
if ($use_feature{hardening}{cfprotection}) {
my $flag = '-fcf-protection';
$flags->append('CFLAGS', $flag);
$flags->append('CXXFLAGS', $flag);
$flags->append('OBJCFLAGS', $flag);
$flags->append('OBJCXXFLAGS', $flag);
}

## Commit

# Set used features to their builtin setting if unset.
Expand Down
46 changes: 42 additions & 4 deletions scripts/Dpkg/Vendor/Ubuntu.pm
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,50 @@ sub run_hook {

require Dpkg::BuildOptions;

my $build_opts = Dpkg::BuildOptions->new();
my $opts_build = Dpkg::BuildOptions->new(envvar => 'DEB_BUILD_OPTIONS');
my $opts_maint = Dpkg::BuildOptions->new(envvar => 'DEB_BUILD_MAINT_OPTIONS');

# in Ubuntu we enable stackclashprotection and cfprotection by
# default - so if these have not been disabled then we need to
# enable them - and if they have been disabled we need to emit
# flags to override and disable them - and ensure
# DEB_BUILD_MAINT_OPTIONS takes precedence over DEB_BUILD_OPTIONS
my $hardening = '';
if ($opts_maint->has('hardening')) {
$hardening = $opts_maint->get('hardening');
} elsif ($opts_build->has('hardening')) {
$hardening = $opts_build->get('hardening');
}

require Dpkg::Arch;

if (!$build_opts->has('noopt')) {
require Dpkg::Arch;
my $arch = Dpkg::Arch::get_host_arch();
my ($abi, $libc, $os, $cpu) = Dpkg::Arch::debarch_to_debtuple($arch);

if ($cpu =~ /^(?:amd64|arm64|i386|ppc64|ppc64el|s390x|x32)$/) {
# Stack clash protection only enabled on amd64, arm64, i386, ppc64,
# ppc64el, s390x, x32
my $disabled = $hardening =~ "-stackclashprotection";
my $flag = $disabled ? '-fno-stack-clash-protection' : '-fstack-clash-protection';
for my $envvar (qw(CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS)) {
$flags->append($envvar, $flag);
}
$flags->set_feature('hardening', 'stackclashprotection', !$disabled);
}


if ($cpu =~ /^(?:amd64|i386|x32)$/) {
# Control flow protection is Intel only so only enabled on amd64,
# i386, and x32
my $disabled = $hardening =~ "-cfprotection";
my $flag = $disabled ? '-fcf-protection=none' : '-fcf-protection';
for my $envvar (qw(CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS)) {
$flags->append($envvar, $flag);
}
$flags->set_feature('hardening', 'cfprotection', !$disabled);
}

my $arch = Dpkg::Arch::get_host_arch();
if (!$opts_build->has('noopt')) {
if (Dpkg::Arch::debarch_eq($arch, 'ppc64el')) {
for my $flag (qw(CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS GCJFLAGS
FFLAGS FCFLAGS)) {
Expand Down
2 changes: 2 additions & 0 deletions scripts/t/Dpkg_BuildFlags.t
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ my %known_features = (
) ],
hardening => [ qw(
bindnow
cfprotection
format
fortify
pie
relro
stackclashprotection
stackprotector
stackprotectorstrong
) ],
Expand Down

0 comments on commit 8109c09

Please sign in to comment.