Skip to content

Commit 54cecb7

Browse files
goldelicogregkh
authored andcommitted
power: generic-adc-battery: fix out-of-bounds write when copying channel properties
commit 932d474 upstream. We did have sporadic problems in the pinctrl framework during boot where a pin group name unexpectedly became NULL leading to a NULL dereference in strcmp. Detailled analysis of the failing cases did reveal that there were two devm allocated objects close to each other. The second one was the affected group_desc in pinmux and the first one was the psy_desc->properties buffer of the gab driver. Review of the gab code showed that the address calculation for one memcpy() is wrong. It does properties + sizeof(type) * index but C is defined to do the index multiplication already for pointer + integer additions. Hence the factor was applied twice and the memcpy() does write outside of the properties buffer. Sometimes it happened to be the pinctrl and triggered the strcmp(NULL). Anyways, it is overkill to use a memcpy() here instead of a simple assignment, which is easier to read and has less risk for wrong address calculations. So we change code to a simple assignment. If we initialize the index to the first free location, we can even remove the local variable 'properties'. This bug seems to exist right from the beginning in 3.7-rc1 in commit e60fea7 ("power: battery: Generic battery driver using IIO") Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> Cc: stable@vger.kernel.org Fixes: e60fea7 ("power: battery: Generic battery driver using IIO") Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d2a97eb commit 54cecb7

1 file changed

Lines changed: 4 additions & 10 deletions

File tree

drivers/power/supply/generic-adc-battery.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,9 @@ static int gab_probe(struct platform_device *pdev)
243243
struct power_supply_desc *psy_desc;
244244
struct power_supply_config psy_cfg = {};
245245
struct gab_platform_data *pdata = pdev->dev.platform_data;
246-
enum power_supply_property *properties;
247246
int ret = 0;
248247
int chan;
249-
int index = 0;
248+
int index = ARRAY_SIZE(gab_props);
250249

251250
adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL);
252251
if (!adc_bat) {
@@ -280,8 +279,6 @@ static int gab_probe(struct platform_device *pdev)
280279
}
281280

282281
memcpy(psy_desc->properties, gab_props, sizeof(gab_props));
283-
properties = (enum power_supply_property *)
284-
((char *)psy_desc->properties + sizeof(gab_props));
285282

286283
/*
287284
* getting channel from iio and copying the battery properties
@@ -295,15 +292,12 @@ static int gab_probe(struct platform_device *pdev)
295292
adc_bat->channel[chan] = NULL;
296293
} else {
297294
/* copying properties for supported channels only */
298-
memcpy(properties + sizeof(*(psy_desc->properties)) * index,
299-
&gab_dyn_props[chan],
300-
sizeof(gab_dyn_props[chan]));
301-
index++;
295+
psy_desc->properties[index++] = gab_dyn_props[chan];
302296
}
303297
}
304298

305299
/* none of the channels are supported so let's bail out */
306-
if (index == 0) {
300+
if (index == ARRAY_SIZE(gab_props)) {
307301
ret = -ENODEV;
308302
goto second_mem_fail;
309303
}
@@ -314,7 +308,7 @@ static int gab_probe(struct platform_device *pdev)
314308
* as come channels may be not be supported by the device.So
315309
* we need to take care of that.
316310
*/
317-
psy_desc->num_properties = ARRAY_SIZE(gab_props) + index;
311+
psy_desc->num_properties = index;
318312

319313
adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg);
320314
if (IS_ERR(adc_bat->psy)) {

0 commit comments

Comments
 (0)