Kernel Hardening

On this page

Enabling a hardening option does not mean all related attacks are blocked. First determine whether the mechanism targets the attack surface, error detection, exploitation conditions, or information leaks, and then verify the actual enabled state.

Target to CheckWhere to Read
Address, permission, and boundary checksSections 1–3
Detection coverage and lockdownSections 4–5
seccomp, allocation protection, and observationSections 6–8
Hardening mechanisms affect different stages Reachable Attack Surface Permissions / seccomp / lockdown Error Occurrence Boundary checks / sanitizer Exploitation Conditions KASLR / Read-only and Non-executable Subsequent Impact Zeroing / Fault Handling The same vulnerability may be constrained by multiple layers, but no single layer constitutes a complete fix. Build support, boot-time enablement, and runtime effectiveness must be verified separately.

1. KASLR and Strict Memory Permissions

KASLR randomizes part of the kernel's address layout during boot. The scope and granularity of randomization vary by architecture, configuration, and implementation; it is incorrect to assume that code, data, and modules are all controlled by a single random base address. On x86, early decompression/relocation code participates in selecting the location and should not be described as being solely completed by the bootloader.

It increases the difficulty for attackers to predict the location of code or data; address leaks and limited entropy can weaken this effect, so it must be combined with address information restrictions. kptr_restrict=2 hides addresses in outputs controlled by %pK rules; it does not mean "only non-root users cannot see them," nor does it guarantee that all kernel address outputs are controlled by this setting.

Mechanisms such as CONFIG_STRICT_KERNEL_RWX and module-related strict permissions constrain writable and executable regions. Read-only data and non-executable data pages limit code modification and direct execution of injected data, but do not automatically prevent all code reuse and data tampering. See Kernel Self-Protection and kptr_restrict documentation.

The user-space /proc/sys/kernel/randomize_va_space controls user process ASLR and cannot be used as evidence that kernel KASLR or per-syscall kernel stack offset randomization is enabled.

2. Stack Protector and Object Boundary Checks

The compiler inserts canaries only into functions that match the option rules; not every function necessarily has a canary. Checks typically occur before the protected function exits; upon detecting canary corruption, it enters a failure handling path. It cannot cover out-of-bounds writes at arbitrary locations, nor does it guarantee immediate detection before data is misused.

Kernel CONFIG_FORTIFY_SOURCE strengthens certain memory/string operations based on object sizes derivable by the compiler. Known errors can be diagnosed at compile time, and some dynamic out-of-bounds accesses can trigger runtime reports and termination paths. Unknown object boundaries and uncovered operations remain gaps; one cannot deduce that "all memcpy calls are safe." It is also not the glibc _FORTIFY_SOURCE=3 compile macro.

CONFIG_HARDENED_USERCOPY checks object and region constraints during kernel-to-user and user-to-kernel copies, addressing certain illegal copies. It does not prove that copied content conforms to business protocols, nor does it make passed lengths automatically trustworthy.

3. KPTI: Limiting Kernel Mappings in User-Space Page Tables

Meltdown-class issues involve transient execution leaks on specific processors. KPTI ensures that page tables used by user space retain only user mappings and a small number of mappings required for entering the kernel, switching to the appropriate kernel page table upon entry.

This reduces the conditions for user-space transient access to a large range of kernel mappings, but it is not a unified solution for all Spectre/Meltdown-class vulnerabilities. Page table switching and TLB management incur overhead; capabilities like PCID can mitigate this; actual impact should be measured against workloads and cannot be fixed to a specific percentage.

Enablement depends on processor vulnerability status, kernel, and boot policies; it cannot be generalized as "automatically disabled for all Intel/AMD generations after a certain point." Check the actual reports in /sys/devices/system/cpu/vulnerabilities/ and distinguish between Not affected, mitigated, and existing risks. See x86 PTI.

4. Detection Tools Have Different Coverage

ToolMain Issues FoundImportant Boundaries
KASANMemory errors like out-of-bounds and use-after-freeCapabilities and costs differ between generic, software tag, and hardware tag modes
KMSANUse and propagation of uninitialized valuesRequires corresponding compiler, architecture, and instrumentation support
UBSANSelected undefined behavior checksWhich sub-checks are enabled determines coverage; it cannot be broadly stated as checking all integer overflows
KFENCESampled detection of heap memory errorsLow overhead relies on sampling; not reporting does not mean all accesses are error-free

