Free Linux Kernel Programming Course | EmbeddedPathashala
2 of 2
Intermediate
Kernel Security / Memory
KASLR Explained – How Linux Randomizes the Kernel’s Own Memory Layout
In Part 1 of this tutorial (part of this free Linux kernel programming course), we covered ASLR — how the Linux kernel randomizes user-space process memory to make exploitation harder. But here is a question: what about the kernel’s own code and data? If an attacker can determine where kernel functions like commit_creds() or prepare_kernel_cred() live in memory, they can target those in a privilege escalation attack — even from user space.
This is exactly the problem that KASLR (Kernel Address Space Layout Randomization) solves. KASLR extends the same randomization idea from user space into kernel space. Starting with the Linux 3.14 kernel, KASLR has been an available and important security feature for any system running a mainstream Linux distribution.
📋 What You Will Learn in Part 2
- Why the kernel’s own virtual address space needs randomization
- How KASLR randomizes the kernel’s load address at boot time
- The kernel boot parameters that control KASLR (
nokaslr,kaslr) - How CONFIG_RANDOMIZE_MEMORY extends KASLR to physical memory maps
- How to write a Bash script to query and display both ASLR and KASLR status
- Security analysis: what KASLR protects and what it does not
- Practical debugging tips when KASLR causes symbol address mismatches
Why Kernel Space Needs Its Own Randomization
User-mode ASLR only randomizes the virtual address space seen by user-space processes. The kernel runs in a completely separate region of the address space — the kernel segment — and without KASLR, that segment always loads at the same base address.
This matters because many privilege escalation exploits do not need to stay in user space. They use a user-space vulnerability as an entry point, then try to call or overwrite kernel functions to gain root-level access. If the kernel’s code and data are always at known addresses, an attacker who knows the kernel version can hardcode those addresses into an exploit.
How KASLR Works – Randomizing the Kernel’s Load Address
When KASLR is active, the bootloader or the kernel’s early boot code selects a random page-aligned offset from the base of RAM and adds it to the kernel’s default load address. This shifts the entire kernel image — its text, data, BSS, and the module area — to a new location in the kernel virtual address space.
This randomization happens once per boot. The offset is chosen at boot time and stays fixed for the entire session. It does not change while the system is running. A power cycle or reboot causes a new random offset to be selected.
Extended KASLR – CONFIG_RANDOMIZE_MEMORY
Basic KASLR only randomizes where the kernel image loads. An extended kernel configuration option called CONFIG_RANDOMIZE_MEMORY goes further. When enabled, it also randomizes:
- The direct physical memory mapping (physmap) — the region where the kernel maps all physical RAM into virtual addresses
- The vmalloc/ioremap region — used for virtually-contiguous kernel allocations and device memory mappings
- The virtual memory map — the region containing
struct pagedescriptors for all physical pages
The key property these share: their order is preserved — the same regions exist in the same relative arrangement as without randomization — but their base addresses are offset early at boot time by a random amount.
This makes certain kernel information-disclosure attacks significantly harder, because knowing the virtual address of one kernel object no longer automatically tells an attacker where the physmap or vmalloc regions start.
Controlling KASLR at Boot Time – Kernel Parameters
Unlike user-mode ASLR which you can change at runtime through procfs, KASLR is controlled at boot time through kernel command-line parameters passed via the bootloader (GRUB, for example). There is no runtime sysctl knob for KASLR.
| Parameter | Effect | When to Use |
|---|---|---|
nokaslr |
Explicitly disables KASLR — kernel loads at its default fixed address | Kernel debugging, live patching, symbol resolution tools that need fixed addresses |
kaslr |
Explicitly enables KASLR (it is on by default on supported kernels; this parameter forces it even if a config tried to disable it) | Hardened production systems where you want to confirm KASLR is definitely active |
To add a boot parameter in GRUB (temporary, for testing):
# 1. Open GRUB menu at boot (hold Shift or Esc during boot)
# 2. Press 'e' to edit the selected entry
# 3. Find the line starting with 'linux' — it contains the kernel parameters
# 4. Add 'nokaslr' at the end of that line (for debugging only)
# 5. Press Ctrl+X or F10 to boot with modified parameters
#
# The modification is temporary — it does NOT persist across reboots.
# Example linux line after editing:
linux /boot/vmlinuz-6.x.x root=/dev/sda1 ro quiet splash nokaslr
To make the change permanent, edit /etc/default/grub and add the parameter to GRUB_CMDLINE_LINUX, then run update-grub. However, permanently disabling KASLR on a production system is strongly discouraged.
How to Check KASLR Status on Your Running System
There is no single runtime file that directly says “KASLR is on/off” the way /proc/sys/kernel/randomize_va_space does for user ASLR. Instead, you infer KASLR status from a combination of sources.
Method 1 – Check the Kernel Command Line
# The kernel stores its boot parameters here
cat /proc/cmdline
# If 'nokaslr' appears in the output, KASLR is disabled.
# If it's absent (or 'kaslr' is present), KASLR is likely active.
Method 2 – Compare Kernel Symbol Addresses Across Reboots
The file /proc/kallsyms lists kernel symbol addresses at runtime. With KASLR active, these addresses differ between boots. With KASLR disabled, they remain fixed across boots.
# View kernel symbol addresses (requires root for actual addresses;
# non-root shows zeros for security)
sudo grep -E "commit_creds|prepare_kernel_cred" /proc/kallsyms
# Reboot the system and run the same command again.
# Different addresses = KASLR is working.
# Same addresses = KASLR is disabled.
/proc/kallsyms. This is intentional — exposing kernel symbol addresses to unprivileged users would undermine KASLR entirely. This behavior is controlled by /proc/sys/kernel/kptr_restrict.Method 3 – Check kptr_restrict
# kptr_restrict controls who can see kernel pointers
cat /proc/sys/kernel/kptr_restrict
# Value 0: All users see real addresses (weakens KASLR protection)
# Value 1: Non-root users see zeros; CAP_SYSLOG can see real addresses
# Value 2: Everyone except kernel itself sees zeros (strongest)
Writing a Bash Script to Query ASLR and KASLR Status
The following script checks both user-mode ASLR and KASLR status on the current system and displays the results clearly. This is a practical exercise for this free Linux kernel programming course — you should run it, understand every line, and try modifying it.
#!/bin/bash
# Script: check_kaslr_aslr.sh
# Purpose: Query and display ASLR and KASLR status on a Linux system
# Usage: sudo bash check_kaslr_aslr.sh
# Compatible with: Linux kernel 3.14+ on x86/x86-64
# ── Colour definitions ──────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No colour / reset
# ── Header ──────────────────────────────────────────────────────
echo -e "${BOLD}${CYAN}============================================${NC}"
echo -e "${BOLD}${CYAN} ASLR / KASLR Status Checker ${NC}"
echo -e "${BOLD}${CYAN} EmbeddedPathashala – Linux Kernel Course ${NC}"
echo -e "${BOLD}${CYAN}============================================${NC}"
echo ""
# ── 1. User-mode ASLR ───────────────────────────────────────────
ASLR_FILE="/proc/sys/kernel/randomize_va_space"
if [ -f "$ASLR_FILE" ]; then
ASLR_VAL=$(cat "$ASLR_FILE")
echo -e "${BOLD}[1] User-Mode ASLR${NC}"
echo -e " Tunable file : ${CYAN}${ASLR_FILE}${NC}"
echo -n " Current value: "
case "$ASLR_VAL" in
0) echo -e "${RED}${BOLD}0 — ASLR DISABLED${NC} (stack, heap, libs at fixed addresses)" ;;
1) echo -e "${YELLOW}${BOLD}1 — ASLR PARTIAL${NC} (mmap, stack, vDSO, libs randomized; heap fixed)" ;;
2) echo -e "${GREEN}${BOLD}2 — ASLR FULL${NC} (mmap, stack, vDSO, libs AND heap randomized)" ;;
*) echo -e "${RED}Unknown value: $ASLR_VAL${NC}" ;;
esac
else
echo -e "${RED}[!] Cannot read $ASLR_FILE — procfs may not be mounted.${NC}"
fi
echo ""
# ── 2. KASLR via kernel command line ────────────────────────────
CMDLINE_FILE="/proc/cmdline"
echo -e "${BOLD}[2] Kernel ASLR (KASLR)${NC}"
if [ -f "$CMDLINE_FILE" ]; then
CMDLINE=$(cat "$CMDLINE_FILE")
echo -e " Kernel cmdline: ${CYAN}${CMDLINE}${NC}"
if echo "$CMDLINE" | grep -qw "nokaslr"; then
echo -e " KASLR status : ${RED}${BOLD}DISABLED${NC} (nokaslr parameter found)"
else
echo -e " KASLR status : ${GREEN}${BOLD}LIKELY ENABLED${NC} (nokaslr not found in cmdline)"
echo -e " ${YELLOW}Note: Verify kernel was compiled with CONFIG_RANDOMIZE_BASE=y${NC}"
fi
else
echo -e "${RED}[!] Cannot read $CMDLINE_FILE${NC}"
fi
echo ""
# ── 3. kptr_restrict ────────────────────────────────────────────
KPTR_FILE="/proc/sys/kernel/kptr_restrict"
echo -e "${BOLD}[3] Kernel Pointer Restriction (kptr_restrict)${NC}"
if [ -f "$KPTR_FILE" ]; then
KPTR_VAL=$(cat "$KPTR_FILE")
echo -n " Current value: "
case "$KPTR_VAL" in
0) echo -e "${RED}0 — ALL users can see kernel pointers (weakens KASLR)${NC}" ;;
1) echo -e "${YELLOW}1 — Non-privileged users see zeros${NC}" ;;
2) echo -e "${GREEN}2 — Everyone except kernel sees zeros (strongest)${NC}" ;;
*) echo -e "Unknown: $KPTR_VAL" ;;
esac
fi
echo ""
# ── 4. Quick sample of randomized kernel symbols ─────────────────
echo -e "${BOLD}[4] Sample kernel symbol addresses (requires root)${NC}"
if [ "$EUID" -eq 0 ]; then
echo -e " ${CYAN}Showing a few symbol addresses from /proc/kallsyms:${NC}"
grep -E " T (commit_creds|prepare_kernel_cred|sys_call_table)" \
/proc/kallsyms 2>/dev/null | head -5
echo -e " ${YELLOW}Tip: Reboot and run again — addresses should differ with KASLR on.${NC}"
else
echo -e " ${RED}Run as root to see actual kernel symbol addresses.${NC}"
fi
echo ""
echo -e "${BOLD}${CYAN}============================================${NC}"
echo -e "${BOLD}Done. EmbeddedPathashala – Free Kernel Course${NC}"
echo -e "${BOLD}${CYAN}============================================${NC}"
Save this as check_kaslr_aslr.sh, make it executable, and run it with sudo:
chmod +x check_kaslr_aslr.sh
sudo bash check_kaslr_aslr.sh
KASLR and Kernel Debugging – When to Disable It
KASLR is excellent for production security but it creates a specific challenge during kernel development and debugging: the symbol addresses your debugger (gdb, crash) knows from the compiled kernel’s symbol table will not match the actual runtime addresses, because KASLR has shifted everything.
The common solutions are:
- Pass
nokaslrat boot during development — Gives you fixed, predictable addresses that match yourSystem.mapandvmlinuxsymbol tables - Use
/proc/kallsymsat runtime — This file always reflects the actual (randomized) addresses, so it remains the ground truth for the current boot session - Use the
crashutility’s offset-aware mode — Modern crash analysis tools can account for KASLR offsets if you provide the correct base
# Find the actual KASLR offset for the current boot
# (requires root and a known kernel symbol address from System.map)
# Step 1: Get the compile-time address of '_text' from System.map
grep " _text" /boot/System.map-$(uname -r)
# Step 2: Get the runtime address of '_text' from kallsyms
sudo grep " _text" /proc/kallsyms
# Step 3: The difference between these two values is the KASLR offset.
# All other kernel symbols are shifted by exactly this same offset.
Best Practices for [K]ASLR in Linux Systems
| Practice | Reason |
|---|---|
Keep randomize_va_space at 2 on production systems |
Maximizes user-space address randomization including the heap |
Never add nokaslr to production GRUB config |
Disabling KASLR permanently exposes kernel symbol addresses |
Keep kptr_restrict at 1 or 2 |
Prevents unprivileged processes from reading kernel pointer values that would defeat KASLR |
| Enable CONFIG_RANDOMIZE_MEMORY in your kernel config | Extends randomization to physmap and vmalloc regions for stronger kernel protection |
Compile user programs with -fPIE -pie |
Allows ASLR to randomize the text segment too; without PIE, the code segment stays at a fixed address |
| Pair [K]ASLR with stack canaries, NX, and SMEP/SMAP | Defense-in-depth: no single mitigation is sufficient; combining multiple layers raises the bar for attackers significantly |
Real-World Context – KASLR on Embedded Linux Systems
For embedded systems engineers — one of the core audiences of this free embedded systems course — KASLR deserves special attention. On embedded Linux targets running on platforms like ARM, RISC-V, or MIPS:
- Constrained entropy — Embedded systems often have limited sources of hardware randomness at early boot. KASLR entropy depends on the quality of the boot-time random seed. If the seed is poor or predictable (common on some microcontrollers without a hardware RNG), KASLR’s effectiveness is reduced.
- Bootloader support matters — Not all embedded bootloaders (U-Boot variants, for example) properly support passing KASLR-compatible randomization seeds to the kernel. Verify this for your platform.
- KASLR vs real-time requirements — The small overhead of KASLR (it adds a tiny amount to boot time for address fixups) is negligible on most embedded Linux platforms running mainline kernel versions.
Frequently Asked Questions – ASLR and KASLR
Q1: Does ASLR protect against all memory exploitation attacks?
No. ASLR is a statistical protection that raises the difficulty of exploitation. Attacks that use information leaks to discover runtime addresses, or that perform brute-force address guessing (especially on 32-bit systems), can still succeed. It must be combined with other defenses.
Q2: What is the difference between ASLR and PIE?
ASLR is a kernel feature that randomizes the placement of memory regions. PIE (Position Independent Executable) is a compiler/linker feature that makes the program’s own text (code) segment relocatable. ASLR can randomize shared libraries and stack without PIE, but the main program’s code segment is only randomized when the binary is built as PIE.
Q3: If KASLR only changes at reboot, is it weaker than user ASLR?
Different, not necessarily weaker. User ASLR re-randomizes every time a new process is created. KASLR is per-boot because the kernel itself is a single long-running instance. An attacker who gains any form of kernel pointer read capability during a session could defeat KASLR for that session, which is why kptr_restrict and strict capability controls are important complements.
Q4: Can I see the actual KASLR offset applied to the kernel?
Yes, if you have root access. Compare the _text symbol’s compile-time address in /boot/System.map-$(uname -r) with its runtime address in /proc/kallsyms. The difference is the KASLR offset for this boot. This capability is intentionally restricted to root, because revealing the offset to unprivileged users would defeat KASLR.
Q5: Does KASLR slow down the kernel?
The performance impact of KASLR at runtime is negligible — essentially zero. The only cost is a small one-time overhead during the kernel’s early boot phase when it applies the random offset and fixes up internal references. On modern hardware this is imperceptible.
Q6: What kernel version introduced KASLR?
KASLR support on x86-64 was introduced in Linux 3.14. User-mode ASLR has been supported since Linux 2.6.12 (around 2005). Both are enabled by default on all modern mainstream Linux distributions.
Q7: Does disabling ASLR in my container affect the host?
Writing to /proc/sys/kernel/randomize_va_space inside a container typically requires CAP_SYS_ADMIN and affects the system-wide setting (since procfs is usually shared with the host in many container setups). Privileged containers that can modify this setting should be treated with care in production environments.
Q8: How does SMEP/SMAP complement KASLR?
SMEP (Supervisor Mode Execution Prevention) and SMAP (Supervisor Mode Access Prevention) are CPU features that prevent the kernel from executing or reading user-space memory. They complement KASLR: even if an attacker knows a kernel address and redirects kernel execution to user space, SMEP blocks that execution. Combined, KASLR + SMEP + SMAP form a strong layered defense.
📝 Part 2 Summary – Key Takeaways
- KASLR randomizes the kernel’s own load address at boot time using a page-aligned random offset
- Available since Linux 3.14; active by default on mainstream x86/ARM Linux distributions
- Controlled via
nokaslr/kaslrboot parameters — no runtime sysctl knob exists - CONFIG_RANDOMIZE_MEMORY extends KASLR to physmap, vmalloc, and virtual memory map regions
- The KASLR offset can be determined by comparing
System.mapvs/proc/kallsyms(root only) - Disable KASLR only during kernel development/debugging; always re-enable on production systems
- KASLR must be combined with
kptr_restrict, SMEP, SMAP, stack canaries, and NX for effective defense-in-depth
