- What is all this about?
- Selecting security hardening options
- Enabling dpkg-buildflags in your debian/rules files
- Handling dpkg-buildflags in your upstream build system
- Testing your packages after conversion
Common questions / problems
- My package already uses hardening-wrapper or hardening-includes. Should I switch to dpkg-buildflags?
- My package builds with optimisation flags other than -O2, e.g. -Os
- How can I use additional flags?
- Are there example patches?
- How can I use this and keep my packages backportable to Squeeze?
- Is there a lintian test?
- My package isn't security-sensitive, should I still convert it?
- My package is (partly) written in OCaml
What is all this about?
dpkg-buildflags allows a uniform setting of default build flags for code written in C and C++. If your package is written in Java, pure Python, pure Perl or shell you don't need to do anything. Good, isn't it?
Default build flags have a number of benefits:
- dpkg-buildflags exports hardened build flags. These build flags enforce more stringent checks both at compile time (detects potential security problems during compilation, helps spotting regressions) and enables/nullifies yet undetected security problems. See next section.
dpkg-buildflags allows rebuilding Debian with new/modified flags. If e.g. someone wants to rebuild Debian for an embedded system with -Os instead of -O2, all it needs is to patch dpkg-buildflags instead of thousands of source packages.
- dpkg-buildflags supports DEB_BUILD_OPTIONS=noopt (policy 4.9.1) Right now only a few packages support it, while dpkg-buildflags directly emits -O0 if noopt is set.
Enabling dpkg-buildflags in your package is two-fold. On the one hand you need to activate the flags in your debian/rules file, on the other hand you need to ensure that the buildsystem of your code abides the necessary flags.
Selecting security hardening options
The standard build flags for Debian 7 ("wheezy") include the following
- Format string checks
- Stack protector
- Read-only relocations
These hardening features are explained in more depth here.
Additionally there are two features, which are not enabled by default:
- Position independent executables (not enabled by default due to potential build failures)
- -z now (not enabled by default due to potential application startup slowdown)
It is recommended to test, whether these two options work with your package and enable them if everything works fine. You can enable them by adding this to your rules file:
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
Enabling dpkg-buildflags in your debian/rules files
rules files based on debhelper and minimised dh(1)
If you use debhelper dh(1) v9 or later format (value 9 or higher in debian/compat), it takes care of the hardened build flags:
Include for buildflags.mk and call to dpkg-buildflags is unnecessary in debian/rules.
There's no need to export CFLAGS and LDFLAGS etc. because they are automatically passed during calls to dh_auto_* programs.
In case you want to add more flags to the defaults, use something like this at the top of debian/rules:
# To enable all, uncomment following line # export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
Don't use *_SET or it overwrites the default hardening flags.
This works fine with buildflags.mk as well.
If you want to stay with earlier compat levels, you can still inject the build flags by passing them to dh_auto_configure, e.g.
override_dh_auto_configure: dh_auto_configure -- $(shell dpkg-buildflags --export=configure)
rules files based on standard debhelper or hand-written rules files
If your build file uses the standard debhelper format, the way of injecting the flags depends on your build system. If it's based on the autotools, passing the exported form of dpkg-buildflags to the configure script is usually needed, e.g.
../configure --prefix=/usr $(shell dpkg-buildflags --export=configure)
If your build system reads the values from standard environment variables like CFLAGS, CXXFLAGS, CPPFLAGS or LDFLAGS, you often need to export these values at the beginning of your rules files. The simplest way to achieve this is to include the following snippet from dpkg at the beginning of your rules file to export all needed flags:
DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/buildflags.mk
rules files based on cdbs
cdbs already exports all dpkg-buildflags. If your package uses cdbs you will usually only need to verify, whether your upstream buildsystem properly follows these flags. (The cdbs bug bug 651964 about missing CPPFLAGS and LDFLAGS was fixed.)
cdbs supports DEB_*_MAINT_APPEND and DEB_BUILD_MAINT_OPTIONS directly (since cdbs 0.4.127) - just make sure to declare them before including CDBS snippets.
Handling dpkg-buildflags in your upstream build system
To fully support all hardened build flags in your upstream buildsystem, please ensure that the following flags are supported:
- CFLAGS, CPPFLAGS and LDFLAGS for code written in C
- CXXFLAGS, CPPFLAGS and LDFLAGS for code written in C++
buildsystems based on the autotools
If your buildsystem is based on autotools it usually requires no further modifications. If might however occur that some variables are hard-coded in one of the Makefile.in files. An examples for this can be found at bug 655870
If your package uses a home-grown buildsystems you first need to check, whether it abides the above-mentioned flags. If not, you can either add the dpkg-buildflags calls directly as part of your Debian-specific modifications. Another solution would to fix the Makefiles to source an already existing environment variable.
Many home-grown Makefiles already support CFLAGS and LDFLAGS, but not CPPFLAGS. In most cases you can simply append CPPFLAGS to CFLAGS, e.g.
CFLAGS = `dpkg-buildflags --get CFLAGS` CFLAGS += `dpkg-buildflags --get CPPFLAGS`
buildsystems for Perl modules
Debhelper has been modified so that the hardened build flags are passed to ?ExtUtils::?MakeMaker and ?ExtUtils::CBuilder, so that most Perl modules should receive hardened build flags once bumped to debhelper level 9. Note that this requires building with debhelper (>= 9.20120312). Note that the dh_auto* minimal rules files need to be used to make use of this.
See more discussion at bug 662666
buildsystems using cmake
cmake doesn't follow CPPFLAGS. A fix was briefly available in sid, but had been revoked since upstream rejected the patch. See bug 653916 for details. As a workaround appending CPPFLAGS to CFLAGS and CXXFLAGS should work in most cases. Debhelper (since 0.9.20120417, only with compat=9 and dh_auto* commands!) and cdbs (since 0.4.110) handle this automatically so the workaround is no longer necessary if they are used.
Testing your packages after conversion
Previously, "hardening-check" from the "hardening-includes" package allowed testing a binary to see whether hardening options have been properly enabled, but "hardening-includes" has now been removed from unstable so this too is no longer available there, As for a replacement, lintian implements the hardening-no-* tags, which were based on the code from hardening-check.
Here's the old information about hardening-check, in case you still have it available:
If you're using only the default flags emitted by dpkg-buildflags, you should see "Stack protected", "Fortify Source functions" and "Read-only relocations" marked as "Yes", e.g.
jmm@pisco:~$ hardening-check /usr/bin/emacs23 /usr/bin/emacs23: Position Independent Executable: no, normal executable! Stack protected: yes Fortify Source functions: yes (some protected functions found) Read-only relocations: yes Immediate binding: no not found!
In some cases, "Stack protected" and "Fortify Source functions" emit false positives, see these notes from hardening-check's manpage:
- Stack Protected: When an executable was built without any character arrays being allocated on the stack, this check will lead to false alarms (since there is no use of stack_chk_fail, even though it was compiled with the correct options.
- Fortify Source functions: When an executable was built such that the fortified versions of the glibc functions are not useful (e.g. use is verified as safe at compile time, or use cannot be verified at runtime), this check will lead to false alarms. In an effort to mitigate this, the check will pass if any fortified function is found, and will fail if only unfortified functions are found. Uncheckable conditions also pass (e.g. no functions that could be fortified are found, or not linked against glibc).
If a package has enabled all flags, the output should look like this:
jmm@pisco:~$ hardening-check /usr/sbin/sshd /usr/sbin/sshd: Position Independent Executable: yes Stack protected: yes Fortify Source functions: yes (some protected functions found) Read-only relocations: yes Immediate binding: yes
hardening-check can only check the resulting binaries and thus might not catch missing hardening flags if they are only missing in a few places. blhc is a small parser written in Perl which checks the build logs for missing hardening flags. It can be used on build logs created by dpkg-buildpackage or buildd.
$ blhc /path/to/log/file
Common questions / problems
My package already uses hardening-wrapper or hardening-includes. Should I switch to dpkg-buildflags?
Yes. These packages have now been removed from unstable. You should use dpkg-buildflags instead, since it's a more generalised solution to the problem and is also useful beyond security hardening.
My package builds with optimisation flags other than -O2, e.g. -Os
You can add the following to your rules before before invoking dpkg-buildflags
How can I use additional flags?
To set additional flags, e.g. -Wl,--as--needed for LDFLAGS, use the new DEB_*_MAINT_APPEND variables (man dpkg-buildflags for more information). Don't use DEB_*_MAINT_SET as it overwrites the default hardening flags. DEB_*_APPEND (without the _MAINT) is not for debian/rules, always use *_MAINT_*.
export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
Don't use something like export LDFLAGS += -Wl,--as-needed, the export will overwrite the default LDFLAGS hardening flags.
make's $(shell) doesn't use local variables, thus you have to define a custom command:
dpkg_buildflags = DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed" dpkg-buildflags ... ./configure $(shell $(dpkg_buildflags) --export=configure)
Are there example patches?
Many of the bugs filed for the hardening flags Wheezy release goal have patches attached.
And more hardening details are explained in Hardening.
How can I use this and keep my packages backportable to Squeeze?
squeeze-backports includes a backport of 188.8.131.52, so all should be fine.
Additionally, dpkg-buildflags already existed in plain Squeeze (emitting only flags w/o hardening:
$ dpkg-buildflags --get CFLAGS -g -O2 $ dpkg-buildflags --get CPPFLAGS $ dpkg-buildflags --get LDFLAGS $ dpkg-buildflags --get CXXFLAGS -g -O2
Most of the convenience functions (/usr/share/dpkg/buildflags.mk and dpkg-buildflags --export=configure) don't exist yet, though. As such, you need to export your flags like this:
CFLAGS:=$(shell dpkg-buildflags --get CFLAGS) CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS) LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)
Is there a lintian test?
A lintian test became available in version 2.5.7 per this bug. The lintian tag hardening-no-bindnow is reported.
My package isn't security-sensitive, should I still convert it?
Yes. dpkg-buildflags easies rebuilding Debian with modified build flags and is useful to spot long-standing bugs in your packages, see this blog posting on Planet Debian for an example.
My package is (partly) written in OCaml
The OCaml runtime itself must be hardened first. For the time being, do nothing elsewhere (especially do not override Lintian tags).