Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: don't infer PTR_TO_CTX for programs with unnamed context type

For program types that don't have named context type name (e.g., BPF
iterator programs or tracepoint programs), ctx_tname will be a non-NULL
empty string. For such programs it shouldn't be possible to have
PTR_TO_CTX argument for global subprogs based on type name alone.
arg:ctx tag is the only way to have PTR_TO_CTX passed into global
subprog for such program types.

Fix this loophole, which currently would assume PTR_TO_CTX whenever
user uses a pointer to anonymous struct as an argument to their global
subprogs. This happens in practice with the following (quite common, in
practice) approach:

typedef struct { /* anonymous */
int x;
} my_type_t;

int my_subprog(my_type_t *arg) { ... }

User's intent is to have PTR_TO_MEM argument for `arg`, but verifier
will complain about expecting PTR_TO_CTX.

This fix also closes unintended s390x-specific KPROBE handling of
PTR_TO_CTX case. Selftest change is necessary to accommodate this.

Fixes: 91cc1a99740e ("bpf: Annotate context types")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20240212233221.2575350-4-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
879bbe7a 824c58fb

+22
+3
kernel/bpf/btf.c
··· 5746 5746 bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n"); 5747 5747 return false; 5748 5748 } 5749 + /* program types without named context types work only with arg:ctx tag */ 5750 + if (ctx_tname[0] == '\0') 5751 + return false; 5749 5752 /* only compare that prog's ctx type name is the same as 5750 5753 * kernel expects. No need to compare field by field. 5751 5754 * It's ok for bpf prog to do:
+19
tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
··· 26 26 return kprobe_typedef_ctx_subprog(ctx); 27 27 } 28 28 29 + /* s390x defines: 30 + * 31 + * typedef user_pt_regs bpf_user_pt_regs_t; 32 + * typedef struct { ... } user_pt_regs; 33 + * 34 + * And so "canonical" underlying struct type is anonymous. 35 + * So on s390x only valid ways to have PTR_TO_CTX argument in global subprogs 36 + * are: 37 + * - bpf_user_pt_regs_t *ctx (typedef); 38 + * - struct bpf_user_pt_regs_t *ctx (backwards compatible struct hack); 39 + * - void *ctx __arg_ctx (arg:ctx tag) 40 + * 41 + * Other architectures also allow using underlying struct types (e.g., 42 + * `struct pt_regs *ctx` for x86-64) 43 + */ 44 + #ifndef bpf_target_s390 45 + 29 46 #define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL))) 30 47 31 48 __weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx) ··· 56 39 { 57 40 return kprobe_struct_ctx_subprog(ctx); 58 41 } 42 + 43 + #endif 59 44 60 45 /* this is current hack to make this work on old kernels */ 61 46 struct bpf_user_pt_regs_t {};