mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
hwmon: (hp-wmi-sensors) Avoid global struct mutation
In the HP WMI sensors driver, make_chip_info() assigns a device-managed
memory allocation to a static global structure, resulting in a
use-after-free when the device unbinds.
During hp_wmi_sensors_probe(), make_chip_info() dynamically allocates a
hwmon_channel_info array using devm_kcalloc() and assigns it to the
static global hp_wmi_chip_info.info pointer.
If multiple instances probe sequentially or concurrently, the shared
global pointer is overwritten by each new device. When any device unbinds,
its devm-managed memory is automatically freed, leaving the global
hp_wmi_chip_info struct and any other active device instances with a
dangling pointer. Subsequent accesses by the hwmon core (such as thermal
zone reads) will dereference this freed memory, causing a use-after-free.
While this is not supposed to happen in the real world (there should only
be one instance of the driver in any system), modifying global structures
is undesirable and should be avoided whenever possible. Allocate struct
hwmon_chip_info as part of struct hp_wmi_sensors instead and initialize it
in make_chip_info() to avoid mutating the global structure.
Fixes: 23902f98f8 ("hwmon: add HP WMI Sensors driver")
Cc: stable@vger.kernel.org
Cc: James Seo <james@equiv.tech>
Acked-by: James Seo <james@equiv.tech
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
59d586c9e4
commit
dc992efeac
|
|
@ -390,6 +390,7 @@ struct hp_wmi_info {
|
|||
*/
|
||||
struct hp_wmi_sensors {
|
||||
struct wmi_device *wdev;
|
||||
struct hwmon_chip_info chip_info;
|
||||
struct hp_wmi_info **info_map[hwmon_max];
|
||||
u8 channel_count[hwmon_max];
|
||||
bool has_intrusion;
|
||||
|
|
@ -1531,11 +1532,6 @@ static const struct hwmon_ops hp_wmi_hwmon_ops = {
|
|||
.write = hp_wmi_hwmon_write,
|
||||
};
|
||||
|
||||
static struct hwmon_chip_info hp_wmi_chip_info = {
|
||||
.ops = &hp_wmi_hwmon_ops,
|
||||
.info = NULL,
|
||||
};
|
||||
|
||||
static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
|
||||
const char *event_description)
|
||||
{
|
||||
|
|
@ -1962,7 +1958,8 @@ static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
|
|||
if (!ptr_channel_info)
|
||||
return -ENOMEM;
|
||||
|
||||
hp_wmi_chip_info.info = ptr_channel_info;
|
||||
state->chip_info.ops = &hp_wmi_hwmon_ops;
|
||||
state->chip_info.info = ptr_channel_info;
|
||||
|
||||
for (type = hwmon_chip; type < hwmon_max; type++) {
|
||||
count = channel_count[type];
|
||||
|
|
@ -2053,7 +2050,7 @@ static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
|
|||
return err;
|
||||
|
||||
hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
|
||||
state, &hp_wmi_chip_info,
|
||||
state, &state->chip_info,
|
||||
NULL);
|
||||
return PTR_ERR_OR_ZERO(hwdev);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user