Skip to main content
RunBook Academy

LinuxXXIX · Linux Security Hardeningsysctl

Kernel hardening with sysctl - the runtime network and security parameters

Intermediate⏱ ~10 minsysctlip

What you'll learn

  • Apply a production sysctl hardening baseline
  • Distinguish security-relevant from performance-relevant sysctls
  • Persist sysctl settings across reboots
  • Recognise when sysctl changes break applications
  • Decide between kexec hardening and kdump crash capture, which are mutually exclusive

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

sysctl is the runtime parameter interface to the kernel. Many security-relevant settings are exposed as sysctls: ASLR, IP forwarding, ICMP redirects, kernel pointer restrictions. This lesson covers a production hardening baseline.

Read sysctls

sysctl net.ipv4.ip_forward
sysctl -a | grep -E 'kernel.randomize|net.ipv4.conf'

A hardening baseline

/etc/sysctl.d/99-hardening.conf:

# Kernel hardening
kernel.randomize_va_space = 2        # full ASLR
kernel.kptr_restrict = 2              # hide kernel pointers
kernel.dmesg_restrict = 1             # restrict dmesg to CAP_SYSLOG
#kernel.kexec_load_disabled = 1      # disable kexec - ALSO DISABLES KDUMP, see below
kernel.sysrq = 0                      # disable magic sysrq
kernel.unprivileged_bpf_disabled = 1  # disable unprivileged BPF
kernel.unprivileged_userns_clone = 0  # disable user namespaces for unprivileged
net.core.bpf_jit_harden = 2           # harden BPF JIT

# Network hardening
net.ipv4.ip_forward = 0               # no forwarding unless router
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

Apply:

sudo sysctl -p /etc/sysctl.d/99-hardening.conf

What each setting does

SettingEffect
kernel.randomize_va_space = 2Full ASLR (defeats memory-based exploits)
kernel.kptr_restrict = 2Hide kernel pointers in /proc/kallsyms
kernel.dmesg_restrict = 1Only CAP_SYSLOG holders can read dmesg
kernel.kexec_load_disabled = 1Block kexec_load(), so root cannot boot an arbitrary kernel. Also disables kdump. Commented out in the baseline above — enable it per host role, not by default
kernel.unprivileged_bpf_disabled = 1Block unprivileged BPF programs
kernel.unprivileged_userns_clone = 0Block unprivileged user namespaces (containers)
net.ipv4.ip_forward = 0No forwarding; set to 1 only on routers
net.ipv4.conf.*.accept_redirects = 0Reject ICMP redirects
net.ipv4.conf.*.accept_source_route = 0Reject source-routed packets
net.ipv4.conf.*.log_martians = 1Log packets with impossible addresses
net.ipv4.icmp_echo_ignore_broadcasts = 1Ignore broadcast pings (smurf attack)
net.ipv4.tcp_syncookies = 1SYN flood protection
net.ipv4.conf.*.rp_filter = 1Reverse-path filter (anti-spoofing)

Test before persisting

A wrong sysctl can break networking:

  • ip_forward = 0 on a router: routing breaks.
  • accept_redirects = 0 on a segment with two routers where the hosts hold only a default route: traffic for the second router’s networks keeps hairpinning through the default gateway instead of being redirected. The symptom is a latency and bandwidth penalty, not a loss of connectivity — and the fix is a specific route (or a correct default), never accepting unauthenticated ICMP from anything on the wire. Leave this at 0.
  • rp_filter = 1 strict mode breaks asymmetric routing. Where return paths genuinely differ, 2 (loose mode) keeps a spoofing check without requiring symmetry. This is the baseline setting most likely to break an existing host: every multi-homed machine built with the policy-routing recipes in linux-policy-routing and linux-multiple-routing-tables relies on paths that strict mode discards, and the drops are silent. Note that the kernel uses max(conf.all.rp_filter, conf.<iface>.rp_filter), so exempting one interface means lowering conf.all too. Count the damage with nstat -az TcpExtIPReversePathFilter.

Test with sysctl -w (not -p) so the change is not persistent:

sudo sysctl -w kernel.kptr_restrict=2

Verify the application or service still works. If it does, persist in the configuration file.

Persist via configuration files

Place files in /etc/sysctl.d/ (named with a numeric prefix; loaded in lexical order):

sudo nano /etc/sysctl.d/99-hardening.conf
sudo sysctl -p /etc/sysctl.d/99-hardening.conf

To make settings survive reboot, the file must end in .conf and be in /etc/sysctl.d/, /run/sysctl.d/, or /usr/local/lib/sysctl.d/.

Verify

sudo sysctl -p /etc/sysctl.d/99-hardening.conf
sudo sysctl kernel.randomize_va_space
sudo sysctl net.ipv4.tcp_syncookies

Common pitfalls

  • net.ipv4.ip_forward = 0 on a Docker host: containers need forwarding. Most container runtimes set this automatically, but check.
  • net.ipv6.conf.*.disable_ipv6 = 1 with IPv6 enabled services: services fail to bind. Verify with ip -6 addr.
  • fs.protected_hardlinks = 1 with old applications: some old applications fail. Verify.
  • kernel.yama.ptrace_scope = 3 with debugging tools: gdb and strace stop working for non-root processes.
  • kernel.kexec_load_disabled = 1 on a host you need crash dumps from: kdump cannot load its capture kernel, so a panic produces no vmcore. Check with cat /sys/kernel/kexec_crash_loaded1 means armed, 0 means no dump. The flag is one-way until reboot.

Knowledge check

Knowledge check · 4 questions

  1. Q1. What does kernel.randomize_va_space = 2 enable?

  2. Q2. net.ipv4.ip_forward = 0 is correct for a Linux host used as a router.

  3. Q3. Which of the following are valid sysctl hardening settings? Select all that apply.

  4. Q4. You roll this hardening baseline out fleet-wide with kernel.kexec_load_disabled = 1 uncommented. Three weeks later a database host panics nightly and the kernel team asks for a vmcore. /var/crash is empty and kdump.service is enabled and active. Why is there no dump?

Passing score: 75%. Answers are checked in this browser.