[PATCH bpf-next 07/18] bpf: Enable r11 based insns

Yonghong Song
2026-04-24T17:15:20Z

BPF_REG_PARAMS (r11) is used for stack argument accesses and
the following are the only insns with r11 presence:
- BPF_LDX | BPF_MEM | BPF_DW (load incoming stack arg)
- BPF_STX | BPF_MEM | BPF_DW (store register to outgoing stack arg)
- BPF_ST | BPF_MEM | BPF_DW (store immediate to outgoing stack arg)

Additionally, validate offsets: loads must use positive 8-byte aligned
offsets (8, 16, ...) since they access incoming args. Stores must use
negative 8-byte aligned offsets (-8, -16, ...) since they write
outgoing args.

The LLVM compiler [1] implemented the above BPF_REG_PARAMS insns.

[1] https://github.com/llvm/llvm-project/pull/189060

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
kernel/bpf/verifier.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 0ba140dabe93..6994536b4e04 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18678,13 +18678,34 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
return err;

for (i = 0; i < insn_cnt; i++, insn++) {
+ u8 class = BPF_CLASS(insn->code);
+ u8 mode = BPF_MODE(insn->code);
+ u8 size = BPF_SIZE(insn->code);
+
if (insn->dst_reg >= MAX_BPF_REG) {
- verbose(env, "R%d is invalid\n", insn->dst_reg);
- return -EINVAL;
+ if (insn->dst_reg != BPF_REG_PARAMS ||
+ (class != BPF_ST && class != BPF_STX) ||
+ mode != BPF_MEM || size != BPF_DW) {
+ verbose(env, "R%d is invalid\n", insn->dst_reg);
+ return -EINVAL;
+ }
+ if (insn->off >= 0 || insn->off % BPF_REG_SIZE) {
+ verbose(env, "invalid stack arg store offset %d\n",
+ insn->off);
+ return -EINVAL;
+ }
}
if (insn->src_reg >= MAX_BPF_REG) {
- verbose(env, "R%d is invalid\n", insn->src_reg);
- return -EINVAL;
+ if (insn->src_reg != BPF_REG_PARAMS ||
+ insn->code != (BPF_LDX | BPF_MEM | BPF_DW)) {
+ verbose(env, "R%d is invalid\n", insn->src_reg);
+ return -EINVAL;
+ }
+ if (insn->off <= 0 || insn->off % BPF_REG_SIZE) {
+ verbose(env, "invalid stack arg load offset %d\n",
+ insn->off);
+ return -EINVAL;
+ }
}
if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) {
struct bpf_insn_aux_data *aux;
--
2.52.0