A number of mechanisms are available in pkgsrc to improve the security of the resulting system. This page describes the mechanisms, and gives hints about detecting and fixing problems.

Mechanisms

Mechanisms can be enabled individually in mk.conf, and are individually described below. They are sorted by whether they are enabled by default, and then by their ordering in mk/defaults/mk.conf.

Typically, a feature will cause some programs to fail to build or work when first enabled. This can be due to latent problems in the program, and can be due to other reasons. After enough testing to have confidence that user problems will be quite rare, individual mechanisms will be enabled by default.

For each mechanism, see the Caveats section below for an explanation of what might go wrong at compile time and at run time, and how to notice and address these problems.

Enabled by default in the stable branch

PKGSRC_USE_FORTIFY

This allows substitute wrappers to be used for some commonly used library functions that do not have built-in bounds checking - but could in some cases.

TODO: Explain FORTIFY_SOURCE 1 vs 2, and which is used. Give a link to a good explanation of the technique. Explain if this is gcc specific.

It has been enabled by default since pkgsrc-2017Q3.

PKGSRC_USE_SSP

This enables a stack-smashing protection mitigation. It is done by adding a guard variable to functions with vulnerable objects. The guards are initialized when a function is entered and then checked when the function exits. The guard check will fail and the program forcibly exited if the variable was modified in the meantime. This can happen in case of buffer overflows or memory corruption, and therefore exposing these bugs.

Different mitigation levels are available:

This mitigation is supported by both GCC and clang. It may be supported in additional compilers, possibly under a different name. It is particularly useful for unsafe programming languages, such as C/C++.

It is enabled by default where known supported since pkgsrc-2017Q3.

More details can be found here:

Enabled by default in pkgsrc HEAD

Not enabled by default

PKGSRC_MKPIE

This requests the creation of PIE (Position Independent Executables) for all executables. The PIE mechanism is normally used for shared libraries, so that they can be loaded at differing addresses at runtime. PIE itself does not have useful security properties; however, it is necessary to fully leverage some, such as ASLR. Some operating systems support Address Space Layout Randomization (ASLR), which causes different addresses to be used each time a program is run. This makes it more difficult for an attacker to guess addresses and thus makes exploits harder to construct. With PIE, ASLR can really be applied to the entire program, instead of the stack and heap only.

PIE executables will only be built for toolchains that are known to support PIE. Currently, this means NetBSD on amd64 and i386.

PKGSRC_MKREPRO

With this option, pkgsrc will try to build packages reproducibly. This allows packages built from the same tree and with the same options, to produce identical results bit by bit. This option should be combined with ASLR and PKGSRC_MKPIE to avoid predictable address offsets for attackers attempting to exploit security vulnerabilities.

More details can be found here:

PKGSRC_USE_RELRO

This also makes the exploitation of some security vulnerabilities more difficult in some cases.

Two different mitigation levels are available:

This is currently supported by GCC. Many software distributions now enable this feature by default, at the "partial" level.

More details can be found here:

PKGSRC_USE_STACK_CHECK

This uses -fstack-check with GCC for another stack protection mitigation.

It asks the compiler to generate code verifying that it does not corrupt the stack. According to GCC's manual page, this is really only useful for multi-threaded programs.

Caveats

Problems with PKGSRC_MKPIE

Recent support for cwrappers

PKGSRC_MKPIE is only supported by pkgtools/cwrappers from the 2017Q3 release on (USE_CWRAPPERS in mk.conf).

Packages failing to build

A number of packages may fail to build with this option enabled. The failures are often related to the absence of the -fPIC compilation flag when building libraries or executables (or ideally -fPIE in the latter case). This flag is added to the CFLAGS already, but requires the package to actually support it.

How to fix

These instructions are meant as a reference only; they likely need to be adapted for many packages individually.

For packages using Makefiles:

MAKE_FLAGS+=    CFLAGS=${CFLAGS:Q}
MAKE_FLAGS+=    LDFLAGS=${LDFLAGS:Q}

For packages using Imakefiles:

MAKE_FLAGS+=    CCOPTIONS=${CFLAGS:Q}
MAKE_FLAGS+=    LOCAL_LDFLAGS=${LDFLAGS:Q}

Run-time crashes

Some programs may fail to run, or crash at random times once built as PIE. Two scenarios are essentially possible:

