summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-03-19 04:21:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-21 18:59:04 -0400
commita14430db686b8e459e1cf070a6ecf391515c9ab9 (patch)
tree43eac5d5bebc70868b3a62dfe5674fde5cd44d87 /drivers/usb
parente670c6af12517d08a403487b1122eecf506021cf (diff)
USB: mos7840: fix use-after-free in TIOCMIWAIT
Use the port wait queue and make sure to check the serial disconnected flag before accessing private port data after waking up. This is is needed as the private port data (including the wait queue itself) can be gone when waking up after a disconnect. Cc: stable <stable@vger.kernel.org> Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/mos7840.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 1b83b01dfb77..b8051fa61911 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -219,7 +219,6 @@ struct moschip_port {
219 char open; 219 char open;
220 char open_ports; 220 char open_ports;
221 wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ 221 wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
222 wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
223 int delta_msr_cond; 222 int delta_msr_cond;
224 struct async_icount icount; 223 struct async_icount icount;
225 struct usb_serial_port *port; /* loop back to the owner of this object */ 224 struct usb_serial_port *port; /* loop back to the owner of this object */
@@ -425,7 +424,7 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
425 } 424 }
426 425
427 mos7840_port->delta_msr_cond = 1; 426 mos7840_port->delta_msr_cond = 1;
428 wake_up_interruptible(&mos7840_port->delta_msr_wait); 427 wake_up_interruptible(&port->port->delta_msr_wait);
429 } 428 }
430} 429}
431 430
@@ -1130,7 +1129,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
1130 1129
1131 /* initialize our wait queues */ 1130 /* initialize our wait queues */
1132 init_waitqueue_head(&mos7840_port->wait_chase); 1131 init_waitqueue_head(&mos7840_port->wait_chase);
1133 init_waitqueue_head(&mos7840_port->delta_msr_wait);
1134 1132
1135 /* initialize our icount structure */ 1133 /* initialize our icount structure */
1136 memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount)); 1134 memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
@@ -2220,13 +2218,18 @@ static int mos7840_ioctl(struct tty_struct *tty,
2220 while (1) { 2218 while (1) {
2221 /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ 2219 /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
2222 mos7840_port->delta_msr_cond = 0; 2220 mos7840_port->delta_msr_cond = 0;
2223 wait_event_interruptible(mos7840_port->delta_msr_wait, 2221 wait_event_interruptible(port->delta_msr_wait,
2224 (mos7840_port-> 2222 (port->serial->disconnected ||
2223 mos7840_port->
2225 delta_msr_cond == 1)); 2224 delta_msr_cond == 1));
2226 2225
2227 /* see if a signal did it */ 2226 /* see if a signal did it */
2228 if (signal_pending(current)) 2227 if (signal_pending(current))
2229 return -ERESTARTSYS; 2228 return -ERESTARTSYS;
2229
2230 if (port->serial->disconnected)
2231 return -EIO;
2232
2230 cnow = mos7840_port->icount; 2233 cnow = mos7840_port->icount;
2231 smp_rmb(); 2234 smp_rmb();
2232 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 2235 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&