|
|
Log in / Subscribe / Register

Bootpatch-SLR: Randomizing Linux Kernel Structure Layouts at Boot

From:  York Jasper Niebuhr <yjn-AT-yjn-systems.com>
To:  linux-hardening-AT-vger.kernel.org
Subject:  [RFC v2 0/5] Bootpatch-SLR: Randomizing Linux Kernel Structure Layouts at Boot
Date:  Sat, 20 Jun 2026 15:32:22 +0200
Message-ID:  <20260620133222.94647-1-yjn@yjn-systems.com>
Cc:  kees-AT-kernel.org, franzen-AT-sec.in.tum.de, ardb-AT-kernel.org
Archive-link:  Article

Hi,
this is the second RFC version of Bootpatch-SLR. Compared to v1, it
implements several bug fixes and general improvements. Additionally, it
greatly simplifies the build integration by moving SPSLR metadata into
ELF sections and getting rid of any extra build artifacts or stages.

RFC v1:
    https://lists.openwall.net/linux-hardening/2026/06/05/21

Changes since RFC v1:
  - Removed the separate pre-link metadata aggregation stage.
  - Moved SPSLR metadata into ELF sections emitted directly by pinpoint.
  - Integrated pinpoint plugin into existing plugin infrastructure.
  - Added per-module selfpatch workspace to support parallel module
    patching.
  - Added the nospslr boot parameter.

Several hardening mechanisms rely on compile-time diversification. While
these approaches can be highly effective, their benefits are reduced in
deployment scenarios where a single kernel build is distributed to
millions of systems. Once the layout and characteristics of that build
become known, they are known for every system running it. Selfpatch-SLR
investigates whether Structure Layout Randomization can be applied after
software has already been built, thereby allowing diversification to
occur at runtime rather than only at compile time. Bootpatch-SLR
explores that idea in the context of the Linux kernel. The goal of this
project is to investigate the feasibility of the approach and identify
assumptions and obstacles that would need to be addressed by a
production-quality implementation.

Additional information about the project can be found on the
documentation website: https://spslr.yjn-systems.com

Selfpatch-SLR consists of two components: pinpoint and selfpatch. During
compilation, the pinpoint GCC plugin records the structure accesses and
static instances of target structures which rely on field offsets to be
randomized. It produces accompanying metadata and injects runtime
descriptors directly into ELF sections in each compilation unit's
assembly output stream. On program startup or kernel boot, selfpatch
chooses the randomized layouts and patches the loaded image's code and
data segments to reflect the new field offsets.

Starting with RFC v2, there are no separate metadata files or other
artifacts that must be tracked by the build system.

The current Bootpatch-SLR prototype focuses on randomizing task_struct
in a v6.12 kernel, at early boot, with a small number of fields exempt
from randomization due to current SPSLR implementation details.
Specifically, early pinpoint stages cause target field offsets to not be
known at compile time, in some contexts, which makes their use inside
static initializer expressions and asm-offset operands impossible.

At this stage, SPSLR tooling is only available for x86_64.

Testing this patch series currently requires a custom toolchain based on
GCC 16, because mainline GCC folds important offsetof-like expressions
before the earliest plugin hooks. The required GCC patch is available
at: https://lists.openwall.net/linux-hardening/2026/06/05/29

On my test system (QEMU TCG on an i9-13900H), the additional boot time
is currently below one second. Most of this time is spent in the
current, largely unoptimized randomizer. The actual image patching phase
takes only a few milliseconds.

The design goal of SPSLR is to eliminate the need for runtime lookup
tables or similar indirection mechanisms. Structure access instructions
are patched directly to reflect the randomized field offsets before
normal kernel execution begins.

As a result, the implementation does not require additional memory
accesses when accessing randomized structures. The current prototype
does, however, introduce a single additional mov instruction per target
structure access. This overhead is an implementation artifact rather
than a fundamental requirement of the approach and may be removed by
future tooling improvements.

This RFC patch series is organized as follows:

 * Patch 1 adds the pinpoint GCC plugin.

 * Patch 2 adds the SPSLR runtime.

 * Patch 3 adds linker scripts and build integration.

 * Patch 4 applies BPSLR to the task_struct.

 * Patch 5 adds a simple tasklist sample module for sanity checking.

The current baseline configuration for testing is defconfig plus
CONFIG_SPSLR. Additionally, CONFIG_SAMPLES, CONFIG_SAMPLES_SPSLR,
and CONFIG_SAMPLE_SPSLR_TASKLIST can be enabled to build a simple
sanity-check module. Among other things, this module prints the values
of offsetof(task_struct, ...). After BPSLR has been applied
successfully, these offsets differ between boots.