Problems with PKGSRC_USE_FORTIFY

Packages failing to build

This feature makes use of pre-processing directives to look for hardened, alternative implementations of essential library calls. Some programs may fail to build as a result; this usually happens for those trying too hard to be portable, or otherwise abusing definitions in the standard library.

This will require a modification to the program, or disabling this feature for part or all of the build.

Run-time crashes

Just like with PKGSRC_MKPIE above, this feature may cause some programs to crash, usually indicating an actual bug in the program. The fix will typically involve patching the original program.

Optimization is required

At least in the case of GCC, FORTIFY will only be applied if optimization is applied while compiling. This means that the CFLAGS should also contain -O, -O2 or another optimization level. This cannot easily be applied globally, as some packages may require specific optimization levels.

Problems with PKGSRC_USE_RELRO

Performance impact

For better protection, full RELRO requires every symbol to be resolved when the program starts, rather than simply when required at run-time. This will have more impact on programs using a lot of symbols, or linked to libraries exposing a lot of symbols. Therefore, daemons or programs otherwise running in background are affected only when started. Programs loading plug-ins at run-time are affected when loading the plug-ins.

The impact is not expected to be noticeable on modern hardware, except in some cases for big programs.

Run-time crashes

Some programs handle plug-ins and dependencies in a way that conflicts with RELRO: for instance, with an initialization routine listing any other plug-in required. With full RELRO, the missing symbols are resolved before the initialization routine can run, and the dynamic loader will not be able to find them directly and abort as a result. Unfortunately, this is how Xorg loads its drivers. Partial RELRO can be applied instead in this case.

Problems with PKGSRC_USE_SSP

Packages failing to build

The stack-smashing protection provided by this option does not work for some programs. The two most common situations in which this happens are:

Both cases will require a modification to the program, or disabling this feature for part or all of the build.

Run-time crashes

Again, this feature may cause some programs to crash, usually indicating an actual bug in the program. Patching the original program is then required.

Performance impact

The compiler emits extra code when using this feature: a check for buffer overflows is performed when entering and exiting functions, requiring an extra variable on the stack. The level of protection can otherwise be adjusted to affect only those functions considered more sensitive by the compiler (with -fstack-protector instead of -fstack-protector-all).

The impact is not expected to be noticeable on modern hardware. However, programs with a hard requirement to run at the fastest possible speed should avoid using this feature, or using libraries built with this feature.

Auditing the system

The illusion of security is worse than having no security at all. This section lists a number of ways to ensure the security features requested are actually effective.

These instructions were obtained and tested on a system derived from NetBSD 7 (amd64). YMMV.

Checking for PIE

The ELF executable type in use changes for binaries built as PIE; without:

$ file /path/to/bin/ary
/path/to/bin/ary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for NetBSD 7.0, not stripped

as opposed to the following binary, built as PIE:

$ file /path/to/pie/bin/ary
/path/to/pie/bin/ary: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for NetBSD 7.0, not stripped

The latter result is then what is expected.

Checking for partial RELRO

The following command should list a section called RELRO:

$ objdump -p /path/to/bin/ary

/path/to/bin/ary:     file format elf64-x86-64

Program Header:
[...]
   RELRO off    0x0000000000000d78 vaddr 0x0000000000600d78 paddr 0x0000000000600d78 align 2**0

This check is now performed automatically if PKG_DEVELOPER is set and RELRO is enabled.

Checking for full RELRO

The dynamic loader will apply RELRO immediately when detecting the presence of the BIND_NOW flag:

$ objdump -x /path/to/bin/ary

/path/to/bin/ary:     file format elf64-x86-64

Dynamic Section:
[...]
  BIND_NOW             0x0000000000000000

This has to be combined with partial RELRO (see above) to be fully efficient.

Checking for SSP

Building objects, binaries and libraries with SSP will affect the presence of additional symbols in the resulting file:

$ nm /path/to/bin/ary
[...]
                 U __stack_chk_fail
0000000000600ea0 B __stack_chk_guard

This is an indicator that the program was indeed built with support for SSP.

This check is now performed automatically (where supported) if PKG_DEVELOPER is set and SSP is enabled.

Add a comment
Contact | Disclaimer | Copyright © 1994-2017 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.
NetBSD® is a registered trademark of The NetBSD Foundation, Inc.