Unsigned wraparound is not itself undefined behavior in C; kernel compile options and sub-checks also affect integer behavior. A test run that reports no issues only indicates that no problems were caught within that execution and coverage scope.

These tools are not exclusively for kernel development: for example, hardware-tag KASAN or KFENCE can be applicable to different production targets, but actual overhead and support conditions should be evaluated; a uniform conclusion of "twice as slow" cannot be given. Refer to KASAN, KMSAN, UBSAN, KFENCE.

5. Lockdown: Limiting High-Privilege Users from Changing Kernel Trust Boundaries

Lockdown can restrict interfaces that read/write kernel memory, replace unverified code, or expose secrets. The integrity and confidentiality modes impose different constraints; the latter further restricts certain read paths. It is inaccurate to describe all BPF and debugging functionalities with a blanket "all disabled."

The status interface is typically /sys/kernel/security/lockdown in securityfs, not /proc/sys/kernel/lockdown. Secure Boot may trigger lockdown depending on the distribution, configuration, and patches, but the two cannot be unconditionally equated; signature verification, module loading policies, and lockdown must be checked separately. See kernel_lockdown(7).

6. Seccomp: Narrowing Interfaces by System Call ABI

The seccomp filter reads the system call number, architecture identifier, instruction address, and scalar parameters, returning actions such as ALLOW, ERRNO, TRAP, KILL_PROCESS, or USER_NOTIF via a classic BPF filter program. There is no actual generic return action named SECCOMP_RET_DENY.

Installation typically requires no_new_privs or satisfying permission conditions within the corresponding namespace. Filters are attached to threads and can synchronize thread groups using TSYNC; allowed fork/exec calls inherit filter constraints. Overlapping filters cannot relax previously stricter results with later ALLOW actions.

What the Filter SeesWhat It Cannot Directly Know
System call numberWithout combining with ABI, the call's meaning cannot be correctly determined
Scalar parameters and pointer valuesCannot be dereferenced into stable path strings
Architecture identifierMust be included in rule evaluation; cannot be ignored

Therefore, allowing openat and comparing pointer values does not equate to allowing only the opening of specified paths.

Target Memory May Change After Supervisor Checks

USER_NOTIF allows the supervisor to receive notifications and handle or respond, but since it reads the target process's mutable memory before allowing the original syscall to continue, it faces TOCTOU (Time-of-Check to Time-of-Use) issues. The notification mechanism is not an automatically secure file access controller. It should be used in conjunction with LSM, file descriptor permissions, and other isolation mechanisms; see seccomp filter documentation.

After checking, modify the path buffer, then choose either "continue using the current pointer" or "operate on the already held object." By comparing the actually used targets, one can see why the facts established at check time become stale.

Preparing the visual
Is the object checked the same as the object subsequently used?

A snapshot of a target process's memory at check time does not freeze its subsequent parameters. Secure operations must be bound to the actually verified object and permissions; CONTINUE cannot be treated as such a binding.

7. Zeroing and Freelist Protection

init_on_alloc / init_on_free can zero objects and pages in the respective allocation or free paths, reducing risks such as old data exposure, but it does not restore dangling pointers to validity, nor does it mean all allocators and special paths use the same handling.

CONFIG_SLAB_FREELIST_RANDOM changes the arrangement of free objects, while CONFIG_SLAB_FREELIST_HARDENED strengthens freelist metadata; random order and pointer protection are different mechanisms. They increase the difficulty of certain heap exploits but cannot replace fixing UAF (Use-After-Free).

8. Read-Only Confirmation of Runtime State

from pathlib import Path

for name in ('/proc/sys/kernel/kptr_restrict',
             '/sys/kernel/security/lockdown',
             '/sys/devices/system/cpu/vulnerabilities/meltdown'):
    try:
        print(name, Path(name).read_text().strip())
    except OSError as exc:
        print(name, type(exc).__name__)

Check the target kernel configuration and /proc/cmdline simultaneously, and then judge based on the runtime state. Having the capability in the configuration does not mean it is adopted at boot; a state file being invisible may simply be due to permission or namespace observation limitations.