diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
| -rw-r--r-- | drivers/usb/core/devio.c | 78 |
1 files changed, 47 insertions, 31 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 308609039c73..38b8bce782d6 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
| @@ -325,21 +325,34 @@ static void async_completed(struct urb *urb) | |||
| 325 | struct async *as = urb->context; | 325 | struct async *as = urb->context; |
| 326 | struct dev_state *ps = as->ps; | 326 | struct dev_state *ps = as->ps; |
| 327 | struct siginfo sinfo; | 327 | struct siginfo sinfo; |
| 328 | struct pid *pid = NULL; | ||
| 329 | uid_t uid = 0; | ||
| 330 | uid_t euid = 0; | ||
| 331 | u32 secid = 0; | ||
| 332 | int signr; | ||
| 328 | 333 | ||
| 329 | spin_lock(&ps->lock); | 334 | spin_lock(&ps->lock); |
| 330 | list_move_tail(&as->asynclist, &ps->async_completed); | 335 | list_move_tail(&as->asynclist, &ps->async_completed); |
| 331 | spin_unlock(&ps->lock); | ||
| 332 | as->status = urb->status; | 336 | as->status = urb->status; |
| 333 | if (as->signr) { | 337 | signr = as->signr; |
| 338 | if (signr) { | ||
| 334 | sinfo.si_signo = as->signr; | 339 | sinfo.si_signo = as->signr; |
| 335 | sinfo.si_errno = as->status; | 340 | sinfo.si_errno = as->status; |
| 336 | sinfo.si_code = SI_ASYNCIO; | 341 | sinfo.si_code = SI_ASYNCIO; |
| 337 | sinfo.si_addr = as->userurb; | 342 | sinfo.si_addr = as->userurb; |
| 338 | kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, | 343 | pid = as->pid; |
| 339 | as->euid, as->secid); | 344 | uid = as->uid; |
| 345 | euid = as->euid; | ||
| 346 | secid = as->secid; | ||
| 340 | } | 347 | } |
| 341 | snoop(&urb->dev->dev, "urb complete\n"); | 348 | snoop(&urb->dev->dev, "urb complete\n"); |
| 342 | snoop_urb(urb, as->userurb); | 349 | snoop_urb(urb, as->userurb); |
| 350 | spin_unlock(&ps->lock); | ||
| 351 | |||
| 352 | if (signr) | ||
| 353 | kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, | ||
| 354 | euid, secid); | ||
| 355 | |||
| 343 | wake_up(&ps->wait); | 356 | wake_up(&ps->wait); |
| 344 | } | 357 | } |
| 345 | 358 | ||
| @@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 982 | USBDEVFS_URB_ZERO_PACKET | | 995 | USBDEVFS_URB_ZERO_PACKET | |
| 983 | USBDEVFS_URB_NO_INTERRUPT)) | 996 | USBDEVFS_URB_NO_INTERRUPT)) |
| 984 | return -EINVAL; | 997 | return -EINVAL; |
| 985 | if (!uurb->buffer) | 998 | if (uurb->buffer_length > 0 && !uurb->buffer) |
| 986 | return -EINVAL; | 999 | return -EINVAL; |
| 987 | if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && | 1000 | if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && |
| 988 | (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { | 1001 | (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { |
| @@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1038 | is_in = 0; | 1051 | is_in = 0; |
| 1039 | uurb->endpoint &= ~USB_DIR_IN; | 1052 | uurb->endpoint &= ~USB_DIR_IN; |
| 1040 | } | 1053 | } |
| 1041 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1042 | uurb->buffer, uurb->buffer_length)) { | ||
| 1043 | kfree(dr); | ||
| 1044 | return -EFAULT; | ||
| 1045 | } | ||
| 1046 | snoop(&ps->dev->dev, "control urb: bRequest=%02x " | 1054 | snoop(&ps->dev->dev, "control urb: bRequest=%02x " |
| 1047 | "bRrequestType=%02x wValue=%04x " | 1055 | "bRrequestType=%02x wValue=%04x " |
| 1048 | "wIndex=%04x wLength=%04x\n", | 1056 | "wIndex=%04x wLength=%04x\n", |
| @@ -1062,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1062 | uurb->number_of_packets = 0; | 1070 | uurb->number_of_packets = 0; |
| 1063 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1071 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
| 1064 | return -EINVAL; | 1072 | return -EINVAL; |
| 1065 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1066 | uurb->buffer, uurb->buffer_length)) | ||
| 1067 | return -EFAULT; | ||
| 1068 | snoop(&ps->dev->dev, "bulk urb\n"); | 1073 | snoop(&ps->dev->dev, "bulk urb\n"); |
| 1069 | break; | 1074 | break; |
| 1070 | 1075 | ||
| @@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1106 | return -EINVAL; | 1111 | return -EINVAL; |
| 1107 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | 1112 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) |
| 1108 | return -EINVAL; | 1113 | return -EINVAL; |
| 1109 | if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | ||
| 1110 | uurb->buffer, uurb->buffer_length)) | ||
| 1111 | return -EFAULT; | ||
| 1112 | snoop(&ps->dev->dev, "interrupt urb\n"); | 1114 | snoop(&ps->dev->dev, "interrupt urb\n"); |
| 1113 | break; | 1115 | break; |
| 1114 | 1116 | ||
| 1115 | default: | 1117 | default: |
| 1116 | return -EINVAL; | 1118 | return -EINVAL; |
| 1117 | } | 1119 | } |
| 1118 | as = alloc_async(uurb->number_of_packets); | 1120 | if (uurb->buffer_length > 0 && |
| 1119 | if (!as) { | 1121 | !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, |
| 1122 | uurb->buffer, uurb->buffer_length)) { | ||
| 1120 | kfree(isopkt); | 1123 | kfree(isopkt); |
| 1121 | kfree(dr); | 1124 | kfree(dr); |
| 1122 | return -ENOMEM; | 1125 | return -EFAULT; |
| 1123 | } | 1126 | } |
| 1124 | as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); | 1127 | as = alloc_async(uurb->number_of_packets); |
| 1125 | if (!as->urb->transfer_buffer) { | 1128 | if (!as) { |
| 1126 | kfree(isopkt); | 1129 | kfree(isopkt); |
| 1127 | kfree(dr); | 1130 | kfree(dr); |
| 1128 | free_async(as); | ||
| 1129 | return -ENOMEM; | 1131 | return -ENOMEM; |
| 1130 | } | 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 | } | ||
| 1131 | as->urb->dev = ps->dev; | 1143 | as->urb->dev = ps->dev; |
| 1132 | as->urb->pipe = (uurb->type << 30) | | 1144 | as->urb->pipe = (uurb->type << 30) | |
| 1133 | __create_pipe(ps->dev, uurb->endpoint & 0xf) | | 1145 | __create_pipe(ps->dev, uurb->endpoint & 0xf) | |
| @@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1169 | kfree(isopkt); | 1181 | kfree(isopkt); |
| 1170 | as->ps = ps; | 1182 | as->ps = ps; |
| 1171 | as->userurb = arg; | 1183 | as->userurb = arg; |
| 1172 | if (uurb->endpoint & USB_DIR_IN) | 1184 | if (is_in && uurb->buffer_length > 0) |
| 1173 | as->userbuffer = uurb->buffer; | 1185 | as->userbuffer = uurb->buffer; |
| 1174 | else | 1186 | else |
| 1175 | as->userbuffer = NULL; | 1187 | as->userbuffer = NULL; |
| @@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1179 | as->uid = cred->uid; | 1191 | as->uid = cred->uid; |
| 1180 | as->euid = cred->euid; | 1192 | as->euid = cred->euid; |
| 1181 | security_task_getsecid(current, &as->secid); | 1193 | security_task_getsecid(current, &as->secid); |
| 1182 | if (!is_in) { | 1194 | if (!is_in && uurb->buffer_length > 0) { |
| 1183 | if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, | 1195 | if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, |
| 1184 | as->urb->transfer_buffer_length)) { | 1196 | uurb->buffer_length)) { |
| 1185 | free_async(as); | 1197 | free_async(as); |
| 1186 | return -EFAULT; | 1198 | return -EFAULT; |
| 1187 | } | 1199 | } |
| @@ -1231,22 +1243,22 @@ static int processcompl(struct async *as, void __user * __user *arg) | |||
| 1231 | if (as->userbuffer) | 1243 | if (as->userbuffer) |
| 1232 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, | 1244 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, |
| 1233 | urb->transfer_buffer_length)) | 1245 | urb->transfer_buffer_length)) |
| 1234 | return -EFAULT; | 1246 | goto err_out; |
| 1235 | if (put_user(as->status, &userurb->status)) | 1247 | if (put_user(as->status, &userurb->status)) |
| 1236 | return -EFAULT; | 1248 | goto err_out; |
| 1237 | if (put_user(urb->actual_length, &userurb->actual_length)) | 1249 | if (put_user(urb->actual_length, &userurb->actual_length)) |
| 1238 | return -EFAULT; | 1250 | goto err_out; |
| 1239 | if (put_user(urb->error_count, &userurb->error_count)) | 1251 | if (put_user(urb->error_count, &userurb->error_count)) |
| 1240 | return -EFAULT; | 1252 | goto err_out; |
| 1241 | 1253 | ||
| 1242 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { | 1254 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { |
| 1243 | for (i = 0; i < urb->number_of_packets; i++) { | 1255 | for (i = 0; i < urb->number_of_packets; i++) { |
| 1244 | if (put_user(urb->iso_frame_desc[i].actual_length, | 1256 | if (put_user(urb->iso_frame_desc[i].actual_length, |
| 1245 | &userurb->iso_frame_desc[i].actual_length)) | 1257 | &userurb->iso_frame_desc[i].actual_length)) |
| 1246 | return -EFAULT; | 1258 | goto err_out; |
| 1247 | if (put_user(urb->iso_frame_desc[i].status, | 1259 | if (put_user(urb->iso_frame_desc[i].status, |
| 1248 | &userurb->iso_frame_desc[i].status)) | 1260 | &userurb->iso_frame_desc[i].status)) |
| 1249 | return -EFAULT; | 1261 | goto err_out; |
| 1250 | } | 1262 | } |
| 1251 | } | 1263 | } |
| 1252 | 1264 | ||
| @@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg) | |||
| 1255 | if (put_user(addr, (void __user * __user *)arg)) | 1267 | if (put_user(addr, (void __user * __user *)arg)) |
| 1256 | return -EFAULT; | 1268 | return -EFAULT; |
| 1257 | return 0; | 1269 | return 0; |
| 1270 | |||
| 1271 | err_out: | ||
| 1272 | free_async(as); | ||
| 1273 | return -EFAULT; | ||
| 1258 | } | 1274 | } |
| 1259 | 1275 | ||
| 1260 | static struct async *reap_as(struct dev_state *ps) | 1276 | static struct async *reap_as(struct dev_state *ps) |
