Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powercap: fix race condition in register_control_type()

The device becomes visible to userspace via device_register()
even before it fully initialized by idr_init(). If userspace
or another thread tries to register a zone immediately after
device_register(), the control_type_valid() will fail because
the control_type is not yet in the list. The IDR is not yet
initialized, so this race condition causes zone registration
failure.

Move idr_init() and list addition before device_register()
fix the race condition.

Signed-off-by: Sumeet Pawnikar <sumeet4linux@gmail.com>
[ rjw: Subject adjustment, empty line added ]
Link: https://patch.msgid.link/20251205190216.5032-1-sumeet4linux@gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Sumeet Pawnikar and committed by
Rafael J. Wysocki
7bda1910 8f0b4cce

+11 -5
+11 -5
drivers/powercap/powercap_sys.c
··· 625 625 INIT_LIST_HEAD(&control_type->node); 626 626 control_type->dev.class = &powercap_class; 627 627 dev_set_name(&control_type->dev, "%s", name); 628 - result = device_register(&control_type->dev); 629 - if (result) { 630 - put_device(&control_type->dev); 631 - return ERR_PTR(result); 632 - } 633 628 idr_init(&control_type->idr); 634 629 635 630 mutex_lock(&powercap_cntrl_list_lock); 636 631 list_add_tail(&control_type->node, &powercap_cntrl_list); 637 632 mutex_unlock(&powercap_cntrl_list_lock); 633 + 634 + result = device_register(&control_type->dev); 635 + if (result) { 636 + mutex_lock(&powercap_cntrl_list_lock); 637 + list_del(&control_type->node); 638 + mutex_unlock(&powercap_cntrl_list_lock); 639 + 640 + idr_destroy(&control_type->idr); 641 + put_device(&control_type->dev); 642 + return ERR_PTR(result); 643 + } 638 644 639 645 return control_type; 640 646 }