Skip to content

Commit 5a3e85c

Browse files
Mukesh Ojhalinusw
authored andcommitted
pinmux: Use sequential access to access desc->pinmux data
When two client of the same gpio call pinctrl_select_state() for the same functionality, we are seeing NULL pointer issue while accessing desc->mux_owner. Let's say two processes A, B executing in pin_request() for the same pin and process A updates the desc->mux_usecount but not yet updated the desc->mux_owner while process B see the desc->mux_usecount which got updated by A path and further executes strcmp and while accessing desc->mux_owner it crashes with NULL pointer. Serialize the access to mux related setting with a mutex lock. cpu0 (process A) cpu1(process B) pinctrl_select_state() { pinctrl_select_state() { pin_request() { pin_request() { ... .... } else { desc->mux_usecount++; desc->mux_usecount && strcmp(desc->mux_owner, owner)) { if (desc->mux_usecount > 1) return 0; desc->mux_owner = owner; } } Signed-off-by: Mukesh Ojha <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Linus Walleij <[email protected]>
1 parent 56c9d1a commit 5a3e85c

File tree

3 files changed

+100
-77
lines changed

3 files changed

+100
-77
lines changed

drivers/pinctrl/core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
220220

221221
/* Set owner */
222222
pindesc->pctldev = pctldev;
223+
#ifdef CONFIG_PINMUX
224+
mutex_init(&pindesc->mux_lock);
225+
#endif
223226

224227
/* Copy basic pin info */
225228
if (pin->name) {

drivers/pinctrl/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ struct pin_desc {
177177
const char *mux_owner;
178178
const struct pinctrl_setting_mux *mux_setting;
179179
const char *gpio_owner;
180+
struct mutex mux_lock;
180181
#endif
181182
};
182183

drivers/pinctrl/pinmux.c

Lines changed: 96 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <linux/array_size.h>
1616
#include <linux/ctype.h>
17+
#include <linux/cleanup.h>
1718
#include <linux/debugfs.h>
1819
#include <linux/device.h>
1920
#include <linux/err.h>
@@ -93,6 +94,7 @@ bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned int pin)
9394
if (!desc || !ops)
9495
return true;
9596

97+
guard(mutex)(&desc->mux_lock);
9698
if (ops->strict && desc->mux_usecount)
9799
return false;
98100

@@ -127,29 +129,31 @@ static int pin_request(struct pinctrl_dev *pctldev,
127129
dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
128130
pin, desc->name, owner);
129131

