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

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 <quic_mojha@quicinc.com>
Link: https://lore.kernel.org/20241014192930.1539673-1-quic_mojha@quicinc.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Mukesh Ojha and committed by
Linus Walleij
5a3e85c3 56c9d1a0

+100 -77
+3
drivers/pinctrl/core.c
··· 220 220 221 221 /* Set owner */ 222 222 pindesc->pctldev = pctldev; 223 + #ifdef CONFIG_PINMUX 224 + mutex_init(&pindesc->mux_lock); 225 + #endif 223 226 224 227 /* Copy basic pin info */ 225 228 if (pin->name) {
+1
drivers/pinctrl/core.h
··· 177 177 const char *mux_owner; 178 178 const struct pinctrl_setting_mux *mux_setting; 179 179 const char *gpio_owner; 180 + struct mutex mux_lock; 180 181 #endif 181 182 }; 182 183
+96 -77
drivers/pinctrl/pinmux.c
··· 14 14 15 15 #include <linux/array_size.h> 16 16 #include <linux/ctype.h> 17 + #include <linux/cleanup.h> 17 18 #include <linux/debugfs.h> 18 19 #include <linux/device.h> 19 20 #include <linux/err.h> ··· 94 93 if (!desc || !ops) 95 94 return true; 96 95 96 + guard(mutex)(&desc->mux_lock); 97 97 if (ops->strict && desc->mux_usecount) 98 98 return false; 99 99 ··· 129 127 dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", 130 128 pin, desc->name, owner); 131 129 132 - if ((!gpio_range || ops->strict) && 133 - desc->mux_usecount && strcmp(desc->mux_owner, owner)) { 134 - dev_err(pctldev->dev, 135 - "pin %s already requested by %s; cannot claim for %s\n", 136 - desc->name, desc->mux_owner, owner); 137 - goto out; 138 - } 130 + scoped_guard(mutex, &desc->mux_lock) { 131 + if ((!gpio_range || ops->strict) && 132 + desc->mux_usecount && strcmp(desc->mux_owner, owner)) { 133 + dev_err(pctldev->dev, 134 + "pin %s already requested by %s; cannot claim for %s\n", 135 + desc->name, desc->mux_owner, owner); 136 + goto out; 137 + } 139 138 140 - if ((gpio_range || ops->strict) && desc->gpio_owner) { 141 - dev_err(pctldev->dev, 142 - "pin %s already requested by %s; cannot claim for %s\n", 143 - desc->name, desc->gpio_owner, owner); 144 - goto out; 145 - } 139 + if ((gpio_range || ops->strict) && desc->gpio_owner) { 140 + dev_err(pctldev->dev, 141 + "pin %s already requested by %s; cannot claim for %s\n", 142 + desc->name, desc->gpio_owner, owner); 143 + goto out; 144 + } 146 145 147 - if (gpio_range) { 148 - desc->gpio_owner = owner; 149 - } else { 150 - desc->mux_usecount++; 151 - if (desc->mux_usecount > 1) 152 - return 0; 146 + if (gpio_range) { 147 + desc->gpio_owner = owner; 148 + } else { 149 + desc->mux_usecount++; 150 + if (desc->mux_usecount > 1) 151 + return 0; 153 152 154 - desc->mux_owner = owner; 153 + desc->mux_owner = owner; 154 + } 155 155 } 156 156 157 157 /* Let each pin increase references to this module */ ··· 182 178 183 179 out_free_pin: 184 180 if (status) { 185 - if (gpio_range) { 186 - desc->gpio_owner = NULL; 187 - } else { 188 - desc->mux_usecount--; 189 - if (!desc->mux_usecount) 190 - desc->mux_owner = NULL; 181 + scoped_guard(mutex, &desc->mux_lock) { 182 + if (gpio_range) { 183 + desc->gpio_owner = NULL; 184 + } else { 185 + desc->mux_usecount--; 186 + if (!desc->mux_usecount) 187 + desc->mux_owner = NULL; 188 + } 191 189 } 192 190 } 193 191 out: ··· 225 219 return NULL; 226 220 } 227 221 228 - if (!gpio_range) { 229 - /* 230 - * A pin should not be freed more times than allocated. 231 - */ 232 - if (WARN_ON(!desc->mux_usecount)) 233 - return NULL; 234 - desc->mux_usecount--; 235 - if (desc->mux_usecount) 236 - return NULL; 222 + scoped_guard(mutex, &desc->mux_lock) { 223 + if (!gpio_range) { 224 + /* 225 + * A pin should not be freed more times than allocated. 226 + */ 227 + if (WARN_ON(!desc->mux_usecount)) 228 + return NULL; 229 + desc->mux_usecount--; 230 + if (desc->mux_usecount) 231 + return NULL; 232 + } 237 233 } 238 234 239 235 /* ··· 247 239 else if (ops->free) 248 240 ops->free(pctldev, pin); 249 241 250 - if (gpio_range) { 251 - owner = desc->gpio_owner; 252 - desc->gpio_owner = NULL; 253 - } else { 254 - owner = desc->mux_owner; 255 - desc->mux_owner = NULL; 256 - desc->mux_setting = NULL; 242 + scoped_guard(mutex, &desc->mux_lock) { 243 + if (gpio_range) { 244 + owner = desc->gpio_owner; 245 + desc->gpio_owner = NULL; 246 + } else { 247 + owner = desc->mux_owner; 248 + desc->mux_owner = NULL; 249 + desc->mux_setting = NULL; 250 + } 257 251 } 258 252 259 253 module_put(pctldev->owner); ··· 468 458 pins[i]); 469 459 continue; 470 460 } 471 - desc->mux_setting = &(setting->data.mux); 461 + scoped_guard(mutex, &desc->mux_lock) 462 + desc->mux_setting = &(setting->data.mux); 472 463 } 473 464 474 465 ret = ops->set_mux(pctldev, setting->data.mux.func, ··· 483 472 err_set_mux: 484 473 for (i = 0; i < num_pins; i++) { 485 474 desc = pin_desc_get(pctldev, pins[i]); 486 - if (desc) 487 - desc->mux_setting = NULL; 475 + if (desc) { 476 + scoped_guard(mutex, &desc->mux_lock) 477 + desc->mux_setting = NULL; 478 + } 488 479 } 489 480 err_pin_request: 490 481 /* On error release all taken pins */ ··· 505 492 unsigned int num_pins = 0; 506 493 int i; 507 494 struct pin_desc *desc; 495 + bool is_equal; 508 496 509 497 if (pctlops->get_group_pins) 510 498 ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, ··· 531 517 pins[i]); 532 518 continue; 533 519 } 534 - if (desc->mux_setting == &(setting->data.mux)) { 520 + scoped_guard(mutex, &desc->mux_lock) 521 + is_equal = (desc->mux_setting == &(setting->data.mux)); 522 + 523 + if (is_equal) { 535 524 pin_free(pctldev, pins[i], NULL); 536 525 } else { 537 526 const char *gname; ··· 625 608 if (desc == NULL) 626 609 continue; 627 610 628 - if (desc->mux_owner && 629 - !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) 630 - is_hog = true; 611 + scoped_guard(mutex, &desc->mux_lock) { 612 + if (desc->mux_owner && 613 + !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) 614 + is_hog = true; 631 615 632 - if (pmxops->strict) { 633 - if (desc->mux_owner) 634 - seq_printf(s, "pin %d (%s): device %s%s", 635 - pin, desc->name, desc->mux_owner, 616 + if (pmxops->strict) { 617 + if (desc->mux_owner) 618 + seq_printf(s, "pin %d (%s): device %s%s", 619 + pin, desc->name, desc->mux_owner, 620 + is_hog ? " (HOG)" : ""); 621 + else if (desc->gpio_owner) 622 + seq_printf(s, "pin %d (%s): GPIO %s", 623 + pin, desc->name, desc->gpio_owner); 624 + else 625 + seq_printf(s, "pin %d (%s): UNCLAIMED", 626 + pin, desc->name); 627 + } else { 628 + /* For non-strict controllers */ 629 + seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, 630 + desc->mux_owner ? desc->mux_owner 631 + : "(MUX UNCLAIMED)", 632 + desc->gpio_owner ? desc->gpio_owner 633 + : "(GPIO UNCLAIMED)", 636 634 is_hog ? " (HOG)" : ""); 637 - else if (desc->gpio_owner) 638 - seq_printf(s, "pin %d (%s): GPIO %s", 639 - pin, desc->name, desc->gpio_owner); 640 - else 641 - seq_printf(s, "pin %d (%s): UNCLAIMED", 642 - pin, desc->name); 643 - } else { 644 - /* For non-strict controllers */ 645 - seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, 646 - desc->mux_owner ? desc->mux_owner 647 - : "(MUX UNCLAIMED)", 648 - desc->gpio_owner ? desc->gpio_owner 649 - : "(GPIO UNCLAIMED)", 650 - is_hog ? " (HOG)" : ""); 651 - } 635 + } 652 636 653 - /* If mux: print function+group claiming the pin */ 654 - if (desc->mux_setting) 655 - seq_printf(s, " function %s group %s\n", 656 - pmxops->get_function_name(pctldev, 657 - desc->mux_setting->func), 658 - pctlops->get_group_name(pctldev, 659 - desc->mux_setting->group)); 660 - else 661 - seq_putc(s, '\n'); 637 + /* If mux: print function+group claiming the pin */ 638 + if (desc->mux_setting) 639 + seq_printf(s, " function %s group %s\n", 640 + pmxops->get_function_name(pctldev, 641 + desc->mux_setting->func), 642 + pctlops->get_group_name(pctldev, 643 + desc->mux_setting->group)); 644 + else 645 + seq_putc(s, '\n'); 646 + } 662 647 } 663 648 664 649 mutex_unlock(&pctldev->mutex);