KASLR and Kernel Memory Layout

July 25, 2026 · View on GitHub

Reference material on how Linux KASLR works, what it randomizes, and how the kernel virtual address space is laid out across architectures.

Table of Contents

Linux KASLR history and implementation

Not all architectures support KASLR (CONFIG_RANDOMIZE_BASE) or enable it by default:

ArchitectureKASLR AddedDateDefault OnNotes
x86_32v3.14 (8ab3820fd5b2)2013-10-13v4.12 (09e43968fc6c)Kconfig default y since v4.12
x86_64v3.14 (8ab3820fd5b2)2013-10-13v4.12 (09e43968fc6c)Kconfig default y since v4.12
arm64v4.6 (f80fb3a3d508)2016-02-24Yes (defconfig)Enabled in upstream arm64 defconfig
MIPS32v4.7 (405bc8fd12f5)2016-05-13NoMax offset 128 MiB (limited by KSEG0)
MIPS64v4.7 (405bc8fd12f5)2016-05-13NoMax offset 1 GiB
s390v5.2 (b2d24b97b2a9)2019-04-29v5.2Kconfig default y from initial commit
PowerPC32v5.5 (2b0e86cc5de6)2019-11-13NoBookE/e500 (PPC_85xx) only
LoongArchv6.3 (e5f02b51fa0c)2023-02-25Yes (defconfig)Enabled in upstream loongson3_defconfig
RISC-V64v6.6 (84fe419dc757)2023-07-22No
arm32Not supported
PowerPC64Not supported
sparcNot supported
SuperH (sh)Not supported
m68kNot supported
MicroBlazeNot supported
OpenRISCNot supported

Even where KASLR is unsupported, disabled, or failed to randomize, the kernel's load address may still vary across boots: a bootloader (U-Boot, GRUB, the EFI stub, Coreboot, etc.) is free to place the image at whatever physical address suits the board's memory map. The kernel is not actively randomizing in that case, but the base is still unknown to a local user a priori. KASLD treats this case identically — the same inference engine narrows the bootloader-chosen base from observable evidence (dmesg landmarks, /proc/iomem, /sys facts, devicetree reservations) to a residual window, or to a single address where the evidence allows. See KASLR runtime states below for the distinction between disabled (kernel at the link-time default), unsupported (arch has no KASLR machinery), and randomization failed (boot stub tried but no random offset applied).

See also:

Default text base and KASLR alignment

When KASLR is disabled, the kernel loads at a fixed virtual address — the "default text base." This address is determined by the architecture's linker script, Kconfig options, or hardware memory map. When KASLR is enabled, the kernel is placed at default + N × IMAGE_ALIGN, where N is chosen randomly within the architecture's valid range. IMAGE_ALIGN is therefore the randomization granularity: each possible position is one "KASLR slot."

The table is the kernel's compile-time default — the address the image lands at when no relocation occurs. On relocating architectures (every supported arch except PowerPC64 and SPARC) the bootloader chooses the load address from the board's memory map. The table is the baseline against which the KASLR slide is measured, not the load address on every system.

