From fdc30b3d448bf86dd45f9df3e8ac0d36a3bdd9b2 Mon Sep 17 00:00:00 2001 From: Taku Izumi 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 : [] Not tainted ip is at check_modem_status+0xf1/0x360 Call Trace: [] show_stack+0x40/0xa0 [] show_regs+0x840/0x880 [] die+0x1c0/0x2c0 [] die_if_kernel+0x50/0x80 [] ia64_fault+0x11e0/0x1300 [] ia64_leave_kernel+0x0/0x280 [] check_modem_status+0xf0/0x360 [] serial8250_get_mctrl+0x20/0xa0 [] uart_read_proc+0x250/0x860 [] proc_file_read+0x1d0/0x4c0 [] vfs_read+0x1b0/0x300 [] sys_read+0x70/0xe0 [] ia64_ret_from_syscall+0x0/0x20 [] __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 Signed-off-by: Taku Izumi Cc: Russell King Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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 c129a0e8e80..c0c472ac531 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.2.3-70-g09d2 From 179fb0c726fa34a1ecbb9385a01c704babb9c0ab Mon Sep 17 00:00:00 2001 From: Olaf Hering 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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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 41431d0d551..d7aaf764849 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 798f1ef2371..e8578d8cd35 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.2.3-70-g09d2 From 98f85d30ced96ac466f30419de8b3fac341ebe75 Mon Sep 17 00:00:00 2001 From: Jiri Slaby 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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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 d7aaf764849..246c5572667 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.2.3-70-g09d2 From 4bf3631cdb012591667ab927fcd7719d92837833 Mon Sep 17 00:00:00 2001 From: Jiri Kosina 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 Cc: Dave Jones Cc: Russell King Cc: Alex Williamson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- 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 c0c472ac531..90621c3312b 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.2.3-70-g09d2 From ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell 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 Signed-off-by: David S. Miller --- drivers/mtd/maps/sun_uflash.c | 4 ++-- drivers/net/sungem.c | 2 +- drivers/net/sunhme.c | 6 +++--- drivers/net/tg3.c | 2 +- drivers/net/tulip/tulip_core.c | 2 +- drivers/sbus/char/envctrl.c | 8 ++++---- drivers/sbus/char/flash.c | 2 +- drivers/sbus/char/openprom.c | 4 ++-- drivers/sbus/sbus.c | 4 ++-- drivers/scsi/qlogicpti.c | 2 +- drivers/serial/sunsu.c | 4 ++-- drivers/video/cg3.c | 2 +- 12 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 4db2055cee3..001af7f7ddd 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -39,7 +39,7 @@ MODULE_VERSION("2.0"); static LIST_HEAD(device_list); struct uflash_dev { - char *name; /* device name */ + const char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; @@ -80,7 +80,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) - up->map.name = up->name; + up->map.name = (char *)up->name; up->map.phys = res->start; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 08ea61db46f..bb07b79817f 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2914,7 +2914,7 @@ static int __devinit gem_get_device_address(struct gem *gp) int use_idprom = 1; if (pcp != NULL) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, "local-mac-address", diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 192bbc91c73..bee5e5b309b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2704,7 +2704,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev->dev_addr[i] = macaddr[i]; macaddr[5]++; } else { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(dp, "local-mac-address", &len); @@ -3081,7 +3081,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, macaddr[5]++; } else { #ifdef CONFIG_SPARC - unsigned char *addr; + const unsigned char *addr; int len; if (qfe_slot != -1 && @@ -3300,7 +3300,7 @@ static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_devic { struct sbus_dev *sdev = to_sbus_device(&dev->dev); struct device_node *dp = dev->node; - char *model = of_get_property(dp, "model", NULL); + const char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 256969e1300..45b4e018b5e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10996,7 +10996,7 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, "local-mac-address", diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e3774a52237..03c14181b6b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1544,7 +1544,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr[i] = last_phys_addr[i] + 1; #if defined(__sparc__) if (pcp) { - unsigned char *addr; + const unsigned char *addr; int len; addr = of_get_property(pcp->prom_node, diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 2cea4f5d208..f2be2ead874 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -726,7 +726,7 @@ static struct miscdevice envctrl_dev = { * Return: None. */ static void envctrl_set_mon(struct i2c_child_t *pchild, - char *chnl_desc, + const char *chnl_desc, int chnl_no) { /* Firmware only has temperature type. It does not distinguish @@ -763,8 +763,8 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { int i = 0, len; - char *pos; - unsigned int *pval; + const char *pos; + const unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ pos = of_get_property(dp, "channels-description", &len); @@ -859,7 +859,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, { int len, i, tbls_size = 0; struct device_node *dp = edev_child->prom_node; - void *pval; + const void *pval; /* Get device address. */ pval = of_get_property(dp, "reg", &len); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 6e99507aeb1..262f01e6859 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -190,7 +190,7 @@ static int __init flash_init(void) } if (!sdev) { #ifdef CONFIG_PCI - struct linux_prom_registers *ebus_regs; + const struct linux_prom_registers *ebus_regs; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 5041c9dfbe3..aec3b9f991f 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -141,7 +141,7 @@ static int copyout(void __user *info, struct openpromio *opp, int len) static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) { - void *pval; + const void *pval; int len; if (!dp || @@ -410,7 +410,7 @@ static int opiocget(void __user *argp, DATA *data) struct opiocdesc op; struct device_node *dp; char *str; - void *pval; + const void *pval; int err, len; if (copy_from_user(&op, argp, sizeof(op))) diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 6349dd617f8..eee590a51d8 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -35,7 +35,7 @@ struct sbus_bus *sbus_root; static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { unsigned long base; - void *pval; + const void *pval; int len, err; sdev->prom_node = dp->node; @@ -86,7 +86,7 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) { - void *pval; + const void *pval; int len; pval = of_get_property(dp, "ranges", &len); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 9f10689905a..c4195ea869e 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi struct scsi_host_template *tpnt = match->data; struct Scsi_Host *host; struct qlogicpti *qpti; - char *fcode; + const char *fcode; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 96a852aa190..bfd44177a21 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)) diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 767c850f8eb..f042428a84f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -266,7 +266,7 @@ static void __devinit cg3_init_fix(struct fb_info *info, int linebytes, static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, struct device_node *dp) { - char *params; + const char *params; char *p; int ww, hh; -- cgit v1.2.3-70-g09d2