From 38d5583ff8900c543322a74471b436d1b8b4018a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= Date: Fri, 8 Dec 2017 20:36:29 +0100 Subject: [PATCH] serial: max310x: Fix invalid memory access during GPIO init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `max310x_spi_probe` function attempted to setup the GPIO bits before the corresponding structs for each serial port were initialized. If the DTS file specified a GPIO hog, this led to a crash because the GPIO stack ended up calling `max310x_gpio_direction_output` which referenced uninitialized memory: [] (max310x_gpio_direction_output) from [] (_gpiod_direction_output_raw+0x94/0x2d4) [] (_gpiod_direction_output_raw) from [] (gpiod_hog+0x6c/0x154) [] (gpiod_hog) from [] (of_gpiochip_add+0x28c/0x444) [] (of_gpiochip_add) from [] (gpiochip_add_data+0x4f8/0x760) [] (gpiochip_add_data) from [] (devm_gpiochip_add_data+0x40/0x7c) [] (devm_gpiochip_add_data) from [] (max310x_spi_probe+0x530/0x894) [] (max310x_spi_probe) from [] (spi_drv_probe+0x7c/0xac) [] (spi_drv_probe) from [] (driver_probe_device+0x234/0x2e8) [] (driver_probe_device) from [] (bus_for_each_drv+0x60/0x94) [] (bus_for_each_drv) from [] (__device_attach+0xb0/0x114) [] (__device_attach) from [] (bus_probe_device+0x84/0x8c) [] (bus_probe_device) from [] (device_add+0x3f4/0x580) [] (device_add) from [] (spi_add_device+0x9c/0x134) [] (spi_add_device) from [] (spi_register_controller+0x484/0x910) [] (spi_register_controller) from [] (orion_spi_probe+0x2f4/0x3b4) [] (orion_spi_probe) from [] (platform_drv_probe+0x50/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x234/0x2e8) [] (driver_probe_device) from [] (__driver_attach+0xb8/0xbc) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x104/0x210) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (do_one_initcall+0x44/0x168) [] (do_one_initcall) from [] (kernel_init_freeable+0x140/0x1cc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x108) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) This can be easily fixed by moving the corresponding code below. And because the UARTs are already there by the time we reach this point, the `goto` needs changing so that more stuff is freed. (I have not tested this error path.) Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ecb6513a6505..8971828d1f21 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1169,23 +1169,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); -#ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ - s->gpio.owner = THIS_MODULE; - s->gpio.parent = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = max310x_gpio_direction_input; - s->gpio.get = max310x_gpio_get; - s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; - s->gpio.base = -1; - s->gpio.ngpio = devtype->nr * 4; - s->gpio.can_sleep = 1; - ret = devm_gpiochip_add_data(dev, &s->gpio, s); - if (ret) - goto out_clk; -#endif - mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { @@ -1237,6 +1220,23 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, devtype->power(&s->p[i].port, 0); } +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr * 4; + s->gpio.can_sleep = 1; + ret = devm_gpiochip_add_data(dev, &s->gpio, s); + if (ret) + goto out_uart; +#endif + /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_ONESHOT | flags, dev_name(dev), s);