Skip to content

Commit f739a69

Browse files
willdeacongregkh
authored andcommitted
pinctrl: devicetree: Avoid taking direct reference to device name string
[ Upstream commit be4c60b ] When populating the pinctrl mapping table entries for a device, the 'dev_name' field for each entry is initialised to point directly at the string returned by 'dev_name()' for the device and subsequently used by 'create_pinctrl()' when looking up the mappings for the device being probed. This is unreliable in the presence of calls to 'dev_set_name()', which may reallocate the device name string leaving the pinctrl mappings with a dangling reference. This then leads to a use-after-free every time the name is dereferenced by a device probe: | BUG: KASAN: invalid-access in strcmp+0x20/0x64 | Read of size 1 at addr 13ffffc153494b00 by task modprobe/590 | Pointer tag: [13], memory tag: [fe] | | Call trace: | __kasan_report+0x16c/0x1dc | kasan_report+0x10/0x18 | check_memory_region | __hwasan_load1_noabort+0x4c/0x54 | strcmp+0x20/0x64 | create_pinctrl+0x18c/0x7f4 | pinctrl_get+0x90/0x114 | devm_pinctrl_get+0x44/0x98 | pinctrl_bind_pins+0x5c/0x450 | really_probe+0x1c8/0x9a4 | driver_probe_device+0x120/0x1d8 Follow the example of sysfs, and duplicate the device name string before stashing it away in the pinctrl mapping entries. Cc: Linus Walleij <[email protected]> Reported-by: Elena Petrova <[email protected]> Tested-by: Elena Petrova <[email protected]> Signed-off-by: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Linus Walleij <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 19378ed commit f739a69

File tree

1 file changed

+20
-5
lines changed

1 file changed

+20
-5
lines changed

drivers/pinctrl/devicetree.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ struct pinctrl_dt_map {
2929
static void dt_free_map(struct pinctrl_dev *pctldev,
3030
struct pinctrl_map *map, unsigned num_maps)
3131
{
32+
int i;
33+
34+
for (i = 0; i < num_maps; ++i) {
35+
kfree_const(map[i].dev_name);
36+
map[i].dev_name = NULL;
37+
}
38+
3239
if (pctldev) {
3340
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
3441
if (ops->dt_free_map)
@@ -63,25 +70,33 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
6370

6471
/* Initialize common mapping table entry fields */
6572
for (i = 0; i < num_maps; i++) {
66-
map[i].dev_name = dev_name(p->dev);
73+
const char *devname;
74+
75+
devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);
76+
if (!devname)
77+
goto err_free_map;
78+
79+
map[i].dev_name = devname;
6780
map[i].name = statename;
6881
if (pctldev)
6982
map[i].ctrl_dev_name = dev_name(pctldev->dev);
7083
}
7184

7285
/* Remember the converted mapping table entries */
7386
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
74-
if (!dt_map) {
75-
dt_free_map(pctldev, map, num_maps);
76-
return -ENOMEM;
77-
}
87+
if (!dt_map)
88+
goto err_free_map;
7889

7990
dt_map->pctldev = pctldev;
8091
dt_map->map = map;
8192
dt_map->num_maps = num_maps;
8293
list_add_tail(&dt_map->node, &p->dt_maps);
8394

8495
return pinctrl_register_map(map, num_maps, false);
96+
97+
err_free_map:
98+
dt_free_map(pctldev, map, num_maps);
99+
return -ENOMEM;
85100
}
86101

87102
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)

0 commit comments

Comments
 (0)