aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-29 11:04:54 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-12 18:16:41 -0400
commit9180135bc80ab11199d482b6111e23f74d65af4a (patch)
tree570d7079252a6a7b821e42383913ec0bfa09e4eb /drivers/usb
parentec6d67e39f5638c792eb7490bf32586ccb9d8005 (diff)
USB: handle zero-length usbfs submissions correctly
This patch (as1262) fixes a bug in usbfs: It refuses to accept zero-length transfers, and it insists that the buffer pointer be valid even if there is no data being transferred. The patch also consolidates a bunch of repetitive access_ok() checks into a single check, which incidentally fixes the lack of such a check for Isochronous URBs. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/devio.c41
1 files changed, 20 insertions, 21 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 46ca2af5ef1c..38b8bce782d6 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -995,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
995 USBDEVFS_URB_ZERO_PACKET | 995 USBDEVFS_URB_ZERO_PACKET |
996 USBDEVFS_URB_NO_INTERRUPT)) 996 USBDEVFS_URB_NO_INTERRUPT))
997 return -EINVAL; 997 return -EINVAL;
998 if (!uurb->buffer) 998 if (uurb->buffer_length > 0 && !uurb->buffer)
999 return -EINVAL; 999 return -EINVAL;
1000 if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && 1000 if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
1001 (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { 1001 (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
@@ -1051,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1051 is_in = 0; 1051 is_in = 0;
1052 uurb->endpoint &= ~USB_DIR_IN; 1052 uurb->endpoint &= ~USB_DIR_IN;
1053 } 1053 }
1054 if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
1055 uurb->buffer, uurb->buffer_length)) {
1056 kfree(dr);
1057 return -EFAULT;
1058 }
1059 snoop(&ps->dev->dev, "control urb: bRequest=%02x " 1054 snoop(&ps->dev->dev, "control urb: bRequest=%02x "
1060 "bRrequestType=%02x wValue=%04x " 1055 "bRrequestType=%02x wValue=%04x "
1061 "wIndex=%04x wLength=%04x\n", 1056 "wIndex=%04x wLength=%04x\n",
@@ -1075,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1075 uurb->number_of_packets = 0; 1070 uurb->number_of_packets = 0;
1076 if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) 1071 if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
1077 return -EINVAL; 1072 return -EINVAL;
1078 if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
1079 uurb->buffer, uurb->buffer_length))
1080 return -EFAULT;
1081 snoop(&ps->dev->dev, "bulk urb\n"); 1073 snoop(&ps->dev->dev, "bulk urb\n");
1082 break; 1074 break;
1083 1075
@@ -1119,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1119 return -EINVAL; 1111 return -EINVAL;
1120 if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) 1112 if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
1121 return -EINVAL; 1113 return -EINVAL;
1122 if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
1123 uurb->buffer, uurb->buffer_length))
1124 return -EFAULT;
1125 snoop(&ps->dev->dev, "interrupt urb\n"); 1114 snoop(&ps->dev->dev, "interrupt urb\n");
1126 break; 1115 break;
1127 1116
1128 default: 1117 default:
1129 return -EINVAL; 1118 return -EINVAL;
1130 } 1119 }
1131 as = alloc_async(uurb->number_of_packets); 1120 if (uurb->buffer_length > 0 &&
1132 if (!as) { 1121 !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
1122 uurb->buffer, uurb->buffer_length)) {
1133 kfree(isopkt); 1123 kfree(isopkt);
1134 kfree(dr); 1124 kfree(dr);
1135 return -ENOMEM; 1125 return -EFAULT;
1136 } 1126 }
1137 as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); 1127 as = alloc_async(uurb->number_of_packets);
1138 if (!as->urb->transfer_buffer) { 1128 if (!as) {
1139 kfree(isopkt); 1129 kfree(isopkt);
1140 kfree(dr); 1130 kfree(dr);
1141 free_async(as);
1142 return -ENOMEM; 1131 return -ENOMEM;
1143 } 1132 }
1133 if (uurb->buffer_length > 0) {
1134 as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
1135 GFP_KERNEL);
1136 if (!as->urb->transfer_buffer) {
1137 kfree(isopkt);
1138 kfree(dr);
1139 free_async(as);
1140 return -ENOMEM;
1141 }
1142 }
1144 as->urb->dev = ps->dev; 1143 as->urb->dev = ps->dev;
1145 as->urb->pipe = (uurb->type << 30) | 1144 as->urb->pipe = (uurb->type << 30) |
1146 __create_pipe(ps->dev, uurb->endpoint & 0xf) | 1145 __create_pipe(ps->dev, uurb->endpoint & 0xf) |
@@ -1182,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1182 kfree(isopkt); 1181 kfree(isopkt);
1183 as->ps = ps; 1182 as->ps = ps;
1184 as->userurb = arg; 1183 as->userurb = arg;
1185 if (uurb->endpoint & USB_DIR_IN) 1184 if (is_in && uurb->buffer_length > 0)
1186 as->userbuffer = uurb->buffer; 1185 as->userbuffer = uurb->buffer;
1187 else 1186 else
1188 as->userbuffer = NULL; 1187 as->userbuffer = NULL;
@@ -1192,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1192 as->uid = cred->uid; 1191 as->uid = cred->uid;
1193 as->euid = cred->euid; 1192 as->euid = cred->euid;
1194 security_task_getsecid(current, &as->secid); 1193 security_task_getsecid(current, &as->secid);
1195 if (!is_in) { 1194 if (!is_in && uurb->buffer_length > 0) {
1196 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, 1195 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
1197 as->urb->transfer_buffer_length)) { 1196 uurb->buffer_length)) {
1198 free_async(as); 1197 free_async(as);
1199 return -EFAULT; 1198 return -EFAULT;
1200 } 1199 }