In 'lookup_or_create_module_kobject()', an internal kobject is created
using 'module_ktype'. So plain 'kobject_put()' causes an attempt to use
an uninitialied completion pointer in 'module_kobject_release()' and
'mod_kobject_put()' should be used instead. But if the driver (e.g. USB
gadget as in this particular case reported by syzkaller) is configured
as compiled-in, THIS_MODULE is NULL and there is no relevant module
object to call the latter against. So introduce an internal wrapper
'__module_kobject_put()' which is expected 'struct module_kobject' and
so fix error handling in 'lookup_or_create_module_kobject()'.

Reported-by: syzbot+7fb8a372e1f6add93...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=7fb8a372e1f6add936dd
Fixes: 1c7777feb0e2 ("kernel: refactor lookup_or_create_module_kobject()")
Signed-off-by: Dmitry Antipov <dmanti...@yandex.ru>
---
 include/linux/module.h |  3 +++
 kernel/module/sysfs.c  | 15 ++++++++++-----
 kernel/params.c        |  3 ++-
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index b3329110d668..2b4ab389c1bc 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -891,6 +891,9 @@ static inline void module_for_each_mod(int(*func)(struct 
module *mod, void *data
 #ifdef CONFIG_SYSFS
 extern struct kset *module_kset;
 extern const struct kobj_type module_ktype;
+void __module_kobject_put(struct module_kobject *mkobj);
+#else /* not CONFIG_SYSFS */
+static inline void __module_kobject_put(struct module_kobject *mkobj) { }
 #endif /* CONFIG_SYSFS */
 
 #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c
index b401ff4b02d2..7519920f4f55 100644
--- a/kernel/module/sysfs.c
+++ b/kernel/module/sysfs.c
@@ -323,11 +323,7 @@ static int module_add_modinfo_attrs(struct module *mod)
 
 static void mod_kobject_put(struct module *mod)
 {
-       DECLARE_COMPLETION_ONSTACK(c);
-
-       mod->mkobj.kobj_completion = &c;
-       kobject_put(&mod->mkobj.kobj);
-       wait_for_completion(&c);
+       __module_kobject_put(&mod->mkobj);
 }
 
 static int mod_sysfs_init(struct module *mod)
@@ -362,6 +358,15 @@ static int mod_sysfs_init(struct module *mod)
        return err;
 }
 
+void __module_kobject_put(struct module_kobject *mkobj)
+{
+       DECLARE_COMPLETION_ONSTACK(c);
+
+       mkobj->kobj_completion = &c;
+       kobject_put(&mkobj->kobj);
+       wait_for_completion(&c);
+}
+
 int mod_sysfs_setup(struct module *mod,
                    const struct load_info *info,
                           struct kernel_param *kparam,
diff --git a/kernel/params.c b/kernel/params.c
index e668fc90b83e..2cf1f17840e0 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -780,7 +780,8 @@ struct module_kobject __modinit * 
lookup_or_create_module_kobject(const char *na
        if (IS_ENABLED(CONFIG_MODULES) && !err)
                err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
        if (err) {
-               kobject_put(&mk->kobj);
+               /* Not 'mod_kobject_put()' because THIS_MODULE may be NULL. */
+               __module_kobject_put(mk);
                pr_crit("Adding module '%s' to sysfs failed (%d), the system 
may be unstable.\n",
                        name, err);
                return NULL;
-- 
2.49.0


Reply via email to