CVE-2026-45868
Description
In the Linux kernel, the following vulnerability has been resolved:
pinctrl: single: fix refcount leak in pcs_add_gpio_func()
of_parse_phandle_with_args() returns a device_node pointer with refcount incremented in gpiospec.np. The loop iterates through all phandles but never releases the reference, causing a refcount leak on each iteration.
Add of_node_put() calls to release the reference after extracting the needed arguments and on the error path when devm_kzalloc() fails.
This bug was detected by our static analysis tool and verified by my code review.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A refcount leak in the Linux kernel's pinctrl-single driver can lead to a denial of service or memory exhaustion.
Vulnerability
A refcount leak exists in the pcs_add_gpio_func() function of the Linux kernel's pinctrl: single driver. The function calls of_parse_phandle_with_args() which returns a device_node pointer with an incremented reference count in gpiospec.np. The loop iterates through all phandles but never releases this reference, causing a refcount leak on each iteration. This vulnerability affects kernel versions that include the said function prior to the fix commit 5b9e84d27e310f22c4ba45fedbc4f5baf43dd823 [1].
Exploitation
An attacker would need to trigger the vulnerable code path, which requires the ability to cause the kernel to parse device tree phandles via the pinctrl-single driver. This could be achieved by loading a specially crafted device tree or by injecting a malicious GPIO specifier. No special privileges other than the ability to trigger the parsing are required.
Impact
The refcount leak causes memory to be consumed over time, potentially leading to a denial of service (DoS) due to memory exhaustion. The kernel may become unresponsive or crash if the leak accumulates enough references.
Mitigation
The fix is included in the Linux kernel commit 5b9e84d27e310f22c4ba45fedbc4f5baf43dd823, which adds the necessary of_node_put() calls to release the reference after extracting the needed arguments and on the error path when devm_kzalloc() fails [1]. Users should update their kernel to a version containing this commit or apply the patch manually.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
16353353309b0fpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
e2e367e56bacpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
99cc7352156cpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2ee0ee3b6ed14d..4aadafe2c50a52 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1363,6 +1363,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1372,6 +1373,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
191bfd5710d6pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 07bf0904204538..491a46e330b30c 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1368,6 +1368,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1377,6 +1378,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
3e3b28bb0b6dpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0659cd3aa3a5a8..2c5b5ce60248e1 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
7814b1431848pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2218d65a7d842b..a2fb549307adb6 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
456a60d06c09pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0659cd3aa3a5a8..2c5b5ce60248e1 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
5b9e84d27e31pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
e2e367e56bacpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
3e3b28bb0b6dpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0659cd3aa3a5a8..2c5b5ce60248e1 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
456a60d06c09pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0659cd3aa3a5a8..2c5b5ce60248e1 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
5b9e84d27e31pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
99cc7352156cpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2ee0ee3b6ed14d..4aadafe2c50a52 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1363,6 +1363,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1372,6 +1373,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
191bfd5710d6pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 07bf0904204538..491a46e330b30c 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1368,6 +1368,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1377,6 +1378,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
7814b1431848pinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2218d65a7d842b..a2fb549307adb6 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
353353309b0fpinctrl: single: fix refcount leak in pcs_add_gpio_func()
1 file changed · +2 −1
drivers/pinctrl/pinctrl-single.c+2 −1 modifieddiff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 998f23d6c3179e..d85e6c1f632186 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); if (!range) { + of_node_put(gpiospec.np); ret = -ENOMEM; break; } @@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) mutex_lock(&pcs->mutex); list_add_tail(&range->node, &pcs->gpiofuncs); mutex_unlock(&pcs->mutex); + of_node_put(gpiospec.np); } return ret; } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing of_node_put() calls in pcs_add_gpio_func() cause a reference-count leak on each device_node pointer returned by of_parse_phandle_with_args()."
Attack vector
An attacker with the ability to supply a malicious device tree (or to trigger re-parsing of GPIO phandles) can cause the kernel to leak a reference-counted device_node pointer on every iteration of the loop in pcs_add_gpio_func() [patch_id=2661901]. The function calls of_parse_phandle_with_args() which increments the refcount on gpiospec.np, but the original code never called of_node_put() to release it. Repeatedly triggering this code path (e.g., through driver probe or reconfiguration) will exhaust the kernel's device_node reference count, eventually preventing the device node from being freed and potentially leading to resource exhaustion or denial of service.
Affected code
The vulnerable function is pcs_add_gpio_func() in drivers/pinctrl/pinctrl-single.c [patch_id=2661901]. The loop calls of_parse_phandle_with_args() which returns a device_node pointer with an incremented refcount in gpiospec.np, but the original code never called of_node_put() to release it.
What the fix does
The patch adds two of_node_put(gpiospec.np) calls in the function pcs_add_gpio_func() [patch_id=2661901]. The first is placed in the error path when devm_kzalloc() fails, ensuring the reference is released before breaking out of the loop. The second is placed after the GPIO range has been successfully added to the list (after list_add_tail()), releasing the reference on the normal success path. These additions ensure that every reference obtained by of_parse_phandle_with_args() is properly decremented, closing the refcount leak.
Preconditions
- configThe system must use Device Tree (DT) with GPIO phandles that trigger the pcs_add_gpio_func() code path.
- authNo authentication required; the vulnerability is in kernel driver initialization code reachable during device probe.
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- git.kernel.org/stable/c/191bfd5710d6a7f48ba4315d8d3e908dcc15243cnvd
- git.kernel.org/stable/c/353353309b0f7afa407df29e455f9d15b5acc296nvd
- git.kernel.org/stable/c/3e3b28bb0b6ddc521a4fdd1c1ba0d35017a0796bnvd
- git.kernel.org/stable/c/456a60d06c09a92680dc35fabca68024badcc28envd
- git.kernel.org/stable/c/5b9e84d27e310f22c4ba45fedbc4f5baf43dd823nvd
- git.kernel.org/stable/c/7814b1431848854b56717086e2b61bea3c59753dnvd
- git.kernel.org/stable/c/99cc7352156c65201c675f750e0e77c4c73d93f5nvd
- git.kernel.org/stable/c/e2e367e56bacb93ce5ac73f0b3297d5c83d38dd4nvd
News mentions
0No linked articles in our index yet.