diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2018-01-24 05:30:59 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2018-01-30 07:31:33 -0500 |
commit | b8c601e8af2d08f733d74defa8465303391bb930 (patch) | |
tree | 49d3f9c1d9ff35af5323362114e837506c78ab01 | |
parent | 8ed5a59dcb47a6f76034ee760b36e089f3e82529 (diff) |
media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
ctrl_is_pointer just hardcoded two known string controls, but that
caused problems when using e.g. custom controls that use a pointer
for the payload.
Reimplement this function: it now finds the v4l2_ctrl (if the driver
uses the control framework) or it calls vidioc_query_ext_ctrl (if the
driver implements that directly).
In both cases it can now check if the control is a pointer control
or not.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: <stable@vger.kernel.org> # for v4.15 and up
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r-- | drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7dff9b4aeb19..30c5be1f0549 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/videodev2.h> | 18 | #include <linux/videodev2.h> |
19 | #include <linux/v4l2-subdev.h> | 19 | #include <linux/v4l2-subdev.h> |
20 | #include <media/v4l2-dev.h> | 20 | #include <media/v4l2-dev.h> |
21 | #include <media/v4l2-fh.h> | ||
22 | #include <media/v4l2-ctrls.h> | ||
21 | #include <media/v4l2-ioctl.h> | 23 | #include <media/v4l2-ioctl.h> |
22 | 24 | ||
23 | static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 25 | static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
@@ -601,24 +603,39 @@ struct v4l2_ext_control32 { | |||
601 | }; | 603 | }; |
602 | } __attribute__ ((packed)); | 604 | } __attribute__ ((packed)); |
603 | 605 | ||
604 | /* The following function really belong in v4l2-common, but that causes | 606 | /* Return true if this control is a pointer type. */ |
605 | a circular dependency between modules. We need to think about this, but | 607 | static inline bool ctrl_is_pointer(struct file *file, u32 id) |
606 | for now this will do. */ | ||
607 | |||
608 | /* Return non-zero if this control is a pointer type. Currently only | ||
609 | type STRING is a pointer type. */ | ||
610 | static inline int ctrl_is_pointer(u32 id) | ||
611 | { | 608 | { |
612 | switch (id) { | 609 | struct video_device *vdev = video_devdata(file); |
613 | case V4L2_CID_RDS_TX_PS_NAME: | 610 | struct v4l2_fh *fh = NULL; |
614 | case V4L2_CID_RDS_TX_RADIO_TEXT: | 611 | struct v4l2_ctrl_handler *hdl = NULL; |
615 | return 1; | 612 | struct v4l2_query_ext_ctrl qec = { id }; |
616 | default: | 613 | const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; |
617 | return 0; | 614 | |
615 | if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) | ||
616 | fh = file->private_data; | ||
617 | |||
618 | if (fh && fh->ctrl_handler) | ||
619 | hdl = fh->ctrl_handler; | ||
620 | else if (vdev->ctrl_handler) | ||
621 | hdl = vdev->ctrl_handler; | ||
622 | |||
623 | if (hdl) { | ||
624 | struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); | ||
625 | |||
626 | return ctrl && ctrl->is_ptr; | ||
618 | } | 627 | } |
628 | |||
629 | if (!ops->vidioc_query_ext_ctrl) | ||
630 | return false; | ||
631 | |||
632 | return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && | ||
633 | (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); | ||
619 | } | 634 | } |
620 | 635 | ||
621 | static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) | 636 | static int get_v4l2_ext_controls32(struct file *file, |
637 | struct v4l2_ext_controls *kp, | ||
638 | struct v4l2_ext_controls32 __user *up) | ||
622 | { | 639 | { |
623 | struct v4l2_ext_control32 __user *ucontrols; | 640 | struct v4l2_ext_control32 __user *ucontrols; |
624 | struct v4l2_ext_control __user *kcontrols; | 641 | struct v4l2_ext_control __user *kcontrols; |
@@ -651,7 +668,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
651 | return -EFAULT; | 668 | return -EFAULT; |
652 | if (get_user(id, &kcontrols->id)) | 669 | if (get_user(id, &kcontrols->id)) |
653 | return -EFAULT; | 670 | return -EFAULT; |
654 | if (ctrl_is_pointer(id)) { | 671 | if (ctrl_is_pointer(file, id)) { |
655 | void __user *s; | 672 | void __user *s; |
656 | 673 | ||
657 | if (get_user(p, &ucontrols->string)) | 674 | if (get_user(p, &ucontrols->string)) |
@@ -666,7 +683,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
666 | return 0; | 683 | return 0; |
667 | } | 684 | } |
668 | 685 | ||
669 | static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) | 686 | static int put_v4l2_ext_controls32(struct file *file, |
687 | struct v4l2_ext_controls *kp, | ||
688 | struct v4l2_ext_controls32 __user *up) | ||
670 | { | 689 | { |
671 | struct v4l2_ext_control32 __user *ucontrols; | 690 | struct v4l2_ext_control32 __user *ucontrols; |
672 | struct v4l2_ext_control __user *kcontrols = | 691 | struct v4l2_ext_control __user *kcontrols = |
@@ -698,7 +717,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
698 | /* Do not modify the pointer when copying a pointer control. | 717 | /* Do not modify the pointer when copying a pointer control. |
699 | The contents of the pointer was changed, not the pointer | 718 | The contents of the pointer was changed, not the pointer |
700 | itself. */ | 719 | itself. */ |
701 | if (ctrl_is_pointer(id)) | 720 | if (ctrl_is_pointer(file, id)) |
702 | size -= sizeof(ucontrols->value64); | 721 | size -= sizeof(ucontrols->value64); |
703 | if (copy_in_user(ucontrols, kcontrols, size)) | 722 | if (copy_in_user(ucontrols, kcontrols, size)) |
704 | return -EFAULT; | 723 | return -EFAULT; |
@@ -912,7 +931,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
912 | case VIDIOC_G_EXT_CTRLS: | 931 | case VIDIOC_G_EXT_CTRLS: |
913 | case VIDIOC_S_EXT_CTRLS: | 932 | case VIDIOC_S_EXT_CTRLS: |
914 | case VIDIOC_TRY_EXT_CTRLS: | 933 | case VIDIOC_TRY_EXT_CTRLS: |
915 | err = get_v4l2_ext_controls32(&karg.v2ecs, up); | 934 | err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); |
916 | compatible_arg = 0; | 935 | compatible_arg = 0; |
917 | break; | 936 | break; |
918 | case VIDIOC_DQEVENT: | 937 | case VIDIOC_DQEVENT: |
@@ -939,7 +958,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
939 | case VIDIOC_G_EXT_CTRLS: | 958 | case VIDIOC_G_EXT_CTRLS: |
940 | case VIDIOC_S_EXT_CTRLS: | 959 | case VIDIOC_S_EXT_CTRLS: |
941 | case VIDIOC_TRY_EXT_CTRLS: | 960 | case VIDIOC_TRY_EXT_CTRLS: |
942 | if (put_v4l2_ext_controls32(&karg.v2ecs, up)) | 961 | if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) |
943 | err = -EFAULT; | 962 | err = -EFAULT; |
944 | break; | 963 | break; |
945 | case VIDIOC_S_EDID: | 964 | case VIDIOC_S_EDID: |