On 5/6/25 13:17, Dmitry Antipov wrote:
> 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()")

I think this specific commit is harmless, rather the underlying problem
was introduced already in 942e443127e9 ("module: Fix mod->mkobj.kobj
potentially freed too early"). Commit f95bbfe18512 ("drivers: base:
handle module_kobject creation") now allowed the problematic code to be
reached by more paths and enabled syzkaller to find it.

> [...]
> 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;

This looks as a valid fix, but I wonder if it wouldn't be simpler to
have module_kobj_release() check if mk->kobj_completion is NULL.

-- 
Thanks,
Petr

Reply via email to