Skip to content

Commit 96adbf7

Browse files
author
Alexei Starovoitov
committed
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>
2 parents 32e18e7 + 63d5a33 commit 96adbf7

File tree

5 files changed

+88
-24
lines changed

5 files changed

+88
-24
lines changed

include/linux/btf.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -531,10 +531,9 @@ s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
531531
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
532532
struct module *owner);
533533
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);
538537
int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type);
539538
bool btf_types_are_same(const struct btf *btf1, u32 id1,
540539
const struct btf *btf2, u32 id2);
@@ -574,12 +573,12 @@ static inline struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf
574573
{
575574
return NULL;
576575
}
577-
static inline const struct btf_member *
578-
btf_get_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)
576+
static inline bool
577+
btf_is_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)
581580
{
582-
return NULL;
581+
return false;
583582
}
584583
static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log,
585584
enum bpf_prog_type prog_type) {

kernel/bpf/btf.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5694,15 +5694,29 @@ static int find_kern_ctx_type_id(enum bpf_prog_type prog_type)
56945694
return ctx_type->type;
56955695
}
56965696

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)
57015700
{
57025701
const struct btf_type *ctx_type;
57035702
const char *tname, *ctx_tname;
57045703

57055704
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+
57065720
while (btf_type_is_modifier(t))
57075721
t = btf_type_by_id(btf, t->type);
57085722
if (!btf_type_is_struct(t)) {
@@ -5711,27 +5725,30 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
57115725
* is not supported yet.
57125726
* BPF_PROG_TYPE_RAW_TRACEPOINT is fine.
57135727
*/
5714-
return NULL;
5728+
return false;
57155729
}
57165730
tname = btf_name_by_offset(btf, t->name_off);
57175731
if (!tname) {
57185732
bpf_log(log, "arg#%d struct doesn't have a name\n", arg);
5719-
return NULL;
5733+
return false;
57205734
}
57215735

57225736
ctx_type = find_canonical_prog_ctx_type(prog_type);
57235737
if (!ctx_type) {
57245738
bpf_log(log, "btf_vmlinux is malformed\n");
57255739
/* should not happen */
5726-
return NULL;
5740+
return false;
57275741
}
57285742
again:
57295743
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off);
57305744
if (!ctx_tname) {
57315745
/* should not happen */
57325746
bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n");
5733-
return NULL;
5747+
return false;
57345748
}
5749+
/* program types without named context types work only with arg:ctx tag */
5750+
if (ctx_tname[0] == '\0')
5751+
return false;
57355752
/* only compare that prog's ctx type name is the same as
57365753
* kernel expects. No need to compare field by field.
57375754
* It's ok for bpf prog to do:
@@ -5740,20 +5757,20 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
57405757
* { // no fields of skb are ever used }
57415758
*/
57425759
if (strcmp(ctx_tname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0)
5743-
return ctx_type;
5760+
return true;
57445761
if (strcmp(ctx_tname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0)
5745-
return ctx_type;
5762+
return true;
57465763
if (strcmp(ctx_tname, tname)) {
57475764
/* bpf_user_pt_regs_t is a typedef, so resolve it to
57485765
* underlying struct and check name again
57495766
*/
57505767
if (!btf_type_is_modifier(ctx_type))
5751-
return NULL;
5768+
return false;
57525769
while (btf_type_is_modifier(ctx_type))
57535770
ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type);
57545771
goto again;
57555772
}
5756-
return ctx_type;
5773+
return true;
57575774
}
57585775

57595776
/* forward declarations for arch-specific underlying types of
@@ -5905,7 +5922,7 @@ static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
59055922
enum bpf_prog_type prog_type,
59065923
int arg)
59075924
{
5908-
if (!btf_get_prog_ctx_type(log, btf, t, prog_type, arg))
5925+
if (!btf_is_prog_ctx_type(log, btf, t, prog_type, arg))
59095926
return -ENOENT;
59105927
return find_kern_ctx_type_id(prog_type);
59115928
}
@@ -7211,7 +7228,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
72117228
if (!btf_type_is_ptr(t))
72127229
goto skip_pointer;
72137230

7214-
if ((tags & ARG_TAG_CTX) || btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
7231+
if ((tags & ARG_TAG_CTX) || btf_is_prog_ctx_type(log, btf, t, prog_type, i)) {
72157232
if (tags & ~ARG_TAG_CTX) {
72167233
bpf_log(log, "arg#%d has invalid combination of tags\n", i);
72177234
return -EINVAL;

kernel/bpf/verifier.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11015,7 +11015,7 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
1101511015
* type to our caller. When a set of conditions hold in the BTF type of
1101611016
* arguments, we resolve it to a known kfunc_ptr_arg_type.
1101711017
*/
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))
1101911019
return KF_ARG_PTR_TO_CTX;
1102011020

1102111021
if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))

tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ int kprobe_typedef_ctx(void *ctx)
2626
return kprobe_typedef_ctx_subprog(ctx);
2727
}
2828

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+
2946
#define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL)))
3047

3148
__weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx)
@@ -40,6 +57,8 @@ int kprobe_resolved_ctx(void *ctx)
4057
return kprobe_struct_ctx_subprog(ctx);
4158
}
4259

60+
#endif
61+
4362
/* this is current hack to make this work on old kernels */
4463
struct bpf_user_pt_regs_t {};
4564

tools/testing/selftests/bpf/progs/verifier_global_subprogs.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,35 @@ int arg_tag_nullable_ptr_fail(void *ctx)
115115
return subprog_nullable_ptr_bad(&x);
116116
}
117117

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+
118147
__noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull)
119148
{
120149
return (*p1) * (*p2); /* good, no need for NULL checks */

0 commit comments

Comments
 (0)