KASLR and KAISER
1. KASLR — Kernel Address Space Layout Randomization
KASLR randomizes the virtual address at which the kernel is loaded.
Simplified pseudocode
// Normal kernel base address
#define KERNEL_BASE 0xffffffff81000000
// Choose a random offset
uint64_t random_offset = get_random_offset();
// Randomized kernel base
uint64_t kernel_base = KERNEL_BASE + random_offset;
// Load kernel at the randomized address
load_kernel(kernel_base);
Example
Without KASLR:
Kernel base = 0xffffffff81000000
With KASLR:
Kernel base = 0xffffffffa7200000
The exact address changes between boots.
Why?
An attacker may need kernel addresses for attacks such as ROP.
Without KASLR:
Attacker knows:
kernel_function = 0xffffffff81012340
↓
Can potentially construct an attack
using known kernel addresses.
With KASLR:
Attacker knows only:
kernel_function = ?????????
↓
Must discover the randomized address first.
2. The problem KAISER solves
Traditionally, the kernel was mapped into the page table of
a user process even though user-mode code was not allowed
to access it.
Simplified:
Process Page Table
│
├── User memory
│ USER = 1
│
└── Kernel memory
USER = 0
PRESENT = 1
USER = 0 means that user-mode code cannot access the page.
But the kernel mapping still exists in the page tables.
Conceptually:
User program
│
│ access kernel virtual address
↓
Page table
│
│ Kernel mapping exists
↓
Permission check
│
│ USER = 0
↓
Access denied / page fault
The problem is that the existence of the mapping can affect
microarchitectural structures such as address-translation
caches.
An attacker can measure timing differences and infer whether
an address is mapped.
This can defeat the purpose of KASLR.
3. KAISER — Kernel Address Isolation
KAISER changes the page-table organization.
Instead of keeping kernel mappings in the page table while
running user code, KAISER uses separate page tables.
User / Shadow page table
User Page Table
│
├── User memory
│
├── Program
│
├── Libraries
│
└── Kernel memory
NOT MAPPED
Kernel page table
Kernel Page Table
│
├── User memory
│
└── Kernel memory
MAPPED
The important difference is:
OLD:
Kernel mapping exists
↓
Access forbidden by permission
↓
Potential side channel
KAISER:
Kernel mapping does NOT exist
↓
No kernel translation available
↓
Side channel is removed
4. Switching between the page tables
On x86, CR3 identifies the current page-table hierarchy.
Simplified:
// Running user program
load_cr3(user_page_table);
// Execute user code
run_user_program();
When entering the kernel:
// System call / interrupt occurs
load_cr3(kernel_page_table);
// Execute kernel code
run_kernel_code();
When returning to user mode:
// Return from kernel
load_cr3(user_page_table);
// Continue user program
continue_user_program();
Conceptually:
SYSTEM CALL
User mode ───────────────────→ Kernel mode
│ │
│ │
│ CR3 = user_page_table │ CR3 = kernel_page_table
│ │
↓ ↓
User mappings Kernel mappings
Kernel absent Kernel present
5. Why this defeats the address-leaking attack
Before KAISER
User page table
Virtual address
│
↓
Page table
│
├── User mapping
│
└── Kernel mapping
│
↓
Translation exists
│
↓
Microarchitectural
side channel
│
↓
Attacker learns that
the address is mapped
│
↓
KASLR weakened
With KAISER
User page table
Virtual address
│
↓
Page table
│
├── User mapping
│
└── Kernel mapping
X
NOT PRESENT
| Feature | KASLR | KAISER |
|---|---|---|
| Full name | Kernel Address Space Layout Randomization | Kernel Address Isolation |
| Main idea | Randomize kernel addresses | Remove kernel mappings from user page tables |
| Main goal | Make kernel addresses difficult to predict | Prevent user space from learning kernel address information |
| Changes addresses? | Yes | No |
| Changes page tables? | Not primarily | Yes |
| Uses separate page tables? | No | Yes |
| Defends against address-discovery side channels? | By itself, not sufficiently | Yes |
KPTI
It is essentially the production Linux version of the page-table isolation idea used by KAISER, introduced as a major mitigation for Meltdown.