Virtually Mapped Kernel Stacks: Understand What Guard Pages Catch Before the Crash Spreads

A guard page can turn a kernel stack access beyond the mapped stack into an immediate fault, but it does not detect every bad write within that stack. Diagnose a guard-page report by establishing which stack and address were involved, then inspect the path that exhausted or crossed its boundary. Do not treat the feature as a general proof of stack memory safety.

This guide is pinned to upstream Linux v6.12. It covers virtually mapped task stacks, architecture eligibility and a proposed qualification plan. It is separate from MCU stack-watermark analysis and sanitizer coverage surveys. No stack overflow, LKDTM trigger or kernel panic was executed.

Check the actual architecture and configuration

The VMAP stack documentation describes virtually contiguous kernel task stacks with guard pages. Architecture support must provide adequate virtual address space, valid mappings when switching stacks and a meaningful response to guard-page faults. Those requirements matter particularly on address-space-constrained systems.

The exact v6.12 Kconfig condition requires HAVE_ARCH_VMAP_STACK and permits VMAP_STACK with no KASAN, with KASAN_HW_TAGS, or with KASAN_VMALLOC. Software KASAN modes need the relevant vmalloc shadow-memory support. Avoid simplifying that condition to “every KASAN build needs the same setting.”

Eligibility is architecture-specific. In the pinned x86 configuration, HAVE_ARCH_VMAP_STACK is selected for X86_64; the arm64 configuration also selects it. These examples do not authorize assuming that a different architecture or vendor branch has equivalent fault handling. Inspect its final generated configuration and entry code.

Record the kernel build, architecture, page size, actual task-stack size, compiler and relevant instrumentation. Do not copy a stack size from another machine: configuration and architecture can change it, and page size is not universally four kilobytes.

Understand the boundary being protected

A virtually mapped stack occupies contiguous kernel virtual addresses backed by pages that need not be physically contiguous. Guard pages sit outside the valid mapped stack. An access into an unmapped guard produces a fault rather than silently overwriting an adjacent mapped object through ordinary contiguous stack growth.

The v6.12 task-stack allocation path requests the architecture’s THREAD_SIZE and alignment, records the vmalloc area and can reuse cached stacks. A task’s virtual stack layout is therefore an allocation and mapping property, not evidence that its current call chain has spare capacity.

A write that remains inside a mapped stack page can corrupt another local object, saved state or another frame without touching a guard. A sufficiently discontinuous erroneous address can also skip the guard entirely. Those cases require other diagnostics and source analysis; guard-page coverage should not be extended to them by implication.

An unmapped leading guard and trailing guard surround a mapped task stack; corruption inside the mapped range need not touch either guard.
Original virtual-stack coverage map; page sizes, stack direction and addresses are intentionally unspecified.

Preserve and classify the fault evidence

  1. Keep the first complete report, fault address, saved stack pointer, registers and available stack trace.
  2. Identify the reported stack type and mapped bounds using matching symbols and the architecture’s diagnostics.
  3. Check whether the fault address falls in a verified guard region, inside the valid stack, or somewhere unrelated.
  4. Trace the interrupted operation and call chain, preserving any indications that unwinding is incomplete.
  5. Inspect earlier warnings and corruption evidence before assigning all causation to the final function.

A guard hit supports a boundary violation, but it does not automatically prove ordinary recursion caused it. An invalid pointer aimed into the guard or corrupted stack state can produce a related symptom. Look for excessive recursion, large local allocations, unexpectedly deep call chains and nested execution, then establish which mechanism fits the actual registers and source.

The last function visible in the trace may only be the one that needed the final bytes. Its caller chain may have consumed most of the stack. Conversely, a plausible-looking chain can be incomplete after corruption. State uncertainty rather than inventing missing frames.

Respect architecture-specific failure behavior

On x86, stack exhaustion can interfere with ordinary page-fault delivery and become a double fault. The pinned x86 handler checks guard information and has a fatal stack-overflow path. Its comments also document a small possibility of misclassification when other corruption coincides with a guard address.

Consequently, “double fault” is not a universal synonym for stack overflow, and a recoverable return to the original operation is not promised. Other architectures have different entry paths and reporting behavior. Qualification must establish whether the chosen crash-capture channel actually survives this specific failure mode.

Task-stack support also does not settle the layout of every interrupt, exception or emergency stack. Inspect those architecture-specific stacks separately. The documentation’s historical note about interrupt stacks should not be turned into a universal statement about all current architecture implementations.

Design separate coverage tests

Proposed case Expected evidence and boundary
Access into leading or trailing guard A fatal boundary diagnostic through the architecture’s supported path
Bad write within a mapped frame No guard-page detection promised; use a separate memory-safety method
Deep but valid workload call chain Normal completion with independently justified stack demand
Failure-report capture The first report remains available through the tested reset/recovery path

Linux documents LKDTM leading and trailing stack-guard tests, but they deliberately exercise a crash boundary. Run such tests only under an approved disposable or recoverable qualification setup, with state preserved and connected equipment made safe. This article supplies no automatic trigger command and claims no executed result.

Keep the guard test distinct from the real workload reproduction. Proving that a guard can fault does not prove that the driver’s deepest production path remains within its valid stack. Likewise, a successful normal workload does not establish that both guard boundaries are configured correctly.

Fix demand without creating a new lifetime bug

If a large local object is implicated, review moving storage to an appropriate allocation or owned object, including failure handling and cleanup. If recursion is implicated, establish a bounded iterative design. Increasing stack size without explaining demand can merely postpone failure.

Do not use stack-backed data for DMA in this configuration; virtually contiguous stack storage does not supply the DMA buffer contract. A repair must preserve ownership, context restrictions and device lifetime, rather than exchanging a stack fault for asynchronous access to expired memory.

Deliver an eligibility map, address classification, source-backed demand explanation and separate guard/normal-workload test plans. The result should state exactly which boundary is protected and which corruption mechanisms remain outside it.

Similar Posts