Skip to content

Commit 96ea081

Browse files
Martin KaFai LauAlexei Starovoitov
authored andcommitted
bpf: Reject struct_ops registration that uses module ptr and the module btf_id is missing
There is a UAF report in the bpf_struct_ops when CONFIG_MODULES=n. In particular, the report is on tcp_congestion_ops that has a "struct module *owner" member. For struct_ops that has a "struct module *owner" member, it can be extended either by the regular kernel module or by the bpf_struct_ops. bpf_try_module_get() will be used to do the refcounting and different refcount is done based on the owner pointer. When CONFIG_MODULES=n, the btf_id of the "struct module" is missing: WARN: resolve_btfids: unresolved symbol module Thus, the bpf_try_module_get() cannot do the correct refcounting. Not all subsystem's struct_ops requires the "struct module *owner" member. e.g. the recent sched_ext_ops. This patch is to disable bpf_struct_ops registration if the struct_ops has the "struct module *" member and the "struct module" btf_id is missing. The btf_type_is_fwd() helper is moved to the btf.h header file for this test. This has happened since the beginning of bpf_struct_ops which has gone through many changes. The Fixes tag is set to a recent commit that this patch can apply cleanly. Considering CONFIG_MODULES=n is not common and the age of the issue, targeting for bpf-next also. Fixes: 1611603 ("bpf: Create argument information for nullable arguments.") Reported-by: Robert Morris <[email protected]> Closes: https://lore.kernel.org/bpf/74665.1733669976@localhost/ Signed-off-by: Martin KaFai Lau <[email protected]> Tested-by: Eduard Zingerman <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent dfa94ce commit 96ea081

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

include/linux/btf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,11 @@ static inline bool btf_type_is_scalar(const struct btf_type *t)
353353
return btf_type_is_int(t) || btf_type_is_enum(t);
354354
}
355355

356+
static inline bool btf_type_is_fwd(const struct btf_type *t)
357+
{
358+
return BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
359+
}
360+
356361
static inline bool btf_type_is_typedef(const struct btf_type *t)
357362
{
358363
return BTF_INFO_KIND(t->info) == BTF_KIND_TYPEDEF;

kernel/bpf/bpf_struct_ops.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,20 @@ void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc)
310310
kfree(arg_info);
311311
}
312312

313+
static bool is_module_member(const struct btf *btf, u32 id)
314+
{
315+
const struct btf_type *t;
316+
317+
t = btf_type_resolve_ptr(btf, id, NULL);
318+
if (!t)
319+
return false;
320+
321+
if (!__btf_type_is_struct(t) && !btf_type_is_fwd(t))
322+
return false;
323+
324+
return !strcmp(btf_name_by_offset(btf, t->name_off), "module");
325+
}
326+
313327
int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
314328
struct btf *btf,
315329
struct bpf_verifier_log *log)
@@ -389,6 +403,13 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
389403
goto errout;
390404
}
391405

406+
if (!st_ops_ids[IDX_MODULE_ID] && is_module_member(btf, member->type)) {
407+
pr_warn("'struct module' btf id not found. Is CONFIG_MODULES enabled? bpf_struct_ops '%s' needs module support.\n",
408+
st_ops->name);
409+
err = -EOPNOTSUPP;
410+
goto errout;
411+
}
412+
392413
func_proto = btf_type_resolve_func_ptr(btf,
393414
member->type,
394415
NULL);

kernel/bpf/btf.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,6 @@ bool btf_type_is_void(const struct btf_type *t)
498498
return t == &btf_void;
499499
}
500500

501-
static bool btf_type_is_fwd(const struct btf_type *t)
502-
{
503-
return BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
504-
}
505-
506501
static bool btf_type_is_datasec(const struct btf_type *t)
507502
{
508503
return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;

0 commit comments

Comments
 (0)