Skip to content

Kasan for JIT: CI test run v5#12674

Open
Tropicao wants to merge 11 commits into
kernel-patches:bpf-next_basefrom
Tropicao:kasan_ci
Open

Kasan for JIT: CI test run v5#12674
Tropicao wants to merge 11 commits into
kernel-patches:bpf-next_basefrom
Tropicao:kasan_ci

Conversation

@Tropicao

@Tropicao Tropicao commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@kernel-patches-daemon-bpf kernel-patches-daemon-bpf Bot force-pushed the bpf-next_base branch 22 times, most recently from a1a89b3 to 76842fa Compare July 8, 2026 03:27
@Tropicao Tropicao changed the title Kasan for JIT: CI test run v3 Kasan for JIT: CI test run v4 Jul 8, 2026
@kernel-patches-daemon-bpf kernel-patches-daemon-bpf Bot force-pushed the bpf-next_base branch 6 times, most recently from a86433a to ef46468 Compare July 9, 2026 06:08
Tropicao added 10 commits July 9, 2026 11:23
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>
---
Changes in v5:
- fix a few incorrect offset values

Changes in v4:
- define insn_off_in_patch inside convert_ctx_accesses main loop to
  avoid old value leakage

Changes in v3:
- new patch
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>
---
Changes in v5:
- fix incorrect marking for single instruction patch

Changes in v4:
- include BPF_ATOMIC in is_mem_insn
- correctly mark instructions in adjust_insn_aux_data if patch generates
  a single instruction (ie replace an instruction)

Changes in v3:
- drop getter
- drop cBPF handling
- update marking shifting logic to track more precisely orignal
  instructions
- systematically mark newly generated instructions as non-stack
  accessing

Changes in v2:
- invert marking logic to cover possible different reg types when the
  verifier covers different states
- add a best-effort processing for classical bpf programs, inspecting
  directly src and dst registers since we don't have verifier env
- make sure to keep marking in sync with prog when it is patched by
  verifier
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>
---
Changes in v4:
- reorganize dependencies (Andrey)
- drop VMAP_STACK dependency

Changes in v2:
- add dependency on kasan for vmalloc and vmalloc'ed stack
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>
---
Changes in v3:
- skip kasan instrumentation if there is no verifier env (cBPF)
- move helper up in the file

Changes in v2:
- move asan functions declaration directly into jit compiler, and guard
  them with IS_ENABLED
- remove faulty stack alignment, no arg is passed to kasan funcs on the
  stack anyway
- make sure to emit call depth accounting code
- do not save unneeded registers
- update helper signature to let caller configure some values (eg:
  is_write)
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>
---
Changes in v3:
- new patch
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>
---
Changes in v5:
- change access type (read -> write) for atomic RMW check

Changes in v4:
- refactor BPF_FETCH handling

Changes in v3:
- fix LLVM23 build failure

Changes in v2:
- support BPF_ATOMICS
- support BPF_ST
- make sure to systematically pass correct instruction to kasan check
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>
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>
---
Changes in v5:
- add kasan_multi_shot helper

Changes in v2:
- fix condition
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>
---
Changes in v5:
- check set_bpf_jit_harden return code in cleanup path

