.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * ioctl32.c: Conversion between 32bit and 64bit native ioctls. |
---|
3 | 4 | * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de> |
---|
.. | .. |
---|
158 | 159 | compat_caddr_t p; |
---|
159 | 160 | u32 clipcount; |
---|
160 | 161 | |
---|
161 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 162 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
162 | 163 | copy_in_user(&p64->w, &p32->w, sizeof(p32->w)) || |
---|
163 | 164 | assign_in_user(&p64->field, &p32->field) || |
---|
164 | 165 | assign_in_user(&p64->chromakey, &p32->chromakey) || |
---|
.. | .. |
---|
244 | 245 | * return: number of created buffers |
---|
245 | 246 | * @memory: buffer memory type |
---|
246 | 247 | * @format: frame format, for which buffers are requested |
---|
| 248 | + * @capabilities: capabilities of this buffer type. |
---|
247 | 249 | * @reserved: future extensions |
---|
248 | 250 | */ |
---|
249 | 251 | struct v4l2_create_buffers32 { |
---|
.. | .. |
---|
251 | 253 | __u32 count; |
---|
252 | 254 | __u32 memory; /* enum v4l2_memory */ |
---|
253 | 255 | struct v4l2_format32 format; |
---|
254 | | - __u32 reserved[8]; |
---|
| 256 | + __u32 capabilities; |
---|
| 257 | + __u32 reserved[7]; |
---|
255 | 258 | }; |
---|
256 | 259 | |
---|
257 | 260 | static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) |
---|
.. | .. |
---|
281 | 284 | |
---|
282 | 285 | static int bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) |
---|
283 | 286 | { |
---|
284 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32))) |
---|
| 287 | + if (!access_ok(p32, sizeof(*p32))) |
---|
285 | 288 | return -EFAULT; |
---|
286 | 289 | return __bufsize_v4l2_format(p32, size); |
---|
287 | 290 | } |
---|
.. | .. |
---|
333 | 336 | struct v4l2_format32 __user *p32, |
---|
334 | 337 | void __user *aux_buf, u32 aux_space) |
---|
335 | 338 | { |
---|
336 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32))) |
---|
| 339 | + if (!access_ok(p32, sizeof(*p32))) |
---|
337 | 340 | return -EFAULT; |
---|
338 | 341 | return __get_v4l2_format32(p64, p32, aux_buf, aux_space); |
---|
339 | 342 | } |
---|
.. | .. |
---|
341 | 344 | static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *p32, |
---|
342 | 345 | u32 *size) |
---|
343 | 346 | { |
---|
344 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32))) |
---|
| 347 | + if (!access_ok(p32, sizeof(*p32))) |
---|
345 | 348 | return -EFAULT; |
---|
346 | 349 | return __bufsize_v4l2_format(&p32->format, size); |
---|
347 | 350 | } |
---|
.. | .. |
---|
350 | 353 | struct v4l2_create_buffers32 __user *p32, |
---|
351 | 354 | void __user *aux_buf, u32 aux_space) |
---|
352 | 355 | { |
---|
353 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 356 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
354 | 357 | copy_in_user(p64, p32, |
---|
355 | 358 | offsetof(struct v4l2_create_buffers32, format))) |
---|
356 | 359 | return -EFAULT; |
---|
.. | .. |
---|
402 | 405 | static int put_v4l2_format32(struct v4l2_format __user *p64, |
---|
403 | 406 | struct v4l2_format32 __user *p32) |
---|
404 | 407 | { |
---|
405 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32))) |
---|
| 408 | + if (!access_ok(p32, sizeof(*p32))) |
---|
406 | 409 | return -EFAULT; |
---|
407 | 410 | return __put_v4l2_format32(p64, p32); |
---|
408 | 411 | } |
---|
.. | .. |
---|
410 | 413 | static int put_v4l2_create32(struct v4l2_create_buffers __user *p64, |
---|
411 | 414 | struct v4l2_create_buffers32 __user *p32) |
---|
412 | 415 | { |
---|
413 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 416 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
414 | 417 | copy_in_user(p32, p64, |
---|
415 | 418 | offsetof(struct v4l2_create_buffers32, format)) || |
---|
| 419 | + assign_in_user(&p32->capabilities, &p64->capabilities) || |
---|
416 | 420 | copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) |
---|
417 | 421 | return -EFAULT; |
---|
418 | 422 | return __put_v4l2_format32(&p64->format, &p32->format); |
---|
.. | .. |
---|
431 | 435 | struct v4l2_standard32 __user *p32) |
---|
432 | 436 | { |
---|
433 | 437 | /* other fields are not set by the user, nor used by the driver */ |
---|
434 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 438 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
435 | 439 | assign_in_user(&p64->index, &p32->index)) |
---|
436 | 440 | return -EFAULT; |
---|
437 | 441 | return 0; |
---|
.. | .. |
---|
440 | 444 | static int put_v4l2_standard32(struct v4l2_standard __user *p64, |
---|
441 | 445 | struct v4l2_standard32 __user *p32) |
---|
442 | 446 | { |
---|
443 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 447 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
444 | 448 | assign_in_user(&p32->index, &p64->index) || |
---|
445 | 449 | assign_in_user(&p32->id, &p64->id) || |
---|
446 | 450 | copy_in_user(p32->name, p64->name, sizeof(p32->name)) || |
---|
.. | .. |
---|
461 | 465 | __s32 fd; |
---|
462 | 466 | } m; |
---|
463 | 467 | __u32 data_offset; |
---|
| 468 | + /* |
---|
| 469 | + * few userspace clients and drivers use reserved fields |
---|
| 470 | + * and it is up to them how these fields are used. v4l2 |
---|
| 471 | + * simply copy reserved fields between them. |
---|
| 472 | + */ |
---|
464 | 473 | __u32 reserved[11]; |
---|
465 | 474 | }; |
---|
466 | 475 | |
---|
| 476 | +/* |
---|
| 477 | + * This is correct for all architectures including i386, but not x32, |
---|
| 478 | + * which has different alignment requirements for timestamp |
---|
| 479 | + */ |
---|
467 | 480 | struct v4l2_buffer32 { |
---|
468 | 481 | __u32 index; |
---|
469 | 482 | __u32 type; /* enum v4l2_buf_type */ |
---|
470 | 483 | __u32 bytesused; |
---|
471 | 484 | __u32 flags; |
---|
472 | 485 | __u32 field; /* enum v4l2_field */ |
---|
473 | | - struct compat_timeval timestamp; |
---|
| 486 | + struct { |
---|
| 487 | + compat_s64 tv_sec; |
---|
| 488 | + compat_s64 tv_usec; |
---|
| 489 | + } timestamp; |
---|
474 | 490 | struct v4l2_timecode timecode; |
---|
475 | 491 | __u32 sequence; |
---|
476 | 492 | |
---|
.. | .. |
---|
484 | 500 | } m; |
---|
485 | 501 | __u32 length; |
---|
486 | 502 | __u32 reserved2; |
---|
487 | | - __u32 reserved; |
---|
| 503 | + __s32 request_fd; |
---|
| 504 | +}; |
---|
| 505 | + |
---|
| 506 | +struct v4l2_buffer32_time32 { |
---|
| 507 | + __u32 index; |
---|
| 508 | + __u32 type; /* enum v4l2_buf_type */ |
---|
| 509 | + __u32 bytesused; |
---|
| 510 | + __u32 flags; |
---|
| 511 | + __u32 field; /* enum v4l2_field */ |
---|
| 512 | + struct old_timeval32 timestamp; |
---|
| 513 | + struct v4l2_timecode timecode; |
---|
| 514 | + __u32 sequence; |
---|
| 515 | + |
---|
| 516 | + /* memory location */ |
---|
| 517 | + __u32 memory; /* enum v4l2_memory */ |
---|
| 518 | + union { |
---|
| 519 | + __u32 offset; |
---|
| 520 | + compat_long_t userptr; |
---|
| 521 | + compat_caddr_t planes; |
---|
| 522 | + __s32 fd; |
---|
| 523 | + } m; |
---|
| 524 | + __u32 length; |
---|
| 525 | + __u32 reserved2; |
---|
| 526 | + __s32 request_fd; |
---|
488 | 527 | }; |
---|
489 | 528 | |
---|
490 | 529 | static int get_v4l2_plane32(struct v4l2_plane __user *p64, |
---|
.. | .. |
---|
495 | 534 | |
---|
496 | 535 | if (copy_in_user(p64, p32, 2 * sizeof(__u32)) || |
---|
497 | 536 | copy_in_user(&p64->data_offset, &p32->data_offset, |
---|
498 | | - sizeof(p64->data_offset))) |
---|
| 537 | + sizeof(p64->data_offset)) || |
---|
| 538 | + copy_in_user(p64->reserved, p32->reserved, |
---|
| 539 | + sizeof(p64->reserved))) |
---|
499 | 540 | return -EFAULT; |
---|
500 | 541 | |
---|
501 | 542 | switch (memory) { |
---|
.. | .. |
---|
527 | 568 | |
---|
528 | 569 | if (copy_in_user(p32, p64, 2 * sizeof(__u32)) || |
---|
529 | 570 | copy_in_user(&p32->data_offset, &p64->data_offset, |
---|
530 | | - sizeof(p64->data_offset))) |
---|
| 571 | + sizeof(p64->data_offset)) || |
---|
| 572 | + copy_in_user(p32->reserved, p64->reserved, |
---|
| 573 | + sizeof(p32->reserved))) |
---|
531 | 574 | return -EFAULT; |
---|
532 | 575 | |
---|
533 | 576 | switch (memory) { |
---|
.. | .. |
---|
557 | 600 | u32 type; |
---|
558 | 601 | u32 length; |
---|
559 | 602 | |
---|
560 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 603 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
| 604 | + get_user(type, &p32->type) || |
---|
| 605 | + get_user(length, &p32->length)) |
---|
| 606 | + return -EFAULT; |
---|
| 607 | + |
---|
| 608 | + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { |
---|
| 609 | + if (length > VIDEO_MAX_PLANES) |
---|
| 610 | + return -EINVAL; |
---|
| 611 | + |
---|
| 612 | + /* |
---|
| 613 | + * We don't really care if userspace decides to kill itself |
---|
| 614 | + * by passing a very big length value |
---|
| 615 | + */ |
---|
| 616 | + *size = length * sizeof(struct v4l2_plane); |
---|
| 617 | + } else { |
---|
| 618 | + *size = 0; |
---|
| 619 | + } |
---|
| 620 | + return 0; |
---|
| 621 | +} |
---|
| 622 | + |
---|
| 623 | +static int bufsize_v4l2_buffer_time32(struct v4l2_buffer32_time32 __user *p32, u32 *size) |
---|
| 624 | +{ |
---|
| 625 | + u32 type; |
---|
| 626 | + u32 length; |
---|
| 627 | + |
---|
| 628 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
561 | 629 | get_user(type, &p32->type) || |
---|
562 | 630 | get_user(length, &p32->length)) |
---|
563 | 631 | return -EFAULT; |
---|
.. | .. |
---|
583 | 651 | { |
---|
584 | 652 | u32 type; |
---|
585 | 653 | u32 length; |
---|
| 654 | + s32 request_fd; |
---|
586 | 655 | enum v4l2_memory memory; |
---|
587 | 656 | struct v4l2_plane32 __user *uplane32; |
---|
588 | 657 | struct v4l2_plane __user *uplane; |
---|
589 | 658 | compat_caddr_t p; |
---|
590 | 659 | int ret; |
---|
591 | 660 | |
---|
592 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 661 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
593 | 662 | assign_in_user(&p64->index, &p32->index) || |
---|
594 | 663 | get_user(type, &p32->type) || |
---|
595 | 664 | put_user(type, &p64->type) || |
---|
.. | .. |
---|
597 | 666 | get_user(memory, &p32->memory) || |
---|
598 | 667 | put_user(memory, &p64->memory) || |
---|
599 | 668 | get_user(length, &p32->length) || |
---|
600 | | - put_user(length, &p64->length)) |
---|
| 669 | + put_user(length, &p64->length) || |
---|
| 670 | + get_user(request_fd, &p32->request_fd) || |
---|
| 671 | + put_user(request_fd, &p64->request_fd)) |
---|
601 | 672 | return -EFAULT; |
---|
602 | 673 | |
---|
603 | 674 | if (V4L2_TYPE_IS_OUTPUT(type)) |
---|
.. | .. |
---|
626 | 697 | return -EFAULT; |
---|
627 | 698 | |
---|
628 | 699 | uplane32 = compat_ptr(p); |
---|
629 | | - if (!access_ok(VERIFY_READ, uplane32, |
---|
| 700 | + if (!access_ok(uplane32, |
---|
| 701 | + num_planes * sizeof(*uplane32))) |
---|
| 702 | + return -EFAULT; |
---|
| 703 | + |
---|
| 704 | + /* |
---|
| 705 | + * We don't really care if userspace decides to kill itself |
---|
| 706 | + * by passing a very big num_planes value |
---|
| 707 | + */ |
---|
| 708 | + if (aux_space < num_planes * sizeof(*uplane)) |
---|
| 709 | + return -EFAULT; |
---|
| 710 | + |
---|
| 711 | + uplane = aux_buf; |
---|
| 712 | + if (put_user_force(uplane, &p64->m.planes)) |
---|
| 713 | + return -EFAULT; |
---|
| 714 | + |
---|
| 715 | + while (num_planes--) { |
---|
| 716 | + ret = get_v4l2_plane32(uplane, uplane32, memory); |
---|
| 717 | + if (ret) |
---|
| 718 | + return ret; |
---|
| 719 | + uplane++; |
---|
| 720 | + uplane32++; |
---|
| 721 | + } |
---|
| 722 | + } else { |
---|
| 723 | + switch (memory) { |
---|
| 724 | + case V4L2_MEMORY_MMAP: |
---|
| 725 | + case V4L2_MEMORY_OVERLAY: |
---|
| 726 | + if (assign_in_user(&p64->m.offset, &p32->m.offset)) |
---|
| 727 | + return -EFAULT; |
---|
| 728 | + break; |
---|
| 729 | + case V4L2_MEMORY_USERPTR: { |
---|
| 730 | + compat_ulong_t userptr; |
---|
| 731 | + |
---|
| 732 | + if (get_user(userptr, &p32->m.userptr) || |
---|
| 733 | + put_user((unsigned long)compat_ptr(userptr), |
---|
| 734 | + &p64->m.userptr)) |
---|
| 735 | + return -EFAULT; |
---|
| 736 | + break; |
---|
| 737 | + } |
---|
| 738 | + case V4L2_MEMORY_DMABUF: |
---|
| 739 | + if (assign_in_user(&p64->m.fd, &p32->m.fd)) |
---|
| 740 | + return -EFAULT; |
---|
| 741 | + break; |
---|
| 742 | + } |
---|
| 743 | + } |
---|
| 744 | + |
---|
| 745 | + return 0; |
---|
| 746 | +} |
---|
| 747 | + |
---|
| 748 | +static int get_v4l2_buffer32_time32(struct v4l2_buffer_time32 __user *p64, |
---|
| 749 | + struct v4l2_buffer32_time32 __user *p32, |
---|
| 750 | + void __user *aux_buf, u32 aux_space) |
---|
| 751 | +{ |
---|
| 752 | + u32 type; |
---|
| 753 | + u32 length; |
---|
| 754 | + s32 request_fd; |
---|
| 755 | + enum v4l2_memory memory; |
---|
| 756 | + struct v4l2_plane32 __user *uplane32; |
---|
| 757 | + struct v4l2_plane __user *uplane; |
---|
| 758 | + compat_caddr_t p; |
---|
| 759 | + int ret; |
---|
| 760 | + |
---|
| 761 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
| 762 | + assign_in_user(&p64->index, &p32->index) || |
---|
| 763 | + get_user(type, &p32->type) || |
---|
| 764 | + put_user(type, &p64->type) || |
---|
| 765 | + assign_in_user(&p64->flags, &p32->flags) || |
---|
| 766 | + get_user(memory, &p32->memory) || |
---|
| 767 | + put_user(memory, &p64->memory) || |
---|
| 768 | + get_user(length, &p32->length) || |
---|
| 769 | + put_user(length, &p64->length) || |
---|
| 770 | + get_user(request_fd, &p32->request_fd) || |
---|
| 771 | + put_user(request_fd, &p64->request_fd)) |
---|
| 772 | + return -EFAULT; |
---|
| 773 | + |
---|
| 774 | + if (V4L2_TYPE_IS_OUTPUT(type)) |
---|
| 775 | + if (assign_in_user(&p64->bytesused, &p32->bytesused) || |
---|
| 776 | + assign_in_user(&p64->field, &p32->field) || |
---|
| 777 | + assign_in_user(&p64->timestamp.tv_sec, |
---|
| 778 | + &p32->timestamp.tv_sec) || |
---|
| 779 | + assign_in_user(&p64->timestamp.tv_usec, |
---|
| 780 | + &p32->timestamp.tv_usec)) |
---|
| 781 | + return -EFAULT; |
---|
| 782 | + |
---|
| 783 | + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { |
---|
| 784 | + u32 num_planes = length; |
---|
| 785 | + |
---|
| 786 | + if (num_planes == 0) { |
---|
| 787 | + /* |
---|
| 788 | + * num_planes == 0 is legal, e.g. when userspace doesn't |
---|
| 789 | + * need planes array on DQBUF |
---|
| 790 | + */ |
---|
| 791 | + return put_user(NULL, &p64->m.planes); |
---|
| 792 | + } |
---|
| 793 | + if (num_planes > VIDEO_MAX_PLANES) |
---|
| 794 | + return -EINVAL; |
---|
| 795 | + |
---|
| 796 | + if (get_user(p, &p32->m.planes)) |
---|
| 797 | + return -EFAULT; |
---|
| 798 | + |
---|
| 799 | + uplane32 = compat_ptr(p); |
---|
| 800 | + if (!access_ok(uplane32, |
---|
630 | 801 | num_planes * sizeof(*uplane32))) |
---|
631 | 802 | return -EFAULT; |
---|
632 | 803 | |
---|
.. | .. |
---|
685 | 856 | compat_caddr_t p; |
---|
686 | 857 | int ret; |
---|
687 | 858 | |
---|
688 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 859 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
689 | 860 | assign_in_user(&p32->index, &p64->index) || |
---|
690 | 861 | get_user(type, &p64->type) || |
---|
691 | 862 | put_user(type, &p32->type) || |
---|
.. | .. |
---|
701 | 872 | copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) || |
---|
702 | 873 | assign_in_user(&p32->sequence, &p64->sequence) || |
---|
703 | 874 | assign_in_user(&p32->reserved2, &p64->reserved2) || |
---|
704 | | - assign_in_user(&p32->reserved, &p64->reserved) || |
---|
| 875 | + assign_in_user(&p32->request_fd, &p64->request_fd) || |
---|
| 876 | + get_user(length, &p64->length) || |
---|
| 877 | + put_user(length, &p32->length)) |
---|
| 878 | + return -EFAULT; |
---|
| 879 | + |
---|
| 880 | + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { |
---|
| 881 | + u32 num_planes = length; |
---|
| 882 | + |
---|
| 883 | + if (num_planes == 0) |
---|
| 884 | + return 0; |
---|
| 885 | + /* We need to define uplane without __user, even though |
---|
| 886 | + * it does point to data in userspace here. The reason is |
---|
| 887 | + * that v4l2-ioctl.c copies it from userspace to kernelspace, |
---|
| 888 | + * so its definition in videodev2.h doesn't have a |
---|
| 889 | + * __user markup. Defining uplane with __user causes |
---|
| 890 | + * smatch warnings, so instead declare it without __user |
---|
| 891 | + * and cast it as a userspace pointer to put_v4l2_plane32(). |
---|
| 892 | + */ |
---|
| 893 | + if (get_user(uplane, &p64->m.planes)) |
---|
| 894 | + return -EFAULT; |
---|
| 895 | + if (get_user(p, &p32->m.planes)) |
---|
| 896 | + return -EFAULT; |
---|
| 897 | + uplane32 = compat_ptr(p); |
---|
| 898 | + |
---|
| 899 | + while (num_planes--) { |
---|
| 900 | + ret = put_v4l2_plane32((void __user *)uplane, |
---|
| 901 | + uplane32, memory); |
---|
| 902 | + if (ret) |
---|
| 903 | + return ret; |
---|
| 904 | + ++uplane; |
---|
| 905 | + ++uplane32; |
---|
| 906 | + } |
---|
| 907 | + } else { |
---|
| 908 | + switch (memory) { |
---|
| 909 | + case V4L2_MEMORY_MMAP: |
---|
| 910 | + case V4L2_MEMORY_OVERLAY: |
---|
| 911 | + if (assign_in_user(&p32->m.offset, &p64->m.offset)) |
---|
| 912 | + return -EFAULT; |
---|
| 913 | + break; |
---|
| 914 | + case V4L2_MEMORY_USERPTR: |
---|
| 915 | + if (assign_in_user(&p32->m.userptr, &p64->m.userptr)) |
---|
| 916 | + return -EFAULT; |
---|
| 917 | + break; |
---|
| 918 | + case V4L2_MEMORY_DMABUF: |
---|
| 919 | + if (assign_in_user(&p32->m.fd, &p64->m.fd)) |
---|
| 920 | + return -EFAULT; |
---|
| 921 | + break; |
---|
| 922 | + } |
---|
| 923 | + } |
---|
| 924 | + |
---|
| 925 | + return 0; |
---|
| 926 | +} |
---|
| 927 | + |
---|
| 928 | +static int put_v4l2_buffer32_time32(struct v4l2_buffer_time32 __user *p64, |
---|
| 929 | + struct v4l2_buffer32_time32 __user *p32) |
---|
| 930 | +{ |
---|
| 931 | + u32 type; |
---|
| 932 | + u32 length; |
---|
| 933 | + enum v4l2_memory memory; |
---|
| 934 | + struct v4l2_plane32 __user *uplane32; |
---|
| 935 | + struct v4l2_plane *uplane; |
---|
| 936 | + compat_caddr_t p; |
---|
| 937 | + int ret; |
---|
| 938 | + |
---|
| 939 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
| 940 | + assign_in_user(&p32->index, &p64->index) || |
---|
| 941 | + get_user(type, &p64->type) || |
---|
| 942 | + put_user(type, &p32->type) || |
---|
| 943 | + assign_in_user(&p32->flags, &p64->flags) || |
---|
| 944 | + get_user(memory, &p64->memory) || |
---|
| 945 | + put_user(memory, &p32->memory)) |
---|
| 946 | + return -EFAULT; |
---|
| 947 | + |
---|
| 948 | + if (assign_in_user(&p32->bytesused, &p64->bytesused) || |
---|
| 949 | + assign_in_user(&p32->field, &p64->field) || |
---|
| 950 | + assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || |
---|
| 951 | + assign_in_user(&p32->timestamp.tv_usec, &p64->timestamp.tv_usec) || |
---|
| 952 | + copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) || |
---|
| 953 | + assign_in_user(&p32->sequence, &p64->sequence) || |
---|
| 954 | + assign_in_user(&p32->reserved2, &p64->reserved2) || |
---|
| 955 | + assign_in_user(&p32->request_fd, &p64->request_fd) || |
---|
705 | 956 | get_user(length, &p64->length) || |
---|
706 | 957 | put_user(length, &p32->length)) |
---|
707 | 958 | return -EFAULT; |
---|
.. | .. |
---|
775 | 1026 | { |
---|
776 | 1027 | compat_caddr_t tmp; |
---|
777 | 1028 | |
---|
778 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 1029 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
779 | 1030 | get_user(tmp, &p32->base) || |
---|
780 | 1031 | put_user_force(compat_ptr(tmp), &p64->base) || |
---|
781 | 1032 | assign_in_user(&p64->capability, &p32->capability) || |
---|
.. | .. |
---|
790 | 1041 | { |
---|
791 | 1042 | void *base; |
---|
792 | 1043 | |
---|
793 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 1044 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
794 | 1045 | get_user(base, &p64->base) || |
---|
795 | 1046 | put_user(ptr_to_compat((void __user *)base), &p32->base) || |
---|
796 | 1047 | assign_in_user(&p32->capability, &p64->capability) || |
---|
.. | .. |
---|
836 | 1087 | __u32 which; |
---|
837 | 1088 | __u32 count; |
---|
838 | 1089 | __u32 error_idx; |
---|
839 | | - __u32 reserved[2]; |
---|
| 1090 | + __s32 request_fd; |
---|
| 1091 | + __u32 reserved[1]; |
---|
840 | 1092 | compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ |
---|
841 | 1093 | }; |
---|
842 | 1094 | |
---|
.. | .. |
---|
886 | 1138 | { |
---|
887 | 1139 | u32 count; |
---|
888 | 1140 | |
---|
889 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 1141 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
890 | 1142 | get_user(count, &p32->count)) |
---|
891 | 1143 | return -EFAULT; |
---|
892 | 1144 | if (count > V4L2_CID_MAX_CTRLS) |
---|
.. | .. |
---|
906 | 1158 | u32 n; |
---|
907 | 1159 | compat_caddr_t p; |
---|
908 | 1160 | |
---|
909 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 1161 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
910 | 1162 | assign_in_user(&p64->which, &p32->which) || |
---|
911 | 1163 | get_user(count, &p32->count) || |
---|
912 | 1164 | put_user(count, &p64->count) || |
---|
913 | 1165 | assign_in_user(&p64->error_idx, &p32->error_idx) || |
---|
| 1166 | + assign_in_user(&p64->request_fd, &p32->request_fd) || |
---|
914 | 1167 | copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved))) |
---|
915 | 1168 | return -EFAULT; |
---|
916 | 1169 | |
---|
.. | .. |
---|
921 | 1174 | if (get_user(p, &p32->controls)) |
---|
922 | 1175 | return -EFAULT; |
---|
923 | 1176 | ucontrols = compat_ptr(p); |
---|
924 | | - if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) |
---|
| 1177 | + if (!access_ok(ucontrols, count * sizeof(*ucontrols))) |
---|
925 | 1178 | return -EFAULT; |
---|
926 | 1179 | if (aux_space < count * sizeof(*kcontrols)) |
---|
927 | 1180 | return -EFAULT; |
---|
.. | .. |
---|
971 | 1224 | * with __user causes smatch warnings, so instead declare it |
---|
972 | 1225 | * without __user and cast it as a userspace pointer where needed. |
---|
973 | 1226 | */ |
---|
974 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 1227 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
975 | 1228 | assign_in_user(&p32->which, &p64->which) || |
---|
976 | 1229 | get_user(count, &p64->count) || |
---|
977 | 1230 | put_user(count, &p32->count) || |
---|
978 | 1231 | assign_in_user(&p32->error_idx, &p64->error_idx) || |
---|
| 1232 | + assign_in_user(&p32->request_fd, &p64->request_fd) || |
---|
979 | 1233 | copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)) || |
---|
980 | 1234 | get_user(kcontrols, &p64->controls)) |
---|
981 | 1235 | return -EFAULT; |
---|
.. | .. |
---|
985 | 1239 | if (get_user(p, &p32->controls)) |
---|
986 | 1240 | return -EFAULT; |
---|
987 | 1241 | ucontrols = compat_ptr(p); |
---|
988 | | - if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) |
---|
| 1242 | + if (!access_ok(ucontrols, count * sizeof(*ucontrols))) |
---|
989 | 1243 | return -EFAULT; |
---|
990 | 1244 | |
---|
991 | 1245 | for (n = 0; n < count; n++) { |
---|
.. | .. |
---|
1018 | 1272 | return 0; |
---|
1019 | 1273 | } |
---|
1020 | 1274 | |
---|
| 1275 | +#ifdef CONFIG_X86_64 |
---|
| 1276 | +/* |
---|
| 1277 | + * x86 is the only compat architecture with different struct alignment |
---|
| 1278 | + * between 32-bit and 64-bit tasks. |
---|
| 1279 | + * |
---|
| 1280 | + * On all other architectures, v4l2_event32 and v4l2_event32_time32 are |
---|
| 1281 | + * the same as v4l2_event and v4l2_event_time32, so we can use the native |
---|
| 1282 | + * handlers, converting v4l2_event to v4l2_event_time32 if necessary. |
---|
| 1283 | + */ |
---|
1021 | 1284 | struct v4l2_event32 { |
---|
1022 | 1285 | __u32 type; |
---|
1023 | 1286 | union { |
---|
.. | .. |
---|
1026 | 1289 | } u; |
---|
1027 | 1290 | __u32 pending; |
---|
1028 | 1291 | __u32 sequence; |
---|
1029 | | - struct compat_timespec timestamp; |
---|
| 1292 | + struct { |
---|
| 1293 | + compat_s64 tv_sec; |
---|
| 1294 | + compat_s64 tv_nsec; |
---|
| 1295 | + } timestamp; |
---|
| 1296 | + __u32 id; |
---|
| 1297 | + __u32 reserved[8]; |
---|
| 1298 | +}; |
---|
| 1299 | + |
---|
| 1300 | +struct v4l2_event32_time32 { |
---|
| 1301 | + __u32 type; |
---|
| 1302 | + union { |
---|
| 1303 | + compat_s64 value64; |
---|
| 1304 | + __u8 data[64]; |
---|
| 1305 | + } u; |
---|
| 1306 | + __u32 pending; |
---|
| 1307 | + __u32 sequence; |
---|
| 1308 | + struct old_timespec32 timestamp; |
---|
1030 | 1309 | __u32 id; |
---|
1031 | 1310 | __u32 reserved[8]; |
---|
1032 | 1311 | }; |
---|
.. | .. |
---|
1034 | 1313 | static int put_v4l2_event32(struct v4l2_event __user *p64, |
---|
1035 | 1314 | struct v4l2_event32 __user *p32) |
---|
1036 | 1315 | { |
---|
1037 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 1316 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
1038 | 1317 | assign_in_user(&p32->type, &p64->type) || |
---|
1039 | 1318 | copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) || |
---|
1040 | 1319 | assign_in_user(&p32->pending, &p64->pending) || |
---|
.. | .. |
---|
1046 | 1325 | return -EFAULT; |
---|
1047 | 1326 | return 0; |
---|
1048 | 1327 | } |
---|
| 1328 | + |
---|
| 1329 | +static int put_v4l2_event32_time32(struct v4l2_event_time32 __user *p64, |
---|
| 1330 | + struct v4l2_event32_time32 __user *p32) |
---|
| 1331 | +{ |
---|
| 1332 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
| 1333 | + assign_in_user(&p32->type, &p64->type) || |
---|
| 1334 | + copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) || |
---|
| 1335 | + assign_in_user(&p32->pending, &p64->pending) || |
---|
| 1336 | + assign_in_user(&p32->sequence, &p64->sequence) || |
---|
| 1337 | + assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || |
---|
| 1338 | + assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) || |
---|
| 1339 | + assign_in_user(&p32->id, &p64->id) || |
---|
| 1340 | + copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) |
---|
| 1341 | + return -EFAULT; |
---|
| 1342 | + return 0; |
---|
| 1343 | +} |
---|
| 1344 | +#endif |
---|
1049 | 1345 | |
---|
1050 | 1346 | struct v4l2_edid32 { |
---|
1051 | 1347 | __u32 pad; |
---|
.. | .. |
---|
1060 | 1356 | { |
---|
1061 | 1357 | compat_uptr_t tmp; |
---|
1062 | 1358 | |
---|
1063 | | - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || |
---|
| 1359 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
1064 | 1360 | assign_in_user(&p64->pad, &p32->pad) || |
---|
1065 | 1361 | assign_in_user(&p64->start_block, &p32->start_block) || |
---|
1066 | 1362 | assign_in_user_cast(&p64->blocks, &p32->blocks) || |
---|
.. | .. |
---|
1076 | 1372 | { |
---|
1077 | 1373 | void *edid; |
---|
1078 | 1374 | |
---|
1079 | | - if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || |
---|
| 1375 | + if (!access_ok(p32, sizeof(*p32)) || |
---|
1080 | 1376 | assign_in_user(&p32->pad, &p64->pad) || |
---|
1081 | 1377 | assign_in_user(&p32->start_block, &p64->start_block) || |
---|
1082 | 1378 | assign_in_user(&p32->blocks, &p64->blocks) || |
---|
.. | .. |
---|
1098 | 1394 | #define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32) |
---|
1099 | 1395 | #define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32) |
---|
1100 | 1396 | #define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32) |
---|
| 1397 | +#define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32) |
---|
1101 | 1398 | #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) |
---|
1102 | 1399 | #define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32) |
---|
1103 | 1400 | #define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32) |
---|
| 1401 | +#define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32) |
---|
1104 | 1402 | #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) |
---|
| 1403 | +#define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32) |
---|
1105 | 1404 | #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) |
---|
1106 | 1405 | #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) |
---|
1107 | 1406 | #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) |
---|
.. | .. |
---|
1111 | 1410 | #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) |
---|
1112 | 1411 | #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) |
---|
1113 | 1412 | #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) |
---|
| 1413 | +#define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32) |
---|
1114 | 1414 | #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) |
---|
1115 | 1415 | #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) |
---|
| 1416 | +#define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32) |
---|
1116 | 1417 | |
---|
1117 | 1418 | #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) |
---|
1118 | 1419 | #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) |
---|
.. | .. |
---|
1182 | 1483 | case VIDIOC_G_FMT32: ncmd = VIDIOC_G_FMT; break; |
---|
1183 | 1484 | case VIDIOC_S_FMT32: ncmd = VIDIOC_S_FMT; break; |
---|
1184 | 1485 | case VIDIOC_QUERYBUF32: ncmd = VIDIOC_QUERYBUF; break; |
---|
| 1486 | + case VIDIOC_QUERYBUF32_TIME32: ncmd = VIDIOC_QUERYBUF_TIME32; break; |
---|
1185 | 1487 | case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break; |
---|
1186 | 1488 | case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break; |
---|
1187 | 1489 | case VIDIOC_QBUF32: ncmd = VIDIOC_QBUF; break; |
---|
| 1490 | + case VIDIOC_QBUF32_TIME32: ncmd = VIDIOC_QBUF_TIME32; break; |
---|
1188 | 1491 | case VIDIOC_DQBUF32: ncmd = VIDIOC_DQBUF; break; |
---|
| 1492 | + case VIDIOC_DQBUF32_TIME32: ncmd = VIDIOC_DQBUF_TIME32; break; |
---|
1189 | 1493 | case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break; |
---|
1190 | 1494 | case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break; |
---|
1191 | 1495 | case VIDIOC_TRY_FMT32: ncmd = VIDIOC_TRY_FMT; break; |
---|
1192 | 1496 | case VIDIOC_G_EXT_CTRLS32: ncmd = VIDIOC_G_EXT_CTRLS; break; |
---|
1193 | 1497 | case VIDIOC_S_EXT_CTRLS32: ncmd = VIDIOC_S_EXT_CTRLS; break; |
---|
1194 | 1498 | case VIDIOC_TRY_EXT_CTRLS32: ncmd = VIDIOC_TRY_EXT_CTRLS; break; |
---|
| 1499 | +#ifdef CONFIG_X86_64 |
---|
1195 | 1500 | case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break; |
---|
| 1501 | + case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; |
---|
| 1502 | +#endif |
---|
1196 | 1503 | case VIDIOC_OVERLAY32: ncmd = VIDIOC_OVERLAY; break; |
---|
1197 | 1504 | case VIDIOC_STREAMON32: ncmd = VIDIOC_STREAMON; break; |
---|
1198 | 1505 | case VIDIOC_STREAMOFF32: ncmd = VIDIOC_STREAMOFF; break; |
---|
.. | .. |
---|
1202 | 1509 | case VIDIOC_S_OUTPUT32: ncmd = VIDIOC_S_OUTPUT; break; |
---|
1203 | 1510 | case VIDIOC_CREATE_BUFS32: ncmd = VIDIOC_CREATE_BUFS; break; |
---|
1204 | 1511 | case VIDIOC_PREPARE_BUF32: ncmd = VIDIOC_PREPARE_BUF; break; |
---|
| 1512 | + case VIDIOC_PREPARE_BUF32_TIME32: ncmd = VIDIOC_PREPARE_BUF_TIME32; break; |
---|
1205 | 1513 | case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break; |
---|
1206 | 1514 | case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break; |
---|
1207 | 1515 | default: ncmd = cmd; break; |
---|
.. | .. |
---|
1283 | 1591 | compatible_arg = 0; |
---|
1284 | 1592 | break; |
---|
1285 | 1593 | |
---|
| 1594 | + case VIDIOC_PREPARE_BUF32_TIME32: |
---|
| 1595 | + case VIDIOC_QUERYBUF32_TIME32: |
---|
| 1596 | + case VIDIOC_QBUF32_TIME32: |
---|
| 1597 | + case VIDIOC_DQBUF32_TIME32: |
---|
| 1598 | + err = bufsize_v4l2_buffer_time32(p32, &aux_space); |
---|
| 1599 | + if (!err) |
---|
| 1600 | + err = alloc_userspace(sizeof(struct v4l2_buffer), |
---|
| 1601 | + aux_space, &new_p64); |
---|
| 1602 | + if (!err) { |
---|
| 1603 | + aux_buf = new_p64 + sizeof(struct v4l2_buffer); |
---|
| 1604 | + err = get_v4l2_buffer32_time32(new_p64, p32, |
---|
| 1605 | + aux_buf, aux_space); |
---|
| 1606 | + } |
---|
| 1607 | + compatible_arg = 0; |
---|
| 1608 | + break; |
---|
| 1609 | + |
---|
1286 | 1610 | case VIDIOC_S_FBUF32: |
---|
1287 | 1611 | err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, |
---|
1288 | 1612 | &new_p64); |
---|
.. | .. |
---|
1326 | 1650 | } |
---|
1327 | 1651 | compatible_arg = 0; |
---|
1328 | 1652 | break; |
---|
| 1653 | +#ifdef CONFIG_X86_64 |
---|
1329 | 1654 | case VIDIOC_DQEVENT32: |
---|
1330 | 1655 | err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64); |
---|
1331 | 1656 | compatible_arg = 0; |
---|
1332 | 1657 | break; |
---|
| 1658 | + case VIDIOC_DQEVENT32_TIME32: |
---|
| 1659 | + err = alloc_userspace(sizeof(struct v4l2_event_time32), 0, &new_p64); |
---|
| 1660 | + compatible_arg = 0; |
---|
| 1661 | + break; |
---|
| 1662 | +#endif |
---|
1333 | 1663 | } |
---|
1334 | 1664 | if (err) |
---|
1335 | 1665 | return err; |
---|
.. | .. |
---|
1394 | 1724 | err = put_v4l2_framebuffer32(new_p64, p32); |
---|
1395 | 1725 | break; |
---|
1396 | 1726 | |
---|
| 1727 | +#ifdef CONFIG_X86_64 |
---|
1397 | 1728 | case VIDIOC_DQEVENT32: |
---|
1398 | 1729 | err = put_v4l2_event32(new_p64, p32); |
---|
1399 | 1730 | break; |
---|
| 1731 | + |
---|
| 1732 | + case VIDIOC_DQEVENT32_TIME32: |
---|
| 1733 | + err = put_v4l2_event32_time32(new_p64, p32); |
---|
| 1734 | + break; |
---|
| 1735 | +#endif |
---|
1400 | 1736 | |
---|
1401 | 1737 | case VIDIOC_G_EDID32: |
---|
1402 | 1738 | err = put_v4l2_edid32(new_p64, p32); |
---|
.. | .. |
---|
1419 | 1755 | err = put_v4l2_buffer32(new_p64, p32); |
---|
1420 | 1756 | break; |
---|
1421 | 1757 | |
---|
| 1758 | + case VIDIOC_PREPARE_BUF32_TIME32: |
---|
| 1759 | + case VIDIOC_QUERYBUF32_TIME32: |
---|
| 1760 | + case VIDIOC_QBUF32_TIME32: |
---|
| 1761 | + case VIDIOC_DQBUF32_TIME32: |
---|
| 1762 | + err = put_v4l2_buffer32_time32(new_p64, p32); |
---|
| 1763 | + break; |
---|
| 1764 | + |
---|
1422 | 1765 | case VIDIOC_ENUMSTD32: |
---|
1423 | 1766 | err = put_v4l2_standard32(new_p64, p32); |
---|
1424 | 1767 | break; |
---|