Skip to content

Commit 03865dd

Browse files
ISCAS-Vulablag-linaro
authored andcommitted
leds: netxbig: Fix GPIO descriptor leak in error paths
The function netxbig_gpio_ext_get() acquires GPIO descriptors but fails to release them when errors occur mid-way through initialization. The cleanup callback registered by devm_add_action_or_reset() only runs on success, leaving acquired GPIOs leaked on error paths. Add goto-based error handling to release all acquired GPIOs before returning errors. Fixes: 9af512e ("leds: netxbig: Convert to use GPIO descriptors") Suggested-by: Markus Elfring <Markus.Elfring@web.de> Signed-off-by: Haotian Zhang <vulab@iscas.ac.cn> Link: https://patch.msgid.link/20251031021620.781-1-vulab@iscas.ac.cn Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 4349596 commit 03865dd

1 file changed

Lines changed: 26 additions & 10 deletions

File tree

drivers/leds/leds-netxbig.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ static int netxbig_gpio_ext_get(struct device *dev,
364364
if (!addr)
365365
return -ENOMEM;
366366

367+
gpio_ext->addr = addr;
368+
gpio_ext->num_addr = 0;
369+
367370
/*
368371
* We cannot use devm_ managed resources with these GPIO descriptors
369372
* since they are associated with the "GPIO extension device" which
@@ -375,45 +378,58 @@ static int netxbig_gpio_ext_get(struct device *dev,
375378
gpiod = gpiod_get_index(gpio_ext_dev, "addr", i,
376379
GPIOD_OUT_LOW);
377380
if (IS_ERR(gpiod))
378-
return PTR_ERR(gpiod);
381+
goto err_set_code;
379382
gpiod_set_consumer_name(gpiod, "GPIO extension addr");
380383
addr[i] = gpiod;
384+
gpio_ext->num_addr++;
381385
}
382-
gpio_ext->addr = addr;
383-
gpio_ext->num_addr = num_addr;
384386

385387
ret = gpiod_count(gpio_ext_dev, "data");
386388
if (ret < 0) {
387389
dev_err(dev,
388390
"Failed to count GPIOs in DT property data-gpios\n");
389-
return ret;
391+
goto err_free_addr;
390392
}
391393
num_data = ret;
392394
data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL);
393-
if (!data)
394-
return -ENOMEM;
395+
if (!data) {
396+
ret = -ENOMEM;
397+
goto err_free_addr;
398+
}
399+
400+
gpio_ext->data = data;
401+
gpio_ext->num_data = 0;
395402

396403
for (i = 0; i < num_data; i++) {
397404
gpiod = gpiod_get_index(gpio_ext_dev, "data", i,
398405
GPIOD_OUT_LOW);
399406
if (IS_ERR(gpiod))
400-
return PTR_ERR(gpiod);
407+
goto err_free_data;
401408
gpiod_set_consumer_name(gpiod, "GPIO extension data");
402409
data[i] = gpiod;
410+
gpio_ext->num_data++;
403411
}
404-
gpio_ext->data = data;
405-
gpio_ext->num_data = num_data;
406412

407413
gpiod = gpiod_get(gpio_ext_dev, "enable", GPIOD_OUT_LOW);
408414
if (IS_ERR(gpiod)) {
409415
dev_err(dev,
410416
"Failed to get GPIO from DT property enable-gpio\n");
411-
return PTR_ERR(gpiod);
417+
goto err_free_data;
412418
}
413419
gpiod_set_consumer_name(gpiod, "GPIO extension enable");
414420
gpio_ext->enable = gpiod;
415421

416422
return devm_add_action_or_reset(dev, netxbig_gpio_ext_remove, gpio_ext);
423+
424+
err_free_data:
425+
for (i = 0; i < gpio_ext->num_data; i++)
426+
gpiod_put(gpio_ext->data[i]);
427+
err_set_code:
428+
ret = PTR_ERR(gpiod);
429+
err_free_addr:
430+
for (i = 0; i < gpio_ext->num_addr; i++)
431+
gpiod_put(gpio_ext->addr[i]);
432+
return ret;
417433
}
418434

419435
static int netxbig_leds_get_of_pdata(struct device *dev,

0 commit comments

Comments
 (0)