speakup_kobj_init()'s error path and speakup_kobj_exit() drop the kobject but do not clear the global pointer. When built-in speakup fails late in speakup_init() (e.g. a kthread_create() failure, whose error path runs speakup_kobj_exit()), the dangling speakup_kobj stays behind, and a later insmod of a synth driver feeds it to sysfs_create_group() through synth_add() -> do_synth_init() - a use-after-free. Clear the pointer right after kobject_put(), so the late sysfs_create_group() fails cleanly on its own NULL check. The removal side needs the same guard: when the kobject setup failed, a first insmod of a synth driver fails in do_synth_init() with synth left set (that error path does not roll it back), and a second insmod goes through synth_release(), whose sysfs_remove_group() would now meet speakup_kobj == NULL and crash on the NULL kobject - a crash the NULL clear above would itself introduce. Skip the group removal when the kobject is gone. Fixes: 2067fd92d75b6 ("staging/speakup: Move out of staging") Cc: stable@vger.kernel.org Cc: Samuel Thibault Reviewed-by: Samuel Thibault Signed-off-by: Hongyu Xie --- drivers/accessibility/speakup/kobjects.c | 2 ++ drivers/accessibility/speakup/synth.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/accessibility/speakup/kobjects.c b/drivers/accessibility/speakup/kobjects.c index a73b478e06de..e1860f8d9d42 100644 --- a/drivers/accessibility/speakup/kobjects.c +++ b/drivers/accessibility/speakup/kobjects.c @@ -1041,6 +1041,7 @@ int speakup_kobj_init(void) sysfs_remove_group(speakup_kobj, &main_attr_group); err_speakup: kobject_put(speakup_kobj); + speakup_kobj = NULL; err_acc: kobject_put(accessibility_kobj); out: @@ -1052,5 +1053,6 @@ void speakup_kobj_exit(void) sysfs_remove_group(speakup_kobj, &i18n_attr_group); sysfs_remove_group(speakup_kobj, &main_attr_group); kobject_put(speakup_kobj); + speakup_kobj = NULL; kobject_put(accessibility_kobj); } diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c index 40870949b3c6..1af80eb116af 100644 --- a/drivers/accessibility/speakup/synth.c +++ b/drivers/accessibility/speakup/synth.c @@ -580,7 +580,7 @@ void synth_release(void) wake_up_process(task); rcu_read_unlock(); wait_event(synth_catch_up_waitq, !atomic_read(&synth_catch_up_count)); - if (synth->attributes.name) + if (synth->attributes.name && speakup_kobj) sysfs_remove_group(speakup_kobj, &synth->attributes); for (var = synth->vars; var->var_id != MAXVARS; var++) speakup_unregister_var(var->var_id); -- 2.32.0