Arch package guidelines/Security
This page describes security packaging guidelines for Arch Linux packages. For C/C++ projects the compiler and linker can apply security hardening options. Arch Linux applies PIE, Fortify source, stack protector, nx and relro by default.
Hardening protections can be reviewed by running checksec.
$ checksec --file=/usr/bin/cat
RELRO is a generic mitigation technique to harden the data sections of an ELF binary/process. When a program is loaded several ELF memory sections need to be written to by the linker but can be turned read-only before turning control over to the program. This prevents attackers of overriding some ELF sections. There are two different RELRO modes:
- Partial RELRO (
-Wl,-z,relro) some sections are marked as read-only after program load except the GOT (
.got.plt) is still writeable.
- Full RELRO (
-Wl,-z,now) during program load all dynamic symbols are resolved, allowing for the complete GOT to be marked read-only.
If an application reports partial relro, investigate if the build toolchain passes our LDFLAGS or allows overriding LDFLAGS. For Go packages investigate if the build method uses
build.go as pure golang Makefile replacement which does not allow passing of LDFLAGS.
For Haskell it is not clear how to achieve Full RELRO at the moment.
A stack canary is added by the compiler between the buffer and control data on the stack. If this well known value is corrupted, a buffer overflow occurred and the running program segfaults to prevent possible arbitrary code execution.
The gcc package has it enabled stack protection by default with the --enable-default-ssp compile option.
Executable-space protection marks memory regions as non-executable, such that an attempt to execute machine code in these regions will cause an exception. It makes use of hardware features such as the NX bit (no-execute bit), or in some cases software emulation of those features.
The gcc package has it enabled by default for C/C++ with --enable-default-pie.
Pass the following flags to
export GOFLAGS='-buildmode=pie' export CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2" export CGO_LDFLAGS="-Wl,-z,relro,-z,now"
Pass the following flag to
runhaskell Setup.hs configure:
RUNPATH/RPATH provides further search paths for the object it is listed in (it can be used both for executable and for shared objects).
$ objdump -x /usr/bin/perl | grep -E 'RPATH|RUNPATH'
If the RPATH value contains a path within an attackers control it can possibly execute code by installing a malicious library in that directory for example CVE-2006-1566 CVE-2005-4280. See Debian:RpathIssue.
The RPATH entry is set by the linker by passing for example the following string to LDFLAGS
-Wl,-rpath -Wl,/usr/local/lib. To make an RUNPATH entry append
--enable-new-dtags to the linker flags.
Fortify source is a macro that adds buffer overflow protection in various functions that perform operations on memory and strings. It checks whether an attacker tries to copy more bytes to overflow a buffer and then stops the execution of the program. This protection is enabled with the default
If a systemd service file is shipped with the package due to upstream not providing any, look into applying the following systemd service hardening features. Systemd provides a way to analyse security features which are enabled for a service.
$ systemd-analyze security reflector.service
A service can be hardened by restricting file system access.
Set up a new file system namespace for the executed process and mounts private
var/tmp directories inside it that is not shared by processes outside the namespace. Useful for programs which write data to
ProtectSystem has three different varieties of mounting directories as read-only for the executed process. The "full" option mounts
/etc read only. ProtectHome makes
/run/user inaccessible to the executed process.
Sets up a new
/dev namespace for the executed process and only adds API pseudo devices such as
/dev/random, but not for physical devices or system memory, system ports and others. This is useful to secure the execute process from writing directly to physical devices, systemd also adds a system call filter for calls within the
These options make the executed process unable to change kernel variables accessible through
/sys, etc. ProtectControlGroups makes the
/sys/fs/cgroup hierarchy read-only.
Making file paths inaccessible can be done as following:
More detailed information can be found in systemd.exec(5).
Ensure that the executed process and its children can never gain new privileges through execve(2).
Prohibit attempts to create memory mappings that are both writable and executable, to change mappings to be executable or to create executable shared memory. This sandboxes a process against allowing an attacker to write in to memory which is also executed. Note that enabling this is not compatible with all applications which rely on a JIT.
Locks down the personality(2) system call so that the kernel execution domain can not be changed.
System calls can be restricted in a service as well, systemd can display syscalls to filter on:
$ systemd-analyze syscall-filter
Predefined groups are available, e.g. to use the recommended starting point for whitelisting system calls for system services use:
System calls can be restricted by their architecture such as to prevent 32-bit binaries from executing on 64-bit machines (no non-native binaries):
If the running process does not require any network access it can be fully disabled by setting up a new network namespace for the process and only configuration a loopback interface.
If network is required, the type of address families used can be restricted for the socket(2) system call by for example only allowing UNIX sockets.
For when only network to localhost or specific IP ranges is required a process can be restricted by only allowing network access to localhost.
More information about network filtering can be found in systemd.resource-control(5).
Sets up a new UTS namespace for the execute process and disallows changing the hostname or domainname.