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

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: 9af512e81964 ("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>

authored by

Haotian Zhang and committed by
Lee Jones
03865dd8 43495961

+26 -10
+26 -10
drivers/leds/leds-netxbig.c
··· 364 364 if (!addr) 365 365 return -ENOMEM; 366 366 367 + gpio_ext->addr = addr; 368 + gpio_ext->num_addr = 0; 369 + 367 370 /* 368 371 * We cannot use devm_ managed resources with these GPIO descriptors 369 372 * since they are associated with the "GPIO extension device" which ··· 378 375 gpiod = gpiod_get_index(gpio_ext_dev, "addr", i, 379 376 GPIOD_OUT_LOW); 380 377 if (IS_ERR(gpiod)) 381 - return PTR_ERR(gpiod); 378 + goto err_set_code; 382 379 gpiod_set_consumer_name(gpiod, "GPIO extension addr"); 383 380 addr[i] = gpiod; 381 + gpio_ext->num_addr++; 384 382 } 385 - gpio_ext->addr = addr; 386 - gpio_ext->num_addr = num_addr; 387 383 388 384 ret = gpiod_count(gpio_ext_dev, "data"); 389 385 if (ret < 0) { 390 386 dev_err(dev, 391 387 "Failed to count GPIOs in DT property data-gpios\n"); 392 - return ret; 388 + goto err_free_addr; 393 389 } 394 390 num_data = ret; 395 391 data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL); 396 - if (!data) 397 - return -ENOMEM; 392 + if (!data) { 393 + ret = -ENOMEM; 394 + goto err_free_addr; 395 + } 396 + 397 + gpio_ext->data = data; 398 + gpio_ext->num_data = 0; 398 399 399 400 for (i = 0; i < num_data; i++) { 400 401 gpiod = gpiod_get_index(gpio_ext_dev, "data", i, 401 402 GPIOD_OUT_LOW); 402 403 if (IS_ERR(gpiod)) 403 - return PTR_ERR(gpiod); 404 + goto err_free_data; 404 405 gpiod_set_consumer_name(gpiod, "GPIO extension data"); 405 406 data[i] = gpiod; 407 + gpio_ext->num_data++; 406 408 } 407 - gpio_ext->data = data; 408 - gpio_ext->num_data = num_data; 409 409 410 410 gpiod = gpiod_get(gpio_ext_dev, "enable", GPIOD_OUT_LOW); 411 411 if (IS_ERR(gpiod)) { 412 412 dev_err(dev, 413 413 "Failed to get GPIO from DT property enable-gpio\n"); 414 - return PTR_ERR(gpiod); 414 + goto err_free_data; 415 415 } 416 416 gpiod_set_consumer_name(gpiod, "GPIO extension enable"); 417 417 gpio_ext->enable = gpiod; 418 418 419 419 return devm_add_action_or_reset(dev, netxbig_gpio_ext_remove, gpio_ext); 420 + 421 + err_free_data: 422 + for (i = 0; i < gpio_ext->num_data; i++) 423 + gpiod_put(gpio_ext->data[i]); 424 + err_set_code: 425 + ret = PTR_ERR(gpiod); 426 + err_free_addr: 427 + for (i = 0; i < gpio_ext->num_addr; i++) 428 + gpiod_put(gpio_ext->addr[i]); 429 + return ret; 420 430 } 421 431 422 432 static int netxbig_leds_get_of_pdata(struct device *dev,