Changes in v3:
- new patch
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
  kernel-patches#165/1   kasan/st_1_not_on_stack:OK
  kernel-patches#165/2   kasan/st_1_on_stack:OK
  kernel-patches#165/3   kasan/st_2_not_on_stack:OK
  kernel-patches#165/4   kasan/st_2_on_stack:OK
  kernel-patches#165/5   kasan/st_4_not_on_stack:OK
  kernel-patches#165/6   kasan/st_4_on_stack:OK
  kernel-patches#165/7   kasan/st_8_not_on_stack:OK
  kernel-patches#165/8   kasan/st_8_on_stack:OK
  kernel-patches#165/9   kasan/stx_1_not_on_stack:OK
  kernel-patches#165/10  kasan/stx_1_on_stack:OK
  kernel-patches#165/11  kasan/stx_2_not_on_stack:OK
  kernel-patches#165/12  kasan/stx_2_on_stack:OK
  kernel-patches#165/13  kasan/stx_4_not_on_stack:OK
  kernel-patches#165/14  kasan/stx_4_on_stack:OK
  kernel-patches#165/15  kasan/stx_8_not_on_stack:OK
  kernel-patches#165/16  kasan/stx_8_on_stack:OK
  kernel-patches#165/17  kasan/ldx_1_not_on_stack:OK
  kernel-patches#165/18  kasan/ldx_1_on_stack:OK
  kernel-patches#165/19  kasan/ldx_2_not_on_stack:OK
  kernel-patches#165/20  kasan/ldx_2_on_stack:OK
  kernel-patches#165/21  kasan/ldx_4_not_on_stack:OK
  kernel-patches#165/22  kasan/ldx_4_on_stack:OK
  kernel-patches#165/23  kasan/ldx_8_not_on_stack:OK
  kernel-patches#165/24  kasan/ldx_8_on_stack:OK
  kernel-patches#165/25  kasan/simple_atomic_4_not_on_stack:OK
  kernel-patches#165/26  kasan/simple_atomic_4_on_stack:OK
  kernel-patches#165/27  kasan/simple_atomic_8_not_on_stack:OK
  kernel-patches#165/28  kasan/simple_atomic_8_on_stack:OK
  kernel-patches#165/29  kasan/load_acquire_1_not_on_stack:SKIP
  kernel-patches#165/30  kasan/load_acquire_1_on_stack:SKIP
  kernel-patches#165/31  kasan/load_acquire_2_not_on_stack:SKIP
  kernel-patches#165/32  kasan/load_acquire_2_on_stack:SKIP
  kernel-patches#165/33  kasan/load_acquire_4_not_on_stack:SKIP
  kernel-patches#165/34  kasan/load_acquire_4_on_stack:SKIP
  kernel-patches#165/35  kasan/load_acquire_8_not_on_stack:SKIP
  kernel-patches#165/36  kasan/load_acquire_8_on_stack:SKIP
  kernel-patches#165/37  kasan/store_release_1_not_on_stack:SKIP
  kernel-patches#165/38  kasan/store_release_1_on_stack:SKIP
  kernel-patches#165/39  kasan/store_release_2_not_on_stack:SKIP
  kernel-patches#165/40  kasan/store_release_2_on_stack:SKIP
  kernel-patches#165/41  kasan/store_release_4_not_on_stack:SKIP
  kernel-patches#165/42  kasan/store_release_4_on_stack:SKIP
  kernel-patches#165/43  kasan/store_release_8_not_on_stack:SKIP
  kernel-patches#165/44  kasan/store_release_8_on_stack:SKIP
  kernel-patches#165/45  kasan/ldx_patched:OK
  kernel-patches#165/46  kasan/ldx_patched_on_stack:OK
  kernel-patches#165/47  kasan/verifier_paths_stack_and_non_stack:OK
  kernel-patches#165/48  kasan/st_blinded:OK
  kernel-patches#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>
---
Changes in v5:
- check snprintf return codes when checking kernel logs
- skip tests in kasan_multi_shot is not enabled
- update simple atomic test expected access type (read -> write)

Changes in v4:
- prevent interleaved kernel logs from breaking kasan report search
- make new kfuncs in bpf_testmod depend on BPF_JIT_KASAN rather than
  KASAN_GENERIC
- initialize buffer passed to bpf_prog_test_run_opts

Changes in v3:
- increase kernel log buffer size
- fix comment style
- check bpf_program__fd return code
- document kasan_multi_shot
- fix copy-paste mistakes on poisoning/unpoisoning sequences
- add test for patch due to constant blinding

Changes in v2:
- simplify tests by just manually poisoning test areas with a dedicated
  kfunc
- introduce one prog per covered instruction family
- make sure that tests do not consume kernel logs (use /dev/kmgs rather
  than klogctl)
- add tests for stack accesses:
  - marking correctly set when there are diverging verifier states
    leading to different memory types
  - marking kept in sync with prog when it is patched
@Tropicao Tropicao changed the title Kasan for JIT: CI test run v4 Kasan for JIT: CI test run v5 Jul 9, 2026
@kernel-patches-daemon-bpf kernel-patches-daemon-bpf Bot force-pushed the bpf-next_base branch 7 times, most recently from 386cc3c to ded8f8a Compare July 11, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant