Skip to contentSkip to conversation

Fix possible NULL pointer access in 8250 serial driver

PATCH In review izumi 4 participants 7 messages Apr 17, 2007 – Apr 19, 2007 TTY layer and serial drivers

lore
Share & tools
lore

izumi

author
#0 lore raw

PATCH 1/1 Fix possible NULL pointer access in 8250 serial driver

Hi,

I encountered the following kernel panic. The cause of this problem was NULL pointer access in check_modem_status() in 8250.c. I confirmed this problem is fixed by the attached patch, but I don't know this is the correct fix.

sadc[4378]: NaT consumption 2216203124768 [1]

Modules linked in: binfmt_misc dm_mirror dm_mod thermal processor fan

container button sg e100 eepro100 mii ehci_hcd ohci_hcd

Pid: 4378, CPU 0, comm: sadc
psr : 00001210085a2010 ifs : 8000000000000289 ip : [<a000000100482071>] Not tainted
ip is at check_modem_status+0xf1/0x360
unat: 0000000000000000 pfs : 0000000000000289 rsc : 0000000000000003
rnat: 800000000000cc18 bsps: 0000000000000000 pr : 0000000000aa6a99
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr: 0009804c8a70033f csd : 0000000000000000 ssd : 0000000000000000
b0 : a000000100481fb0 b6 : a0000001004822e0 b7 : a000000100477f20 f6 : 1003e2222222222222222 f7 : 0ffdba200000000000000
f8 : 100018000000000000000 f9 : 10002a000000000000000
f10 : 0fffdccccccccc8c00000 f11 : 1003e0000000000000000
r1 : a000000100b9af40 r2 : 0000000000000008 r3 : a000000100ad4e21 r8 : 00000000000000bb r9 : 0000000000000001 r10 : 0000000000000000 r11 : a000000100ad4d58 r12 : e0000000037b7df0 r13 : e0000000037b0000 r14 : 0000000000000001 r15 : 0000000000000018 r16 : a000000100ad4d6c r17 : 0000000000000000 r18 : 0000000000000000 r19 : 0000000000000000 r20 : a00000010099bc88 r21 : 00000000000000bb r22 : 00000000000000bb r23 : c003fffffc0ff3fe r24 : c003fffffc000000 r25 : 00000000000ff3fe r26 : a0000001009b7ad0 r27 : 0000000000000001 r28 : a0000001009b7ad8 r29 : 0000000000000000 r30 : a0000001009b7ad0 r31 : a0000001009b7ad0

Call Trace:
[<a000000100013940>] show_stack+0x40/0xa0

sp=e0000000037b7810 bsp=e0000000037b1118 [<a0000001000145a0>] show_regs+0x840/0x880 sp=e0000000037b79e0 bsp=e0000000037b10c0 [<a0000001000368e0>] die+0x1c0/0x2c0 sp=e0000000037b79e0 bsp=e0000000037b1078 [<a000000100036a30>] die_if_kernel+0x50/0x80 sp=e0000000037b7a00 bsp=e0000000037b1048 [<a000000100037c40>] ia64_fault+0x11e0/0x1300 sp=e0000000037b7a00 bsp=e0000000037b0fe8 [<a00000010000bdc0>] ia64_leave_kernel+0x0/0x280 sp=e0000000037b7c20 bsp=e0000000037b0fe8 [<a000000100482070>] check_modem_status+0xf0/0x360 sp=e0000000037b7df0 bsp=e0000000037b0fa0 [<a000000100482300>] serial8250_get_mctrl+0x20/0xa0 sp=e0000000037b7df0 bsp=e0000000037b0f80 [<a000000100478170>] uart_read_proc+0x250/0x860 sp=e0000000037b7df0 bsp=e0000000037b0ee0 [<a0000001001c16d0>] proc_file_read+0x1d0/0x4c0 sp=e0000000037b7e10 bsp=e0000000037b0e80 [<a0000001001394b0>] vfs_read+0x1b0/0x300 sp=e0000000037b7e20 bsp=e0000000037b0e30 [<a000000100139cd0>] sys_read+0x70/0xe0 sp=e0000000037b7e20 bsp=e0000000037b0db0 [<a00000010000bc20>] ia64_ret_from_syscall+0x0/0x20 sp=e0000000037b7e30 bsp=e0000000037b0db0 [<a000000000010620>] __kernel_syscall_via_break+0x0/0x20 sp=e0000000037b8000 bsp=e0000000037b0db0

Thanks,
Taku Izumi

Fix the possible NULL pointer access in check_modem_status() in 8250.c. The check_modem_status() would access 'info' member of uart_port structure, but it is not initialized before uart_open() is called. The check_modem_status() can be called through /proc/tty/driver/serial before uart_open() is called.

---
 drivers/serial/8250.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletion(-)
drivers/serial/8250.c +2 -1
Index: linux-2.6.21-rc5/drivers/serial/8250.c
===================================================================
@@ -1310,7 +1310,8 @@
 {
 	unsigned int status = serial_in(up, UART_MSR);
 
-	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+	    up->port.info != NULL) {
 		if (status & UART_MSR_TERI)
 			up->port.icount.rng++;
 		if (status & UART_MSR_DDSR)
#1 lore raw
Quoted 75 lines · On Tue, 17 Apr 2007 11:15:46 +0900 izumi <[email protected]> wrote:

Hi,

I encountered the following kernel panic. The cause of this problem was NULL pointer access in check_modem_status() in 8250.c. I confirmed this problem is fixed by the attached patch, but I don't know this is the correct fix.

sadc[4378]: NaT consumption 2216203124768 [1]

Modules linked in: binfmt_misc dm_mirror dm_mod thermal processor fan

container button sg e100 eepro100 mii ehci_hcd ohci_hcd

Pid: 4378, CPU 0, comm: sadc
psr : 00001210085a2010 ifs : 8000000000000289 ip : [<a000000100482071>] Not tainted
ip is at check_modem_status+0xf1/0x360
unat: 0000000000000000 pfs : 0000000000000289 rsc : 0000000000000003
rnat: 800000000000cc18 bsps: 0000000000000000 pr : 0000000000aa6a99
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr: 0009804c8a70033f csd : 0000000000000000 ssd : 0000000000000000
b0 : a000000100481fb0 b6 : a0000001004822e0 b7 : a000000100477f20 f6 : 1003e2222222222222222 f7 : 0ffdba200000000000000
f8 : 100018000000000000000 f9 : 10002a000000000000000
f10 : 0fffdccccccccc8c00000 f11 : 1003e0000000000000000
r1 : a000000100b9af40 r2 : 0000000000000008 r3 : a000000100ad4e21 r8 : 00000000000000bb r9 : 0000000000000001 r10 : 0000000000000000 r11 : a000000100ad4d58 r12 : e0000000037b7df0 r13 : e0000000037b0000 r14 : 0000000000000001 r15 : 0000000000000018 r16 : a000000100ad4d6c r17 : 0000000000000000 r18 : 0000000000000000 r19 : 0000000000000000 r20 : a00000010099bc88 r21 : 00000000000000bb r22 : 00000000000000bb r23 : c003fffffc0ff3fe r24 : c003fffffc000000 r25 : 00000000000ff3fe r26 : a0000001009b7ad0 r27 : 0000000000000001 r28 : a0000001009b7ad8 r29 : 0000000000000000 r30 : a0000001009b7ad0 r31 : a0000001009b7ad0

Call Trace:
[<a000000100013940>] show_stack+0x40/0xa0

sp=e0000000037b7810 bsp=e0000000037b1118 [<a0000001000145a0>] show_regs+0x840/0x880 sp=e0000000037b79e0 bsp=e0000000037b10c0 [<a0000001000368e0>] die+0x1c0/0x2c0 sp=e0000000037b79e0 bsp=e0000000037b1078 [<a000000100036a30>] die_if_kernel+0x50/0x80 sp=e0000000037b7a00 bsp=e0000000037b1048 [<a000000100037c40>] ia64_fault+0x11e0/0x1300 sp=e0000000037b7a00 bsp=e0000000037b0fe8 [<a00000010000bdc0>] ia64_leave_kernel+0x0/0x280 sp=e0000000037b7c20 bsp=e0000000037b0fe8 [<a000000100482070>] check_modem_status+0xf0/0x360 sp=e0000000037b7df0 bsp=e0000000037b0fa0 [<a000000100482300>] serial8250_get_mctrl+0x20/0xa0 sp=e0000000037b7df0 bsp=e0000000037b0f80 [<a000000100478170>] uart_read_proc+0x250/0x860 sp=e0000000037b7df0 bsp=e0000000037b0ee0 [<a0000001001c16d0>] proc_file_read+0x1d0/0x4c0 sp=e0000000037b7e10 bsp=e0000000037b0e80 [<a0000001001394b0>] vfs_read+0x1b0/0x300 sp=e0000000037b7e20 bsp=e0000000037b0e30 [<a000000100139cd0>] sys_read+0x70/0xe0 sp=e0000000037b7e20 bsp=e0000000037b0db0 [<a00000010000bc20>] ia64_ret_from_syscall+0x0/0x20 sp=e0000000037b7e30 bsp=e0000000037b0db0 [<a000000000010620>] __kernel_syscall_via_break+0x0/0x20 sp=e0000000037b8000 bsp=e0000000037b0db0

drivers/serial/8250.c renamed from drivers/serial/8250.c~fix-possible-null-pointer-access-in-8250-serial-driver +2 -1
@@ -1310,7 +1310,8 @@ static unsigned int check_modem_status(s
 {
 	unsigned int status = serial_in(up, UART_MSR);
 
-	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+	    up->port.info != NULL) {
 		if (status & UART_MSR_TERI)
 			up->port.icount.rng++;
 		if (status & UART_MSR_DDSR)
Quoted 2 lines

_

I'd imagine that other serial drivers might get upset having their ->get_mcrtl() called prior to being opened. Perhaps we should be fixing this in uart_read_proc()?

#2 lore raw
Quoted 4 lines

I'd imagine that other serial drivers might get upset having their ->get_mcrtl() called prior to being opened. Perhaps we should be fixing this in uart_read_proc()?

I looked at other serial drivers and I could not find any other drivers which accesses port->info in their ->get_mctrl(). This is why we fix this problem in 8250 driver. But if there is a possibility that other drivers accesses port->info in their ->get_mctrl(), we should be fixing this in uart_read_proc(), as you said.

How about the following patch? We've also confirmed the problem is fixed by it.

Thanks,
Kenji Kaneshige

This patch fixes the problem that uninitialized (NULL) 'info' member of uart_port structure can be accessed if serial driver is accessed through /proc filesystem before uart_open(), which initializes the 'info' member', is called.

---
 drivers/serial/serial_core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/serial/serial_core.c +1 -1
Index: linux-2.6.21-rc5/drivers/serial/serial_core.c
===================================================================
@@ -1665,7 +1665,7 @@ static int uart_line_info(char *buf, str
 	unsigned int status;
 	int mmio, ret;
 
-	if (!port)
+	if (!port || !port->info)
 		return 0;
 
 	mmio = port->iotype >= UPIO_MEM;
#3 lore raw
Quoted 6 lines · On Wed, 18 Apr 2007 17:21:53 +0900 Kenji Kaneshige…
Quoted 4 lines

I'd imagine that other serial drivers might get upset having their ->get_mcrtl() called prior to being opened. Perhaps we should be fixing this in uart_read_proc()?

Quoted 6 lines

I looked at other serial drivers and I could not find any other drivers which accesses port->info in their ->get_mctrl(). This is why we fix this problem in 8250 driver. But if there is a possibility that other drivers accesses port->info in their ->get_mctrl(), we should be fixing this in uart_read_proc(), as you said.

OK. But port->info might not be the only state which is initialised in open() which is used in get_mctrl().

Quoted 3 lines

How about the following patch? We've also confirmed the problem is fixed by it.

Thanks. Or we could just avoid calling into ->get_mctrl() if the port isn't opened. Russell? Any preferences?

Quoted 28 lines

This patch fixes the problem that uninitialized (NULL) 'info' member of uart_port structure can be accessed if serial driver is accessed through /proc filesystem before uart_open(), which initializes the 'info' member', is called.

---
 drivers/serial/serial_core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6.21-rc5/drivers/serial/serial_core.c
===================================================================

drivers/serial/serial_core.c +1 -1
@@ -1665,7 +1665,7 @@ static int uart_line_info(char *buf, str
 	unsigned int status;
 	int mmio, ret;
 
-	if (!port)
+	if (!port || !port->info)
 		return 0;
 
 	mmio = port->iotype >= UPIO_MEM;
#4 lore raw
In reply to Kenji Kaneshige
Quoted 11 lines · Kenji Kaneshige
Quoted 4 lines

I'd imagine that other serial drivers might get upset having their ->get_mcrtl() called prior to being opened. Perhaps we should be fixing this in uart_read_proc()?

I looked at other serial drivers and I could not find any other drivers which accesses port->info in their ->get_mctrl(). This is why we fix this problem in 8250 driver. But if there is a possibility that other drivers accesses port->info in their ->get_mctrl(), we should be fixing this in uart_read_proc(), as you said.

NAK. This means that you change the list of ports available on the machine to be limited to only those which are currently open. Utterly useless for debugging, where you normally want people to dump the contents of /proc/tty/driver/*.

The original patch was better.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:
author
#5 lore raw
Quoted 7 lines · Russell King

NAK. This means that you change the list of ports available on the machine to be limited to only those which are currently open. Utterly useless for debugging, where you normally want people to dump the contents of /proc/tty/driver/*.

The original patch was better.

Is the original patch sufficient? or is there anything we should
correct?

Taku Izumi <[email protected]>

#6 lore raw
Quoted 7 lines · On Thu, 19 Apr 2007 11:28:37 +0900 izumi <[email protected]> wrote:
Quoted 5 lines · Russell King

NAK. This means that you change the list of ports available on the machine to be limited to only those which are currently open. Utterly useless for debugging, where you normally want people to dump the contents of /proc/tty/driver/*.

Quoted 6 lines
Quoted 2 lines

The original patch was better.

Is the original patch sufficient? or is there anything we should
correct?

Would it be better to do something like

drivers/serial/serial_core.c renamed from drivers/serial/serial_core.c~a +6 -3
@@ -1686,9 +1686,12 @@ static int uart_line_info(char *buf, str
 		pm_state = state->pm_state;
 		if (pm_state)
 			uart_change_pm(state, 0);
-		spin_lock_irq(&port->lock);
-		status = port->ops->get_mctrl(port);
-		spin_unlock_irq(&port->lock);
+		status = 0;
+		if (port->info) {
+			spin_lock_irq(&port->lock);
+			status = port->ops->get_mctrl(port);
+			spin_unlock_irq(&port->lock);
+		}
 		if (pm_state)
 			uart_change_pm(state, pm_state);
 		mutex_unlock(&state->mutex);

_

so that a) we treat all uart types in the same way and b) the same problem doesn't occur later with some other driver which is assuming an opened device in its ->get_mctrl() handler?