]> git.itanic.dy.fi Git - linux-stable/commitdiff
driver core: class: properly reference count class_dev_iter()
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 May 2023 19:20:14 +0000 (21:20 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 May 2023 10:03:36 +0000 (11:03 +0100)
When class_dev_iter is initialized, the reference count for the subsys
private structure is incremented, but never decremented, causing a
memory leak over time.  To resolve this, save off a pointer to the
internal structure into the class_dev_iter structure and then when the
iterator is finished, drop the reference count.

Reported-and-tested-by: syzbot+e7afd76ad060fa0d2605@syzkaller.appspotmail.com
Fixes: 7b884b7f24b4 ("driver core: class.c: convert to only use class_to_subsys")
Reported-by: Mirsad Goran Todorovac <mirsad.todorovac@alu.unizg.hr>
Cc: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Rafael J. Wysocki <rafael@kernel.org>
Tested-by: Mirsad Goran Todorovac <mirsad.todorovac@alu.unizg.hr>
Link: https://lore.kernel.org/r/2023051610-stove-condense-9a77@gregkh
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/class.c
include/linux/device/class.h

index ac1808d1a2e8f0012beb816b97a7101b048b688c..05d9df90f621be89cdbd7d1ecee888c18a6b688b 100644 (file)
@@ -320,6 +320,7 @@ void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class,
                start_knode = &start->p->knode_class;
        klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode);
        iter->type = type;
+       iter->sp = sp;
 }
 EXPORT_SYMBOL_GPL(class_dev_iter_init);
 
@@ -361,6 +362,7 @@ EXPORT_SYMBOL_GPL(class_dev_iter_next);
 void class_dev_iter_exit(struct class_dev_iter *iter)
 {
        klist_iter_exit(&iter->ki);
+       subsys_put(iter->sp);
 }
 EXPORT_SYMBOL_GPL(class_dev_iter_exit);
 
index 9deeaeb457bbaa504fffbf71c8b368ca4da3034f..abf3d3bfb6fe4dc3f29e26c599a8b18a676793ba 100644 (file)
@@ -74,6 +74,7 @@ struct class {
 struct class_dev_iter {
        struct klist_iter               ki;
        const struct device_type        *type;
+       struct subsys_private           *sp;
 };
 
 int __must_check class_register(const struct class *class);