]>
Commit | Line | Data |
---|---|---|
12eb7899 GKH |
1 | From foo@baz Thu Oct 4 12:38:43 PDT 2018 |
2 | From: Vincent Whitchurch <vincent.whitchurch@axis.com> | |
3 | Date: Fri, 31 Aug 2018 09:04:18 +0200 | |
4 | Subject: gpio: Fix crash due to registration race | |
5 | ||
6 | From: Vincent Whitchurch <vincent.whitchurch@axis.com> | |
7 | ||
8 | [ Upstream commit d49b48f088c323dbacae44dfbe56d9c985c8a2a1 ] | |
9 | ||
10 | gpiochip_add_data_with_key() adds the gpiochip to the gpio_devices list | |
11 | before of_gpiochip_add() is called, but it's only the latter which sets | |
12 | the ->of_xlate function pointer. gpiochip_find() can be called by | |
13 | someone else between these two actions, and it can find the chip and | |
14 | call of_gpiochip_match_node_and_xlate() which leads to the following | |
15 | crash due to a NULL ->of_xlate(). | |
16 | ||
17 | Unhandled prefetch abort: page domain fault (0x01b) at 0x00000000 | |
18 | Modules linked in: leds_gpio(+) gpio_generic(+) | |
19 | CPU: 0 PID: 830 Comm: insmod Not tainted 4.18.0+ #43 | |
20 | Hardware name: ARM-Versatile Express | |
21 | PC is at (null) | |
22 | LR is at of_gpiochip_match_node_and_xlate+0x2c/0x38 | |
23 | Process insmod (pid: 830, stack limit = 0x(ptrval)) | |
24 | (of_gpiochip_match_node_and_xlate) from (gpiochip_find+0x48/0x84) | |
25 | (gpiochip_find) from (of_get_named_gpiod_flags+0xa8/0x238) | |
26 | (of_get_named_gpiod_flags) from (gpiod_get_from_of_node+0x2c/0xc8) | |
27 | (gpiod_get_from_of_node) from (devm_fwnode_get_index_gpiod_from_child+0xb8/0x144) | |
28 | (devm_fwnode_get_index_gpiod_from_child) from (gpio_led_probe+0x208/0x3c4 [leds_gpio]) | |
29 | (gpio_led_probe [leds_gpio]) from (platform_drv_probe+0x48/0x9c) | |
30 | (platform_drv_probe) from (really_probe+0x1d0/0x3d4) | |
31 | (really_probe) from (driver_probe_device+0x78/0x1c0) | |
32 | (driver_probe_device) from (__driver_attach+0x120/0x13c) | |
33 | (__driver_attach) from (bus_for_each_dev+0x68/0xb4) | |
34 | (bus_for_each_dev) from (bus_add_driver+0x1a8/0x268) | |
35 | (bus_add_driver) from (driver_register+0x78/0x10c) | |
36 | (driver_register) from (do_one_initcall+0x54/0x1fc) | |
37 | (do_one_initcall) from (do_init_module+0x64/0x1f4) | |
38 | (do_init_module) from (load_module+0x2198/0x26ac) | |
39 | (load_module) from (sys_finit_module+0xe0/0x110) | |
40 | (sys_finit_module) from (ret_fast_syscall+0x0/0x54) | |
41 | ||
42 | One way to fix this would be to rework the hairy registration sequence | |
43 | in gpiochip_add_data_with_key(), but since I'd probably introduce a | |
44 | couple of new bugs if I attempted that, simply add a check for a | |
45 | non-NULL of_xlate function pointer in | |
46 | of_gpiochip_match_node_and_xlate(). This works since the driver looking | |
47 | for the gpio will simply fail to find the gpio and defer its probe and | |
48 | be reprobed when the driver which is registering the gpiochip has fully | |
49 | completed its probe. | |
50 | ||
51 | Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> | |
52 | Signed-off-by: Linus Walleij <linus.walleij@linaro.org> | |
53 | Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> | |
54 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
55 | --- | |
56 | drivers/gpio/gpiolib-of.c | 1 + | |
57 | 1 file changed, 1 insertion(+) | |
58 | ||
59 | --- a/drivers/gpio/gpiolib-of.c | |
60 | +++ b/drivers/gpio/gpiolib-of.c | |
61 | @@ -31,6 +31,7 @@ static int of_gpiochip_match_node_and_xl | |
62 | struct of_phandle_args *gpiospec = data; | |
63 | ||
64 | return chip->gpiodev->dev.of_node == gpiospec->np && | |
65 | + chip->of_xlate && | |
66 | chip->of_xlate(chip, gpiospec, NULL) >= 0; | |
67 | } | |
68 |