Fix possible NULL pointer access in 8250 serial driver
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
@@ -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 )
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 fancontainer button sg e100 eepro100 mii
ehci_hcdohci_hcdPid: 4378, CPU 0, comm: sadc
psr :00001210085a2010ifs : 8000000000000289 ip : [<a000000100482071>] Not tainted
ip is atcheck_modem_status+0xf1/0x360
unat: 0000000000000000 pfs : 0000000000000289 rsc : 0000000000000003
rnat:800000000000cc18bsps: 0000000000000000 pr :0000000000aa6a99
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr:0009804c8a70033fcsd : 0000000000000000 ssd : 0000000000000000
b0 :a000000100481fb0b6 :a0000001004822e0b7 :a000000100477f20f6 :1003e2222222222222222f7 :0ffdba200000000000000
f8 : 100018000000000000000 f9 :10002a000000000000000
f10 :0fffdccccccccc8c00000f11 :1003e0000000000000000
r1 :a000000100b9af40r2 : 0000000000000008 r3 :a000000100ad4e21r8 :00000000000000bbr9 : 0000000000000001 r10 : 0000000000000000 r11 :a000000100ad4d58r12 :e0000000037b7df0r13 :e0000000037b0000r14 : 0000000000000001 r15 : 0000000000000018 r16 :a000000100ad4d6cr17 : 0000000000000000 r18 : 0000000000000000 r19 : 0000000000000000 r20 :a00000010099bc88r21 :00000000000000bbr22 :00000000000000bbr23 :c003fffffc0ff3fer24 :c003fffffc000000r25 :00000000000ff3fer26 :a0000001009b7ad0r27 : 0000000000000001 r28 :a0000001009b7ad8r29 : 0000000000000000 r30 :a0000001009b7ad0r31 :a0000001009b7ad0Call Trace: [<a000000100013940>] show_stack+0x40/0xa0sp=e0000000037b7810 bsp=e0000000037b1118 [<
a0000001000145a0>]show_regs+0x840/0x880sp=e0000000037b79e0 bsp=e0000000037b10c0 [<a0000001000368e0>]die+0x1c0/0x2c0sp=e0000000037b79e0 bsp=e0000000037b1078 [<a000000100036a30>]die_if_kernel+0x50/0x80sp=e0000000037b7a00 bsp=e0000000037b1048 [<a000000100037c40>]ia64_fault+0x11e0/0x1300sp=e0000000037b7a00 bsp=e0000000037b0fe8 [<a00000010000bdc0>]ia64_leave_kernel+0x0/0x280sp=e0000000037b7c20 bsp=e0000000037b0fe8 [<a000000100482070>]check_modem_status+0xf0/0x360sp=e0000000037b7df0 bsp=e0000000037b0fa0 [<a000000100482300>]serial8250_get_mctrl+0x20/0xa0sp=e0000000037b7df0 bsp=e0000000037b0f80 [<a000000100478170>]uart_read_proc+0x250/0x860sp=e0000000037b7df0 bsp=e0000000037b0ee0 [<a0000001001c16d0>]proc_file_read+0x1d0/0x4c0sp=e0000000037b7e10 bsp=e0000000037b0e80 [<a0000001001394b0>]vfs_read+0x1b0/0x300sp=e0000000037b7e20 bsp=e0000000037b0e30 [<a000000100139cd0>]sys_read+0x70/0xe0sp=e0000000037b7e20 bsp=e0000000037b0db0 [<a00000010000bc20>]ia64_ret_from_syscall+0x0/0x20sp=e0000000037b7e30 bsp=e0000000037b0db0 [<a000000000010620>]__kernel_syscall_via_break+0x0/0x20sp=e0000000037b8000 bsp=e0000000037b0db0drivers/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()?
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
@@ -1665,7 +1665,7 @@ static int uart_line_info(char *buf, strunsigned int status;int mmio, ret; -if (!port) +if (!port || !port->info)return 0 ; mmio = port->iotype >=UPIO_MEM ;
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->infoin their ->get_mctrl(). This is why we fix this problem in 8250 driver. But if there is a possibility that other drivers accessesport->infoin their ->get_mctrl(), we should be fixing this inuart_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_portstructure can be accessed if serial driver is accessed through /proc filesystem beforeuart_open(), which initializes the 'info' member', is called.Signed-off-by Kenji Kaneshige <[email protected]>Signed-off-by Taku Izumi <[email protected]>--- 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, strunsigned int status;int mmio, ret; -if (!port) +if (!port || !port->info)return 0 ; mmio = port->iotype >=UPIO_MEM ;
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->infoin their ->get_mctrl(). This is why we fix this problem in 8250 driver. But if there is a possibility that other drivers accessesport->infoin their ->get_mctrl(), we should be fixing this inuart_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:
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]>
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?