With this configuration, the modified kernel successfully boots and
passes simple task_struct-related userspace tests. In addition, I have
successfully started an Ubuntu 24.04 userspace on top of BPSLR.

I have also attempted to port BPSLR to v6.18 and later releases. While I
got the system to build, occasional runtime failures currently prevent
successful operation.

I assume some kernel behaviors, access patterns, or subsystem
interactions present in newer kernels are not yet handled correctly by
the prototype. I am aware of but have not yet addressed BTF and I
suspect there are several other mechanisms that conflict with current
BPSLR assumptions and need to still be addressed separately.

Open questions:

  - I am currently investigating a QEMU TCG based validation tool to
    verify that all accesses to randomized structures are correctly
    instrumented. Feedback on this validation strategy would be welcome.

  - The current implementation uses a custom instruction immediate
    labeling mechanism in pinpoint. Longer term I would like to move
    this functionality into assembler and linker infrastructure and
    would appreciate suggestions on the most appropriate direction.

Additional background on these ideas follows in a reply to this cover
letter to keep the RFC itself reasonably concise.

I greatly appreciate any feedback on this.

Thanks,
Jasper

York Jasper Niebuhr (5):
  SPSLR pinpoint plugin
  SPSLR selfpatch
  SPSLR build integration
  SPSLR source integration
  SPSLR tasklist sample module

 Makefile                                      |  11 +
 arch/x86/boot/compressed/Makefile             |   2 +
 arch/x86/entry/vdso/Makefile                  |   3 +-
 arch/x86/kernel/vmlinux.lds.S                 |  23 +
 drivers/firmware/efi/libstub/Makefile         |   2 +
 include/linux/compiler_types.h                |  12 +
 include/linux/sched.h                         |  50 +-
 include/linux/spslr.h                         |  65 ++
 init/Kconfig                                  |   7 +
 init/main.c                                   |  32 +
 kernel/Makefile                               |   2 +
 kernel/module/main.c                          |  92 +++
 kernel/spslr/Makefile                         |   5 +
 kernel/spslr/pinpoint.h                       |  89 +++
 kernel/spslr/spslr.c                          | 527 +++++++++++++++
 kernel/spslr/spslr_env.c                      |  74 +++
 kernel/spslr/spslr_env.h                      |  45 ++
 kernel/spslr/spslr_randomizer.c               | 598 ++++++++++++++++++
 kernel/spslr/spslr_randomizer.h               |  29 +
 samples/Kconfig                               |   3 +
 samples/Makefile                              |   1 +
 samples/spslr/Kconfig                         |  17 +
 samples/spslr/Makefile                        |   1 +
 samples/spslr/tasklist/Makefile               |   1 +
 samples/spslr/tasklist/tasklist.c             |  67 ++
 scripts/Makefile.gcc-plugins                  |   9 +
 scripts/gcc-plugins/Makefile                  |  17 +
 scripts/gcc-plugins/pinpoint.c                |  94 +++
 .../gcc-plugins/pinpoint_asm_offset_pass.c    | 133 ++++
 scripts/gcc-plugins/pinpoint_config.h         |   7 +
 scripts/gcc-plugins/pinpoint_error.h          |  28 +
 scripts/gcc-plugins/pinpoint_final.h          |   3 +
 scripts/gcc-plugins/pinpoint_gc_preserve.c    |  10 +
 scripts/gcc-plugins/pinpoint_gc_preserve.h    |  39 ++
 scripts/gcc-plugins/pinpoint_layout_hash.c    |  55 ++
 scripts/gcc-plugins/pinpoint_layout_hash.h    |   8 +
 scripts/gcc-plugins/pinpoint_on_finish_decl.c | 205 ++++++
 scripts/gcc-plugins/pinpoint_on_finish_type.c |  21 +
 scripts/gcc-plugins/pinpoint_on_finish_unit.c | 346 ++++++++++
 .../pinpoint_on_preserve_component_ref.c      |  95 +++
 .../pinpoint_on_register_attributes.c         |  53 ++
 scripts/gcc-plugins/pinpoint_on_start_unit.c  |  11 +
 .../gcc-plugins/pinpoint_rtl_pin_lower_pass.c | 278 ++++++++
 .../pinpoint_separate_offset_pass.c           | 324 ++++++++++
 scripts/gcc-plugins/pinpoint_separator.c      | 123 ++++
 scripts/gcc-plugins/pinpoint_serialize.c      | 298 +++++++++
 scripts/gcc-plugins/pinpoint_serialize.h      | 114 ++++
 scripts/gcc-plugins/pinpoint_stage0.h         | 105 +++
 scripts/gcc-plugins/pinpoint_stage1.h         |  11 +
 scripts/gcc-plugins/pinpoint_stage2.h         |  22 +
 scripts/gcc-plugins/pinpoint_target.c         | 460 ++++++++++++++
 scripts/gcc-plugins/safe-attribs.h            |   8 +
 scripts/gcc-plugins/safe-diagnostic.h         |   9 +
 scripts/gcc-plugins/safe-gcc-plugin.h         |   6 +
 scripts/gcc-plugins/safe-ggc.h                |   8 +
 scripts/gcc-plugins/safe-gimple.h             |  14 +
 scripts/gcc-plugins/safe-input.h              |   9 +
 scripts/gcc-plugins/safe-langhooks.h          |   8 +
 scripts/gcc-plugins/safe-md5.h                |   8 +
 scripts/gcc-plugins/safe-output.h             |   8 +
 scripts/gcc-plugins/safe-plugin-version.h     |   8 +
 scripts/gcc-plugins/safe-rtl.h                |  17 +
 scripts/gcc-plugins/safe-tree.h               |  10 +
 scripts/module.lds.S                          |  25 +
 64 files changed, 4742 insertions(+), 23 deletions(-)
 create mode 100644 include/linux/spslr.h
 create mode 100644 kernel/spslr/Makefile
 create mode 100644 kernel/spslr/pinpoint.h
 create mode 100644 kernel/spslr/spslr.c
 create mode 100644 kernel/spslr/spslr_env.c
 create mode 100644 kernel/spslr/spslr_env.h
 create mode 100644 kernel/spslr/spslr_randomizer.c
 create mode 100644 kernel/spslr/spslr_randomizer.h
 create mode 100644 samples/spslr/Kconfig
 create mode 100644 samples/spslr/Makefile
 create mode 100644 samples/spslr/tasklist/Makefile
 create mode 100644 samples/spslr/tasklist/tasklist.c
 create mode 100644 scripts/gcc-plugins/pinpoint.c
 create mode 100644 scripts/gcc-plugins/pinpoint_asm_offset_pass.c
 create mode 100644 scripts/gcc-plugins/pinpoint_config.h
 create mode 100644 scripts/gcc-plugins/pinpoint_error.h
 create mode 100644 scripts/gcc-plugins/pinpoint_final.h
 create mode 100644 scripts/gcc-plugins/pinpoint_gc_preserve.c
 create mode 100644 scripts/gcc-plugins/pinpoint_gc_preserve.h
 create mode 100644 scripts/gcc-plugins/pinpoint_layout_hash.c
 create mode 100644 scripts/gcc-plugins/pinpoint_layout_hash.h
 create mode 100644 scripts/gcc-plugins/pinpoint_on_finish_decl.c
 create mode 100644 scripts/gcc-plugins/pinpoint_on_finish_type.c
 create mode 100644 scripts/gcc-plugins/pinpoint_on_finish_unit.c
 create mode 100644 scripts/gcc-plugins/pinpoint_on_preserve_component_ref.c
 create mode 100644 scripts/gcc-plugins/pinpoint_on_register_attributes.c
 create mode 100644 scripts/gcc-plugins/pinpoint_on_start_unit.c
 create mode 100644 scripts/gcc-plugins/pinpoint_rtl_pin_lower_pass.c
 create mode 100644 scripts/gcc-plugins/pinpoint_separate_offset_pass.c
 create mode 100644 scripts/gcc-plugins/pinpoint_separator.c
 create mode 100644 scripts/gcc-plugins/pinpoint_serialize.c
 create mode 100644 scripts/gcc-plugins/pinpoint_serialize.h
 create mode 100644 scripts/gcc-plugins/pinpoint_stage0.h
 create mode 100644 scripts/gcc-plugins/pinpoint_stage1.h
 create mode 100644 scripts/gcc-plugins/pinpoint_stage2.h
 create mode 100644 scripts/gcc-plugins/pinpoint_target.c
 create mode 100644 scripts/gcc-plugins/safe-attribs.h
 create mode 100644 scripts/gcc-plugins/safe-diagnostic.h
 create mode 100644 scripts/gcc-plugins/safe-gcc-plugin.h
 create mode 100644 scripts/gcc-plugins/safe-ggc.h
 create mode 100644 scripts/gcc-plugins/safe-gimple.h
 create mode 100644 scripts/gcc-plugins/safe-input.h
 create mode 100644 scripts/gcc-plugins/safe-langhooks.h
 create mode 100644 scripts/gcc-plugins/safe-md5.h
 create mode 100644 scripts/gcc-plugins/safe-output.h
 create mode 100644 scripts/gcc-plugins/safe-plugin-version.h
 create mode 100644 scripts/gcc-plugins/safe-rtl.h
 create mode 100644 scripts/gcc-plugins/safe-tree.h

-- 
2.43.0




Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds