Kahibaro
Discord Login Register

Kernel hardening

Why Kernel Hardening Matters

The kernel is the most privileged part of the system. If someone can run arbitrary code in kernel mode, every other defense (file permissions, containers, user separation, SELinux, etc.) can be bypassed.

Kernel hardening focuses on:

This chapter assumes general hardening ideas are known and focuses specifically on kernel-related techniques and configuration.

Threats Targeting the Kernel

Kernel hardening addresses several specific classes of attacks:

Kernel hardening tries both to remove opportunities and add safety belts so that if a vulnerability exists, exploitation is less likely.

Kernel Configuration for Hardening

Many protections are controlled at kernel build time via CONFIG_* options. On major distributions you usually consume these as prebuilt kernels, but the options still matter:

  zgrep CONFIG_HARDENED /proc/config.gz

or inspect /boot/config-$(uname -r).

Below is an overview of key categories.

Compile-Time Hardening Options

Stack Protection

Read-Only and No-Execute Data

Fortified Functions

Control-Flow Integrity (CFI) and Related

Some architectures and toolchains support extra protection:

On general-purpose distro kernels, these may not yet be widely available, but are worth enabling on custom or embedded builds when supported.

Other Miscellaneous Hardening Configs

Examples you might encounter:

Disabling Unnecessary Features

The most impactful hardening step is often removing what you don’t need:

In a custom kernel configuration tool (e.g., make menuconfig), you would:

For distribution kernels you can’t easily change CONFIG_*, but you can reduce attack surface at runtime (e.g., blacklisting modules), discussed below.

Runtime Kernel Hardening Settings (sysctl and boot parameters)

Hardening does not require compiling your own kernel. Many protections are controlled via:

Virtual Memory and Address Space Protections

Kernel ASLR and Memory Randomization

On modern kernels, Address Space Layout Randomization (ASLR) is usually on by default.

Check and enable:

sysctl kernel.randomize_va_space
sysctl -w kernel.randomize_va_space=2

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

kernel.randomize_va_space = 2

Restricting /dev/mem and /dev/kmem

These devices give low-level memory access and are rarely needed on production systems.

Relevant options (varies by kernel):

Check sysctl parameter:

Recommended:

sysctl -w kernel.kptr_restrict=2

Persist:

kernel.kptr_restrict = 2

Protecting System Call and Debug Interfaces

seccomp and Unprivileged System Calls

Some kernels provide toggles to prevent unprivileged processes from using potentially dangerous interfaces:

Recommended on general-purpose systems:

sysctl -w kernel.unprivileged_bpf_disabled=1

Persist:

kernel.unprivileged_bpf_disabled = 1

User namespaces improve container isolation but also expand the kernel attack surface. Decision depends on your container model and risk appetite. If you don’t use unprivileged containers, consider:

sysctl -w kernel.unprivileged_userns_clone=0

ptrace Restrictions

ptrace allows one process to debug or control another, which can be powerful and dangerous.

Recommended baseline:

sysctl -w kernel.yama.ptrace_scope=1

Hardened environments may choose 2 or 3, but that can break debuggers and some monitoring tools.

dmesg Restrictions

dmesg can leak sensitive kernel information.

Recommended:

sysctl -w kernel.dmesg_restrict=1

Persist:

kernel.dmesg_restrict = 1

Namespaces and User Isolation

Namespaces (user, PID, mount, etc.) are a core part of containerization but also increase kernel complexity and attack surface. Beyond kernel.unprivileged_userns_clone, some hardened kernels and distros provide extra tweaks:

Exact options are distro-specific, but the principle is: only allow the namespaces and features you actually use.

Hardening Boot Parameters (GRUB / Kernel CMDLINE)

Kernel parameters can enforce security-related behaviors from the earliest boot phase. You add them to your bootloader config, for example on GRUB-based systems:

Examples of hardening parameters:

A hardened command line might look like:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash slab_nomerge page_alloc.shuffle=1 vsyscall=none debugfs=off"

Always test changes carefully, as some options carry performance costs or can break specific workloads.

Limiting and Hardening Kernel Modules

Kernel modules are loadable pieces of kernel code. Reducing and controlling them is a major hardening step.

Disabling Module Loading at Runtime

