diff options
| author | Johan Hovold <jhovold@gmail.com> | 2013-07-26 05:55:17 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-26 17:14:09 -0400 |
| commit | d8a083cc746664916d9d36ed9e4d08a29525f245 (patch) | |
| tree | 900f44cde51c3523929b92222fc720a32bcd2811 | |
| parent | a8825734e9169ddd0a2a343ceb8ce7d3ecfa08a7 (diff) | |
USB: mos7840: fix race in register handling
Fix race in mos7840_get_reg which unconditionally manipulated the
control urb (which may already be in use) by adding a control-urb busy
flag.
Cc: stable@vger.kernel.org
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/usb/serial/mos7840.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 603fb70dde80..73dda1cc8028 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c | |||
| @@ -183,6 +183,10 @@ | |||
| 183 | #define LED_ON_MS 500 | 183 | #define LED_ON_MS 500 |
| 184 | #define LED_OFF_MS 500 | 184 | #define LED_OFF_MS 500 |
| 185 | 185 | ||
| 186 | enum mos7840_flag { | ||
| 187 | MOS7840_FLAG_CTRL_BUSY, | ||
| 188 | }; | ||
| 189 | |||
| 186 | static int device_type; | 190 | static int device_type; |
| 187 | 191 | ||
| 188 | static const struct usb_device_id id_table[] = { | 192 | static const struct usb_device_id id_table[] = { |
| @@ -241,6 +245,8 @@ struct moschip_port { | |||
| 241 | bool led_flag; | 245 | bool led_flag; |
| 242 | struct timer_list led_timer1; /* Timer for LED on */ | 246 | struct timer_list led_timer1; /* Timer for LED on */ |
| 243 | struct timer_list led_timer2; /* Timer for LED off */ | 247 | struct timer_list led_timer2; /* Timer for LED off */ |
| 248 | |||
| 249 | unsigned long flags; | ||
| 244 | }; | 250 | }; |
| 245 | 251 | ||
| 246 | /* | 252 | /* |
| @@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb) | |||
| 460 | case -ESHUTDOWN: | 466 | case -ESHUTDOWN: |
| 461 | /* this urb is terminated, clean up */ | 467 | /* this urb is terminated, clean up */ |
| 462 | dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); | 468 | dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); |
| 463 | return; | 469 | goto out; |
| 464 | default: | 470 | default: |
| 465 | dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); | 471 | dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); |
| 466 | return; | 472 | goto out; |
| 467 | } | 473 | } |
| 468 | 474 | ||
| 469 | dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); | 475 | dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); |
| @@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb) | |||
| 476 | mos7840_handle_new_msr(mos7840_port, regval); | 482 | mos7840_handle_new_msr(mos7840_port, regval); |
| 477 | else if (mos7840_port->MsrLsr == 1) | 483 | else if (mos7840_port->MsrLsr == 1) |
| 478 | mos7840_handle_new_lsr(mos7840_port, regval); | 484 | mos7840_handle_new_lsr(mos7840_port, regval); |
| 485 | out: | ||
| 486 | clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); | ||
| 479 | } | 487 | } |
| 480 | 488 | ||
| 481 | static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | 489 | static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, |
| @@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | |||
| 486 | unsigned char *buffer = mcs->ctrl_buf; | 494 | unsigned char *buffer = mcs->ctrl_buf; |
| 487 | int ret; | 495 | int ret; |
| 488 | 496 | ||
| 497 | if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) | ||
| 498 | return -EBUSY; | ||
| 499 | |||
| 489 | dr->bRequestType = MCS_RD_RTYPE; | 500 | dr->bRequestType = MCS_RD_RTYPE; |
| 490 | dr->bRequest = MCS_RDREQ; | 501 | dr->bRequest = MCS_RDREQ; |
| 491 | dr->wValue = cpu_to_le16(Wval); /* 0 */ | 502 | dr->wValue = cpu_to_le16(Wval); /* 0 */ |
| @@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | |||
| 497 | mos7840_control_callback, mcs); | 508 | mos7840_control_callback, mcs); |
| 498 | mcs->control_urb->transfer_buffer_length = 2; | 509 | mcs->control_urb->transfer_buffer_length = 2; |
| 499 | ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); | 510 | ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); |
| 511 | if (ret) | ||
| 512 | clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); | ||
| 513 | |||
| 500 | return ret; | 514 | return ret; |
| 501 | } | 515 | } |
| 502 | 516 | ||
