ASLR and KASLR in the Linux Kernel
How the Linux kernel randomizes memory addresses to protect your system — explained for free in this Linux kernel development course
Updated content
No paywall
Friendly depth
Welcome to this lecture in the free Linux kernel development course on EmbeddedPathashala. In this tutorial, you will learn about two of the most important memory security features built into the Linux kernel: ASLR (Address Space Layout Randomization) and KASLR (Kernel Address Space Layout Randomization). These features are active on virtually every Linux system you will ever encounter, and understanding them is critical for anyone serious about Linux kernel programming, Linux device driver development, or embedded systems security.
If you have ever wondered why your program’s stack and heap addresses change every time you run it, or why kernel symbols show different addresses after each reboot, this lecture answers all of that — clearly and completely.
🎓 What You Will Learn
- What ASLR is and why the Linux kernel needs it
- The three ASLR levels controlled via
/proc/sys/kernel/randomize_va_space - What KASLR is and how it differs from userspace ASLR
- How to verify ASLR behavior on a live Linux system using
/proc/self/maps - How to enable and disable ASLR for debugging purposes
- The security limitations of ASLR and KASLR
- How PIE (Position Independent Executable) connects with ASLR
- Practical commands every Linux kernel developer should know
Prerequisites
Before you start this lecture, make sure you are comfortable with:
- Basic Linux process model — what user space and kernel space mean
- The concept of virtual memory and virtual address spaces (VAS)
- Reading /proc/PID/maps output — covered in the previous lecture of this free Linux kernel course
- Compiling and running simple C programs on Linux
Why Does the Linux Kernel Randomize Memory Addresses?
Before understanding ASLR and KASLR, you need to understand the problem they solve. In the early days of Linux, every process had a predictable, fixed memory layout. The stack always started at the same address. The heap always grew from the same base. Shared libraries always loaded at the same virtual addresses.
This predictability was a serious security problem. Attackers who found a buffer overflow vulnerability in a program could craft an exploit that jumped to an exact, known address — the beginning of the stack, for example, or a known function in libc. This class of attack is called a return-to-libc attack. Since the attacker already knew where everything lived in memory, writing a reliable exploit was straightforward.
The Linux kernel’s answer to this problem was simple in concept: randomize the addresses. If the attacker cannot predict where the stack, heap, or libraries will be loaded, crafting a reliable exploit becomes dramatically harder. This is the fundamental idea behind ASLR.
Understanding the Three Levels of ASLR
The Linux kernel exposes ASLR control through a kernel tunable parameter available at /proc/sys/kernel/randomize_va_space. You can read the current value with:
cat /proc/sys/kernel/randomize_va_space
The kernel accepts three possible values for this parameter:
| Value | Mode | What Gets Randomized |
|---|---|---|
| 0 | ASLR OFF | Nothing — all segments have fixed, predictable addresses |
| 1 | Partial ASLR | Stack, VDSO page, and shared memory (shmem) segments |
| 2 | Full ASLR (default) | Stack, VDSO, shmem, heap, and all mmap-based allocations including shared libraries |
To change this value temporarily (until next reboot), you need root privileges:
# Disable ASLR temporarily — only for debugging
sudo sh -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
# Re-enable full ASLR
sudo sh -c 'echo 2 > /proc/sys/kernel/randomize_va_space'
To make a change persistent across reboots, add it to /etc/sysctl.conf or a file in /etc/sysctl.d/:
# In /etc/sysctl.conf or /etc/sysctl.d/99-security.conf
kernel.randomize_va_space = 2
# Apply without rebooting:
sudo sysctl -p
Verifying ASLR Behavior with /proc/self/maps
The cleanest way to verify that ASLR is working is to look at the heap and stack addresses for a process across two separate runs. The /proc/self/maps pseudo-file shows the virtual memory map of the currently running process. We can use grep to filter only the heap and stack entries.
# Run this command twice and compare the addresses
grep -E "\[heap\]|\[stack\]" /proc/self/maps
Here is what you should expect to see when ASLR is enabled (value = 2):
# First run:
560915f82000-560915fa3000 rw-p 00000000 00:00 0 [heap]
7ffdb94d5000-7ffdb94f6000 rw-p 00000000 00:00 0 [stack]
# Second run (addresses are completely different — ASLR working):
55852f9f1000-55852fa12000 rw-p 00000000 00:00 0 [heap]
7ffc8cc04000-7ffc8cc25000 rw-p 00000000 00:00 0 [stack]
And here is what you will see when ASLR is disabled (value = 0):
# First run:
55555578a000-5555557ac000 rw-p 00000000 00:00 0 [heap]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
# Second run (addresses are IDENTICAL — ASLR is off):
55555578a000-5555557ac000 rw-p 00000000 00:00 0 [heap]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
+random offset 🎲
randomized 🎲
(libc, libpthread, other .so)
randomized 🎲
randomized 🎲
randomized (PIE) 🎲
randomized (PIE) 🎲
ASLR and PIE — Position Independent Executables
There is an important nuance that many beginners miss: ASLR alone is not enough to randomize the code segment (.text) and data segment of the main executable. For those to be randomized, the binary must be compiled as a PIE — Position Independent Executable.
A PIE binary uses only relative addressing internally — it makes no assumptions about where it will be loaded in memory. The kernel can therefore place it anywhere in the virtual address space, and ASLR will randomize that base address on each run.
On modern Linux distributions (Ubuntu 20.04+, Fedora 30+, Debian 11+), GCC generates PIE binaries by default. You can verify this:
# Check whether a binary is PIE
file /usr/bin/ls
# Output: ELF 64-bit LSB pie executable, x86-64, ...
# Explicitly compile as PIE (though it's usually the default now):
gcc -fPIE -pie -o myprog myprog.c
# Compile as non-PIE (disables code segment randomization):
gcc -no-pie -o myprog_fixed myprog.c
KASLR — Kernel Address Space Layout Randomization
Everything we have covered so far applies to user space. But what about the kernel itself? The Linux kernel also has its own virtual address space, and it loads kernel code, data, and modules at specific addresses. Without protection, an attacker who gained read access to kernel memory (through a vulnerability) could map out the entire kernel layout and plan a privilege escalation attack.
KASLR solves this problem for the kernel. It randomizes the base address at which the kernel image is decompressed and loaded into physical and virtual memory at boot time. This means that kernel symbols (functions, data structures, module code) live at different addresses after every reboot.
Checking KASLR Status
You can verify whether KASLR is active in several ways:
# Method 1: Check kernel command line — look for 'nokaslr' being absent
cat /proc/cmdline
# Method 2: Check dmesg for KASLR information at boot
sudo dmesg | grep -i kaslr
# Method 3: On a KASLR-enabled system, /proc/kallsyms shows
# randomized addresses (non-root users see 0 for all symbols):
head -5 /proc/kallsyms # As normal user — all zeros (privacy protection)
sudo head -5 /proc/kallsyms # As root — real addresses, different each boot
Disabling KASLR for Kernel Debugging
When you are developing and debugging your own Linux kernel module, KASLR can make debugging harder because symbol addresses change on each boot. During active kernel development, you may want to disable it temporarily:
# Add 'nokaslr' to the kernel boot parameters in your bootloader
# For GRUB, edit /etc/default/grub:
GRUB_CMDLINE_LINUX="nokaslr"
# Then update grub:
sudo update-grub # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # Fedora/RHEL
Security Limits of ASLR and KASLR
ASLR and KASLR are valuable defenses, but they are not impenetrable. As a Linux kernel developer, you need to understand their limits so you can design systems that use additional complementary protections.
| Attack Technique | Defeats ASLR? | Countermeasure |
|---|---|---|
| Information leak (reading memory) | Yes — reveals real addresses | Fix the information leak vulnerability first |
| Brute-force (32-bit systems) | Often yes — entropy is low | Use 64-bit; enable crash-on-exploit features |
| Heap spray | Partially — reduces precision needed | SLAB/SLUB hardening, guard pages |
| Return-Oriented Programming (ROP) | Partially — combined with leak, yes | CFI (Control Flow Integrity), shadow stack |
| JIT spraying | Partially — JIT code is predictable | JIT hardening in engines |
Modern Linux kernels layer many additional mitigations on top of ASLR/KASLR. In Linux 6.x, these include KPTI (Kernel Page Table Isolation, a Meltdown mitigation), stack canaries, NX/XD bits (non-executable pages), SMEP/SMAP (Supervisor Mode Execution/Access Prevention), and CFI support. No single mechanism is sufficient — defense in depth is always the right strategy.
Common Mistakes and Troubleshooting
After setting randomize_va_space to 0 for debugging, always restore it. Create a small shell script for your debugging sessions that automatically restores ASLR on exit.
ASLR is one layer of defense, not a complete security solution. Always combine it with RELRO, stack canaries, NX, and secure coding practices.
On embedded Linux boards, developers sometimes disable PIE to save a few bytes. On memory-constrained bare-metal targets this is fine, but on Linux-based embedded devices, always use PIE so ASLR can randomize your program’s load address.
By default, /proc/kallsyms shows all-zero addresses to non-root users (controlled by kptr_restrict). This is intentional — it prevents userspace programs from mapping out kernel layout even if KASLR entropy is low.
Best Practices for Linux Kernel Developers
- Always verify ASLR is at level 2 (cat /proc/sys/kernel/randomize_va_space) before declaring a system production-ready.
- Compile all userspace programs with -fPIE -pie for full text-segment randomization.
- Keep kptr_restrict set to 1 or 2 in production to hide kernel pointers from userspace.
- Use checksec to audit the hardening properties of your binaries: ASLR support, PIE, stack canary, NX, RELRO.
- Never hardcode memory addresses in kernel modules — always resolve symbols dynamically using kallsyms_lookup_name() or exported symbol tables.
- Enable CONFIG_RANDOMIZE_BASE (KASLR) and CONFIG_RANDOMIZE_MEMORY when configuring a kernel build for any production-facing system.
Checking Binary Security Properties with checksec
The checksec tool is widely used in the Linux kernel and security communities to quickly audit a binary’s security properties. It shows whether a binary benefits from ASLR (via PIE), stack canary, NX, RELRO, and other protections.
# Install checksec (if not already present):
sudo apt install checksec # Debian/Ubuntu
sudo dnf install checksec # Fedora
# Check a binary:
checksec --file=/usr/bin/bash
# Example output for a well-hardened binary:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols Yes /usr/bin/bash
Each field in the output maps to a security mitigation. For the purpose of this free Linux kernel course, focus on the PIE column — if it shows “PIE enabled”, that binary gets full ASLR coverage including its code and data segments.
Key Takeaways
ASLR Protects User Processes
Randomizes heap, stack, mmap, and (with PIE) code segment addresses each run. Controlled via /proc/sys/kernel/randomize_va_space.
KASLR Protects the Kernel
Randomizes the kernel image load address at every boot. Active by default in Linux 3.14+ and fully matured in Linux 6.x.
PIE is Required for Full ASLR
Without PIE, the executable’s own code/data segments stay at fixed addresses even with ASLR=2. Always build with -fPIE -pie.
ASLR is Not a Silver Bullet
Information leaks, brute force on 32-bit, and ROP chains can defeat ASLR. Use it as one layer in a defense-in-depth strategy.
Summary
In this lecture of the free Linux kernel development course, you learned how the Linux kernel protects virtual memory through address randomization. ASLR shuffles user process segments on every run, making exploit development significantly harder. KASLR does the same at the kernel level on every boot. Both are enabled by default on modern Linux 6.x systems and embedded Linux platforms.
You also saw how to verify, enable, and disable these features using standard Linux tools — knowledge that is directly applicable whether you are working on Linux kernel module development, embedded Linux, or security hardening of Linux systems.
Frequently Asked Questions (FAQ)
cat /proc/sys/kernel/randomize_va_space. A value of 2 means full ASLR is active (the default and recommended setting). A value of 0 means ASLR is completely disabled. A value of 1 means partial ASLR (stack and VDSO only, not heap).kptr_restrict kernel parameter. When set to 1 (default on most distributions), kernel pointers are hidden from unprivileged users by displaying as zeros. This prevents normal users from using /proc/kallsyms to map out kernel memory layout and defeat KASLR. As root, you will see the real (randomized) addresses.nokaslr to the kernel boot parameters during development to make kernel symbol addresses stable across reboots, which simplifies working with tools like crash, gdb, and kgdb. Always restore the default after debugging.CONFIG_RANDOMIZE_BASE. On Linux 6.x, there is also CONFIG_RANDOMIZE_MEMORY which additionally randomizes the kernel’s direct physical memory mapping, providing an extra layer of protection beyond classic KASLR./etc/sysctl.d/ configuration files which are applied at boot by the systemd-sysctl service.Continue Learning — 100% Free
EmbeddedPathashala offers a complete free Linux kernel development course, free Linux device drivers course, and free embedded systems course — all at no cost, forever.
