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

Merge branch 'fix-global-subprog-ptr_to_ctx-arg-handling'

Andrii Nakryiko says:

====================
Fix global subprog PTR_TO_CTX arg handling

Fix confusing and incorrect inference of PTR_TO_CTX argument type in BPF
global subprogs. For some program types (iters, tracepoint, any program type
that doesn't have fixed named "canonical" context type) when user uses (in
a correct and valid way) a pointer argument to user-defined anonymous struct
type, verifier will incorrectly assume that it has to be PTR_TO_CTX argument.
While it should be just a PTR_TO_MEM argument with allowed size calculated
from user-provided (even if anonymous) struct.

This did come up in practice and was very confusing to users, so let's prevent
this going forward. We had to do a slight refactoring of
btf_get_prog_ctx_type() to make it easy to support a special s390x KPROBE use
cases. See details in respective patches.

v1->v2:
- special-case typedef bpf_user_pt_regs_t handling for KPROBE programs,
fixing s390x after changes in patch #2.
====================

Link: https://lore.kernel.org/r/20240212233221.2575350-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+88 -24
+8 -9
include/linux/btf.h
··· 531 531 int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt, 532 532 struct module *owner); 533 533 struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id); 534 - const struct btf_type * 535 - btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 536 - const struct btf_type *t, enum bpf_prog_type prog_type, 537 - int arg); 534 + bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 535 + const struct btf_type *t, enum bpf_prog_type prog_type, 536 + int arg); 538 537 int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type); 539 538 bool btf_types_are_same(const struct btf *btf1, u32 id1, 540 539 const struct btf *btf2, u32 id2); ··· 573 574 { 574 575 return NULL; 575 576 } 576 - static inline const struct btf_member * 577 - btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 578 - const struct btf_type *t, enum bpf_prog_type prog_type, 579 - int arg) 577 + static inline bool 578 + btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 579 + const struct btf_type *t, enum bpf_prog_type prog_type, 580 + int arg) 580 581 { 581 - return NULL; 582 + return false; 582 583 } 583 584 static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log, 584 585 enum bpf_prog_type prog_type) {
+31 -14
kernel/bpf/btf.c
··· 5694 5694 return ctx_type->type; 5695 5695 } 5696 5696 5697 - const struct btf_type * 5698 - btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 5699 - const struct btf_type *t, enum bpf_prog_type prog_type, 5700 - int arg) 5697 + bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf, 5698 + const struct btf_type *t, enum bpf_prog_type prog_type, 5699 + int arg) 5701 5700 { 5702 5701 const struct btf_type *ctx_type; 5703 5702 const char *tname, *ctx_tname; 5704 5703 5705 5704 t = btf_type_by_id(btf, t->type); 5705 + 5706 + /* KPROBE programs allow bpf_user_pt_regs_t typedef, which we need to 5707 + * check before we skip all the typedef below. 5708 + */ 5709 + if (prog_type == BPF_PROG_TYPE_KPROBE) { 5710 + while (btf_type_is_modifier(t) && !btf_type_is_typedef(t)) 5711 + t = btf_type_by_id(btf, t->type); 5712 + 5713 + if (btf_type_is_typedef(t)) { 5714 + tname = btf_name_by_offset(btf, t->name_off); 5715 + if (tname && strcmp(tname, "bpf_user_pt_regs_t") == 0) 5716 + return true; 5717 + } 5718 + } 5719 + 5706 5720 while (btf_type_is_modifier(t)) 5707 5721 t = btf_type_by_id(btf, t->type); 5708 5722 if (!btf_type_is_struct(t)) { ··· 5725 5711 * is not supported yet. 5726 5712 * BPF_PROG_TYPE_RAW_TRACEPOINT is fine. 5727 5713 */ 5728 - return NULL; 5714 + return false; 5729 5715 } 5730 5716 tname = btf_name_by_offset(btf, t->name_off); 5731 5717 if (!tname) { 5732 5718 bpf_log(log, "arg#%d struct doesn't have a name\n", arg); 5733 - return NULL; 5719 + return false; 5734 5720 } 5735 5721 5736 5722 ctx_type = find_canonical_prog_ctx_type(prog_type); 5737 5723 if (!ctx_type) { 5738 5724 bpf_log(log, "btf_vmlinux is malformed\n"); 5739 5725 /* should not happen */ 5740 - return NULL; 5726 + return false; 5741 5727 } 5742 5728 again: 5743 5729 ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off); 5744 5730 if (!ctx_tname) { 5745 5731 /* should not happen */ 5746 5732 bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n"); 5747 - return NULL; 5733 + return false; 5748 5734 } 5735 + /* program types without named context types work only with arg:ctx tag */ 5736 + if (ctx_tname[0] == '\0') 5737 + return false; 5749 5738 /* only compare that prog's ctx type name is the same as 5750 5739 * kernel expects. No need to compare field by field. 5751 5740 * It's ok for bpf prog to do: ··· 5757 5740 * { // no fields of skb are ever used } 5758 5741 */ 5759 5742 if (strcmp(ctx_tname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0) 5760 - return ctx_type; 5743 + return true; 5761 5744 if (strcmp(ctx_tname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0) 5762 - return ctx_type; 5745 + return true; 5763 5746 if (strcmp(ctx_tname, tname)) { 5764 5747 /* bpf_user_pt_regs_t is a typedef, so resolve it to 5765 5748 * underlying struct and check name again 5766 5749 */ 5767 5750 if (!btf_type_is_modifier(ctx_type)) 5768 - return NULL; 5751 + return false; 5769 5752 while (btf_type_is_modifier(ctx_type)) 5770 5753 ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type); 5771 5754 goto again; 5772 5755 } 5773 - return ctx_type; 5756 + return true; 5774 5757 } 5775 5758 5776 5759 /* forward declarations for arch-specific underlying types of ··· 5922 5905 enum bpf_prog_type prog_type, 5923 5906 int arg) 5924 5907 { 5925 - if (!btf_get_prog_ctx_type(log, btf, t, prog_type, arg)) 5908 + if (!btf_is_prog_ctx_type(log, btf, t, prog_type, arg)) 5926 5909 return -ENOENT; 5927 5910 return find_kern_ctx_type_id(prog_type); 5928 5911 } ··· 7228 7211 if (!btf_type_is_ptr(t)) 7229 7212 goto skip_pointer; 7230 7213 7231 - if ((tags & ARG_TAG_CTX) || btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { 7214 + if ((tags & ARG_TAG_CTX) || btf_is_prog_ctx_type(log, btf, t, prog_type, i)) { 7232 7215 if (tags & ~ARG_TAG_CTX) { 7233 7216 bpf_log(log, "arg#%d has invalid combination of tags\n", i); 7234 7217 return -EINVAL;
+1 -1
kernel/bpf/verifier.c
··· 11015 11015 * type to our caller. When a set of conditions hold in the BTF type of 11016 11016 * arguments, we resolve it to a known kfunc_ptr_arg_type. 11017 11017 */ 11018 - if (btf_get_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno)) 11018 + if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno)) 11019 11019 return KF_ARG_PTR_TO_CTX; 11020 11020 11021 11021 if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))
+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 {};
+29
tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
··· 115 115 return subprog_nullable_ptr_bad(&x); 116 116 } 117 117 118 + typedef struct { 119 + int x; 120 + } user_struct_t; 121 + 122 + __noinline __weak int subprog_user_anon_mem(user_struct_t *t) 123 + { 124 + return t ? t->x : 0; 125 + } 126 + 127 + SEC("?tracepoint") 128 + __failure __log_level(2) 129 + __msg("invalid bpf_context access") 130 + __msg("Caller passes invalid args into func#1 ('subprog_user_anon_mem')") 131 + int anon_user_mem_invalid(void *ctx) 132 + { 133 + /* can't pass PTR_TO_CTX as user memory */ 134 + return subprog_user_anon_mem(ctx); 135 + } 136 + 137 + SEC("?tracepoint") 138 + __success __log_level(2) 139 + __msg("Func#1 ('subprog_user_anon_mem') is safe for any args that match its prototype") 140 + int anon_user_mem_valid(void *ctx) 141 + { 142 + user_struct_t t = { .x = 42 }; 143 + 144 + return subprog_user_anon_mem(&t); 145 + } 146 + 118 147 __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull) 119 148 { 120 149 return (*p1) * (*p2); /* good, no need for NULL checks */