diff options
| -rw-r--r-- | drivers/usb/core/devio.c | 41 |
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 | } |
