Skip to content

bpf: add support for KASAN checks in JITed programs#12754

Open
kernel-patches-daemon-bpf[bot] wants to merge 10 commits into
bpf-next_basefrom
series/1124557=>bpf-next
Open

bpf: add support for KASAN checks in JITed programs#12754
kernel-patches-daemon-bpf[bot] wants to merge 10 commits into
bpf-next_basefrom
series/1124557=>bpf-next

Conversation

@kernel-patches-daemon-bpf

Copy link
Copy Markdown

Pull request for series with
subject: bpf: add support for KASAN checks in JITed programs
version: 5
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 36ffa86
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: c3d5ef2
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: a455304
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: b1d4514
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 30f77a0
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: e821c22
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 77f02c9
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

Tropicao added 7 commits July 10, 2026 17:02
When the verifier patches an ebpf program with bpf_patch_insn_data, it
then calls adjust_insn_aux_data to make sure that insn_aux_data takes
into account the newly inserted patch. Some of the data offset is pretty
straightforward to deduce, it is for example the case for
indirect_target, as any patch affecting indirect calls will
systematically move the original instruction to the end of the new
patch.

In order to introduce KASAN support for eBPF JIT, we need to mark any
load/store instruction that accesses non-stack memory, but updating this
new marking after a patch is not as straightforward as for indirect
calls: the original BPF_ST/BPF_STX/BPF_LDX can be at the beginning, at
the end or somewhere in the middle of the new patch: we then need some
additional info to properly update this marking.

Add a new parameter to bpf_patch_insn_data and adjust_insn_aux_data to
convey the info about the new location in the patch of the original
instruction. This info does not always make sense depending on the
generated patch (eg, some bpf helpers being inlined by the verifier, and
so turned into multiple new instructions without any remaining BPF_CALL),
the parameter can then be set to -1. It will be used in next patches to
properly handle insn_aux_data adjustment for the new KASAN
instrumentation

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
In order to prepare to emit KASAN checks in JITed programs, JIT
compilers need to be aware about whether some load/store instructions
are targeting the bpf program stack, as those should not be monitored
(we already have guard pages for that, and it is difficult anyway to
correctly monitor any kind of data passed on stack).

To support this need, make the BPF verifier mark the instructions
depending on whether they could access or not memory other than stack.
As different states in the verifier could lead to different memory types
for the same access, just marking an instruction as accessing stack only
is not enough (it could be some other memory type in another verifier
state), so the algorithm rather sets by default any load/store
instruction as stack only, and if _any_ state leads to any memory access
type other than PTR_TO_STACK, it overrides this setting. It also takes
care about shifting back the instruction marking in adjust_insn_aux_data
if the verifier patches instructions. However, if the verifier generates
new BPF_ST/BPF_STX/BPF_LDX while patching some instructions, those new
ones are systematically marked as non-stack-accessing: this may
over-instrument a few memory accessing instructions, but it allows
making sure that we will not miss accidentally any.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Add a new Kconfig option CONFIG_BPF_JIT_KASAN that automatically enables
generic KASAN (Kernel Address SANitizer) memory access checks for
JIT-compiled BPF programs as well, when both KASAN (and more
specifically, generic KASAN with KASAN_VMALLOC) and JIT compiler are
enabled. This new Kconfig is not a user selectable one: it is either
automatically enabled if KASAN is enabled on a compatible platform. When
enabled, the JIT compiler will emit shadow memory checks before memory
loads and stores to detect use-after-free or out-of-bounds accesses at
runtime. The option is gated behind HAVE_EBPF_JIT_KASAN, as it needs
proper arch-specific implementation.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Add the emit_kasan_check() function that emits KASAN shadow memory
checks before memory accesses in JIT-compiled BPF programs. The
implementation relies on the existing __asan_{load,store}X functions
from KASAN subsystem. The helper:
- ensures that the kasan instrumention is actually needed: if the
  instruction being processed accesses the program stack, we skip the
  instrumentation, as those accesses are already protected with page
  guards
- saves registers. This includes caller-saved registers, but also
  temporary registers, as those were possibly used by the
  affected program. Theoretically, r10 and r11 should be saved as well,
  but the number of called function and their scope being limited, they
  are skipped for the sake of reducing the overhead
- computes the accessed address and stores it in %rdi
- calls the relevant function, depending on the instruction being a load
  or a store, and the size of the access.
- restores registers

The special care needed when inserting this instrumentation comes at the
cost of a non negligeable increase in JITed code size. For example, a
bare

  mov 	0x0(%si),rbx # Load in rbx content at address stored in rsi

becomes

  push    %rax
  push    %rcx
  push    %rdx
  push    %rsi
  push    %rdi
  push    %r8
  push    %r9
  mov     %rsi,%rdi
  call    0xffffffff81da0a60 <__asan_load8>
  pop     %r9
  pop     %r8
  pop     %rdi
  pop     %rsi
  pop     %rdx
  pop     %rcx
  pop     %rax
  mov     0x0(%rsi),rbx

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
In order to prepare for KASAN checks insertion before every
memory-related load or store, group all BPF_ST instructions that indeed
access memory in a single helper to allow instrumenting those in one
call, rather than having to instrument all cases individually.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Insert KASAN shadow memory checks before memory load and store
operations in JIT-compiled BPF programs. This helps detect memory safety
bugs such as use-after-free and out-of-bounds accesses at runtime.

