* [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic
@ 2026-07-23 21:13 Guenter Roeck
2026-07-23 21:25 ` sashiko-bot
2026-07-23 21:32 ` Vincent Jardin
0 siblings, 2 replies; 3+ messages in thread
From: Guenter Roeck @ 2026-07-23 21:13 UTC (permalink / raw)
To: Hardware Monitoring; +Cc: Guenter Roeck, Vincent Jardin
Sashiko reports:
At the start of the loop in pmbus_notify(), the code unconditionally casts
every attribute to a struct sensor_device_attribute:
drivers/hwmon/pmbus/pmbus_core.c:pmbus_notify() {
for (i = 0; i < data->num_attributes; i++) {
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int index = attr->index;
...
}
However, data->group.attrs can contain other types like struct
pmbus_samples_reg or struct pmbus_sensor, which only embed a base
struct device_attribute.
If da is a struct pmbus_samples_reg, dev_attr is the last member. Casting
it to struct sensor_device_attribute and reading the index field appears
to access memory past the end of the allocation, which might trigger a
slab-out-of-bounds read.
Additionally, if da is a struct pmbus_sensor, casting it causes the index
field to overlap with the page, phase, and reg fields. Could this produce
a garbage mask on little-endian systems that spuriously matches the target
reg, page, and flags during an alert?
Fix the problem by using struct sensor_device_attr in struct pmbus_sensor
and struct pmbus_label. Since those attributes never trigger a
notification, set the value of attr->index to -1 for them. Use this value
to distinguish from boolean attributes which _can_ trigger a notification
and use the index field to encode mask, page, and register values.
Fixes: f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
Cc: Vincent Jardin <vjardin@free.fr>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
RFT: Build-tested only
drivers/hwmon/pmbus/pmbus_core.c | 61 +++++++++++++++++++-------------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 0081f16c3a95..42703968f157 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -45,7 +45,7 @@ module_param(wp, int, 0444);
struct pmbus_sensor {
struct pmbus_sensor *next;
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
- struct device_attribute attribute;
+ struct sensor_device_attribute attribute;
u8 page; /* page number */
u8 phase; /* phase number, 0xff for all phases */
u16 reg; /* register */
@@ -68,7 +68,7 @@ struct pmbus_boolean {
struct pmbus_label {
char name[PMBUS_NAME_SIZE]; /* sysfs label name */
- struct device_attribute attribute;
+ struct sensor_device_attribute attribute;
char label[PMBUS_NAME_SIZE]; /* label */
};
#define to_pmbus_label(_attr) \
@@ -1241,7 +1241,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
struct pmbus_data *data = i2c_get_clientdata(client);
s64 val;
@@ -1261,7 +1262,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev->parent);
struct pmbus_data *data = i2c_get_clientdata(client);
- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
s64 val;
int ret;
u16 regval;
@@ -1283,7 +1285,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
static ssize_t pmbus_show_label(struct device *dev,
struct device_attribute *da, char *buf)
{
- struct pmbus_label *label = to_pmbus_label(da);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_label *label = to_pmbus_label(attr);
return sysfs_emit(buf, "%s\n", label->label);
}
@@ -1436,8 +1439,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
bool update, bool readonly,
bool writeonly, bool convert)
{
+ struct sensor_device_attribute *a;
struct pmbus_sensor *sensor;
- struct device_attribute *a;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
@@ -1461,12 +1464,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
sensor->update = update;
sensor->convert = convert;
sensor->data = -ENODATA;
- pmbus_dev_attr_init(a, sensor->name,
- readonly ? 0444 : 0644,
- writeonly ? pmbus_show_zero : pmbus_show_sensor,
- pmbus_set_sensor);
+ pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
+ writeonly ? pmbus_show_zero : pmbus_show_sensor,
+ pmbus_set_sensor, -1);
- if (pmbus_add_attribute(data, &a->attr))
+ if (pmbus_add_attribute(data, &a->dev_attr.attr))
return NULL;
sensor->next = data->sensors;
@@ -1483,8 +1485,8 @@ static int pmbus_add_label(struct pmbus_data *data,
const char *name, int seq,
const char *lstring, int index, int phase)
{
+ struct sensor_device_attribute *a;
struct pmbus_label *label;
- struct device_attribute *a;
label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
if (!label)
@@ -1508,8 +1510,8 @@ static int pmbus_add_label(struct pmbus_data *data,
lstring, index, phase);
}
- pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
- return pmbus_add_attribute(data, &a->attr);
+ pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
+ return pmbus_add_attribute(data, &a->dev_attr.attr);
}
/*
@@ -2397,7 +2399,7 @@ struct pmbus_samples_attr {
struct pmbus_samples_reg {
int page;
struct pmbus_samples_attr *attr;
- struct device_attribute dev_attr;
+ struct sensor_device_attribute attribute;
};
static struct pmbus_samples_attr pmbus_samples_registers[] = {
@@ -2419,14 +2421,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
}
};
-#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
+#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
static ssize_t pmbus_show_samples(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int val;
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_samples_reg *reg = to_samples_reg(attr);
scoped_guard(pmbus_lock, client) {
val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
@@ -2444,7 +2447,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
int ret;
long val;
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_samples_reg *reg = to_samples_reg(attr);
if (kstrtol(buf, 0, &val) < 0)
return -EINVAL;
@@ -2459,6 +2463,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
struct pmbus_samples_attr *attr)
{
+ struct sensor_device_attribute *a;
struct pmbus_samples_reg *reg;
reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
@@ -2468,10 +2473,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
reg->attr = attr;
reg->page = page;
- pmbus_dev_attr_init(®->dev_attr, attr->name, 0644,
- pmbus_show_samples, pmbus_set_samples);
+ a = ®->attribute;
- return pmbus_add_attribute(data, ®->dev_attr.attr);
+ pmbus_attr_init(a, attr->name, 0644,
+ pmbus_show_samples, pmbus_set_samples, -1);
+
+ return pmbus_add_attribute(data, &a->dev_attr.attr);
}
static int pmbus_add_samples_attributes(struct i2c_client *client,
@@ -2979,9 +2986,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int index = attr->index;
- u16 smask = pb_index_to_mask(index);
- u8 spage = pb_index_to_page(index);
- u16 sreg = pb_index_to_reg(index);
+ u16 smask, sreg;
+ u8 spage;
+
+ if (index == -1)
+ continue;
+
+ smask = pb_index_to_mask(index);
+ spage = pb_index_to_page(index);
+ sreg = pb_index_to_reg(index);
if (reg == sreg && page == spage && (smask & flags)) {
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
--
2.45.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic
2026-07-23 21:13 [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic Guenter Roeck
@ 2026-07-23 21:25 ` sashiko-bot
2026-07-23 21:32 ` Vincent Jardin
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-07-23 21:25 UTC (permalink / raw)
To: Guenter Roeck; +Cc: linux-hwmon
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] sysfs_notify and kobject_uevent are called on the wrong kobject (data->dev->kobj instead of data->hwmon_dev->kobj), silently breaking hwmon event notifications.
--
--- Patch [1]: [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic ---
commit 05911e6740d7877a722e1540f907a611d74a3925
Author: Guenter Roeck <linux@roeck-us.net>
hwmon: (pmbus) Fix type confusion in notification logic
This commit fixes a potential slab-out-of-bounds read and garbage mask issue
in pmbus_notify() caused by casting non-sensor attributes to struct
sensor_device_attribute. It introduces a proper sensor_device_attribute
embedded in pmbus_sensor and pmbus_label and initializes their index to -1 so
they can be filtered out during notifications.
> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index 3143b9e0316c4..dfe7e071017d2 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c
[ ... ]
> @@ -2979,9 +2986,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
> struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
> struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> int index = attr->index;
> - u16 smask = pb_index_to_mask(index);
> - u8 spage = pb_index_to_page(index);
> - u16 sreg = pb_index_to_reg(index);
> + u16 smask, sreg;
> + u8 spage;
> +
> + if (index == -1)
> + continue;
> +
> + smask = pb_index_to_mask(index);
> + spage = pb_index_to_page(index);
> + sreg = pb_index_to_reg(index);
>
> if (reg == sreg && page == spage && (smask & flags)) {
> dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
[Severity: High]
This isn't a bug introduced by this patch, but is it intended to notify on
the parent I2C device kobject instead of the hwmon class device?
Looking at the subsequent lines in pmbus_notify() in
drivers/hwmon/pmbus/pmbus_core.c, sysfs_notify() and kobject_uevent() are
called using data->dev->kobj instead of data->hwmon_dev->kobj:
if (reg == sreg && page == spage && (smask & flags)) {
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
flags &= ~smask;
}
Since the hwmon attributes are registered under the hwmon class device, will
this silently fail to wake up userspace applications monitoring these sysfs
files because the target attributes are not on data->dev->kobj?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723211336.3046042-1-linux@roeck-us.net?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic
2026-07-23 21:13 [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic Guenter Roeck
2026-07-23 21:25 ` sashiko-bot
@ 2026-07-23 21:32 ` Vincent Jardin
1 sibling, 0 replies; 3+ messages in thread
From: Vincent Jardin @ 2026-07-23 21:32 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Hardware Monitoring
Hi Guenter,
> Fixes: f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
> Cc: Vincent Jardin <vjardin@free.fr>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> ---
> RFT: Build-tested only
Thanks for providing it so quickly !
Code looks ok. I'll test it with the MPQ8646 using the serie I sent
so I can confirm it.
It'll may take some times since I have to run many tests on a WIP board.
I'll keep you posted,
Vincent
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-23 21:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 21:13 [RFT PATCH] hwmon: (pmbus) Fix type confusion in notification logic Guenter Roeck
2026-07-23 21:25 ` sashiko-bot
2026-07-23 21:32 ` Vincent Jardin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox