[PATCH] serial: max310x: Fix invalid memory access during GPIO init

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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:

 [<c04598c0>] (max310x_gpio_direction_output) from [<c03f5a2c>] (_gpiod_direction_output_raw+0x94/0x2d4)
 [<c03f5a2c>] (_gpiod_direction_output_raw) from [<c03f991c>] (gpiod_hog+0x6c/0x154)
 [<c03f991c>] (gpiod_hog) from [<c03fa2d8>] (of_gpiochip_add+0x28c/0x444)
 [<c03fa2d8>] (of_gpiochip_add) from [<c03f6b2c>] (gpiochip_add_data+0x4f8/0x760)
 [<c03f6b2c>] (gpiochip_add_data) from [<c03f6dd4>] (devm_gpiochip_add_data+0x40/0x7c)
 [<c03f6dd4>] (devm_gpiochip_add_data) from [<c0459fec>] (max310x_spi_probe+0x530/0x894)
 [<c0459fec>] (max310x_spi_probe) from [<c0503294>] (spi_drv_probe+0x7c/0xac)
 [<c0503294>] (spi_drv_probe) from [<c046628c>] (driver_probe_device+0x234/0x2e8)
 [<c046628c>] (driver_probe_device) from [<c0464890>] (bus_for_each_drv+0x60/0x94)
 [<c0464890>] (bus_for_each_drv) from [<c0465f78>] (__device_attach+0xb0/0x114)
 [<c0465f78>] (__device_attach) from [<c0465548>] (bus_probe_device+0x84/0x8c)
 [<c0465548>] (bus_probe_device) from [<c0463a00>] (device_add+0x3f4/0x580)
 [<c0463a00>] (device_add) from [<c0504164>] (spi_add_device+0x9c/0x134)
 [<c0504164>] (spi_add_device) from [<c0504c18>] (spi_register_controller+0x484/0x910)
 [<c0504c18>] (spi_register_controller) from [<c0506ee0>] (orion_spi_probe+0x2f4/0x3b4)
 [<c0506ee0>] (orion_spi_probe) from [<c0467dac>] (platform_drv_probe+0x50/0xb0)
 [<c0467dac>] (platform_drv_probe) from [<c046628c>] (driver_probe_device+0x234/0x2e8)
 [<c046628c>] (driver_probe_device) from [<c04663f8>] (__driver_attach+0xb8/0xbc)
 [<c04663f8>] (__driver_attach) from [<c04647e8>] (bus_for_each_dev+0x68/0x9c)
 [<c04647e8>] (bus_for_each_dev) from [<c046574c>] (bus_add_driver+0x104/0x210)
 [<c046574c>] (bus_add_driver) from [<c0466f14>] (driver_register+0x78/0xf4)
 [<c0466f14>] (driver_register) from [<c0101bdc>] (do_one_initcall+0x44/0x168)
 [<c0101bdc>] (do_one_initcall) from [<c0a00dc0>] (kernel_init_freeable+0x140/0x1cc)
 [<c0a00dc0>] (kernel_init_freeable) from [<c078c590>] (kernel_init+0x8/0x108)
 [<c078c590>] (kernel_init) from [<c0107a50>] (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 <jan.kundrat@xxxxxxxxx>
---
 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 9dfedbe6c071..53c3cc5803ab 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1173,23 +1173,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++) {
@@ -1241,6 +1224,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);
-- 
2.14.3


--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux