Skip to content

Commit

Permalink
USB: mos7840: fix race in register handling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johan Hovold authored and Greg Kroah-Hartman committed Jul 26, 2013
1 parent a882573 commit d8a083c
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions drivers/usb/serial/mos7840.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@
#define LED_ON_MS 500
#define LED_OFF_MS 500

enum mos7840_flag {
MOS7840_FLAG_CTRL_BUSY,
};

static int device_type;

static const struct usb_device_id id_table[] = {
Expand Down Expand Up @@ -241,6 +245,8 @@ struct moschip_port {
bool led_flag;
struct timer_list led_timer1; /* Timer for LED on */
struct timer_list led_timer2; /* Timer for LED off */

unsigned long flags;
};

/*
Expand Down Expand Up @@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
return;
goto out;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
return;
goto out;
}

dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
Expand All @@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb)
mos7840_handle_new_msr(mos7840_port, regval);
else if (mos7840_port->MsrLsr == 1)
mos7840_handle_new_lsr(mos7840_port, regval);
out:
clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
}

static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
Expand All @@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
unsigned char *buffer = mcs->ctrl_buf;
int ret;

if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
return -EBUSY;

dr->bRequestType = MCS_RD_RTYPE;
dr->bRequest = MCS_RDREQ;
dr->wValue = cpu_to_le16(Wval); /* 0 */
Expand All @@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
mos7840_control_callback, mcs);
mcs->control_urb->transfer_buffer_length = 2;
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
if (ret)
clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);

return ret;
}

Expand Down

0 comments on commit d8a083c

Please sign in to comment.