CompilerFlags

Differences between revisions 1 and 96 (spanning 95 versions)
Revision 1 as of 2008-05-02 21:18:34
Size: 1755
Editor: c-76-105-157-155
Comment: initial pass
Revision 96 as of 2019-03-08 00:23:27
Size: 18299
Editor: kees
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This page documents the Ubuntu-specific default compiler flags in the toolchain. Based on the work from GccSsp, [:Security/HardeningWrapper:], and DistCompiler. Please attempt to fix a source package's problems before disabling a given compiler feature.

== -fstack-protector ==

First enabled in Ubuntu 6.10.
See GccSsp for further details.

Failure example: {{{
## page was renamed from CompilerFlags
||<tablestyle="float:right; font-size: 0.9em; width:30%; background:#F1F1ED; background-repeat: no-repeat; background-position: 98% 0.5ex; margin: 0 0 1em 1em; padding: 0.5em;"><<TableOfContents>>||

This page documents the Ubuntu-specific default compiler flags in the toolchain used to help provide additional [[Security/Features|security features]] to Ubuntu. It is based on the work from GccSsp, [[Security/HardeningWrapper]], and DistCompilerFlags. Please attempt to fix a source package's problems before disabling a given compiler feature, and document the package and bug numbers in the Problems section below.

= Default Flags =

<<Anchor(stack-protector)>>
== -fstack-protector-strong --param=ssp-buffer-size=4 ==

First enabled in Ubuntu 6.10 as {{{-fstack-protector}}}, which enables run-time stack overflow verification using a stack canary. See GccSsp for further details. Most problems are related to packages that do not use stdlib directly (kernel modules, certain libraries, etc).

Starting in Ubuntu 10.10, {{{--param ssp-buffer-size=4}}} was added as well to increase the number of functions protected by the stack protector. (The upstream default is "8".)

Starting in Ubuntu 14.10, {{{-fstack-protector-strong}}} became the default protection level.

Failure examples:
 {{{
Line 11: Line 21:

Disabled with {{{-fno-stack-protector}}} or {{{-nostdlib}}}.
  Indicates a program was compiled to expect to have the stdlib available, but did not find it at runtime.

 {{{
undefined reference to `__stack_chk_fail_local'
}}}
  Indicates a program is being linked without the needed libraries. Usually this is a result of calling `ld` instead of `gcc` during a build to perform linking (e.g. see https://launchpad.net/bugs/588519).

 {{{
*** stack smashing detected ***
Aborted
}}}
  A function did not correctly maintain its stack variables. Usually indicates a stack buffer overflow.

Disabled with {{{-fno-stack-protector}}} or {{{-nostdlib}}} in {{{CPPFLAGS}}}.

<<Anchor(fortify-source)>>
Line 16: Line 39:
First enabled in Ubuntu 8.10. See [:Security/FortifySource:] for more details. First enabled in Ubuntu 8.10. Provides compile-time best-practices errors for certain libc functions, and provides run-time checks of buffer lengths and memory regions. Only activated when compiled with {{{-O1}}} or higher. Most problems are related to common unsafe uses of certain libc functions. (For implementation details, see [[http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html|this post]]. Starting with Jaunty, [[https://lists.ubuntu.com/archives/ubuntu-devel/2009-March/027832.html|fwrite]] was [[http://launchpadlibrarian.net/24428002/glibc_2.9-4ubuntu3_2.9-4ubuntu4.diff.gz|removed]] from the list of functions that are marked with "warn_unused_result".)
Line 22: Line 46:
  The return value from {{{system()}}}, {{{write()}}}, and similar functions should be evaluated and handled appropriately. In cases where one absolutely must throw away the return value, it can be discarded with an empty test: {{{if (system("...")) { } }}}, though this is not recommended.
Line 26: Line 51:
  When using {{{open()}}} with {{{O_CREAT}}}, best-practice is to define a valid {{{mode}}} argument. For the least modes, try using {{{(S_IRUSR|S_IWUSR)}}} first. If that doesn't work as expected in the program, then start adding back perms. For example, user and group: {{{(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)}}}; user, group, and other: {{{(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)}}}.
Line 30: Line 56:

Reduced checking via {{{-D_FORTIFY_SOURCE=1}}}. Disabled with {{{-U_FORTIFY_SOURCE}}} or {{{-D_FORTIFY_SOURCE=0}}}.
  The call to {{{read()}}} was done into a buffer with the wrong size. Double-check the size argument and the buffer size.

 {{{
*** %n in writable segment detected ***
Aborted
}}}
  On x86, use of {{{"%n"}}} in a format string is limited to read-only memory (not stack or heap allocated strings).

 {{{
*** buffer overflow detected ***
Aborted
}}}
  A buffer was going to be written past the end of its maximum length. For example, a call to {{{sprintf}}} should be changed to use {{{snprintf}}}. Other common cases include {{{read}}} warnings above, or {{{realpath}}} and {{{getwd}}} notes below. Since glibc version 2.15, {{{select}}} macros also make sure {{{FD_*}}} uses will not overflow. Please use {{{poll}}} instead. For a list of most of the run-time checked functions, see the output of:

   {{{
readelf -sW $(ldd /bin/ls | awk '{if ($1 ~ /^libc\.so\./) {print $3; exit}}') | \
  egrep ' FUNC .*_chk(@@| |$)' | \
  sed -re 's/ \([0-9]+\)$//g; s/.* //g; s/@.*//g;' | \
  egrep '^__.*_chk$' | \
  sed -re 's/^__//g; s/_chk$//g' | \
  sort
}}}

  In the case of structures with "char allocme[1]" style strings where the string is mapped on top of a preallocated memory range, swapping {{{strcpy}}} with either {{{strncpy}}} or {{{memcpy}}} with the actual length of the allocated target is the right change to make.

 {{{
*** invalid %N$ use detected ***
Aborted (core dumped)
}}}
  Format string positional values are being skipped, which means their type (and size on the stack) cannot be checked. This could cause unexpected results including stack content leaks, especially when using `%n`. This is invalid, for example: `printf("%2$s\n", 0, "Test");` because position 1 is skipped.

 {{{
*** longjmp causes uninitialized stack frame ***: $program terminated
}}}
  Something has gone wrong with an invalid longjmp use.

Disable unused result tests with {{{-Wno-unused-result}}} in {{{CPPFLAGS}}}. Totally disabled with {{{-U_FORTIFY_SOURCE}}} or {{{-D_FORTIFY_SOURCE=0}}} in {{{CFLAGS}}}.


<<Anchor(format-security)>>
Line 35: Line 98:
First enabled in Ubuntu 8.10. These options should only cause FTBFS if the package is compiling with {{{-Werror}}}. First enabled in Ubuntu 8.10. Enables compile-time warnings about misuse of format strings, some of which can have security implications. These options should only cause build failures if the package is compiling with {{{-Werror}}} or {{{-Werror=format-security}}}. For details on marking up source to gain these warnings, see the [[http://library.gnome.org/devel/glib/stable/glib-Miscellaneous-Macros.html#G-GNUC-PRINTF--CAPS|glib macro documentation]] about gcc's "format" attribute.
Line 39: Line 102:
warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
}}}
  For packages that aren't already building with {{{-Wall}}}, format character to argument types will be checked. Verify the correct variables for a given format string.

 {{{
Line 41: Line 109:

This is caused by code that fails to use {{{"%s"}}} for a {{{*printf}}} function. For example: {{{
printf(buf);
}}}
should be: {{{
printf("%s",buf);
}}}

Disabled with {{{-Wno-format-security}}} or {{{-Wformat=0}}}.
  This is caused by code that forgot to use {{{"%s"}}} for a {{{*printf}}} function. For example:
   {{{
fprintf(stderr,buf);
}}}
  should be:
   {{{
fprintf(stderr,"%s",buf);
}}}

Note: {{{-Werror=format-security}}} is turned on by default in 13.04 and later releases of Ubuntu.

Disabled with {{{-Wno-format-security}}} or {{{-Wformat=0}}} in {{{CPPFLAGS}}}.

<<Anchor(PIE)>>
== -fPIE ==

First enabled in Ubuntu 16.10. Builds all objects with text relocation to allow for full ASLR. This option depends on [[#linker-PIE|-pie]], below.

Disabled with {{{-fno-PIE}}}.

= Flags passed to the linker =

<<Anchor(relro)>>
Line 53: Line 134:
First enabled in Ubuntu 8.10. First enabled in Ubuntu 8.10. Provides a read-only relocation table area in the final ELF. This option paves the way for using {{{-z now}}} which forces all relocations to be resolved at run-time (which would cause some additional initial load delay), providing an even higher level of protection to the relocation table -- it could then be entirely read-only which can be used to further harden long-running programs like daemons.
Line 58: Line 139:

<<Anchor(immediate-binding)>>
== -Wl,-z,now ==

First enabled in Ubuntu 16.10. When linking as [[#linker-PIE|PIE]] (an executable shared object), this enables immediate relocation table binding (BINDNOW) to gain full [[#relro|RELRO]] coverage over the resulting ELF binary.

Disabled with {{{-Wl,-z,lazy}}}

<<Anchor(linker-PIE)>>
== -Wl,-pie ==

First enabled in Ubuntu 16.10. This builds binary as a Position Independent Executable (an executable shared object). (This option depends on [[#PIE|-fPIE]] and is augmented by [[#immediate-binding|immediate binding]])

Disabled with {{{-Wl,-no-pie -Wl,-z,lazy}}}

<<Anchor(hashstyle)>>
== -Wl,--hash-style= ==

First enabled in Ubuntu 8.04 (or earlier?) as {{{-Wl,--hash-style=both}}}. Enabled as {{{-Wl,--hash-style=gnu}}} in Ubuntu 10.10. Set the type of the linker's hash table(s). The gnu hash style results in smaller objects and faster dynamic linking at runtime.

<<Anchor(nocopydtneeded)>>
== -Wl,--no-copy-dt-needed-entries ==

Also known as {{{--no-add-needed}}}. First enabled in Ubuntu 11.04 (but disabled in the final 11.04 release), and permanently enabled in Ubuntu 11.10. This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries mentioned on the command line. This option also has an effect on the resolution of symbols in dynamic libraries. This will be the default in the upcoming binutils-2.22 release.

This may result in build errors. More information and recipes how to fix such build errors can be found at
NattyNarwhal/ToolchainTransition and [[http://wiki.debian.org/ToolChain/DSOLinking#Not_resolving_symbols_in_indirect_dependent_shared_libraries|the corresponding Debian page]].

<<Anchor(asneeded)>>
== -Wl,--as-needed ==

First enabled in Ubuntu 11.04 (but disabled in the final 11.04 release), and permanently enabled in Ubuntu 11.10.
With this option the linker will only add a DT_NEEDED tag for a dynamic library mentioned on the command line, if if the library is actually used.

A common build error with this option enabled is seen when libraries appear on the command line before objects referencing these libraries. More information and recipes how to fix such build errors can be found at
NattyNarwhal/ToolchainTransition and [[http://wiki.debian.org/ToolChain/DSOLinking#Only_link_with_needed_libraries|the corresponding Debian page]].

<<Anchor(triage)>>
= Failure Triage =

== catching backtraces from glibc abort ==
When glibc aborts due to the stack protector or glibc fortification checks, it writes a backtrace to the controlling terminal of the process ({{{/dev/tty}}}) and not {{{stderr}}}. This can lead to unexpected results when running scripts, X, or other applications where {{{stderr}}} and the controlling terminal are not the same location. To have this written to {{{stderr}}} instead, the process needs to run with the environment variable {{{LIBC_FATAL_STDERR_=1}}} set (yes, there is a trailing underscore in the variable name).

== FORTIFY return value checking ==

When encountering "ignoring return value of ..." build problems due to the FORTIFY flag, it is best to follow this general approach (and to refer to the above individual sections on a case-by-case basis):

 0. If there are examples of error handlers in near-by code, emulate them. An example can be seen with [[http://launchpadlibrarian.net/19891829/fortify-warnings.patch.dpatch|conntrack]]. This is, obviously, the preferred method of dealing with it.
 0. If there isn't an obvious way to handle the error, then stubbing out an empty handler is the next way to go -- fundamentally, this doesn't improve (or weaken) the quality of the code -- ignoring the return code is what's already happening, so this doesn't change anything. However, what it _does_ do, is allows the FORTIFY option to still be enabled, which means the program will gain the run-time FORTIFY protections.
 0. If there isn't a way to work around the error, and the problem is isolated to a small area of the source code, I've disabled FORTIFY for _only_ [[http://launchpadlibrarian.net/17169346/sysklogd_1.5-2ubuntu5_1.5-2ubuntu6.diff.gz|those source files]], which can be a pain, depending on the package's build methods.
 0. If nothing works, and other people have looked at it, and no one has any ideas about how to work around a problem with FORTIFY, then it's time to disable it for the entire build using the -U_FORTIFY_SOURCE CFLAG.

Now, in all of these situations, upstream needs to be notified. Especially for the #2, where they need to make a larger design decision about how to deal with the unhandled error condition.

Also, in situations where you've had to disable FORTIFY (#3, #4), please document the issue in the "Problems" section below (preferably also with a bug).

=== Ignoring return code of write() ===

If the error is ignoring the return code of write() or a similar function then it indicates that the
code is not implementing retry support for writes. write(2) says

{{{
       If a write() is interrupted by a signal handler before any bytes are
       written, then the call fails with the error EINTR; if it is interrupted
       after at least one byte has been written, the call succeeds, and
       returns the number of bytes written.
}}}

So something like the following should be used to retry when there is a short write
(thanks to SteveLangasek)

{{{
  do {
      written = write(fd, buf, count);
      if (written == count)
          break;
      if (written > 0) {
          buf += written;
          count -= written;
      }
  } while (written >= 0 || errno == EINTR);
  if (written < 0) {
    /* Handle error */
  }
}}}

== aborts in realpath and getwd ==
Some applications call {{{realpath(3)}}} and {{{getwd(3)}}} with a buffer that is potentially too small (it should be {{{PATH_MAX}}} long). This is usually a result of not including {{{limits.h}}} or not using {{{PATH_MAX}}} to define the size of the buffer used in the {{{realpath(3)}}} call (there is some confusion here: MAXPATHLEN should be equal to PATH_MAX, but may not be defined without {{{limits.h}}}). So far, xulrunner and linux86 have been found and fixed, so there may be others. For an example of how to fix this, please see the [[http://launchpadlibrarian.net/25307061/linux86_0.16.17-3ubuntu1_0.16.17-3ubuntu2.diff.gz|linux86 debdiff]].

== thread sanitizer vs PIE ==

If an executable linked with the thread sanitizer fails on startup with a message like

{{{
==3581==ERROR: ThreadSanitizer failed to allocate 0x4000 (16384) bytes at address 1ff65735c0000 (errno: 12)
}}}

then it needs to be built without PIE (i.e. pass -no-pie to the link step).

<<Anchor(extensions)>>
= Extending FORTIFY =
If you are writing libraries or other code where you want to provide mark-up in headers to yell loudly when a function is misused, you can add them yourself.

== warn_if_result_ignored ==

 * Add to your function declaration: {{{__attribute__ ((warn_unused_result))}}}

<<Anchor(problems)>>
= Problems =
If the upstream source cannot be reasonably fixed and a package must have compiler flags disabled or some other work-around, please open a launchpad bug, tag it with "hardening-ftbfs", and link to it here along with an explanation of what the problem is:

== General ==

=== libxfont1 ===
   doesn't work with -Bsymbolic-functions (can't work, see https://launchpad.net/bugs/230460 for analysis).

=== sysklogd ===
  When built with FORTIFY_SOURCE, klogd misdirects calls to syslog() into glibc instead of into syslog.o. See https://bugs.launchpad.net/ubuntu/+source/sysklogd/+bug/255635

  Workaround: added -U_FORTIFY_SOURCE to klogd.o's Makefile line.

=== synergy ===
  Fails to build with FORTIFY_SOURCE, and when patched to solve the warnings, it seems to hang and behave strangely. See https://bugs.launchpad.net/bugs/250869 and http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=488460

  Workaround: added -U_FORTIFY_SOURCE to debian/rules CXXFLAGS.

=== gclcvs ===
  FTBFS with the error "__stack_chk_fail is undefined" and needs the "-fno-stack-protector" CFLAG to fix the FTBFS, see https://bugs.launchpad.net/ubuntu/+source/gclcvs/+bug/638068

=== pth ===
  Runtime error on ARM, where the package uses setjmp/longjmp to implement user space threading. It does not work however since the stack pointer sanity check introduced in longjmp in glibc 2.11 . Disabled FORTIFY_SOURCE for the armel build of the package, see https://bugs.launchpad.net/ubuntu/+source/gnupg2/+bug/599862

=== tcc ===
  tcc 0.9.27~git20140923.9d7fb33-3 introduces new tests (test3 and abitest) which fail on i386 with undefined symbol '__stack_chk_fail_local' when stack protection is enabled. Added "-fno-stack-protector" as a workaround, see https://bugs.launchpad.net/ubuntu/+source/tcc/+bug/1500147

== Valid Code, But Compiler Is Unhappy ==

=== bacula ===
   Upstream has strange unions that upsets FORTIFY_SOURCE. https://bugs.launchpad.net/ubuntu/+source/bacula/+bug/265102

=== wine ===
   FORTIFY_SOURCE generates too many false positives, upstream is disabling it entirely. http://bugs.winehq.org/show_bug.cgi?id=24606 https://bugs.launchpad.net/ubuntu/+source/wine1.2/+bug/665270

=== zsnes ===
   Upstream has strange memory manipulations that upsets FORTIFY_SOURCE. https://bugs.launchpad.net/ubuntu/intrepid/+source/zsnes/+bug/250425

== Conflicting Goals ==

=== duma ===

   Duma is a library specifically to find various overflows, etc, so it get confused by glibc getting in the way.

== Test Suites Not Updated ==

=== binutils ===
   Add -Wno-format-security to CFLAGS, CXXFLAGS, due to picky default hardening options.

=== binutils-avr ===
   Set -Wno-format-security and -U_FORTIFY_SOURCE to avoid FTBFS. https://bugs.edge.launchpad.net/ubuntu/+source/binutils-avr/+bug/301732

=== gdb ===
   Testsuite reports false failures due to warnings, etc.

=== scheme2c ===

   https://launchpad.net/ubuntu/+source/scheme2c/2011.07.26-2 shows longjmp failures.

= Notes =
 * To see a list of all the #define'd variables, use: {{{cpp -dM /dev/null}}}

This page documents the Ubuntu-specific default compiler flags in the toolchain used to help provide additional security features to Ubuntu. It is based on the work from GccSsp, Security/HardeningWrapper, and DistCompilerFlags. Please attempt to fix a source package's problems before disabling a given compiler feature, and document the package and bug numbers in the Problems section below.

Default Flags

-fstack-protector-strong --param=ssp-buffer-size=4

First enabled in Ubuntu 6.10 as -fstack-protector, which enables run-time stack overflow verification using a stack canary. See GccSsp for further details. Most problems are related to packages that do not use stdlib directly (kernel modules, certain libraries, etc).

Starting in Ubuntu 10.10, --param ssp-buffer-size=4 was added as well to increase the number of functions protected by the stack protector. (The upstream default is "8".)

Starting in Ubuntu 14.10, -fstack-protector-strong became the default protection level.

Failure examples:

  • '__stack_chk_fail' symbol not found
    • Indicates a program was compiled to expect to have the stdlib available, but did not find it at runtime.
    undefined reference to `__stack_chk_fail_local'
    • Indicates a program is being linked without the needed libraries. Usually this is a result of calling ld instead of gcc during a build to perform linking (e.g. see https://launchpad.net/bugs/588519).

    *** stack smashing detected ***
    Aborted
    • A function did not correctly maintain its stack variables. Usually indicates a stack buffer overflow.

Disabled with -fno-stack-protector or -nostdlib in CPPFLAGS.

-D_FORTIFY_SOURCE=2

First enabled in Ubuntu 8.10. Provides compile-time best-practices errors for certain libc functions, and provides run-time checks of buffer lengths and memory regions. Only activated when compiled with -O1 or higher. Most problems are related to common unsafe uses of certain libc functions. (For implementation details, see this post. Starting with Jaunty, fwrite was removed from the list of functions that are marked with "warn_unused_result".)

Failure examples:

  • error: ignoring return value of 'int system(const char*)', declared with attribute warn_unused_result
    • The return value from system(), write(), and similar functions should be evaluated and handled appropriately. In cases where one absolutely must throw away the return value, it can be discarded with an empty test: if (system("...")) { } , though this is not recommended.

    error: call to '__open_missing_mode' declared with attribute error: open with O_CREAT in second argument needs 3 arguments
    • When using open() with O_CREAT, best-practice is to define a valid mode argument. For the least modes, try using (S_IRUSR|S_IWUSR) first. If that doesn't work as expected in the program, then start adding back perms. For example, user and group: (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); user, group, and other: (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH).

    warning: call to ‘__read_chk_warn’ declared with attribute warning: read called with bigger length than size of the destination buffer
    • The call to read() was done into a buffer with the wrong size. Double-check the size argument and the buffer size.

    *** %n in writable segment detected ***
    Aborted
    • On x86, use of "%n" in a format string is limited to read-only memory (not stack or heap allocated strings).

    *** buffer overflow detected ***
    Aborted
    • A buffer was going to be written past the end of its maximum length. For example, a call to sprintf should be changed to use snprintf. Other common cases include read warnings above, or realpath and getwd notes below. Since glibc version 2.15, select macros also make sure FD_* uses will not overflow. Please use poll instead. For a list of most of the run-time checked functions, see the output of:

      • readelf -sW $(ldd /bin/ls | awk '{if ($1 ~ /^libc\.so\./) {print $3; exit}}') | \
          egrep ' FUNC .*_chk(@@| |$)' | \
          sed -re 's/ \([0-9]+\)$//g; s/.* //g; s/@.*//g;' | \
          egrep '^__.*_chk$' | \
          sed -re 's/^__//g; s/_chk$//g' | \
          sort

      In the case of structures with "char allocme[1]" style strings where the string is mapped on top of a preallocated memory range, swapping strcpy with either strncpy or memcpy with the actual length of the allocated target is the right change to make.

    *** invalid %N$ use detected ***
    Aborted (core dumped)
    • Format string positional values are being skipped, which means their type (and size on the stack) cannot be checked. This could cause unexpected results including stack content leaks, especially when using %n. This is invalid, for example: printf("%2$s\n", 0, "Test"); because position 1 is skipped.

    *** longjmp causes uninitialized stack frame ***: $program terminated
    • Something has gone wrong with an invalid longjmp use.

Disable unused result tests with -Wno-unused-result in CPPFLAGS. Totally disabled with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0 in CFLAGS.

-Wformat -Wformat-security

First enabled in Ubuntu 8.10. Enables compile-time warnings about misuse of format strings, some of which can have security implications. These options should only cause build failures if the package is compiling with -Werror or -Werror=format-security. For details on marking up source to gain these warnings, see the glib macro documentation about gcc's "format" attribute.

Failure examples:

  • warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
    • For packages that aren't already building with -Wall, format character to argument types will be checked. Verify the correct variables for a given format string.

    warning: format not a string literal and no format arguments
    • This is caused by code that forgot to use "%s" for a *printf function. For example:

      • fprintf(stderr,buf);
      should be:
      • fprintf(stderr,"%s",buf);

Note: -Werror=format-security is turned on by default in 13.04 and later releases of Ubuntu.

Disabled with -Wno-format-security or -Wformat=0 in CPPFLAGS.

-fPIE

First enabled in Ubuntu 16.10. Builds all objects with text relocation to allow for full ASLR. This option depends on -pie, below.

Disabled with -fno-PIE.

Flags passed to the linker

-Wl,-z,relro

First enabled in Ubuntu 8.10. Provides a read-only relocation table area in the final ELF. This option paves the way for using -z now which forces all relocations to be resolved at run-time (which would cause some additional initial load delay), providing an even higher level of protection to the relocation table -- it could then be entirely read-only which can be used to further harden long-running programs like daemons.

No known failure examples.

Disabled with -Wl,-z,norelro in LDFLAGS.

-Wl,-z,now

First enabled in Ubuntu 16.10. When linking as PIE (an executable shared object), this enables immediate relocation table binding (BINDNOW) to gain full RELRO coverage over the resulting ELF binary.

Disabled with -Wl,-z,lazy

-Wl,-pie

First enabled in Ubuntu 16.10. This builds binary as a Position Independent Executable (an executable shared object). (This option depends on -fPIE and is augmented by immediate binding)

Disabled with -Wl,-no-pie -Wl,-z,lazy

-Wl,--hash-style=

First enabled in Ubuntu 8.04 (or earlier?) as -Wl,--hash-style=both. Enabled as -Wl,--hash-style=gnu in Ubuntu 10.10. Set the type of the linker's hash table(s). The gnu hash style results in smaller objects and faster dynamic linking at runtime.

-Wl,--no-copy-dt-needed-entries

Also known as --no-add-needed. First enabled in Ubuntu 11.04 (but disabled in the final 11.04 release), and permanently enabled in Ubuntu 11.10. This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries mentioned on the command line. This option also has an effect on the resolution of symbols in dynamic libraries. This will be the default in the upcoming binutils-2.22 release.

This may result in build errors. More information and recipes how to fix such build errors can be found at NattyNarwhal/ToolchainTransition and the corresponding Debian page.

-Wl,--as-needed

First enabled in Ubuntu 11.04 (but disabled in the final 11.04 release), and permanently enabled in Ubuntu 11.10. With this option the linker will only add a DT_NEEDED tag for a dynamic library mentioned on the command line, if if the library is actually used.

A common build error with this option enabled is seen when libraries appear on the command line before objects referencing these libraries. More information and recipes how to fix such build errors can be found at NattyNarwhal/ToolchainTransition and the corresponding Debian page.

Failure Triage

catching backtraces from glibc abort

When glibc aborts due to the stack protector or glibc fortification checks, it writes a backtrace to the controlling terminal of the process (/dev/tty) and not stderr. This can lead to unexpected results when running scripts, X, or other applications where stderr and the controlling terminal are not the same location. To have this written to stderr instead, the process needs to run with the environment variable LIBC_FATAL_STDERR_=1 set (yes, there is a trailing underscore in the variable name).

FORTIFY return value checking

When encountering "ignoring return value of ..." build problems due to the FORTIFY flag, it is best to follow this general approach (and to refer to the above individual sections on a case-by-case basis):

  1. If there are examples of error handlers in near-by code, emulate them. An example can be seen with conntrack. This is, obviously, the preferred method of dealing with it.

  2. If there isn't an obvious way to handle the error, then stubbing out an empty handler is the next way to go -- fundamentally, this doesn't improve (or weaken) the quality of the code -- ignoring the return code is what's already happening, so this doesn't change anything. However, what it _does_ do, is allows the FORTIFY option to still be enabled, which means the program will gain the run-time FORTIFY protections.
  3. If there isn't a way to work around the error, and the problem is isolated to a small area of the source code, I've disabled FORTIFY for _only_ those source files, which can be a pain, depending on the package's build methods.

  4. If nothing works, and other people have looked at it, and no one has any ideas about how to work around a problem with FORTIFY, then it's time to disable it for the entire build using the -U_FORTIFY_SOURCE CFLAG.

Now, in all of these situations, upstream needs to be notified. Especially for the #2, where they need to make a larger design decision about how to deal with the unhandled error condition.

Also, in situations where you've had to disable FORTIFY (#3, #4), please document the issue in the "Problems" section below (preferably also with a bug).

Ignoring return code of write()

If the error is ignoring the return code of write() or a similar function then it indicates that the code is not implementing retry support for writes. write(2) says

       If  a  write()  is interrupted by a signal handler before any bytes are
       written, then the call fails with the error EINTR; if it is interrupted
       after  at  least  one  byte  has  been  written, the call succeeds, and
       returns the number of bytes written.

So something like the following should be used to retry when there is a short write (thanks to SteveLangasek)

  do {
      written = write(fd, buf, count);
      if (written == count)
          break;
      if (written > 0) {
          buf += written;
          count -= written;
      }
  } while (written >= 0 || errno == EINTR);
  if (written < 0) {
    /* Handle error */
  }

aborts in realpath and getwd

Some applications call realpath(3) and getwd(3) with a buffer that is potentially too small (it should be PATH_MAX long). This is usually a result of not including limits.h or not using PATH_MAX to define the size of the buffer used in the realpath(3) call (there is some confusion here: MAXPATHLEN should be equal to PATH_MAX, but may not be defined without limits.h). So far, xulrunner and linux86 have been found and fixed, so there may be others. For an example of how to fix this, please see the linux86 debdiff.

thread sanitizer vs PIE

If an executable linked with the thread sanitizer fails on startup with a message like

==3581==ERROR: ThreadSanitizer failed to allocate 0x4000 (16384) bytes at address 1ff65735c0000 (errno: 12)

then it needs to be built without PIE (i.e. pass -no-pie to the link step).

Extending FORTIFY

If you are writing libraries or other code where you want to provide mark-up in headers to yell loudly when a function is misused, you can add them yourself.

warn_if_result_ignored

  • Add to your function declaration: __attribute__ ((warn_unused_result))

Problems

If the upstream source cannot be reasonably fixed and a package must have compiler flags disabled or some other work-around, please open a launchpad bug, tag it with "hardening-ftbfs", and link to it here along with an explanation of what the problem is:

General

libxfont1

sysklogd

synergy

gclcvs

pth

  • Runtime error on ARM, where the package uses setjmp/longjmp to implement user space threading. It does not work however since the stack pointer sanity check introduced in longjmp in glibc 2.11 . Disabled FORTIFY_SOURCE for the armel build of the package, see https://bugs.launchpad.net/ubuntu/+source/gnupg2/+bug/599862

tcc

Valid Code, But Compiler Is Unhappy

bacula

wine

zsnes

Conflicting Goals

duma

  • Duma is a library specifically to find various overflows, etc, so it get confused by glibc getting in the way.

Test Suites Not Updated

binutils

  • Add -Wno-format-security to CFLAGS, CXXFLAGS, due to picky default hardening options.

binutils-avr

gdb

  • Testsuite reports false failures due to warnings, etc.

scheme2c

Notes

  • To see a list of all the #define'd variables, use: cpp -dM /dev/null

ToolChain/CompilerFlags (last edited 2024-03-22 22:52:13 by eslerm)