public inbox for linux-arm-kernel@lists.infradead.org 
 help / color / mirror / Atom feed
From: "Alexis Lothoré (eBPF Foundation)" <alexis.lothore@bootlin•com>
To: Alexei Starovoitov <ast@kernel•org>,
	 Daniel Borkmann <daniel@iogearbox•net>,
	Andrii Nakryiko <andrii@kernel•org>,
	 Martin KaFai Lau <martin.lau@linux•dev>,
	 Eduard Zingerman <eddyz87@gmail•com>,
	 Kumar Kartikeya Dwivedi <memxor@gmail•com>,
	Song Liu <song@kernel•org>,
	 Yonghong Song <yonghong.song@linux•dev>,
	Jiri Olsa <jolsa@kernel•org>,
	 John Fastabend <john.fastabend@gmail•com>,
	 Thomas Gleixner <tglx@kernel•org>,
	Ingo Molnar <mingo@redhat•com>,  Borislav Petkov <bp@alien8•de>,
	Dave Hansen <dave.hansen@linux•intel.com>,
	 x86@kernel•org, "H. Peter Anvin" <hpa@zytor•com>,
	 Shuah Khan <shuah@kernel•org>,
	Maxime Coquelin <mcoquelin.stm32@gmail•com>,
	 Alexandre Torgue <alexandre.torgue@foss•st.com>,
	 Ihor Solodrai <ihor.solodrai@linux•dev>
Cc: ebpf@linuxfoundation•org,
	"Bastien Curutchet" <bastien.curutchet@bootlin•com>,
	"Thomas Petazzoni" <thomas.petazzoni@bootlin•com>,
	bpf@vger•kernel.org, linux-kernel@vger•kernel.org,
	linux-kselftest@vger•kernel.org,
	linux-stm32@st-md-mailman•stormreply.com,
	linux-arm-kernel@lists•infradead.org,
	"Alexis Lothoré (eBPF Foundation)" <alexis.lothore@bootlin•com>
Subject: [PATCH bpf-next v2 1/8] bpf: mark instructions accessing program stack
Date: Thu, 04 Jun 2026 22:21:59 +0200	[thread overview]
Message-ID: <20260604-kasan-v2-1-c066e627fda8@bootlin.com> (raw)
In-Reply-To: <20260604-kasan-v2-0-c066e627fda8@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:
- add a setter that allows the verifier to mark instructions accessing
  non-stack memory
- add a getter that allows JIT compilers to check whether instructions
  being JITed are accessing the stack _and only_ the stack. If no env is
  provided (eg this is a cBPF program), do a best-effort check based on
  source and destination registers.

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.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin•com>
---
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
---
 include/linux/bpf.h          |  2 ++
 include/linux/bpf_verifier.h |  2 ++
 kernel/bpf/core.c            | 17 +++++++++++++++++
 kernel/bpf/fixups.c          | 16 +++++++++++-----
 kernel/bpf/verifier.c        |  9 +++++++++
 5 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 8599b451dd7a..ff80d1d62bff 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1560,6 +1560,8 @@ void bpf_jit_uncharge_modmem(u32 size);
 bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
 bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
 				 int insn_idx);
+bool bpf_insn_accesses_stack_only(const struct bpf_verifier_env *env,
+				  const struct bpf_prog *prog, int insn_idx);
 u16 bpf_out_stack_arg_cnt(const struct bpf_verifier_env *env, const struct bpf_prog *prog);
 #else
 static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index c248ff41f42a..0f3f055d6c14 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -722,6 +722,8 @@ struct bpf_insn_aux_data {
 	u16 const_reg_map_mask;
 	u16 const_reg_subprog_mask;
 	u32 const_reg_vals[10];
+	/* instruction can access non-stack memory */
+	bool non_stack_access;
 };
 
 #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index a656a8572bdb..393d9eacd215 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1583,6 +1583,22 @@ bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struc
 	return env->insn_aux_data[insn_idx].indirect_target;
 }
 
+bool bpf_insn_accesses_stack_only(const struct bpf_verifier_env *env,
+				  const struct bpf_prog *prog, int insn_idx)
+{
+	struct bpf_insn *insn;
+
+	/* cBPF: we have no verifier state, do a best-effort check based on
+	 * dst/src reg
+	 */
+	insn_idx += prog->aux->subprog_start;
+	insn = (struct bpf_insn *)prog->insnsi + insn_idx;
+	if (!env)
+		return insn->dst_reg == BPF_REG_FP ||
+		       insn->src_reg == BPF_REG_FP;
+	return !env->insn_aux_data[insn_idx].non_stack_access;
+}
+
 u16 bpf_out_stack_arg_cnt(const struct bpf_verifier_env *env, const struct bpf_prog *prog)
 {
 	const struct bpf_subprog_info *sub;
@@ -1592,6 +1608,7 @@ u16 bpf_out_stack_arg_cnt(const struct bpf_verifier_env *env, const struct bpf_p
 	sub = &env->subprog_info[prog->aux->func_idx];
 	return sub->stack_arg_cnt - bpf_in_stack_arg_cnt(sub);
 }
+
 #endif /* CONFIG_BPF_JIT */
 
 /* Base function for offset calculation. Needs to go into .text section,
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 5aa3f7d99ac9..5228c910fbf5 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -185,16 +185,22 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
 	}
 
 	/*
-	 * The indirect_target flag of the original instruction was moved to the last of the
-	 * new instructions by the above memmove and memset, but the indirect jump target is
-	 * actually the first instruction, so move it back. This also matches with the behavior
-	 * of bpf_insn_array_adjust(), which preserves xlated_off to point to the first new
-	 * instruction.
+	 * The indirect_target and non_stack_access flags of the original
+	 * instruction were moved to the last of the new instructions by the
+	 * above memmove and memset, but those actually match the first
+	 * instruction, so move them back. This also matches with the behavior
+	 * of bpf_insn_array_adjust(), which preserves xlated_off to point to
+	 * the first new instruction.
 	 */
 	if (data[off + cnt - 1].indirect_target) {
 		data[off].indirect_target = 1;
 		data[off + cnt - 1].indirect_target = 0;
 	}
+
+	if (data[off + cnt - 1].non_stack_access) {
+		data[off].non_stack_access = 1;
+		data[off + cnt - 1].non_stack_access = 0;
+	}
 }
 
 static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8ed484cb1a8a..b3f0f430ad6a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3143,6 +3143,11 @@ static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
 	env->insn_aux_data[idx].indirect_target = true;
 }
 
+static void mark_non_stack_access(struct bpf_verifier_env *env, int idx)
+{
+	env->insn_aux_data[idx].non_stack_access = true;
+}
+
 #define LR_FRAMENO_BITS	3
 #define LR_SPI_BITS	6
 #define LR_ENTRY_BITS	(LR_SPI_BITS + LR_FRAMENO_BITS + 1)
@@ -6300,6 +6305,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
 		else
 			coerce_reg_to_size_sx(&regs[value_regno], size);
 	}
+
+	if (!err && reg->type != PTR_TO_STACK)
+		mark_non_stack_access(env, insn_idx);
+
 	return err;
 }
 

-- 
2.54.0



  reply	other threads:[~2026-06-04 20:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-04 20:21 [PATCH bpf-next v2 0/8] bpf: add support for KASAN checks in JITed programs Alexis Lothoré (eBPF Foundation)
2026-06-04 20:21 ` Alexis Lothoré (eBPF Foundation) [this message]
2026-06-04 21:13   ` [PATCH bpf-next v2 1/8] bpf: mark instructions accessing program stack bot+bpf-ci
2026-06-04 20:22 ` [PATCH bpf-next v2 2/8] bpf: add BPF_JIT_KASAN for KASAN instrumentation of JITed programs Alexis Lothoré (eBPF Foundation)
2026-06-04 21:13   ` bot+bpf-ci
2026-06-04 20:22 ` [PATCH bpf-next v2 3/8] bpf, x86: add helper to emit kasan checks in x86 " Alexis Lothoré (eBPF Foundation)
2026-06-04 20:22 ` [PATCH bpf-next v2 4/8] bpf, x86: refactor BPF_ST management in do_jit Alexis Lothoré (eBPF Foundation)
2026-06-04 21:13   ` bot+bpf-ci
2026-06-04 20:22 ` [PATCH bpf-next v2 5/8] bpf, x86: emit KASAN checks into x86 JITed programs Alexis Lothoré (eBPF Foundation)
2026-06-04 20:22 ` [PATCH bpf-next v2 6/8] bpf, x86: enable KASAN for JITed programs on x86 Alexis Lothoré (eBPF Foundation)
2026-06-04 20:22 ` [PATCH bpf-next v2 7/8] selftests/bpf: add helper to check whether eBPF KASAN is active Alexis Lothoré (eBPF Foundation)
2026-06-04 20:22 ` [PATCH bpf-next v2 8/8] selftests/bpf: add tests to validate KASAN on JIT programs Alexis Lothoré (eBPF Foundation)
2026-06-04 21:45   ` bot+bpf-ci

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260604-kasan-v2-1-c066e627fda8@bootlin.com \
    --to=alexis.lothore@bootlin$(echo .)com \
    --cc=alexandre.torgue@foss$(echo .)st.com \
    --cc=andrii@kernel$(echo .)org \
    --cc=ast@kernel$(echo .)org \
    --cc=bastien.curutchet@bootlin$(echo .)com \
    --cc=bp@alien8$(echo .)de \
    --cc=bpf@vger$(echo .)kernel.org \
    --cc=daniel@iogearbox$(echo .)net \
    --cc=dave.hansen@linux$(echo .)intel.com \
    --cc=ebpf@linuxfoundation$(echo .)org \
    --cc=eddyz87@gmail$(echo .)com \
    --cc=hpa@zytor$(echo .)com \
    --cc=ihor.solodrai@linux$(echo .)dev \
    --cc=john.fastabend@gmail$(echo .)com \
    --cc=jolsa@kernel$(echo .)org \
    --cc=linux-arm-kernel@lists$(echo .)infradead.org \
    --cc=linux-kernel@vger$(echo .)kernel.org \
    --cc=linux-kselftest@vger$(echo .)kernel.org \
    --cc=linux-stm32@st-md-mailman$(echo .)stormreply.com \
    --cc=martin.lau@linux$(echo .)dev \
    --cc=mcoquelin.stm32@gmail$(echo .)com \
    --cc=memxor@gmail$(echo .)com \
    --cc=mingo@redhat$(echo .)com \
    --cc=shuah@kernel$(echo .)org \
    --cc=song@kernel$(echo .)org \
    --cc=tglx@kernel$(echo .)org \
    --cc=thomas.petazzoni@bootlin$(echo .)com \
    --cc=x86@kernel$(echo .)org \
    --cc=yonghong.song@linux$(echo .)dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox