version 1.48, 2021/10/01 15:48:03
|
version 1.49, 2021/10/02 14:48:27
|
Line 1
|
Line 1
|
[[!meta title="Hardening pkgsrc"]] |
This page has been moved to [the pkgsrc guide](//www.NetBSD.org/docs/pkgsrc/hardening.html). |
|
|
A number of mechanisms are available in |
|
[pkgsrc](https://www.pkgsrc.org/) 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 |
|
|
|
### 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. |
|
|
|
Two mitigation levels are available: |
|
|
|
- "weak" only enables checks at compile-time. |
|
- "strong" enables checks at compile-time and runtime. |
|
|
|
`strong` 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: |
|
|
|
* "yes", which will only protect functions considered vulnerable |
|
by the compiler; |
|
* "all", which will protect every function; |
|
* "strong", the default, which will apply a better balance between the two settings above. |
|
|
|
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++. |
|
|
|
"yes" is enabled by default where known supported since pkgsrc-2017Q3. |
|
"strong" is enabled by default where known supported since pkgsrc-2021Q4. |
|
|
|
More details can be found here: |
|
|
|
* <https://en.wikipedia.org/wiki/Buffer_overflow_protection> |
|
|
|
### 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 x86, ARM, SPARC64, m68k, and MIPS. |
|
|
|
PKGSRC_MKPIE was enabled by default after the pkgsrc-2021Q3 branch. |
|
|
|
|
|
### PKGSRC_USE_RELRO |
|
|
|
This also makes the exploitation of some security vulnerabilities more |
|
difficult in some cases. |
|
|
|
Two different mitigation levels are available: |
|
|
|
* partial: the ELF sections are reordered so that internal data sections |
|
precede the program's own data sections, and non-PLT GOT is read-only; |
|
* full: in addition to partial RELRO, every relocation is performed immediately |
|
when starting the program (with a slight performance impact), allowing the |
|
entire GOT to be read-only. |
|
|
|
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: |
|
|
|
* <https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro> |
|
* <http://tk-blog.blogspot.co.at/2009/02/relro-not-so-well-known-memory.html> |
|
|
|
## Not enabled by default |
|
|
|
### 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: |
|
|
|
* <https://reproducible-builds.org/> |
|
|
|
More work likely needs to be done before pkgsrc is fully reproducible. |
|
|
|
### 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` |
|
|
|
### 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. This is nearly always due to a bug in |
|
the program being exposed due to ASLR. |
|
|
|
### Disabling PKGSRC_MKPIE on a per-package basis |
|
|
|
Ideally, packages should be fixed for compatibility with MKPIE. |
|
However, in some cases this is very difficult, due to complex build systems, |
|
packages using non-standard toolchains, or programming languages with odd |
|
bootstrapping mechanisms. |
|
|
|
To disable `PKGSRC_MKPIE` on a per-package basis, set `MKPIE_SUPPORTED= no` in the package's Makefile before `bsd.prefs.mk` is included. |
|
|
|
## 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 |
|
by adding in the package `Makefile`: |
|
|
|
FORTIFY_SUPPORTED= no |
|
|
|
### 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. |
|
|
|
### Disabling RELRO on a per-package basis |
|
|
|
To disable RELRO on a per-package basis, set `RELRO_SUPPORTED= no` in the package's Makefile before `bsd.prefs.mk` is included. |
|
|
|
## Problems with `PKGSRC_USE_SSP` |
|
|
|
### Packages failing to build |
|
|
|
The stack-smashing protection provided by this option does not work for some |
|
programs. The most common situation in which this happens is when the program |
|
allocates variables on the stack, with the size determined at run-time. |
|
|
|
Both cases will require a modification to the program, or disabling this feature |
|
by adding in the package `Makefile`: |
|
|
|
SSP_SUPPORTED= no |
|
|
|
### Run-time crashes |
|
|
|
Again, this feature may cause some programs to crash via a SIGABRT, |
|
usually indicating an actual bug in the program. |
|
|
|
On NetBSD `LOG_CRIT` level `syslog()` messages are sent and - by |
|
default - appended to `/var/log/messages`, e.g.: |
|
|
|
Jan 6 15:42:51 <hostname> -: <hostname> <program> - - - buffer overflow detected; terminated |
|
|
|
(where `<hostname>` is the `hostname(1)` and `<program>` is the |
|
`basename(1)` of the program crashed). |
|
|
|
Patching the original program is then required. |
|
|
|
Rebuilding the package via: |
|
|
|
% env CFLAGS=-g INSTALL_UNSTRIPPED=yes make replace |
|
|
|
and inspecting the `backtrace` of the coredump via the debugger |
|
should point out the problematic call by inspecting the frame |
|
calling the `_chk()' (SSP) function. |
|
|
|
### 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. |
|
|
|
If it is needed to disable SSP check per-package, please add in the package |
|
`Makefile`: |
|
|
|
CHECK_SSP_SUPPORTED= no |
|