kallsyms: Disable preemption for find_kallsyms_symbol_value
authorJiri Olsa <jolsa@kernel.org>
Mon, 3 Apr 2023 22:02:54 +0000 (00:02 +0200)
committerAndrii Nakryiko <andrii@kernel.org>
Wed, 5 Apr 2023 00:11:59 +0000 (17:11 -0700)
Artem reported suspicious RCU usage [1]. The reason is that verifier
calls find_kallsyms_symbol_value with preemption enabled which will
trigger suspicious RCU usage warning in rcu_dereference_sched call.

Disabling preemption in find_kallsyms_symbol_value and adding
__find_kallsyms_symbol_value function.

Fixes: 31bf1dbccfb0 ("bpf: Fix attaching fentry/fexit/fmod_ret/lsm to modules")
Reported-by: Artem Savkov <asavkov@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Tested-by: Artem Savkov <asavkov@redhat.com>
Reviewed-by: Zhen Lei <thunder.leizhen@huawei.com>
Link: https://lore.kernel.org/bpf/20230403220254.2191240-1-jolsa@kernel.org
[1] https://lore.kernel.org/bpf/ZBrPMkv8YVRiWwCR@samus.usersys.redhat.com/

kernel/module/kallsyms.c

index ab2376a..bdc911d 100644 (file)
@@ -442,7 +442,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 }
 
 /* Given a module and name of symbol, find and return the symbol's value */
-unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
+static unsigned long __find_kallsyms_symbol_value(struct module *mod, const char *name)
 {
        unsigned int i;
        struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
@@ -466,7 +466,7 @@ static unsigned long __module_kallsyms_lookup_name(const char *name)
        if (colon) {
                mod = find_module_all(name, colon - name, false);
                if (mod)
-                       return find_kallsyms_symbol_value(mod, colon + 1);
+                       return __find_kallsyms_symbol_value(mod, colon + 1);
                return 0;
        }
 
@@ -475,7 +475,7 @@ static unsigned long __module_kallsyms_lookup_name(const char *name)
 
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               ret = find_kallsyms_symbol_value(mod, name);
+               ret = __find_kallsyms_symbol_value(mod, name);
                if (ret)
                        return ret;
        }
@@ -494,6 +494,16 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        return ret;
 }
 
+unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
+{
+       unsigned long ret;
+
+       preempt_disable();
+       ret = __find_kallsyms_symbol_value(mod, name);
+       preempt_enable();
+       return ret;
+}
+
 int module_kallsyms_on_each_symbol(const char *modname,
                                   int (*fn)(void *, const char *,
                                             struct module *, unsigned long),