Pull uvc compat XU ioctl fixes from Andy Lutomirski: "uvc's compat XU ioctls go through tons of potentially buggy indirection. The first patch removes the indirection. The second one cleans up the code. Compile-tested only. I have the hardware, but I have absolutely no idea what XU does, how to use it, what software to recompile as 32-bit, or what to test in that software" * tag '20160610_uvc_compat_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/luto/linux: uvc_v4l2: Simplify compat ioctl implementation uvc: Forward compat ioctls to their handlers directly
Unified · Split
| @@ -1274,8 +1274,6 @@ struct uvc_xu_control_mapping32 { · 1273 unmodified lines | ||
| 1274 | 1274 | static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, |
| 1275 | 1275 | const struct uvc_xu_control_mapping32 __user *up) |
| 1276 | 1276 | { |
| 1277 | − struct uvc_menu_info __user *umenus; | |
| 1278 | − struct uvc_menu_info __user *kmenus; | |
| 1279 | 1277 | compat_caddr_t p; |
| 1280 | 1278 | |
| 1281 | 1279 | if (!access_ok(VERIFY_READ, up, sizeof(*up)) || |
| @@ -1292,17 +1290,7 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, · 10 unmodified lines | ||
| 1292 | 1290 | |
| 1293 | 1291 | if (__get_user(p, &up->menu_info)) |
| 1294 | 1292 | return -EFAULT; |
| 1295 | − umenus = compat_ptr(p); | |
| 1296 | − if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus))) | |
| 1297 | − return -EFAULT; | |
| 1298 | − | |
| 1299 | − kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus)); | |
| 1300 | − if (kmenus == NULL) | |
| 1301 | − return -EFAULT; | |
| 1302 | − kp->menu_info = kmenus; | |
| 1303 | − | |
| 1304 | − if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus))) | |
| 1305 | − return -EFAULT; | |
| 1293 | + kp->menu_info = compat_ptr(p); | |
| 1306 | 1294 | |
| 1307 | 1295 | return 0; |
| 1308 | 1296 | } |
| @@ -1310,10 +1298,6 @@ static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, · 1 unmodified line | ||
| 1310 | 1298 | static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, |
| 1311 | 1299 | struct uvc_xu_control_mapping32 __user *up) |
| 1312 | 1300 | { |
| 1313 | − struct uvc_menu_info __user *umenus; | |
| 1314 | − struct uvc_menu_info __user *kmenus = kp->menu_info; | |
| 1315 | − compat_caddr_t p; | |
| 1316 | − | |
| 1317 | 1301 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || |
| 1318 | 1302 | __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) || |
| 1319 | 1303 | __put_user(kp->menu_count, &up->menu_count)) |
| @@ -1322,16 +1306,6 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, · 2 unmodified lines | ||
| 1322 | 1306 | if (__clear_user(up->reserved, sizeof(up->reserved))) |
| 1323 | 1307 | return -EFAULT; |
| 1324 | 1308 | |
| 1325 | − if (kp->menu_count == 0) | |
| 1326 | − return 0; | |
| 1327 | − | |
| 1328 | − if (get_user(p, &up->menu_info)) | |
| 1329 | − return -EFAULT; | |
| 1330 | − umenus = compat_ptr(p); | |
| 1331 | − | |
| 1332 | − if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus))) | |
| 1333 | − return -EFAULT; | |
| 1334 | − | |
| 1335 | 1309 | return 0; |
| 1336 | 1310 | } |
| 1337 | 1311 | |
| @@ -1346,8 +1320,6 @@ struct uvc_xu_control_query32 { · 8 unmodified lines | ||
| 1346 | 1320 | static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, |
| 1347 | 1321 | const struct uvc_xu_control_query32 __user *up) |
| 1348 | 1322 | { |
| 1349 | − u8 __user *udata; | |
| 1350 | − u8 __user *kdata; | |
| 1351 | 1323 | compat_caddr_t p; |
| 1352 | 1324 | |
| 1353 | 1325 | if (!access_ok(VERIFY_READ, up, sizeof(*up)) || |
| @@ -1361,17 +1333,7 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, · 7 unmodified lines | ||
| 1361 | 1333 | |
| 1362 | 1334 | if (__get_user(p, &up->data)) |
| 1363 | 1335 | return -EFAULT; |
| 1364 | − udata = compat_ptr(p); | |
| 1365 | − if (!access_ok(VERIFY_READ, udata, kp->size)) | |
| 1366 | − return -EFAULT; | |
| 1367 | − | |
| 1368 | − kdata = compat_alloc_user_space(kp->size); | |
| 1369 | − if (kdata == NULL) | |
| 1370 | − return -EFAULT; | |
| 1371 | − kp->data = kdata; | |
| 1372 | − | |
| 1373 | − if (copy_in_user(kdata, udata, kp->size)) | |
| 1374 | − return -EFAULT; | |
| 1336 | + kp->data = compat_ptr(p); | |
| 1375 | 1337 | |
| 1376 | 1338 | return 0; |
| 1377 | 1339 | } |
| @@ -1379,26 +1341,10 @@ static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, · 1 unmodified line | ||
| 1379 | 1341 | static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, |
| 1380 | 1342 | struct uvc_xu_control_query32 __user *up) |
| 1381 | 1343 | { |
| 1382 | − u8 __user *udata; | |
| 1383 | − u8 __user *kdata = kp->data; | |
| 1384 | − compat_caddr_t p; | |
| 1385 | − | |
| 1386 | 1344 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || |
| 1387 | 1345 | __copy_to_user(up, kp, offsetof(typeof(*up), data))) |
| 1388 | 1346 | return -EFAULT; |
| 1389 | 1347 | |
| 1390 | − if (kp->size == 0) | |
| 1391 | − return 0; | |
| 1392 | − | |
| 1393 | − if (get_user(p, &up->data)) | |
| 1394 | − return -EFAULT; | |
| 1395 | − udata = compat_ptr(p); | |
| 1396 | − if (!access_ok(VERIFY_READ, udata, kp->size)) | |
| 1397 | − return -EFAULT; | |
| 1398 | − | |
| 1399 | − if (copy_in_user(udata, kdata, kp->size)) | |
| 1400 | − return -EFAULT; | |
| 1401 | − | |
| 1402 | 1348 | return 0; |
| 1403 | 1349 | } |
| 1404 | 1350 | |
| @@ -1408,47 +1354,44 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, · 3 unmodified lines | ||
| 1408 | 1354 | static long uvc_v4l2_compat_ioctl32(struct file *file, |
| 1409 | 1355 | unsigned int cmd, unsigned long arg) |
| 1410 | 1356 | { |
| 1357 | + struct uvc_fh *handle = file->private_data; | |
| 1411 | 1358 | union { |
| 1412 | 1359 | struct uvc_xu_control_mapping xmap; |
| 1413 | 1360 | struct uvc_xu_control_query xqry; |
| 1414 | 1361 | } karg; |
| 1415 | 1362 | void __user *up = compat_ptr(arg); |
| 1416 | − mm_segment_t old_fs; | |
| 1417 | 1363 | long ret; |
| 1418 | 1364 | |
| 1419 | 1365 | switch (cmd) { |
| 1420 | 1366 | case UVCIOC_CTRL_MAP32: |
| 1421 | − cmd = UVCIOC_CTRL_MAP; | |
| 1422 | 1367 | ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); |
| 1368 | + if (ret) | |
| 1369 | + return ret; | |
| 1370 | + ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap); | |
| 1371 | + if (ret) | |
| 1372 | + return ret; | |
| 1373 | + ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); | |
| 1374 | + if (ret) | |
| 1375 | + return ret; | |
| 1376 | + | |
| 1423 | 1377 | break; |
| 1424 | 1378 | |
| 1425 | 1379 | case UVCIOC_CTRL_QUERY32: |
| 1426 | − cmd = UVCIOC_CTRL_QUERY; | |
| 1427 | 1380 | ret = uvc_v4l2_get_xu_query(&karg.xqry, up); |
| 1381 | + if (ret) | |
| 1382 | + return ret; | |
| 1383 | + ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); | |
| 1384 | + if (ret) | |
| 1385 | + return ret; | |
| 1386 | + ret = uvc_v4l2_put_xu_query(&karg.xqry, up); | |
| 1387 | + if (ret) | |
| 1388 | + return ret; | |
| 1428 | 1389 | break; |
| 1429 | 1390 | |
| 1430 | 1391 | default: |
| 1431 | 1392 | return -ENOIOCTLCMD; |
| 1432 | 1393 | } |
| 1433 | 1394 | |
| 1434 | − old_fs = get_fs(); | |
| 1435 | − set_fs(KERNEL_DS); | |
| 1436 | − ret = video_ioctl2(file, cmd, (unsigned long)&karg); | |
| 1437 | − set_fs(old_fs); | |
| 1438 | − | |
| 1439 | − if (ret < 0) | |
| 1440 | − return ret; | |
| 1441 | − | |
| 1442 | − switch (cmd) { | |
| 1443 | − case UVCIOC_CTRL_MAP: | |
| 1444 | − ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); | |
| 1445 | − break; | |
| 1446 | − | |
| 1447 | − case UVCIOC_CTRL_QUERY: | |
| 1448 | − ret = uvc_v4l2_put_xu_query(&karg.xqry, up); | |
| 1449 | − break; | |
| 1450 | − } | |
| 1451 | − | |
| 1452 | 1395 | return ret; |
| 1453 | 1396 | } |
| 1454 | 1397 | #endif |