The "default text base" here is the image base (_text) — the start of the kernel image, which is what KASLR aligns and what KASLD reports. The familiar _stext (start of the code section) sits a fixed head gap above _text: zero on most architectures (so _text == _stext), but non-zero where a header precedes the code (arm64's .head.text, 0x10000). KASLD solves the image base and shows _stext as a derived line only when the two differ; a leaked _stext (e.g. from /proc/kallsyms) is normalized back to the image base when it is consumed, so the slide is always measured against _text.

ArchitectureDefault text baseDerivationIMAGE_ALIGNKASLR slotsEntropy
x86_640xffffffff81000000__START_KERNEL_map + PHYSICAL_START (page_64_types.h)2 MiB504²~9 bits
x86_320xc0000000PAGE_OFFSET (3G/1G vmsplit default)2 MiB248²~8 bits
arm640xffff800080000000³KIMAGE_VADDR = _PAGE_END(VA_BITS_MIN) + module-region size (memory.h)64 KiB⁴~1073M~30 bits
arm320xc0008000PAGE_OFFSET + TEXT_OFFSET (0x8000, from arch/arm/Makefile)No KASLR
MIPS320x80100400KSEG0 (0x80000000) + 1 MiB + TEXT_OFFSET (0x400, from head.S)64 KiBvariesvaries
MIPS640xffffffff80100400CKSEG0 (0xffffffff80000000) + 1 MiB + TEXT_OFFSET (0x400)64 KiBvariesvaries
s3900x3FFE0100000CONFIG_KERNEL_IMAGE_BASE + TEXT_OFFSET (1 MiB)16 KiB~131K~17 bits
PowerPC320xc0000000PAGE_OFFSET (3G/1G default); BookE only16 KiB¹variesvaries
PowerPC640xc000000000000000PAGE_OFFSET (Kconfig)No KASLR
LoongArch0x9000000000200000DMW1 (0x9000000000000000) + TEXT_OFFSET (2 MiB, from Makefile)64 KiBvariesvaries
RISC-V640xffffffff80002000KERNEL_LINK_ADDR (top 2 GiB of VA) + TEXT_OFFSET (0x2000, .head.text)2 MiB512²~9 bits
RISC-V320xc0002000PAGE_OFFSET + TEXT_OFFSET (0x2000)No KASLR

The "Derivation" column shows where each default address comes from. On most architectures the formula is PAGE_OFFSET + TEXT_OFFSET, where PAGE_OFFSET is the start of the kernel virtual address space (set by hardware mapping or Kconfig) and TEXT_OFFSET is the offset from the mapping base to the .text section entry point (set by the linker script or boot protocol). x86_64 is an exception: the kernel image virtual base (__START_KERNEL_map = 0xffffffff80000000) is separate from PAGE_OFFSET (the direct-map base), and PHYSICAL_START (16 MiB) is added for alignment with the physical load address.

¹ PowerPC32 defines a KASLR_VIRT_ALIGN (16 KiB) larger than its IMAGE_ALIGN (4 KiB): BookE KASLR places the text base on the 16 KiB grid, so 16 KiB is the KASLR slot granularity while 4 KiB is only the page alignment.

² The slot count is an upper bound. Every architecture's KASLR placement code refuses positions where the image would extend past the end of the randomization region, so the actual available slots are:

valid_slots = (range_size - kernel_size) / IMAGE_ALIGN

kernel_size is measured differently per architecture. On x86 (arch/x86/boot/compressed/kaslr.c), it is init_size from the boot header — the decompression buffer requirement, which is larger than the final loaded kernel size. On RISC-V (arch/riscv/mm/init.c), it is _end − _start — the actual in-memory kernel size with no overhead. On x86, MODULES_VADDR is defined as __START_KERNEL_map + KERNEL_IMAGE_SIZE with no gap, so the ceiling is hard.

³ The arm64 row is the VA_BITS_MIN = 48 case (4K/16K 4-level, plus 52-bit LVA) — the common one. Sub-48 configs place the image higher and randomize over a smaller window, since KIMAGE_VADDR = _PAGE_END(VA_BITS_MIN) + module-region size and _PAGE_END = -(1 << (VA_BITS_MIN − 1)): 4K 3-level (VA_BITS = 39, common on Android) → 0xffffffc080000000, 64K 2-level (42), 16K 3-level (47). KASLD detects the running VA_BITS with an mmap boundary probe (mmap_arm64_va_bits) and resolves the per-config text band and entropy accordingly.

⁴ The arm64 text base is aligned to EFI_KIMG_ALIGN (64 KiB on 4K/16K pages, 128 KiB on 64K pages), NOT the 2 MiB seed step. Under KASLR the EFI stub loads the image at 64 KiB alignment (weaker than the 2 MiB boot protocol), and the kernel grafts the low 2 MiB bits of that physical address into the virtual KASLR displacement so text can still be mapped with 2 MiB blocks. The result is a virtual text base that steps by 64 KiB, not 2 MiB, so 64 KiB is the alignment of _text (the slot count divides the window by 64 KiB). The 2 MiB seed step governs only the high bits of the displacement.

ArchitectureMax slotsApprox. kernel_sizeTypical runtime slotsReduction
x86_64504init_size ≈ 70 MiB~469~7%
x86_32248init_size ≈ 40 MiB~228~8%
RISC-V64512_end−_start ≈ 30 MiB~497~3%
s390~131K≈ 70 MiB~127K~3%
arm64~1073M≈ 50 MiB~1073M<0.01%

On x86 and RISC-V, where total entropy is ~9 bits (~500 slots), a 3–8% reduction is material. On s390 (~17 bits) and arm64 (~25 bits) the effect is negligible.

KASLR runtime states

A KASLR-capable architecture can be in one of four runtime states on any given boot. The states have different exploitation implications and KASLD reports them distinctly:

StateWhere the kernel landedSlot entropyBootloader entropy
ActiveOne of valid_slots positions chosen uniformlyFull (log2(valid_slots))Subsumed by KASLR — placement is randomized within the bootloader-determined range
DisabledThe arch's compile-time default text base, exactly0 bits — fully predictableNone — opt-out is honoured before the bootloader chooses
UnsupportedBootloader-determined physical address; virtual address is hardware-fixed (e.g. PAGE_OFFSET + TEXT_OFFSET on arm32)0 bits — arch has no KASLR machineryWhatever entropy the bootloader's placement policy provides — often per-boot deterministic
Randomization failedBoot-stub- or firmware-deterministic, not the link-time default0 bits — boot stub skipped the random offsetWhatever entropy the deterministic fallback path provides — typically the lowest aligned slot the firmware allocator returns, identical across boots on the same hardware

The path a boot takes to each state — and the load-bearing disabled vs randomization failed distinction — at a glance:

KASLR runtime-state decision flow: whether the architecture has KASLR machinery, whether KASLR was opted out, and whether a boot entropy source was available select one of unsupported, disabled, randomization-failed, or active; three yield zero bits but land at different, non-interchangeable positions

The four states are entered by different mechanisms:

  • Active — the default for any KASLR-supporting arch when the entropy source is available and not opted out.

  • Disabled is reached by an explicit opt-out:

    • nokaslr on the kernel cmdline (every KASLR-supporting arch).
    • CONFIG_RANDOMIZE_BASE=n at build time.
    • Hibernation resume on x86 (the kernel must land at the same address as the snapshot, so KASLR is forced off — see arch/x86/boot/compressed/kaslr.c).
    • The kexec_file token on LoongArch (kernel loaded by kexec_file_load(2) honours the loader's chosen address).
    • The elfcorehdr= kdump handoff path on s390 (the panic kernel must land at a known address).
    • FDT without /chosen/kaslr-seed on riscv64 non-EFI boot (the kernel falls back to the link-time default; the EFI path goes through the randomization failed state instead).
  • Unsupported applies to architectures where the kernel build has no KASLR machinery: arm32, PowerPC64, RISC-V32, SPARC.

  • Randomization failed applies when the KASLR machinery ran but could not produce a random offset:

    • arm64 EFI stub: no EFI_RNG_PROTOCOL, no FDT kaslr-seed (dmesg: KASLR disabled due to lack of seed).
    • arm64: FDT remap failure during early init (dmesg: KASLR disabled due to FDT remapping failure).
    • s390 boot stub: CPU has no PRNG instruction (dmesg: KASLR disabled: CPU has no PRNG).
    • s390 boot stub: not enough memory to relocate (dmesg: KASLR disabled: not enough memory).
    • riscv64 EFI stub: the same shape as arm64 (EFI_RNG_PROTOCOL falls back to a deterministic firmware-allocated position when no random source is exposed). The riscv64 no-seed dmesg signal is not always emitted by the kernel; whether the engine enters the randomization failed or disabled state depends on which indicator the components observe.

The dmesg line in the third state begins with the same KASLR disabled prefix as a deliberate opt-out — distinguishing them requires inspecting the reason text. The kernel is still relocated by the boot stub but lands at a firmware-determined position rather than the link-time default, so consumers MUST NOT treat this signal as a pin-to-default. KASLD emits a distinct scalar fact (SF_VIRT_KASLR_RANDOMIZATION_FAILED + SF_PHYS_KASLR_RANDOMIZATION_FAILED versus SF_VIRT_KASLR_DISABLED + SF_PHYS_KASLR_DISABLED) and neither sets the summary's kaslr.disabled flag nor pins Q_VIRT_IMAGE_BASE or Q_PHYS_IMAGE_BASE from this signal.

Per-host fingerprintability: in the randomization failed state, the position is deterministic per (firmware, kernel build, hardware) tuple. An operator who has previously captured ground truth on the same machine can re-use the slide on subsequent boots without re-leaking — a substantively different security posture from active KASLR where each boot is independent.

Physical and virtual KASLR

Linux KASLR randomizes the kernel location in both physical memory (where the kernel image resides in RAM) and virtual memory (where the kernel is mapped in the address space). Depending on the architecture, these may be randomized together using a single offset (coupled) or independently using separate offsets (decoupled).

On architectures where physical and virtual randomization are coupled (i.e. the same offset), leaking either a physical or virtual kernel address trivially reveals the other. On architectures where they are decoupled, a physical address leak does not directly reveal the virtual address (and vice versa), providing stronger isolation.

ArchitecturePhys/Virt RelationshipSinceNotes
x86_32Coupledv3.14Virtual offset equals physical offset
arm64Decoupledv4.6EFI stub randomizes physical; kaslr_early_init randomizes virtual; linear map has limited entropy
MIPS32/64Coupledv4.7Single relocation offset; fixed kseg0 virt-to-phys mapping
x86_64Decoupledv4.8Separate find_random_phys_addr / find_random_virt_addr; also CONFIG_RANDOMIZE_MEMORY for memory sections
s390Decoupledv5.2Identity-mapped (virt = phys) through v6.7; v6.8+ moves kernel text to a separate high mapping and randomizes the identity base independently, so KASLD models it decoupled (TEXT_TRACKS_DIRECTMAP=0)
PowerPC32Coupledv5.5Same offset applied to both addresses
LoongArchCoupledv6.3Single relocation offset; direct-mapped windows
RISC-V64Virtual onlyv6.6Only virtual address randomized; physical depends on bootloader

KASLD models this relationship with two orthogonal per-architecture flags — TEXT_TRACKS_DIRECTMAP (does kernel text slide with the linear map?) and DIRECTMAP_STATIC (is the compile-time direct-map projection sound at runtime?). The quadrant they form decides the inference strategy, and every supported architecture sits on its diagonal:

Architecture coupling quadrant: DIRECTMAP_STATIC against TEXT_TRACKS_DIRECTMAP, with each architecture placed in its cell

See also:

Kernel sections

The kernel virtual address space contains distinct sections (text, modules, direct map, etc.) mapped at different address ranges. KASLR randomizes the kernel text base address, but not all sections are randomized together — depending on the architecture, other sections may be at fixed addresses, use the same KASLR offset, or be randomized independently.

The map below shows the x86_64 virtual and physical address spaces, with the KASLD quantity (Q_*) that resolves each region annotated alongside it:

Kernel address-space map for x86_64: virtual and physical bands with the Q_* quantity that resolves each

ArchitectureText ↔ PhysText ↔ Direct mapText ↔ ModulesNotes
x86_64IndependentIndependentIndependentThree separate randomizations (CONFIG_RANDOMIZE_MEMORY)
x86_32CoupledCoupledFixed module regionSingle KASLR offset
arm64IndependentIndependentFixed module regionSeparate phys/virt randomization
arm32CoupledFixed (PAGE_OFFSET - 16M)No KASLR
MIPS32/64CoupledCoupled (kseg0)Fixed module regionHardware-defined mapping
PowerPC32CoupledCoupledFixed (PAGE_OFFSET - 256M)
PowerPC64CoupledShared VASNo KASLR
LoongArch64CoupledCoupledFixed module regionDirect-mapped windows
RISC-V64Virtual onlyDecoupledCoupled (shifts with kernel)Module region anchored to kernel _end; text ↔ directmap coupled on legacy pre-v5.10 kernels (no KASLR)
RISC-V32CoupledSame as PAGE_OFFSETNo KASLR

On coupled architectures, all sections are at fixed offsets from each other: a physical address reveals the virtual text base via phys_to_directmap_virt(), the direct map is at a known offset (TEXT_OFFSET) from the text base, and modules are either at a fixed address or a constant offset from PAGE_OFFSET. A single leak from any section is sufficient to derive the others. On decoupled architectures like x86_64, each section is randomized independently — a physical address reveals nothing about the virtual text base, and the direct map base (virt_page_offset_base) is randomized separately.

RISC-V64 is notable: the module region is anchored to the kernel image (MODULES_VADDR = PFN_ALIGN(&_end) - SZ_2G, MODULES_END = PFN_ALIGN(&_start)), so modules shift with the randomized kernel rather than occupying a fixed region. See architecture.md → Cross-region derivation for how KASLD exploits this.

Virtual memory split (vmsplit)

On 32-bit systems, the 4 GiB virtual address space is divided between userspace and the kernel. The boundary — PAGE_OFFSET (also known as the "vmsplit") — determines where the kernel virtual address space begins.

The most common configuration is a 3G/1G split (PAGE_OFFSET=0xC0000000), but embedded systems and custom kernels may use different splits:

SplitPAGE_OFFSETUser / KernelNotes
1G/3G0x400000001 GiB / 3 GiBRare
2G(opt)/2G0x78000000~1.9 GiB / ~2.1 GiBx86_32 only
2G/2G0x800000002 GiB / 2 GiBCommon on embedded ARM
3G(opt)/1G0xB0000000~2.75 GiB / ~1.25 GiBx86_32 only
3G/1G0xC00000003 GiB / 1 GiBDefault for most distros

The vmsplit affects nearly all kernel virtual address boundaries: the kernel text base, direct map, and (on some architectures) the module region all shift with PAGE_OFFSET. This means KASLR analysis, address validation, and memory layout interpretation depend on knowing the correct vmsplit.

Since KASLD is typically compiled on one system and deployed to another, the compile-time PAGE_OFFSET assumption may not match the target system. KASLD handles this at runtime: components that detect the actual PAGE_OFFSET (e.g. mmap_brute_vmsplit, boot_config) emit a pageoffset tagged result, and the orchestrator automatically adjusts all layout boundaries before performing validation and analysis.

ArchitectureConfigurable vmsplitConfig optionDefault
x86_32YesCONFIG_VMSPLIT_*0xC0000000 (3G/1G)
arm32YesCONFIG_PAGE_OFFSET / CONFIG_VMSPLIT_*0xC0000000 (3G/1G)
PowerPC32YesCONFIG_PAGE_OFFSET0xC0000000 (3G/1G)
x86_64No0xFF00000000000000 (5-level) / 0xFFFF800000000000 (4-level)
arm64No0xFFF0000000000000 (52-bit VA)
MIPS32No0x80000000 (hardware kseg0)
MIPS64No0xFFFFFFFF80000000 (xkseg)
PowerPC64No0xC000000000000000
LoongArch64No0x9000000000000000
RISC-V32No0xC0000000
RISC-V64No0xFF60000000000000 (SV57)

See also:

Function Granular KASLR (FG-KASLR)

Function Granular KASLR (aka "finer-grained KASLR") patches for the 5.5.0-rc7 kernel were proposed in February 2020 but have not been merged as of 2026.

This optional non-mainline mitigation "rearranges your kernel code at load time on a per-function level granularity" and can be enabled with the CONFIG_FG_KASLR flag.

FG-KASLR ensures the location of kernel and module functions are independently randomized and no longer located at a constant offset from the kernel .text base.

On systems which support FG-KASLR patches (x86_64 from 2020, arm64 from 2023), this makes calculating offsets to useful functions more difficult and renders kernel pointer leaks significantly less useful.

However, some regions of the kernel are not randomized (such as symbols before __startup_secondary_64 on x86_64) and offsets remain consistent across reboots. Additionally, FG-KASLR randomizes only kernel functions, leaving other useful kernel data (such as modprobe_path and core_pattern usermode helpers) unchanged at a static offset.

See also:

Glossary

KASLR and kernel-memory-layout terms used across the docs and in KASLD's output. For KASLD's own engine and tool vocabulary (quantity, estimate, covering, rule, …), see architecture.md → Glossary.

  • slide — the per-boot offset between the kernel's compile-time default base and where it actually loaded. The quantity KASLR randomizes; reported as slide +0x…. See Default text base.
  • default text base — the fixed virtual address the kernel image loads at when KASLR is disabled; the baseline the slide is measured against. See Default text base.
  • image base (_text) — the start of the kernel image: the address KASLR aligns and KASLD solves. _stext (code-section start) sits a fixed head gap above it, zero on most architectures. See Default text base.
  • IMAGE_ALIGN / KASLR slot — the randomization granularity. The kernel lands at default + N × IMAGE_ALIGN; each candidate position is one slot. See Default text base.
  • entropy — the number of random bits in the placement, log2(slots); shown as ~N bits. See Default text base.
  • runtime state — which of four conditions a KASLR-capable boot is in (randomized, disabled, …). See KASLR runtime states.
  • PAGE_OFFSET — the start of the kernel virtual address space; on 32-bit, the user/kernel boundary (the vmsplit). See vmsplit.
  • vmsplit — the division of a 32-bit address space between userspace and kernel, set by PAGE_OFFSET. See vmsplit.
  • directmap (direct / linear map) — the contiguous 1:1 mapping of physical RAM into the kernel virtual address space. See Kernel sections.
  • vmemmap — the virtual region holding the struct page array. See Kernel sections.
  • coupled / decoupled — whether physical and virtual KASLR share one offset (coupled — either leak reveals the other) or use independent offsets (decoupled). KASLD names this with two per-arch flags; see architecture.md → Glossary and Physical and virtual KASLR.
  • FG-KASLR — Function Granular KASLR: per-function reordering, so a single leak no longer implies a constant offset to other functions. See FG-KASLR.