130-
if ((!gpio_range || ops->strict) &&
131-
desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
132-
dev_err(pctldev->dev,
133-
"pin %s already requested by %s; cannot claim for %s\n",
134-
desc->name, desc->mux_owner, owner);
135-
goto out;
136-
}
132+
scoped_guard(mutex, &desc->mux_lock) {
133+
if ((!gpio_range || ops->strict) &&
134+
desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
135+
dev_err(pctldev->dev,
136+
"pin %s already requested by %s; cannot claim for %s\n",
137+
desc->name, desc->mux_owner, owner);
138+
goto out;
139+
}
137140

138-
if ((gpio_range || ops->strict) && desc->gpio_owner) {
139-
dev_err(pctldev->dev,
140-
"pin %s already requested by %s; cannot claim for %s\n",
141-
desc->name, desc->gpio_owner, owner);
142-
goto out;
143-
}
141+
if ((gpio_range || ops->strict) && desc->gpio_owner) {
142+
dev_err(pctldev->dev,
143+
"pin %s already requested by %s; cannot claim for %s\n",
144+
desc->name, desc->gpio_owner, owner);
145+
goto out;
146+
}
144147

145-
if (gpio_range) {
146-
desc->gpio_owner = owner;
147-
} else {
148-
desc->mux_usecount++;
149-
if (desc->mux_usecount > 1)
150-
return 0;
148+
if (gpio_range) {
149+
desc->gpio_owner = owner;
150+
} else {
151+
desc->mux_usecount++;
152+
if (desc->mux_usecount > 1)
153+
return 0;
151154

152-
desc->mux_owner = owner;
155+
desc->mux_owner = owner;
156+
}
153157
}
154158

155159
/* Let each pin increase references to this module */
@@ -178,12 +182,14 @@ static int pin_request(struct pinctrl_dev *pctldev,
178182

179183
out_free_pin:
180184
if (status) {
181-
if (gpio_range) {
182-
desc->gpio_owner = NULL;
183-
} else {
184-
desc->mux_usecount--;
185-
if (!desc->mux_usecount)
186-
desc->mux_owner = NULL;
185+
scoped_guard(mutex, &desc->mux_lock) {
186+
if (gpio_range) {
187+
desc->gpio_owner = NULL;
188+
} else {
189+
desc->mux_usecount--;
190+
if (!desc->mux_usecount)
191+
desc->mux_owner = NULL;
192+
}
187193
}
188194
}
189195
out:
@@ -219,15 +225,17 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
219225
return NULL;
220226
}
221227

222-
if (!gpio_range) {
223-
/*
224-
* A pin should not be freed more times than allocated.
225-
*/
226-
if (WARN_ON(!desc->mux_usecount))
227-
return NULL;
228-
desc->mux_usecount--;
229-
if (desc->mux_usecount)
230-
return NULL;
228+
scoped_guard(mutex, &desc->mux_lock) {
229+
if (!gpio_range) {
230+
/*
231+
* A pin should not be freed more times than allocated.
232+
*/
233+
if (WARN_ON(!desc->mux_usecount))
234+
return NULL;
235+
desc->mux_usecount--;
236+
if (desc->mux_usecount)
237+
return NULL;
238+
}
231239
}
232240

233241
/*
@@ -239,13 +247,15 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
239247
else if (ops->free)
240248
ops->free(pctldev, pin);
241249

242-
if (gpio_range) {
243-
owner = desc->gpio_owner;
244-
desc->gpio_owner = NULL;
245-
} else {
246-
owner = desc->mux_owner;
247-
desc->mux_owner = NULL;
248-
desc->mux_setting = NULL;
250+
scoped_guard(mutex, &desc->mux_lock) {
251+
if (gpio_range) {
252+
owner = desc->gpio_owner;
253+
desc->gpio_owner = NULL;
254+
} else {
255+
owner = desc->mux_owner;
256+
desc->mux_owner = NULL;
257+
desc->mux_setting = NULL;
258+
}
249259
}
250260

251261
module_put(pctldev->owner);
@@ -458,7 +468,8 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting)
458468
pins[i]);
459469
continue;
460470
}
461-
desc->mux_setting = &(setting->data.mux);
471+
scoped_guard(mutex, &desc->mux_lock)
472+
desc->mux_setting = &(setting->data.mux);
462473
}
463474

464475
ret = ops->set_mux(pctldev, setting->data.mux.func,
@@ -472,8 +483,10 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting)
472483
err_set_mux:
473484
for (i = 0; i < num_pins; i++) {
474485
desc = pin_desc_get(pctldev, pins[i]);
475-
if (desc)
476-
desc->mux_setting = NULL;
486+
if (desc) {
487+
scoped_guard(mutex, &desc->mux_lock)
488+
desc->mux_setting = NULL;
489+
}
477490
}
478491
err_pin_request:
479492
/* On error release all taken pins */
@@ -492,6 +505,7 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting)
492505
unsigned int num_pins = 0;
493506
int i;
494507
struct pin_desc *desc;
508+
bool is_equal;
495509

496510
if (pctlops->get_group_pins)
497511
ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
@@ -517,7 +531,10 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting)
517531
pins[i]);
518532
continue;
519533
}
520-
if (desc->mux_setting == &(setting->data.mux)) {
534+
scoped_guard(mutex, &desc->mux_lock)
535+
is_equal = (desc->mux_setting == &(setting->data.mux));
536+
537+
if (is_equal) {
521538
pin_free(pctldev, pins[i], NULL);
522539
} else {
523540
const char *gname;
@@ -608,40 +625,42 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
608625
if (desc == NULL)
609626
continue;
610627

611-
if (desc->mux_owner &&
612-
!strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev)))
613-
is_hog = true;
614-
615-
if (pmxops->strict) {
616-
if (desc->mux_owner)
617-
seq_printf(s, "pin %d (%s): device %s%s",
618-
pin, desc->name, desc->mux_owner,
628+
scoped_guard(mutex, &desc->mux_lock) {
629+
if (desc->mux_owner &&
630+
!strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev)))
631+
is_hog = true;
632+
633+
if (pmxops->strict) {
634+
if (desc->mux_owner)
635+
seq_printf(s, "pin %d (%s): device %s%s",
636+
pin, desc->name, desc->mux_owner,
637+
is_hog ? " (HOG)" : "");
638+
else if (desc->gpio_owner)
639+
seq_printf(s, "pin %d (%s): GPIO %s",
640+
pin, desc->name, desc->gpio_owner);
641+
else
642+
seq_printf(s, "pin %d (%s): UNCLAIMED",
643+
pin, desc->name);
644+
} else {
645+
/* For non-strict controllers */
646+
seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name,
647+
desc->mux_owner ? desc->mux_owner
648+
: "(MUX UNCLAIMED)",
649+
desc->gpio_owner ? desc->gpio_owner
650+
: "(GPIO UNCLAIMED)",
619651
is_hog ? " (HOG)" : "");
620-
else if (desc->gpio_owner)
621-
seq_printf(s, "pin %d (%s): GPIO %s",
622-
pin, desc->name, desc->gpio_owner);
652+
}
653+
654+
/* If mux: print function+group claiming the pin */
655+
if (desc->mux_setting)
656+
seq_printf(s, " function %s group %s\n",
657+
pmxops->get_function_name(pctldev,
658+
desc->mux_setting->func),
659+
pctlops->get_group_name(pctldev,
660+
desc->mux_setting->group));
623661
else
624-
seq_printf(s, "pin %d (%s): UNCLAIMED",
625-
pin, desc->name);
626-
} else {
627-
/* For non-strict controllers */
628-
seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name,
629-
desc->mux_owner ? desc->mux_owner
630-
: "(MUX UNCLAIMED)",
631-
desc->gpio_owner ? desc->gpio_owner
632-
: "(GPIO UNCLAIMED)",
633-
is_hog ? " (HOG)" : "");
662+
seq_putc(s, '\n');
634663
}
635-
636-
/* If mux: print function+group claiming the pin */
637-
if (desc->mux_setting)
638-
seq_printf(s, " function %s group %s\n",
639-
pmxops->get_function_name(pctldev,
640-
desc->mux_setting->func),
641-
pctlops->get_group_name(pctldev,
642-
desc->mux_setting->group));
643-
else
644-
seq_putc(s, '\n');
645664
}
646665

647666
mutex_unlock(&pctldev->mutex);

0 commit comments

Comments
 (0)