Some hardened setups disable module loading once boot is complete.

To disable further loading after boot:

sysctl -w kernel.modules_disabled=1

Note: once set to 1, it cannot be reverted without a reboot. This is typically used in highly controlled, immutable systems where all needed modules are built-in.

Blacklisting Unneeded or Risky Modules

Instead of disabling all modules, you can prevent specific ones from loading.

Create a file, for example /etc/modprobe.d/blacklist-hardening.conf:

blacklist firewire-core
blacklist usb-storage
blacklist cramfs
blacklist udf

This ensures these modules won’t load automatically. You can blacklist:

Use lsmod, lspci, lsusb, and logs to see which modules are actually in use before blacklisting.

Locking Module Options

Some risky behaviors can be disabled via module parameters. For example, some network modules have debugging or promiscuous-mode settings that you might want to lock down. These are very module-specific; consult modinfo <module> and module documentation.

You can enforce parameters via /etc/modprobe.d/*.conf. Example:

options usbcore autorun=0

LSM-Based Kernel Hardening Layers

Linux Security Modules (LSMs) add policy-driven access control and other hardening. A full explanation of SELinux/AppArmor is handled elsewhere; here we focus on kernel-perspective aspects.

Enabling and Enforcing LSMs

At boot, the kernel chooses which LSMs to enable and in what order (varies by distro and kernel version).

Commonly:

Typical kernel parameters:

On modern kernels, lsm= parameter can set LSM ordering, e.g.:

lsm=lockdown,yama,integrity,apparmor,bpf

Consult your distro documentation; some handle this implicitly.

Kernel Lockdown Mode

Kernel Lockdown restricts some operations even from root, to protect against tampering with the running kernel (especially in secure boot scenarios).

Modes:

To enable via kernel cmdline:

lockdown=integrity

or

lockdown=confidentiality

Lockdown interacts with Secure Boot on many distros (it may be enabled automatically when Secure Boot is active).

Hardening eBPF and Tracing Facilities

eBPF is powerful for observability and networking, but it’s also complex and has had security issues.

Restricting eBPF

We already mentioned:

Additional steps may include:

On some hardened kernels you can:

Debugfs, Tracing, and Perf

Debugging and tracing feature sets (debugfs, ftrace, perf_event_open) expose a lot of kernel internals.

  sysctl kernel.perf_event_paranoid

Typical recommended values:

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

  kernel.perf_event_paranoid = 3

Hardened Kernel Projects and Distro Variants

If you manage security-sensitive environments, it can be worth using kernels with additional hardening patches:

When evaluating such kernels, consider:

Practical Hardening Workflow

A realistic kernel hardening approach on a general-purpose server might look like:

  1. Inventory and remove what you don’t need
    • Identify unused subsystems, filesystems, network stacks.
    • Blacklist unneeded modules.
    • Avoid auto-mounting debugfs.
  2. Tighten sysctl settings
    • kernel.randomize_va_space=2
    • kernel.kptr_restrict=2
    • kernel.dmesg_restrict=1
    • kernel.yama.ptrace_scope=1
    • kernel.unprivileged_bpf_disabled=1
    • kernel.perf_event_paranoid=3 (if you don’t need perf for unprivileged users)
    • Disable unprivileged user namespaces if safe for your use case.
  3. Harden boot parameters
    • Add slab_nomerge, page_alloc.shuffle=1, vsyscall=none, debugfs=off where supported.
    • Ensure LSMs are enabled and enforcing (e.g., SELinux/AppArmor).
  4. Consider module policies
    • On static, controlled systems, disable further module loading with kernel.modules_disabled=1 after boot.
    • Otherwise, at least constrain who can insert modules (e.g., ensure only trusted admins, restrict CAP_SYS_MODULE).
  5. Monitor and iterate
    • Watch logs for warnings or failures tied to new settings.
    • Adjust where necessary (for example, debugging tools might need relaxed ptrace or perf settings in staging environments).

Balancing Security, Stability, and Performance

Kernel hardening is always a trade-off:

Good practice:

Kernel hardening is most effective when combined with other layers: application hardening, network controls, strong authentication, and good operational practices.

Views: 26

Comments

Please login to add a comment.

Don't have an account? Register now!