The main instructions being targeted are BPF_ST, BPF_STX and BPF_LDX,
but not all of them are being instrumented:
- if the load/store instruction is in fact accessing the program stack,
  emit_kasan_check silently skips the instrumentation, as we can already
  benefit from guard pages to monitor stack accesses.
- if the load/store instruction is a BPF_PROBE_MEM or a BPF_PROBE_ATOMIC
  instruction, we do not instrument it, as the passed address can fault
  (hence the custom fault management with BPF_PROBE_XXX instructions),
  and so the corresponding kasan check could fault as well.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Mark x86 as supporting KASAN checks in JITed programs so that the
corresponding JIT compiler inserts checks on the translated
instructions.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 520d7d7
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1124557
version: 5

Tropicao added 3 commits July 10, 2026 17:02
Add two simple helpers to allow checking whether KASAN for eBPF tests
should be executed:
- one helper to check if BPF_JIT_KASAN is enabled in kernel
  configuration
- one helper to check if the kernel is running with kasan_multi_shot
  (otherwise only the first test will be able to trigger a report)

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Move set_bpf_jit_harden to testing helpers so that other selftests can
change the hardening configuration without re-implementing a helper.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Add a basic KASAN test runner that loads and test-run programs that can
trigger memory management bugs. The test captures kernel logs and ensure
that the expected KASAN splat is emitted by searching for the
corresponding first lines in the report, hence validated that the needed
instrumentation has been inserted by the JIT compiler before the
relevant memory accesses. To allow each test to trigger the expected
report, the kernel must run with the kasan_multi_shot configuration.

The runner covers different cases and settings: in the nominal case, it
validates kasan reports on basic instructions (on all supported accesses
sizes) but also when report _should not_ be emitted (eg: for accesses on
program stack). The runner also comes with a few specialized tests that
are then not executed for all sizes/locations:
- specific atomic ops
- test for instructions involving different verifier states, with some
  states flagging memory as stack, and other states as non-stack memory
- tests that validate the stack marking shifting when a patch is emitted
  by the verifier (zext/rnd_hi32, constant blindind)

A few of those tests depends on cpuv4 (load_acquire and store_release).

  # ./test_progs -a kasan
  #165/1   kasan/st_1_not_on_stack:OK
  #165/2   kasan/st_1_on_stack:OK
  #165/3   kasan/st_2_not_on_stack:OK
  #165/4   kasan/st_2_on_stack:OK
  #165/5   kasan/st_4_not_on_stack:OK
  #165/6   kasan/st_4_on_stack:OK
  #165/7   kasan/st_8_not_on_stack:OK
  #165/8   kasan/st_8_on_stack:OK
  #165/9   kasan/stx_1_not_on_stack:OK
  #165/10  kasan/stx_1_on_stack:OK
  #165/11  kasan/stx_2_not_on_stack:OK
  #165/12  kasan/stx_2_on_stack:OK
  #165/13  kasan/stx_4_not_on_stack:OK
  #165/14  kasan/stx_4_on_stack:OK
  #165/15  kasan/stx_8_not_on_stack:OK
  #165/16  kasan/stx_8_on_stack:OK
  #165/17  kasan/ldx_1_not_on_stack:OK
  #165/18  kasan/ldx_1_on_stack:OK
  #165/19  kasan/ldx_2_not_on_stack:OK
  #165/20  kasan/ldx_2_on_stack:OK
  #165/21  kasan/ldx_4_not_on_stack:OK
  #165/22  kasan/ldx_4_on_stack:OK
  #165/23  kasan/ldx_8_not_on_stack:OK
  #165/24  kasan/ldx_8_on_stack:OK
  #165/25  kasan/simple_atomic_4_not_on_stack:OK
  #165/26  kasan/simple_atomic_4_on_stack:OK
  #165/27  kasan/simple_atomic_8_not_on_stack:OK
  #165/28  kasan/simple_atomic_8_on_stack:OK
  #165/29  kasan/load_acquire_1_not_on_stack:SKIP
  #165/30  kasan/load_acquire_1_on_stack:SKIP
  #165/31  kasan/load_acquire_2_not_on_stack:SKIP
  #165/32  kasan/load_acquire_2_on_stack:SKIP
  #165/33  kasan/load_acquire_4_not_on_stack:SKIP
  #165/34  kasan/load_acquire_4_on_stack:SKIP
  #165/35  kasan/load_acquire_8_not_on_stack:SKIP
  #165/36  kasan/load_acquire_8_on_stack:SKIP
  #165/37  kasan/store_release_1_not_on_stack:SKIP
  #165/38  kasan/store_release_1_on_stack:SKIP
  #165/39  kasan/store_release_2_not_on_stack:SKIP
  #165/40  kasan/store_release_2_on_stack:SKIP
  #165/41  kasan/store_release_4_not_on_stack:SKIP
  #165/42  kasan/store_release_4_on_stack:SKIP
  #165/43  kasan/store_release_8_not_on_stack:SKIP
  #165/44  kasan/store_release_8_on_stack:SKIP
  #165/45  kasan/ldx_patched:OK
  #165/46  kasan/ldx_patched_on_stack:OK
  #165/47  kasan/verifier_paths_stack_and_non_stack:OK
  #165/48  kasan/st_blinded:OK
  #165     kasan:OK (SKIP: 16/48)
  Summary: 1/32 PASSED, 16 SKIPPED, 0 FAILED

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant