From fdc30b3d448bf86dd45f9df3e8ac0d36a3bdd9b2 Mon Sep 17 00:00:00 2001
From: Taku Izumi <izumi2005@soft.fujitsu.com>
Date: Mon, 23 Apr 2007 14:41:00 -0700
Subject: Fix possible NULL pointer access in 8250 serial driver

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

    Call Trace:
    [<a000000100013940>] show_stack+0x40/0xa0
    [<a0000001000145a0>] show_regs+0x840/0x880
    [<a0000001000368e0>] die+0x1c0/0x2c0
    [<a000000100036a30>] die_if_kernel+0x50/0x80
    [<a000000100037c40>] ia64_fault+0x11e0/0x1300
    [<a00000010000bdc0>] ia64_leave_kernel+0x0/0x280
    [<a000000100482070>] check_modem_status+0xf0/0x360
    [<a000000100482300>] serial8250_get_mctrl+0x20/0xa0
    [<a000000100478170>] uart_read_proc+0x250/0x860
    [<a0000001001c16d0>] proc_file_read+0x1d0/0x4c0
    [<a0000001001394b0>] vfs_read+0x1b0/0x300
    [<a000000100139cd0>] sys_read+0x70/0xe0
    [<a00000010000bc20>] ia64_ret_from_syscall+0x0/0x20
    [<a000000000010620>] __kernel_syscall_via_break+0x0/0x20

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.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Taku Izumi <izumi2005@soft.fujitsu.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/serial/8250.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'drivers/serial')

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c129a0e..c0c472a 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1310,7 +1310,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 {
 	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)
-- 
cgit v1.1


From 179fb0c726fa34a1ecbb9385a01c704babb9c0ab Mon Sep 17 00:00:00 2001
From: Olaf Hering <olaf@aepfle.de>
Date: Mon, 23 Apr 2007 14:41:15 -0700
Subject: do not truncate irq number for icom adapter

irq values are u32, not u8. Large irq numbers will be truncated,
free_irq may free a different irq.

Remove incorrectly sized struct member and use the one from pci_dev.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/serial/icom.c | 5 ++---
 drivers/serial/icom.h | 1 -
 2 files changed, 2 insertions(+), 4 deletions(-)

(limited to 'drivers/serial')

diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 41431d0..d7aaf76 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -1473,7 +1473,7 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
 		}
 	}
 
-	free_irq(icom_adapter->irq_number, (void *) icom_adapter);
+	free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
 	iounmap(icom_adapter->base_addr);
 	icom_free_adapter(icom_adapter);
 	pci_release_regions(icom_adapter->pci_dev);
@@ -1539,7 +1539,6 @@ static int __devinit icom_probe(struct pci_dev *dev,
 	}
 
 	 icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
-	 icom_adapter->irq_number = dev->irq;
 	 icom_adapter->pci_dev = dev;
 	 icom_adapter->version = ent->driver_data;
 	 icom_adapter->subsystem_id = ent->subdevice;
@@ -1570,7 +1569,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
 		icom_port = &icom_adapter->port_info[index];
 
 		if (icom_port->status == ICOM_PORT_ACTIVE) {
-			icom_port->uart_port.irq = icom_port->adapter->irq_number;
+			icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
 			icom_port->uart_port.type = PORT_ICOM;
 			icom_port->uart_port.iotype = UPIO_MEM;
 			icom_port->uart_port.membase =
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
index 798f1ef..e8578d8 100644
--- a/drivers/serial/icom.h
+++ b/drivers/serial/icom.h
@@ -258,7 +258,6 @@ struct icom_port {
 struct icom_adapter {
 	void __iomem * base_addr;
 	unsigned long base_addr_pci;
-	unsigned char irq_number;
 	struct pci_dev *pci_dev;
 	struct icom_port port_info[4];
 	int index;
-- 
cgit v1.1


From 98f85d30ced96ac466f30419de8b3fac341ebe75 Mon Sep 17 00:00:00 2001
From: Jiri Slaby <jirislaby@gmail.com>
Date: Mon, 23 Apr 2007 14:41:20 -0700
Subject: Char: icom, mark __init as __devinit

Two functions are called from __devinit context, but they are marked as
__init. Fix this.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/serial/icom.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'drivers/serial')

diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index d7aaf76..246c557 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -164,7 +164,7 @@ static void free_port_memory(struct icom_port *icom_port)
 	}
 }
 
-static int __init get_port_memory(struct icom_port *icom_port)
+static int __devinit get_port_memory(struct icom_port *icom_port)
 {
 	int index;
 	unsigned long stgAddr;
@@ -1380,7 +1380,7 @@ static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *i
 			    0x8024 + 2 - 2 * (icom_port->port - 2);
 	}
 }
-static int __init icom_load_ports(struct icom_adapter *icom_adapter)
+static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
 {
 	struct icom_port *icom_port;
 	int port_num;
-- 
cgit v1.1


From 4bf3631cdb012591667ab927fcd7719d92837833 Mon Sep 17 00:00:00 2001
From: Jiri Kosina <jkosina@suse.cz>
Date: Mon, 23 Apr 2007 14:41:21 -0700
Subject: 8250: fix possible deadlock between serial8250_handle_port() and
 serial8250_interrupt()

Commit 40b36daa introduced possibility that serial8250_backup_timeout() ->
serial8250_handle_port() locks port.lock without disabling irqs, thus
allowing deadlock against interrupt handler (port.lock is acquired in
serial8250_interrupt()).

Spotted by lockdep.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Cc: Dave Jones <davej@codemonkey.org.uk>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/serial/8250.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'drivers/serial')

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c0c472a..90621c3 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1334,8 +1334,9 @@ static inline void
 serial8250_handle_port(struct uart_8250_port *up)
 {
 	unsigned int status;
+	unsigned long flags;
 
-	spin_lock(&up->port.lock);
+	spin_lock_irqsave(&up->port.lock, flags);
 
 	status = serial_inp(up, UART_LSR);
 
@@ -1347,7 +1348,7 @@ serial8250_handle_port(struct uart_8250_port *up)
 	if (status & UART_LSR_THRE)
 		transmit_chars(up);
 
-	spin_unlock(&up->port.lock);
+	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 /*
-- 
cgit v1.1


From ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9 Mon Sep 17 00:00:00 2001
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Thu, 29 Mar 2007 00:49:54 -0700
Subject: [SPARC/64] constify of_get_property return: drivers

The only unfortunate bit here is that the name field of struct map_info
is not const, so for now we put a cast on the assignment of it.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/serial/sunsu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'drivers/serial')

diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 96a852a..bfd4417 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1387,8 +1387,8 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
 	struct device_node *ap = of_find_node_by_path("/aliases");
 
 	if (ap) {
-		char *keyb = of_get_property(ap, "keyboard", NULL);
-		char *ms = of_get_property(ap, "mouse", NULL);
+		const char *keyb = of_get_property(ap, "keyboard", NULL);
+		const char *ms = of_get_property(ap, "mouse", NULL);
 
 		if (keyb) {
 			if (dp == of_find_node_by_path(keyb))
-- 
cgit v1.1