summaryrefslogtreecommitdiff
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2023-09-20 21:09:10 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-10-20 00:08:57 +0300
commit97306abdeaca8b75cae44e0eca928c78d72dadbd (patch)
treede0b08dcbe1f815350649f26be11e720fef3cbc9 /drivers/pinctrl
parentd67b5a2b97b6e8959117ff71fc2daa30e66c8290 (diff)
downloadlinux-97306abdeaca8b75cae44e0eca928c78d72dadbd.tar.xz
pinctrl: avoid unsafe code pattern in find_pinctrl()
commit c153a4edff6ab01370fcac8e46f9c89cca1060c2 upstream. The code in find_pinctrl() takes a mutex and traverses a list of pinctrl structures. Later the caller bumps up reference count on the found structure. Such pattern is not safe as pinctrl that was found may get deleted before the caller gets around to increasing the reference count. Fix this by taking the reference count in find_pinctrl(), while it still holds the mutex. Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Link: https://lore.kernel.org/r/ZQs1RgTKg6VJqmPs@google.com Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/core.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 9e57f4c62e60..27e41873c04f 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1007,17 +1007,20 @@ static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
static struct pinctrl *find_pinctrl(struct device *dev)
{
- struct pinctrl *p;
+ struct pinctrl *entry, *p = NULL;
mutex_lock(&pinctrl_list_mutex);
- list_for_each_entry(p, &pinctrl_list, node)
- if (p->dev == dev) {
- mutex_unlock(&pinctrl_list_mutex);
- return p;
+
+ list_for_each_entry(entry, &pinctrl_list, node) {
+ if (entry->dev == dev) {
+ p = entry;
+ kref_get(&p->users);
+ break;
}
+ }
mutex_unlock(&pinctrl_list_mutex);
- return NULL;
+ return p;
}
static void pinctrl_free(struct pinctrl *p, bool inlist);
@@ -1126,7 +1129,6 @@ struct pinctrl *pinctrl_get(struct device *dev)
p = find_pinctrl(dev);
if (p) {
dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
- kref_get(&p->users);
return p;
}