Differences between revisions 1 and 58 (spanning 57 versions)
Revision 1 as of 2007-07-07 21:49:19
Size: 94
Editor: ?MoritzMuehlenhoff
Comment: Initial entry
Revision 58 as of 2011-12-13 23:58:35
Size: 20712
Editor: ?SimonRuderich
Comment: Documentat that buildflags.mk overwrites variables.
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
There will be more content soon.

Links:
[http://people.redhat.com/drepper/nonselsec.pdf]
<<TableOfContents>>

= Using Hardening Options =

Several compile-time options (detailed below) can be used to help harden a resulting binary against memory corruption attacks, or provide additional warning messages during compiles. This can be done either through "dpkg-buildflags", or one of the packages provided by the "hardening-wrapper" source: "hardening-wrapper" or "hardening-includes".

Using "dpkg-buildflags" is the recommended way to incorporate the build flags in Debian.

"hardening-wrapper" is a set of scripts that divert the compiler, designed to help provide these options without requiring packaging changes.

"hardening-includes" is a single Makefile snippet that can be included in {{{debian/rules}}} from which the compile-time environment variables can be augmented to include the hardening options.

See [[ReleaseGoals/SecurityHardeningBuildFlags]] for additional information.

Choosing the appropriate method is up to you.

== dpkg-buildflags ==

To use "dpkg-buildflags", either switch to dh(1) to do builds (requires debian/compat=9), or use it directly in your builds to set the default compiler and linker flags:

{{{
CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS)
CFLAGS:=$(shell dpkg-buildflags --get CFLAGS)
CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS)
LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)

hello.o: hello.c
    $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o hello.o hello.c
}}}

Or you can use the new buildflags.mk file (dpkg >= 1.16.1) to set all *FLAGS:

{{{
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
}}}

buildflags.mk overwrites the *FLAGS, so additions to the flags must happen after the include. Make sure to append to the *FLAGS instead of overwriting them, e.g. use CFLAGS += -Wextra instead of CFLAGS = -Wextra:

{{{
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

CFLAGS += -Wextra
}}}


---- /!\ '''Edit conflict - other version:''' ----
buildflags.mk overwrites the *FLAGS, so additions to the flags must happen after the include. Make sure to append to the *FLAGS instead of overwriting them, e.g. use CFLAGS += -Wextra instead of CFLAGS = -Wextra:

{{{
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

CFLAGS += -Wextra
}}}


---- /!\ '''Edit conflict - your version:''' ----

---- /!\ '''End of edit conflict''' ----
This also works with DEB_BUILD_MAINT_OPTIONS, just declare it before the include (needs dpkg >= 1.16.1.1):

{{{
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
}}}

When building programs that handle untrusted data (parsers, network listeners, etc.), or run with elevated privileges (PAM, X, etc.), please enable "PIE" and "BINDNOW" in the build. The "all" option enables "PIE" and "BINDNOW" and future hardening flags:

{{{
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
}}}

