Commit 93cf9b90 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: avoid urb->pipe in usbfs

This patch (as948) removes most of the references to urb->pipe from
the usbfs routines in devio.c.  The one tricky aspect is in
snoop_urb(), which can be called before the URB is submitted and which
uses usb_urb_dir_in().  For this to work properly, the URB's direction
flag must be set manually in proc_do_submiturb().

The patch also fixes a minor bug; the wValue, wIndex, and wLength
fields were snooped in proc_do_submiturb() without conversion from
le16 to CPU-byte-ordering.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 4326ed0b
...@@ -289,10 +289,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) ...@@ -289,10 +289,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop) if (!usbfs_snoop)
return; return;
if (urb->pipe & USB_DIR_IN) dev_info(&urb->dev->dev, "direction=%s\n",
dev_info(&urb->dev->dev, "direction=IN\n"); usb_urb_dir_in(urb) ? "IN" : "OUT");
else
dev_info(&urb->dev->dev, "direction=OUT\n");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length); urb->transfer_buffer_length);
...@@ -910,6 +908,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -910,6 +908,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL; struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen; unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1; int ret, ifnum = -1;
int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET)) URB_NO_FSBR|URB_ZERO_PACKET))
...@@ -924,16 +923,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -924,16 +923,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum))) if ((ret = checkintf(ps, ifnum)))
return ret; return ret;
} }
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; is_in = 1;
else ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; } else {
is_in = 0;
ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
}
if (!ep) if (!ep)
return -ENOENT; return -ENOENT;
switch(uurb->type) { switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL: case USBDEVFS_URB_TYPE_CONTROL:
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) if (!usb_endpoint_xfer_control(&ep->desc))
!= USB_ENDPOINT_XFER_CONTROL)
return -EINVAL; return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
...@@ -952,23 +953,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -952,23 +953,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr); kfree(dr);
return ret; return ret;
} }
uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0; uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8; uurb->buffer += 8;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
uurb->endpoint |= USB_DIR_IN;
} else {
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length)) {
kfree(dr); kfree(dr);
return -EFAULT; return -EFAULT;
} }
snoop(&ps->dev->dev, "control urb: bRequest=%02x " snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x " "bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n", "wIndex=%04x wLength=%04x\n",
dr->bRequest, dr->bRequestType, dr->wValue, dr->bRequest, dr->bRequestType,
dr->wIndex, dr->wLength); __le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
break; break;
case USBDEVFS_URB_TYPE_BULK: case USBDEVFS_URB_TYPE_BULK:
switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
return -EINVAL; return -EINVAL;
...@@ -977,7 +987,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -977,7 +987,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0; uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL; return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT; return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n"); snoop(&ps->dev->dev, "bulk urb\n");
break; break;
...@@ -986,8 +997,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -986,8 +997,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */ /* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL; return -EINVAL;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) if (!usb_endpoint_xfer_isoc(&ep->desc))
!= USB_ENDPOINT_XFER_ISOC)
return -EINVAL; return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
...@@ -1014,12 +1024,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1014,12 +1024,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT: case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0; uurb->number_of_packets = 0;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) if (!usb_endpoint_xfer_int(&ep->desc))
!= USB_ENDPOINT_XFER_INT)
return -EINVAL; return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL; return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT; return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n"); snoop(&ps->dev->dev, "interrupt urb\n");
break; break;
...@@ -1039,8 +1049,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1039,8 +1049,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM; return -ENOMEM;
} }
as->urb->dev = ps->dev; as->urb->dev = ps->dev;
as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); as->urb->pipe = (uurb->type << 30) |
as->urb->transfer_flags = uurb->flags; __create_pipe(ps->dev, uurb->endpoint & 0xf) |
(uurb->endpoint & USB_DIR_IN);
as->urb->transfer_flags = uurb->flags |
(is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr; as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame; as->urb->start_frame = uurb->start_frame;
...@@ -1070,13 +1083,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1070,13 +1083,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid; as->uid = current->uid;
as->euid = current->euid; as->euid = current->euid;
security_task_getsecid(current, &as->secid); security_task_getsecid(current, &as->secid);
if (!(uurb->endpoint & USB_DIR_IN)) { if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
as->urb->transfer_buffer_length)) {
free_async(as); free_async(as);
return -EFAULT; return -EFAULT;
} }
} }
snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb); snoop_urb(as->urb, as->userurb);
async_newpending(as); async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
...@@ -1126,7 +1139,7 @@ static int processcompl(struct async *as, void __user * __user *arg) ...@@ -1126,7 +1139,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (put_user(urb->error_count, &userurb->error_count)) if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT; return -EFAULT;
if (usb_pipeisoc(urb->pipe)) { if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length, if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length)) &userurb->iso_frame_desc[i].actual_length))
...@@ -1240,7 +1253,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) ...@@ -1240,7 +1253,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (put_user(urb->error_count, &userurb->error_count)) if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT; return -EFAULT;
if (usb_pipeisoc(urb->pipe)) { if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length, if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length)) &userurb->iso_frame_desc[i].actual_length))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment