Skip to content

Commit 0b075c0

Browse files
mukeshojha-linuxlinusw
authored andcommitted
pinmux: fix race causing mux_owner NULL with active mux_usecount
commit 5a3e85c ("pinmux: Use sequential access to access desc->pinmux data") tried to address the issue when two client of the same gpio calls pinctrl_select_state() for the same functionality, was resulting in NULL pointer issue while accessing desc->mux_owner. However, issue was not completely fixed due to the way it was handled and it can still result in the same NULL pointer. The issue occurs due to the following interleaving: cpu0 (process A) cpu1 (process B) pin_request() { pin_free() { mutex_lock() desc->mux_usecount--; //becomes 0 .. mutex_unlock() mutex_lock(desc->mux) desc->mux_usecount++; // becomes 1 desc->mux_owner = owner; mutex_unlock(desc->mux) mutex_lock(desc->mux) desc->mux_owner = NULL; mutex_unlock(desc->mux) This sequence leads to a state where the pin appears to be in use (`mux_usecount == 1`) but has no owner (`mux_owner == NULL`), which can cause NULL pointer on next pin_request on the same pin. Ensure that updates to mux_usecount and mux_owner are performed atomically under the same lock. Only clear mux_owner when mux_usecount reaches zero and no new owner has been assigned. Fixes: 5a3e85c ("pinmux: Use sequential access to access desc->pinmux data") Signed-off-by: Mukesh Ojha <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Linus Walleij <[email protected]>
1 parent ac51d04 commit 0b075c0

File tree

1 file changed

+9
-11
lines changed

1 file changed

+9
-11
lines changed

drivers/pinctrl/pinmux.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -236,18 +236,7 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
236236
if (desc->mux_usecount)
237237
return NULL;
238238
}
239-
}
240-
241-
/*
242-
* If there is no kind of request function for the pin we just assume
243-
* we got it by default and proceed.
244-
*/
245-
if (gpio_range && ops->gpio_disable_free)
246-
ops->gpio_disable_free(pctldev, gpio_range, pin);
247-
else if (ops->free)
248-
ops->free(pctldev, pin);
249239

250-
scoped_guard(mutex, &desc->mux_lock) {
251240
if (gpio_range) {
252241
owner = desc->gpio_owner;
253242
desc->gpio_owner = NULL;
@@ -258,6 +247,15 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
258247
}
259248
}
260249

250+
/*
251+
* If there is no kind of request function for the pin we just assume
252+
* we got it by default and proceed.
253+
*/
254+
if (gpio_range && ops->gpio_disable_free)
255+
ops->gpio_disable_free(pctldev, gpio_range, pin);
256+
else if (ops->free)
257+
ops->free(pctldev, pin);
258+
261259
module_put(pctldev->owner);
262260

263261
return owner;

0 commit comments

Comments
 (0)