CDBS packages can either use the flags mentioned above or can use the following flag before loading CDBS files to enable hardening flags (if this flag is not set not all hardening flags are used, see [[http://bugs.debian.org/651964|#651964]]):

{{{
CDBS_FIX_COMPILE_FLAGS = 1
}}}

Due to [[http://bugs.debian.org/651966|#651966]] it's not possible to use DEB_BUILD_MAINT_OPTIONS if CDBS_FIX_COMPILE_FLAGS is used. To enable "PIE" and "BINDOW" set the flags manually.

See the "HARDENING" section of the "dpkg-buildflags" manpage for more details.

== hardening-wrapper ==

To use "hardening-wrapper", add it to the Build-Depends of your package, and enable it in the {{{debian/rules}}} file:

{{{
export DEB_BUILD_HARDENING=1
}}}

After that, any use of gcc, g++, or ld will have all hardening features enabled by default. Each feature can be disabled individually (via {{{export DEB_BUILD_HARDENING_[feature]=0}}}, see below), if there are complications with the build resulting from the new features. (So far, only rare issues with stack protector and PIE support have been documented.)

To illustrate the effects of the options, a [[http://anonscm.debian.org/loggerhead/hardening/master/annotate/head:/example/trivial.c|trivial]] C source (with [[http://anonscm.debian.org/loggerhead/hardening/master/annotate/head:/example/Makefile|Makefile]]) is used as an example.

== hardening-includes ==

To use "hardening-includes", add it to the Build-Depends of your package, include its Makefile snippet in {{{debian/rules}}}, and adjust the compiler flags to use it. For example, with a pure debhelper-7 style {{{debian/rules}}}:

{{{
#!/usr/bin/make -f

include /usr/share/hardening-includes/hardening.make

CFLAGS=$(shell dpkg-buildflags --get CFLAGS)
LDFLAGS=$(shell dpkg-buildflags --get LDFLAGS)
CFLAGS+=$(HARDENING_CFLAGS)
LDFLAGS+=$(HARDENING_LDFLAGS)

%:
        dh $@
}}}

If you're building C++, use {{{CXXFLAGS}}} instead of {{{CFLAGS}}} above, etc. If building C and C++, use both.

Each hardening feature can be disabled individually (via {{{export DEB_BUILD_HARDENING_[feature]=0}}}, see below), if there are complications with the build resulting from the new features. (So far, only rare issues with stack protector and PIE support have been documented.)

See the [[http://anonscm.debian.org/loggerhead/hardening/master/annotate/head:/hardening-wrapper/hardening.make|Makefile snippet]] for more documentation on disabling features on a per-target basis, compiler option filtering, etc.

To illustrate the effects of the options, a [[http://anonscm.debian.org/loggerhead/hardening/master/annotate/head:/example/trivial.c|trivial]] C source (with [[http://anonscm.debian.org/loggerhead/hardening/master/annotate/head:/example/Makefile|Makefile]]) is used as an example.

= Validation =

To verify that the resulting binary does, in fact, have hardening features enabled, you can use "hardening-check" from the "hardening-includes" package to test each ELF binary:

{{{
$ hardening-check /usr/sbin/sshd
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes
 Read-only relocations: yes
 Immediate binding: yes
}}}

If your binary does not make use of character arrays on the stack, it's possible that "Stack protected" will report "no", since there was no stack it found to protect. If you absolutely want to protect all stacks, you can add "-fstack-protector-all", but this tends not to be needed, and there are some trade-offs on speed.

If your binary does not make use of FORTIFY_SOURCE-protected glibc routines, it's possible that "Fortify Source functions" will report "no", since there were no functions used that included the glibc fortification routines.

= Environment variables =

Both "hardening-wrapper" and "hardening-includes" react to the following set of environment variables and change the behavior of the compiler flags.

== DEB_BUILD_HARDENING_FORMAT (gcc/g++ -Wformat -Wformat-security -Werror=format-security) ==

Quoting the gcc man page:
  If `-Wformat` is specified, also warn about uses of format
  functions that represent possible security problems. At present,
  this warns about calls to `printf` and `scanf` functions where the
  format string is not a string literal and there are no format
  arguments, as in `printf (foo);`. This may be a security hole if
  the format string came from untrusted input and contains `%n`.
[[http://en.wikipedia.org/wiki/Format_string_attack]]

Default compile:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
}}}

Hardened compile:
{{{
$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
}}}

Known problems: (Common build failures, non-availability on some archs)

 * None so far.

== DEB_BUILD_HARDENING_FORTIFY (gcc/g++ -D_FORTIFY_SOURCE=2) ==

During code generation the compiler knows a great deal of information about
buffer sizes (where possible), and attempts to replace insecure unlimited
length buffer function calls with length-limited ones. This is especially
useful for old, crufty code. Additionally, format strings in writable memory that contain '%n' are blocked. If an application depends on such a format string, it will need to be worked around.

Note that for this feature to be fully enabled,
the source must also be compiled with -O1 or higher.

Default build:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
}}}

Hardened build:
{{{
$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ ./trivial $(perl -e 'print "A"x100')
*** buffer overflow detected ***: ./trivial terminated
}}}

Known problems: (Common build failures, non-availability on some archs)

 * Code compiled with -Werror and using memcpy/strcpy with qualifier overrides will fail with FORTIFY enabled. See https://launchpad.net/bugs/217481

== DEB_BUILD_HARDENING_STACKPROTECTOR (gcc/g++ -fstack-protector --param ssp-buffer-size=4) ==

This is a mainline GCC feature, which adds safety checks against stack
overwrites. This renders many potential code injection attacks into
aborting situations. In the best case this turns code injection vulnerabilities
into denial of service or into non-issues (depending on the application).
[[http://en.wikipedia.org/wiki/Stack-smashing_protection]]

Default build:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
}}}

Hardened build (with FORTIFY disabled, since it catches the stack overflow before it happens):
{{{
$ DEB_BUILD_HARDENING=1 DEB_BUILD_HARDENING_FORTIFY=0 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: ./trivial terminated
}}}

Known problems: (Common build failures, non-availability on some archs)

 * Not supported on ia64 and alpha. (disabled for these archs by default in hardening-wrapper 1.8)
 {{{warning: -fstack-protector not supported for this target}}}
 * Not supported on mips and hppa. (disabled for these archs by default in hardening-wrapper 1.10)
 {{{warning: -fstack-protector not supported for this target}}}

== DEB_BUILD_HARDENING_PIE (gcc/g++ -fPIE -pie) ==

[[http://en.wikipedia.org/wiki/Position-independent_code#Position-independent_executables|Position Independent Executable]] are needed to take advantage of [[http://en.wikipedia.org/wiki/ASLR|Address Space Layout Randomization]], supported by some kernel versions. While ASLR can already be enforced for data areas in the stack and heap (brk and mmap), the code areas must be compiled as position-independent. Shared libraries already do this (-fPIC), so they gain ASLR automatically, but binary {{{.text}}} regions need to be build PIE to gain ASLR. When this happens, [[http://en.wikipedia.org/wiki/Return-oriented_programming|ROP]] attacks are much harder since there are no static locations to bounce off of during a memory corruption attack.

Default build:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ file trivial
trivial: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped
}}}

Hardened build:
{{{
$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ file trivial
trivial: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, not stripped
}}}

Known problems: (Common build failures, non-availability on some archs)

 * Doesn't work on hppa and m68k (disabled for these archs by default in hardening-wrapper 1.6)
 * Doesn't work on some assembler, due to lack of registers. e.g.:
 {{{vf_decimate.c:26: error: can't find a register in class 'BREG' while reloading 'asm'}}}

== DEB_BUILD_HARDENING_RELRO (ld -z relro) ==

During program load, several ELF memory sections need to be written to by the linker, but can be
turned read-only before turning over control to the program. Most notably this prevents GOT overwrite
attacks.

Default build:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ objdump -x trivial | grep RELRO
}}}

Hardened build:
{{{
$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ objdump -x trivial | grep RELRO
   RELRO off 0x0000000000000de8 vaddr 0x0000000000200de8 paddr 0x0000000000200de8 align 2**0
}}}

Known problems: (Common build failures, non-availability on some archs)

 * Unimplemented on ia64 (ld silently ignores the option).

== DEB_BUILD_HARDENING_BINDNOW (ld -z now) ==

During program load, all dynamic symbols are resolved, allowing for the PLT to be marked read-only (due to -z relro above). For very large application, this can incur some performance loss during initial load while symbols are resolved.

Default build:
{{{
$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ readelf -d trivial | grep BIND
}}}

Hardened build:
{{{
$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ readelf -d trivial | grep BIND
 0x0000000000000018 (BIND_NOW)
}}}

Known problems: (Common build failures, non-availability on some archs)

 * None.

= State of implementation =

An [[http://lists.debian.org/debian-devel-announce/2008/01/msg00006.html|email]] was sent to the debian-devel-announce list in 2006 introducing the hardening-wrapper package and describing the way to integrate this hardening features in Debian.

[[http://lists.debian.org/debian-gcc/2009/10/msg00186.html|A discussion]] has been fired on the debian-gcc list, as well as several bugs ([[DebianBug:552688|bug 552688]], [[DebianBug:489771|bug 489771]]) reported to decide the best way to enable hardening compiler options.

Packages that have a bug report asking for the inclusion of this features can be found on the [[http://bugs.debian.org/cgi-bin/pkgreport.cgi?tag=hardening;users=debian-security@lists.debian.org|bug tracker]].

A list of packages including hardening-wrapper and hardening-includes in their build-deps can be retrieved with the folowing commands:

 * reverse-build-depends --only-main --distribution unstable hardening-wrapper
 * reverse-build-depends --only-main --distribution unstable hardening-includes

After their meeting on the 14-16 January 2011, the debian security team announced in an [[http://lists.debian.org/debian-devel-announce/2011/01/msg00006.html|email]] they intend to push the inclusion of hardening features for the wheezy release. A Birds of a Feather-session will be organized during the 2011 debconf to setup a process.

= Notes on Memory Corruption Mitigation Methods =

== User Space ==

=== Stack Protector ===

gcc's -fstack-protector attempts to detect when a stack has been overwritten and aborts the program. Ubuntu has had this enabled by default since Edgy. [[https://wiki.ubuntu.com/GccSsp|Some programs]] do not play nice with it, and can be worked around with -fno-stack-protector. It would be nice to enable this by default, and for gcc to only attempt to use it when libc is being linked against.

Already done in sendmail.

=== heap protection ===

In glibc2.5, no additional work needed.

=== libc pointer encryption ===

In mainline glibc, as PTR_MANGLE.

=== gcc -D_FORTIFY_SOURCE=2 -O1 ===

Compile-time protection against static sized buffer overflows. No known regressions or performance loss. This should be enabled system-wide

=== gcc -Wformat -Wformat-security ===

While not all programs correctly implement the printf hints (like [[http://developer.gnome.org/doc/API/2.0/glib/glib-Miscellaneous-Macros.html|glib's G_GNUC_PRINTF macro]]), adding this will at least call out simple printf format string vulnerabilities. Any programs whose builds become "noisy" as a result, should be fixed anyway.

=== gcc -pie -fPIE ===

This is especially difficult to plumb into packaging in a safe way, since it requires the executable be built with -fPIE for any .o files that are linked at the end with -pie. There is some amount of performance loss, but only due to the -fPIE, which is already true for all the linked libraries (via their -fPIC).

Already done with openssh, sendmail.

=== ld -z relro ===

(Or via gcc with -Wl,-z,relro) Already done with sendmail.

=== ld -z now ===

(Or via gcc with -Wl,-z,now).

== Kernel Space ==

=== non-exec memory segmentation (ExecShield) ===

Stops execution of code in heap/stack. i386 specific (nx already does this for amd64), and introduces some small level of performance loss (5% for CPU-bound). Some people have worked on getting it pushed into the mainline kernel. Current state unknown -- would be very handy to have due to the popularity of i386. Marcus Better may be willing to continue to maintain the patchset for Debian.

Some applications appear to break when run in the protected memory layout. Most of these issues should be fixed due to RH (and SUSE?) already running with these protections.

Additional work for user-space is identifying programs that build assembly but fail to explicitly mark their stack as non-exec (gnupg, for example).

=== -fstack-protector ===

Is available for amd64 builds:

 config CC_STACKPROTECTOR

=== runtime memory allocation validation ===

Detect double-frees in kernel space. No idea where it stands.

=== Address Space Layout Randomization ===

 * mmap: in mainline
 * stack: in mainline
 * vdso: in since 2.6.18 (COMPAT_VDSO disables it)
 * heap/exec: in -mm, 2.6.24
 * brk: 2.6.25

Having heap/exec ASLR is a prerequisite for -pie being useful. Presently, openssh is compiled with -pie.

=== /proc/$pid/maps protection ===

Present in 2.6.22; requires sysctl toggle (kernel.maps_protect = 1). Became non-optional in [[http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=3bbfe0596746e1590888a6e1e6a07583265238b7|2.6.27]]

=== /dev/mem protection ===

Included in 2.6.25.

=== link protections ===

From the GRSecurity patchset, protections against hardlink/symlink creation/following in world-writable areas. (Solves tmp races.) May potentially break things like postfix that manipulation hardlinks? Breaks POSIX. Getting taken in mainline may be tpossible with a build-time or proc toggle.

[[http://lkml.org/lkml/2005/3/10/101]]
[[http://lkml.org/lkml/2005/4/18/167]]

=== chroot, dmesg, fifo protections ===

Also from GRSecurity patchset.

== Documentation ==
 * [[https://wiki.ubuntu.com/CompilerFlags]]
 * [[http://people.redhat.com/drepper/nonselsec.pdf]]
 * [[http://www.suse.de/~krahmer/no-nx.pdf]]
 * http://www.neworder.box.sk/newsread.php?newsid=13007
 * [[http://www.hackinthebox.org/modules.php?op=modload&name=News&file=article&sid=15604&mode=thread&order=0&thold=0]]
 * [[http://www.phrack.org/archives/58/p58-0x04]]
 * [[http://insecure.org/sploits/non-executable.stack.problems.html]]
 * [[http://www.phrack.org/archives/59/p59-0x09.txt]]
 * [[http://www.coresecurity.com/files/attachments/Richarte_Stackguard_2002.pdf]]
 * [[http://www.redhat.com/archives/fedora-tools-list/2004-September/msg00002.html]]
 * [[http://www.gentoo.org/proj/en/hardened/hardened-toolchain.xml]]
 * [[http://labs.mwrinfosecurity.com/notices/security_mechanisms_in_linux_environment__part_1___userspace_memory_protection/]]
 * [[http://labs.mwrinfosecurity.com/notices/assessing_the_tux_strength_part_2_into_the_kernel/]]

Using Hardening Options

Several compile-time options (detailed below) can be used to help harden a resulting binary against memory corruption attacks, or provide additional warning messages during compiles. This can be done either through "dpkg-buildflags", or one of the packages provided by the "hardening-wrapper" source: "hardening-wrapper" or "hardening-includes".

Using "dpkg-buildflags" is the recommended way to incorporate the build flags in Debian.

"hardening-wrapper" is a set of scripts that divert the compiler, designed to help provide these options without requiring packaging changes.

"hardening-includes" is a single Makefile snippet that can be included in debian/rules from which the compile-time environment variables can be augmented to include the hardening options.

See ReleaseGoals/SecurityHardeningBuildFlags for additional information.

Choosing the appropriate method is up to you.

dpkg-buildflags

To use "dpkg-buildflags", either switch to dh(1) to do builds (requires debian/compat=9), or use it directly in your builds to set the default compiler and linker flags:

CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS)
CFLAGS:=$(shell dpkg-buildflags --get CFLAGS)
CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS)
LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)

hello.o: hello.c
    $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o hello.o hello.c

Or you can use the new buildflags.mk file (dpkg >= 1.16.1) to set all *FLAGS:

DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

buildflags.mk overwrites the *FLAGS, so additions to the flags must happen after the include. Make sure to append to the *FLAGS instead of overwriting them, e.g. use CFLAGS += -Wextra instead of CFLAGS = -Wextra:

DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

CFLAGS += -Wextra


/!\ Edit conflict - other version:


buildflags.mk overwrites the *FLAGS, so additions to the flags must happen after the include. Make sure to append to the *FLAGS instead of overwriting them, e.g. use CFLAGS += -Wextra instead of CFLAGS = -Wextra:

DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

CFLAGS += -Wextra


/!\ Edit conflict - your version:



/!\ End of edit conflict


This also works with DEB_BUILD_MAINT_OPTIONS, just declare it before the include (needs dpkg >= 1.16.1.1):

export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk

When building programs that handle untrusted data (parsers, network listeners, etc.), or run with elevated privileges (PAM, X, etc.), please enable "PIE" and "BINDNOW" in the build. The "all" option enables "PIE" and "BINDNOW" and future hardening flags:

export DEB_BUILD_MAINT_OPTIONS = hardening=+all

CDBS packages can either use the flags mentioned above or can use the following flag before loading CDBS files to enable hardening flags (if this flag is not set not all hardening flags are used, see #651964):

CDBS_FIX_COMPILE_FLAGS = 1

Due to #651966 it's not possible to use DEB_BUILD_MAINT_OPTIONS if CDBS_FIX_COMPILE_FLAGS is used. To enable "PIE" and "BINDOW" set the flags manually.

See the "HARDENING" section of the "dpkg-buildflags" manpage for more details.

hardening-wrapper

To use "hardening-wrapper", add it to the Build-Depends of your package, and enable it in the debian/rules file:

export DEB_BUILD_HARDENING=1

After that, any use of gcc, g++, or ld will have all hardening features enabled by default. Each feature can be disabled individually (via export DEB_BUILD_HARDENING_[feature]=0, see below), if there are complications with the build resulting from the new features. (So far, only rare issues with stack protector and PIE support have been documented.)

To illustrate the effects of the options, a trivial C source (with Makefile) is used as an example.

hardening-includes

To use "hardening-includes", add it to the Build-Depends of your package, include its Makefile snippet in debian/rules, and adjust the compiler flags to use it. For example, with a pure debhelper-7 style debian/rules:

include /usr/share/hardening-includes/hardening.make

CFLAGS=$(shell dpkg-buildflags --get CFLAGS)
LDFLAGS=$(shell dpkg-buildflags --get LDFLAGS)
CFLAGS+=$(HARDENING_CFLAGS)
LDFLAGS+=$(HARDENING_LDFLAGS)

%:
        dh $@

If you're building C++, use CXXFLAGS instead of CFLAGS above, etc. If building C and C++, use both.

Each hardening feature can be disabled individually (via export DEB_BUILD_HARDENING_[feature]=0, see below), if there are complications with the build resulting from the new features. (So far, only rare issues with stack protector and PIE support have been documented.)

See the Makefile snippet for more documentation on disabling features on a per-target basis, compiler option filtering, etc.

To illustrate the effects of the options, a trivial C source (with Makefile) is used as an example.

Validation

To verify that the resulting binary does, in fact, have hardening features enabled, you can use "hardening-check" from the "hardening-includes" package to test each ELF binary:

$ hardening-check /usr/sbin/sshd 
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes
 Read-only relocations: yes
 Immediate binding: yes

If your binary does not make use of character arrays on the stack, it's possible that "Stack protected" will report "no", since there was no stack it found to protect. If you absolutely want to protect all stacks, you can add "-fstack-protector-all", but this tends not to be needed, and there are some trade-offs on speed.

If your binary does not make use of FORTIFY_SOURCE-protected glibc routines, it's possible that "Fortify Source functions" will report "no", since there were no functions used that included the glibc fortification routines.

Environment variables

Both "hardening-wrapper" and "hardening-includes" react to the following set of environment variables and change the behavior of the compiler flags.

DEB_BUILD_HARDENING_FORMAT (gcc/g++ -Wformat -Wformat-security -Werror=format-security)

Quoting the gcc man page:

  • If -Wformat is specified, also warn about uses of format functions that represent possible security problems. At present, this warns about calls to printf and scanf functions where the format string is not a string literal and there are no format arguments, as in printf (foo);. This may be a security hole if the format string came from untrusted input and contains %n.

http://en.wikipedia.org/wiki/Format_string_attack

Default compile:

$ make trivial
cc -Wall -O2    trivial.c   -o trivial

Hardened compile:

$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2    trivial.c   -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments

Known problems: (Common build failures, non-availability on some archs)

  • None so far.

DEB_BUILD_HARDENING_FORTIFY (gcc/g++ -D_FORTIFY_SOURCE=2)

During code generation the compiler knows a great deal of information about buffer sizes (where possible), and attempts to replace insecure unlimited length buffer function calls with length-limited ones. This is especially useful for old, crufty code. Additionally, format strings in writable memory that contain '%n' are blocked. If an application depends on such a format string, it will need to be worked around.

Note that for this feature to be fully enabled, the source must also be compiled with -O1 or higher.

Default build:

$ make trivial
cc -Wall -O2    trivial.c   -o trivial
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)

Hardened build:

$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2    trivial.c   -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ ./trivial $(perl -e 'print "A"x100')
*** buffer overflow detected ***: ./trivial terminated

Known problems: (Common build failures, non-availability on some archs)

DEB_BUILD_HARDENING_STACKPROTECTOR (gcc/g++ -fstack-protector --param ssp-buffer-size=4)

This is a mainline GCC feature, which adds safety checks against stack overwrites. This renders many potential code injection attacks into aborting situations. In the best case this turns code injection vulnerabilities into denial of service or into non-issues (depending on the application). http://en.wikipedia.org/wiki/Stack-smashing_protection

Default build:

$ make trivial
cc -Wall -O2    trivial.c   -o trivial
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)

Hardened build (with FORTIFY disabled, since it catches the stack overflow before it happens):

$ DEB_BUILD_HARDENING=1 DEB_BUILD_HARDENING_FORTIFY=0 make trivial
cc -Wall -O2    trivial.c   -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ ./trivial $(perl -e 'print "A"x100')
Your first argument was: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: ./trivial terminated

Known problems: (Common build failures, non-availability on some archs)

  • Not supported on ia64 and alpha. (disabled for these archs by default in hardening-wrapper 1.8)

    warning: -fstack-protector not supported for this target

  • Not supported on mips and hppa. (disabled for these archs by default in hardening-wrapper 1.10)

    warning: -fstack-protector not supported for this target

DEB_BUILD_HARDENING_PIE (gcc/g++ -fPIE -pie)

Position Independent Executable are needed to take advantage of Address Space Layout Randomization, supported by some kernel versions. While ASLR can already be enforced for data areas in the stack and heap (brk and mmap), the code areas must be compiled as position-independent. Shared libraries already do this (-fPIC), so they gain ASLR automatically, but binary .text regions need to be build PIE to gain ASLR. When this happens, ROP attacks are much harder since there are no static locations to bounce off of during a memory corruption attack.

Default build:

$ make trivial
cc -Wall -O2    trivial.c   -o trivial
$ file trivial
trivial: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped

Hardened build:

$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2    trivial.c   -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ file trivial
trivial: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, not stripped

Known problems: (Common build failures, non-availability on some archs)

  • Doesn't work on hppa and m68k (disabled for these archs by default in hardening-wrapper 1.6)
  • Doesn't work on some assembler, due to lack of registers. e.g.:

    vf_decimate.c:26: error: can't find a register in class 'BREG' while reloading 'asm'

DEB_BUILD_HARDENING_RELRO (ld -z relro)

During program load, several ELF memory sections need to be written to by the linker, but can be turned read-only before turning over control to the program. Most notably this prevents GOT overwrite attacks.

Default build:

$ make trivial
cc -Wall -O2    trivial.c   -o trivial
$ objdump -x trivial | grep RELRO

Hardened build:

$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2    trivial.c   -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ objdump -x trivial | grep RELRO
   RELRO off    0x0000000000000de8 vaddr 0x0000000000200de8 paddr 0x0000000000200de8 align 2**0

Known problems: (Common build failures, non-availability on some archs)

  • Unimplemented on ia64 (ld silently ignores the option).

DEB_BUILD_HARDENING_BINDNOW (ld -z now)

During program load, all dynamic symbols are resolved, allowing for the PLT to be marked read-only (due to -z relro above). For very large application, this can incur some performance loss during initial load while symbols are resolved.

Default build:

$ make trivial
cc -Wall -O2 trivial.c -o trivial
$ readelf -d trivial | grep BIND

Hardened build:

$ DEB_BUILD_HARDENING=1 make trivial
cc -Wall -O2 trivial.c -o trivial
trivial.c: In function 'main':
trivial.c:16: warning: format not a string literal and no format arguments
$ readelf -d trivial | grep BIND
 0x0000000000000018 (BIND_NOW)           

Known problems: (Common build failures, non-availability on some archs)

  • None.

State of implementation

An email was sent to the debian-devel-announce list in 2006 introducing the hardening-wrapper package and describing the way to integrate this hardening features in Debian.

A discussion has been fired on the debian-gcc list, as well as several bugs (bug 552688, bug 489771) reported to decide the best way to enable hardening compiler options.

Packages that have a bug report asking for the inclusion of this features can be found on the bug tracker.

A list of packages including hardening-wrapper and hardening-includes in their build-deps can be retrieved with the folowing commands:

  • reverse-build-depends --only-main --distribution unstable hardening-wrapper
  • reverse-build-depends --only-main --distribution unstable hardening-includes

After their meeting on the 14-16 January 2011, the debian security team announced in an email they intend to push the inclusion of hardening features for the wheezy release. A Birds of a Feather-session will be organized during the 2011 debconf to setup a process.

Notes on Memory Corruption Mitigation Methods

User Space

Stack Protector

gcc's -fstack-protector attempts to detect when a stack has been overwritten and aborts the program. Ubuntu has had this enabled by default since Edgy. Some programs do not play nice with it, and can be worked around with -fno-stack-protector. It would be nice to enable this by default, and for gcc to only attempt to use it when libc is being linked against.

Already done in sendmail.

heap protection

In glibc2.5, no additional work needed.

libc pointer encryption

In mainline glibc, as PTR_MANGLE.

gcc -D_FORTIFY_SOURCE=2 -O1

Compile-time protection against static sized buffer overflows. No known regressions or performance loss. This should be enabled system-wide

gcc -Wformat -Wformat-security

While not all programs correctly implement the printf hints (like glib's G_GNUC_PRINTF macro), adding this will at least call out simple printf format string vulnerabilities. Any programs whose builds become "noisy" as a result, should be fixed anyway.

gcc -pie -fPIE

This is especially difficult to plumb into packaging in a safe way, since it requires the executable be built with -fPIE for any .o files that are linked at the end with -pie. There is some amount of performance loss, but only due to the -fPIE, which is already true for all the linked libraries (via their -fPIC).

Already done with openssh, sendmail.

ld -z relro

(Or via gcc with -Wl,-z,relro) Already done with sendmail.

ld -z now

(Or via gcc with -Wl,-z,now).

Kernel Space

non-exec memory segmentation (ExecShield)

Stops execution of code in heap/stack. i386 specific (nx already does this for amd64), and introduces some small level of performance loss (5% for CPU-bound). Some people have worked on getting it pushed into the mainline kernel. Current state unknown -- would be very handy to have due to the popularity of i386. Marcus Better may be willing to continue to maintain the patchset for Debian.

Some applications appear to break when run in the protected memory layout. Most of these issues should be fixed due to RH (and SUSE?) already running with these protections.

Additional work for user-space is identifying programs that build assembly but fail to explicitly mark their stack as non-exec (gnupg, for example).

-fstack-protector

Is available for amd64 builds:

  • config CC_STACKPROTECTOR

runtime memory allocation validation

Detect double-frees in kernel space. No idea where it stands.

Address Space Layout Randomization

  • mmap: in mainline
  • stack: in mainline
  • vdso: in since 2.6.18 (COMPAT_VDSO disables it)
  • heap/exec: in -mm, 2.6.24
  • brk: 2.6.25

Having heap/exec ASLR is a prerequisite for -pie being useful. Presently, openssh is compiled with -pie.

/proc/$pid/maps protection

Present in 2.6.22; requires sysctl toggle (kernel.maps_protect = 1). Became non-optional in 2.6.27

/dev/mem protection

Included in 2.6.25.

From the GRSecurity patchset, protections against hardlink/symlink creation/following in world-writable areas. (Solves tmp races.) May potentially break things like postfix that manipulation hardlinks? Breaks POSIX. Getting taken in mainline may be tpossible with a build-time or proc toggle.

http://lkml.org/lkml/2005/3/10/101 http://lkml.org/lkml/2005/4/18/167

chroot, dmesg, fifo protections

Also from GRSecurity patchset.

Documentation