]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Reject struct_ops registration that uses module ptr and the module btf_id is...
authorMartin KaFai Lau <martin.lau@kernel.org>
Fri, 20 Dec 2024 20:18:18 +0000 (12:18 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 3 Jan 2025 18:16:46 +0000 (10:16 -0800)
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: 1611603537a4 ("bpf: Create argument information for nullable arguments.")
Reported-by: Robert Morris <rtm@csail.mit.edu>
Closes: https://lore.kernel.org/bpf/74665.1733669976@localhost/
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20241220201818.127152-1-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/btf.h
kernel/bpf/bpf_struct_ops.c
kernel/bpf/btf.c

index 4214e76c916861462e45e98690fcf461c05ca737..2a08a2b55592eedc09188052c1b06dfa6688f241 100644 (file)
@@ -353,6 +353,11 @@ static inline bool btf_type_is_scalar(const struct btf_type *t)
        return btf_type_is_int(t) || btf_type_is_enum(t);
 }
 
+static inline bool btf_type_is_fwd(const struct btf_type *t)
+{
+       return BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
+}
+
 static inline bool btf_type_is_typedef(const struct btf_type *t)
 {
        return BTF_INFO_KIND(t->info) == BTF_KIND_TYPEDEF;
index 606efe32485a985b854aa7e96e1a7f7cfd5057d3..040fb1cd840b653148b0941bf525841494025fcb 100644 (file)
@@ -310,6 +310,20 @@ void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc)
        kfree(arg_info);
 }
 
+static bool is_module_member(const struct btf *btf, u32 id)
+{
+       const struct btf_type *t;
+
+       t = btf_type_resolve_ptr(btf, id, NULL);
+       if (!t)
+               return false;
+
+       if (!__btf_type_is_struct(t) && !btf_type_is_fwd(t))
+               return false;
+
+       return !strcmp(btf_name_by_offset(btf, t->name_off), "module");
+}
+
 int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
                             struct btf *btf,
                             struct bpf_verifier_log *log)
@@ -389,6 +403,13 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
                        goto errout;
                }
 
+               if (!st_ops_ids[IDX_MODULE_ID] && is_module_member(btf, member->type)) {
+                       pr_warn("'struct module' btf id not found. Is CONFIG_MODULES enabled? bpf_struct_ops '%s' needs module support.\n",
+                               st_ops->name);
+                       err = -EOPNOTSUPP;
+                       goto errout;
+               }
+
                func_proto = btf_type_resolve_func_ptr(btf,
                                                       member->type,
                                                       NULL);
index 28246c59e12e21363950d16e6a070e018d6f2f7d..8396ce1d0fba3014fe5af3419502cfde74782466 100644 (file)
@@ -498,11 +498,6 @@ bool btf_type_is_void(const struct btf_type *t)
        return t == &btf_void;
 }
 
-static bool btf_type_is_fwd(const struct btf_type *t)
-{
-       return BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
-}
-
 static bool btf_type_is_datasec(const struct btf_type *t)
 {
        return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;