Kernel Hardening in NullSec Linux
A security-focused distribution needs a security-focused kernel. NullSec Linux ships with extensive hardening: grsecurity patches, enhanced ASLR, strict sysctl defaults, and mandatory access control for every service. Here's what we changed and why.
◉ The Threat Model
NullSec is used for security testing. That means:
- Users run untrusted code (exploit development, malware analysis)
- Network exposure is high (listening services, port scanning)
- Privilege escalation attempts are likely (pen testing practice)
- Persistence mechanisms may be tested (rootkits, backdoors)
The kernel must assume hostile user-space. Defense in depth at every layer.
◉ Grsecurity Patches
We apply the grsecurity patchset (self-compiled, not the commercial version). Key features:
ASLR+
Standard ASLR randomizes stack, heap, and libraries. Grsecurity's ASLR+ adds:
- Stronger entropy (32-bit on x86_64 vs 28-bit default)
- VDSO randomization
- Per-thread stack randomization
- Brute force detection and throttling
# Verify ASLR entropy
cat /proc/sys/kernel/randomize_va_space
# Should be 2 (full randomization)
# Check brute force protection
cat /proc/sys/kernel/grsecurity/deter_bruteforce
# Should be 1
RBAC (Role-Based Access Control)
Fine-grained access control beyond traditional Unix permissions:
# Example gradm policy for nginx
role nginx u
subject /usr/sbin/nginx
/ h
/var/www r
/var/log/nginx a
/run/nginx.pid rw
/etc/nginx r
-CAP_ALL
+CAP_NET_BIND_SERVICE
Each process sees only what it needs. No ambient capabilities.
PaX Memory Protections
- MPROTECT: Prevents writable+executable memory
- RANDKSTACK: Randomizes kernel stack between syscalls
- UDEREF: Separates kernel/user address spaces
- REFCOUNT: Hardens reference counting against overflow
◉ Kernel Config
Our kernel config enables every hardening option:
# Memory hardening
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y # Zero memory on alloc
CONFIG_INIT_ON_FREE_DEFAULT_ON=y # Zero memory on free
CONFIG_HARDENED_USERCOPY=y # Bounds-checked copies
CONFIG_FORTIFY_SOURCE=y # Buffer overflow detection
# Stack protection
CONFIG_STACKPROTECTOR_STRONG=y # Stack canaries
CONFIG_SHADOW_CALL_STACK=y # ARM64: separate return stack
CONFIG_VMAP_STACK=y # Guard pages around stack
# Address space randomization
CONFIG_RANDOMIZE_BASE=y # KASLR
CONFIG_RANDOMIZE_MEMORY=y # Randomize physical memory
# Control flow integrity
CONFIG_CFI_CLANG=y # Forward-edge CFI
CONFIG_CFI_PERMISSIVE=n # Strict mode
# Misc hardening
CONFIG_UBSAN_BOUNDS=y # Bounds checking
CONFIG_SLAB_FREELIST_RANDOM=y # Randomize freelist
CONFIG_SLAB_FREELIST_HARDENED=y # Harden freelist pointers
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y # Randomize page allocation
◉ Sysctl Defaults
Runtime kernel parameters, set in /etc/sysctl.d/99-nullsec.conf:
# Network hardening
net.ipv4.conf.all.rp_filter = 1 # Strict reverse path
net.ipv4.conf.all.accept_redirects = 0 # Ignore ICMP redirects
net.ipv4.conf.all.send_redirects = 0 # Don't send redirects
net.ipv4.tcp_syncookies = 1 # SYN flood protection
net.ipv4.tcp_timestamps = 0 # Disable TCP timestamps
# Kernel hardening
kernel.kptr_restrict = 2 # Hide kernel pointers
kernel.dmesg_restrict = 1 # Restrict dmesg access
kernel.perf_event_paranoid = 3 # Restrict perf
kernel.unprivileged_bpf_disabled = 1 # No unprivileged eBPF
kernel.yama.ptrace_scope = 2 # Restrict ptrace
# Filesystem hardening
fs.protected_symlinks = 1 # Symlink protection
fs.protected_hardlinks = 1 # Hardlink protection
fs.protected_fifos = 2 # FIFO protection
fs.protected_regular = 2 # Regular file protection
fs.suid_dumpable = 0 # No SUID core dumps
◉ AppArmor Profiles
Every service runs under mandatory access control. Our profile collection:
| Service | Profile Status | Notes |
|---|---|---|
| NetworkManager | Enforcing | Read /etc, write /run only |
| sshd | Enforcing | Minimal filesystem access |
| dhclient | Enforcing | Network only |
| cups | Enforcing | USB and /var/spool |
| snapd | Disabled | Not installed |
| All others | Complain | Logging violations |
Security tools (nmap, Metasploit, etc.) run without AppArmor confinement — they need raw access to function.
◉ Module Restrictions
Kernel modules are locked down after boot:
# /etc/modprobe.d/nullsec.conf
# Disable rarely-used filesystems
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install squashfs /bin/false
install udf /bin/false
# Disable rarely-used network protocols
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
# After boot:
# echo 1 > /proc/sys/kernel/modules_disabled
◉ Secure Boot
NullSec supports Secure Boot with our own signing keys:
- Kernel signed with our MOK (Machine Owner Key)
- All modules signed at build time
- DKMS modules re-signed automatically
- Users can enroll our key via mokutil
◉ Performance Impact
Hardening has costs. Our measurements on typical workloads:
| Feature | Overhead |
|---|---|
| ASLR+ | ~1% |
| Init on alloc/free | ~3-5% |
| CFI | ~1-2% |
| AppArmor | ~1% |
| Total | ~6-9% |
Worth it for a security-focused distro. If you need raw speed, use a different kernel.
◉ Verifying Hardening
Check your installation:
# Check kernel config
zcat /proc/config.gz | grep -E 'HARDENED|FORTIFY|STACK|CFI'
# Check sysctl values
sysctl -a | grep -E 'kptr|dmesg|ptrace|bpf'
# Check AppArmor status
aa-status
# Run hardening audit
lynis audit system --pentest
Full kernel config at nullsec-linux/kernel/config.