> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_gotox.c 
> b/tools/testing/selftests/bpf/prog_tests/bpf_gotox.c
> index 73dc63882b7d..866b4a14ccb7 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_gotox.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_gotox.c

[ ... ]

> @@ -393,6 +417,52 @@ reject_offsets(struct bpf_insn *insns, __u32 insn_cnt, 
> int off1, int off2, int o
>               close(prog_fd);
>  }
>
> +static void
> +check_cross_subprog_gotox_target(struct bpf_gotox *skel __always_unused)
> +{
> +     struct bpf_insn insns[] = {
> +             /* main subprog [0,14) */
> +             BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
> +             BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_CALL, 0, 12),
> +             BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 0),
> +             BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, 0, 4),
> +             BPF_LD_IMM64_RAW(BPF_REG_2, BPF_PSEUDO_MAP_VALUE, 0),
> +             BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, 0),
> +             BPF_JMP_A(3),
> +             BPF_LD_IMM64_RAW(BPF_REG_2, BPF_PSEUDO_MAP_VALUE, 0),
> +             BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, 0),
> +             BPF_RAW_INSN(BPF_JMP | BPF_JA | BPF_X, BPF_REG_2, 0, 0, 0),
> +             BPF_MOV64_IMM(BPF_REG_0, 1),
> +             BPF_EXIT_INSN(),
> +
> +             /* static subprog [14,16) */
> +             BPF_MOV64_IMM(BPF_REG_0, 42),
> +             BPF_EXIT_INSN(),
> +     };
> +     int good_fd, bad_fd, prog_fd;
> +
> +     good_fd = create_jt_map_with_target(12);
> +     if (!ASSERT_GE(good_fd, 0, "create_good_jt_map"))
> +             return;
> +
> +     bad_fd = create_jt_map_with_target(14);
> +     if (!ASSERT_GE(bad_fd, 0, "create_bad_jt_map")) {
> +             close(good_fd);
> +             return;
> +     }
> +
> +     insns[4].imm = bad_fd;
> +     insns[8].imm = good_fd;
> +
> +     prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
> +                             insns, ARRAY_SIZE(insns), NULL);
> +     if (!ASSERT_EQ(prog_fd, -EACCES, "cross_subprog_gotox_prog_load"))
                                 ^^^^^^^

Does this test expect the correct error code? The kernel fix in commit
8f33cb405e13 ("bpf: Fix gotox target validation against CFG") rejects an
unmodeled gotox target with -EINVAL when the CFG jump table check fails:

kernel/bpf/verifier.c:check_indirect_jump() {
    for (i = 0; i < n; i++) {
        if (!is_cfg_indirect_jump_target(env, env->gotox_tmp_buf->items[i])) {
            verbose(env, "gotox target %u from map id=%d is not in the CFG jump 
table\n", ...);
            return -EINVAL;
        }
    }
}

This -EINVAL propagates unchanged through do_check() -> do_check_common() ->
bpf_check() -> the BPF_PROG_LOAD syscall handler.

The existing reject_offsets() tests in this file legitimately expect -EACCES
because they fail in check_map_access (the INSN_ARRAY read path for bad size
or map-value access checks), a different code path. This new program is
structurally valid through all the loads and only fails at the gotox
instruction's CFG-jump-table check.

Should the assertion compare against -EINVAL instead of -EACCES?

> +             close(prog_fd);
> +
> +     close(bad_fd);
> +     close(good_fd);
> +}

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27216356316

Reply via email to