media: v4l2: allocate v4l2_clip objects early
authorArnd Bergmann <arnd@arndb.de>
Fri, 30 Oct 2020 16:55:26 +0000 (17:55 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 16 Nov 2020 09:31:06 +0000 (10:31 +0100)
The v4l2_format based ioctls can have an indirect pointer to an array
of v4l2_clip structures for overlay mode, depending on the 'type' member.
There are only five drivers that use the overlay mode and copy the
data through the __user pointer.

Change the five drivers to use memcpy() instead, and copy the data
in common code using the check_array_args() helpers. This allows
for a subsequent patch that use the same mechanism for compat
ioctl handlers.

Note that there is another pointer for a 'bitmap' that is only
used in the 'vivid' driver and nowhere else. There is no easy
way to use the same trick without adding complexity to the
common code, so this remains a __user pointer.

[hverkuil: fix: CHECK: spaces preferred around that '*' (ctx:VxV)]
[hverkuil: fix: CHECK: Alignment should match open parenthesis]

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/common/saa7146/saa7146_video.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/test-drivers/vivid/vivid-vid-cap.c
drivers/media/test-drivers/vivid/vivid-vid-out.c
drivers/media/v4l2-core/v4l2-ioctl.c
include/uapi/linux/videodev2.h

index ccd15b4d4920b547ba4e43e8addfff0680325107..7b8795eca5893c76012b4bac6c7aa6c08c735524 100644 (file)
@@ -771,10 +771,8 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
        vv->ov.nclips = f->fmt.win.clipcount;
        if (vv->ov.nclips > 16)
                vv->ov.nclips = 16;
-       if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
-                               sizeof(struct v4l2_clip) * vv->ov.nclips)) {
-               return -EFAULT;
-       }
+       memcpy(vv->ov.clips, f->fmt.win.clips,
+              sizeof(struct v4l2_clip) * vv->ov.nclips);
 
        /* vv->ov.fh is used to indicate that we have valid overlay information, too */
        vv->ov.fh = fh;
index 8824dd0fb331e41184061055b2d497a34e89f2a1..ef2ead36b70ed666d222ac95d55429bc2f817460 100644 (file)
@@ -2143,12 +2143,8 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
        clips = kmalloc(size,GFP_KERNEL);
        if (NULL == clips)
                return -ENOMEM;
-       if (n > 0) {
-               if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
-                       kfree(clips);
-                       return -EFAULT;
-               }
-       }
+       if (n > 0)
+               memcpy(clips, win->clips, sizeof(struct v4l2_clip) * n);
 
        /* clip against screen */
        if (NULL != btv->fbuf.base)
index 9a6a6b68f8e3e179c3bd0fcc6dcf883aa3ac1924..94c1c10d0fead6963335057e00aac2ccca75ac93 100644 (file)
@@ -1265,9 +1265,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct saa7134_dev *dev = video_drvdata(file);
-       struct v4l2_clip __user *clips = f->fmt.win.clips;
        u32 clipcount = f->fmt.win.clipcount;
-       int err = 0;
        int i;
 
        if (saa7134_no_overlay > 0) {
@@ -1275,20 +1273,18 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
                return -EINVAL;
        }
        f->fmt.win = dev->win;
-       f->fmt.win.clips = clips;
-       if (clips == NULL)
+       if (!f->fmt.win.clips)
                clipcount = 0;
        if (dev->nclips < clipcount)
                clipcount = dev->nclips;
        f->fmt.win.clipcount = clipcount;
 
-       for (i = 0; !err && i < clipcount; i++) {
-               if (copy_to_user(&f->fmt.win.clips[i].c, &dev->clips[i].c,
-                                       sizeof(struct v4l2_rect)))
-                       err = -EFAULT;
+       for (i = 0; i < clipcount; i++) {
+               memcpy(&f->fmt.win.clips[i].c, &dev->clips[i].c,
+                      sizeof(struct v4l2_rect));
        }
 
-       return err;
+       return 0;
 }
 
 static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
@@ -1396,9 +1392,8 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
        dev->win    = f->fmt.win;
        dev->nclips = f->fmt.win.clipcount;
 
-       if (copy_from_user(dev->clips, f->fmt.win.clips,
-                          sizeof(struct v4l2_clip) * dev->nclips))
-               return -EFAULT;
+       memcpy(dev->clips, f->fmt.win.clips,
+              sizeof(struct v4l2_clip) * dev->nclips);
 
        if (priv == dev->overlay_owner) {
                spin_lock_irqsave(&dev->slock, flags);
index eadf28ab1e393d77da83684a637fd460c93adce2..b9caa4b26209ef1951d1ef5024e016c89eeb07b9 100644 (file)
@@ -1107,11 +1107,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
                    ((compose->width + 7) / 8) * compose->height))
                        return -EFAULT;
        }
-       if (clipcount && win->clips) {
-               if (copy_to_user(win->clips, dev->clips_cap,
-                                clipcount * sizeof(dev->clips_cap[0])))
-                       return -EFAULT;
-       }
+       if (clipcount && win->clips)
+               memcpy(win->clips, dev->clips_cap,
+                      clipcount * sizeof(dev->clips_cap[0]));
        return 0;
 }
 
@@ -1141,9 +1139,8 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
        if (win->clipcount > MAX_CLIPS)
                win->clipcount = MAX_CLIPS;
        if (win->clipcount) {
-               if (copy_from_user(dev->try_clips_cap, win->clips,
-                                  win->clipcount * sizeof(dev->clips_cap[0])))
-                       return -EFAULT;
+               memcpy(dev->try_clips_cap, win->clips,
+                      win->clipcount * sizeof(dev->clips_cap[0]));
                for (i = 0; i < win->clipcount; i++) {
                        struct v4l2_rect *r = &dev->try_clips_cap[i].c;
 
@@ -1166,9 +1163,8 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
                                        return -EINVAL;
                        }
                }
-               if (copy_to_user(win->clips, dev->try_clips_cap,
-                                win->clipcount * sizeof(dev->clips_cap[0])))
-                       return -EFAULT;
+               memcpy(win->clips, dev->try_clips_cap,
+                      win->clipcount * sizeof(dev->clips_cap[0]));
        }
        return 0;
 }
index ee3446e3217ccfac4a9c967aeb6f64be1ed1591c..ac1e981e83420bc981fa72f2ff36ebffc6076beb 100644 (file)
@@ -857,11 +857,9 @@ int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
                    ((dev->compose_out.width + 7) / 8) * dev->compose_out.height))
                        return -EFAULT;
        }
-       if (clipcount && win->clips) {
-               if (copy_to_user(win->clips, dev->clips_out,
-                                clipcount * sizeof(dev->clips_out[0])))
-                       return -EFAULT;
-       }
+       if (clipcount && win->clips)
+               memcpy(win->clips, dev->clips_out,
+                      clipcount * sizeof(dev->clips_out[0]));
        return 0;
 }
 
@@ -891,9 +889,8 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
        if (win->clipcount > MAX_CLIPS)
                win->clipcount = MAX_CLIPS;
        if (win->clipcount) {
-               if (copy_from_user(dev->try_clips_out, win->clips,
-                                  win->clipcount * sizeof(dev->clips_out[0])))
-                       return -EFAULT;
+               memcpy(dev->try_clips_out, win->clips,
+                      win->clipcount * sizeof(dev->clips_out[0]));
                for (i = 0; i < win->clipcount; i++) {
                        struct v4l2_rect *r = &dev->try_clips_out[i].c;
 
@@ -916,9 +913,8 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
                                        return -EINVAL;
                        }
                }
-               if (copy_to_user(win->clips, dev->try_clips_out,
-                                win->clipcount * sizeof(dev->clips_out[0])))
-                       return -EFAULT;
+               memcpy(win->clips, dev->try_clips_out,
+                      win->clipcount * sizeof(dev->clips_out[0]));
        }
        return 0;
 }
index b8be61a09776d1a42dd48f9406f0faca10f98d42..f0f6906a879de6b416d5b1fcf5b51d8f00e7131c 100644 (file)
@@ -1582,7 +1582,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
        switch (p->type) {
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
-               struct v4l2_clip __user *clips = p->fmt.win.clips;
+               struct v4l2_clip *clips = p->fmt.win.clips;
                u32 clipcount = p->fmt.win.clipcount;
                void __user *bitmap = p->fmt.win.bitmap;
 
@@ -3084,6 +3084,27 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                }
                break;
        }
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT: {
+               struct v4l2_format *fmt = parg;
+
+               if (fmt->type != V4L2_BUF_TYPE_VIDEO_OVERLAY &&
+                   fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+                       break;
+               if (fmt->fmt.win.clipcount > 2048)
+                       return -EINVAL;
+               if (!fmt->fmt.win.clipcount)
+                       break;
+
+               *user_ptr = (void __user *)fmt->fmt.win.clips;
+               *kernel_ptr = (void **)&fmt->fmt.win.clips;
+               *array_size = sizeof(struct v4l2_clip)
+                               * fmt->fmt.win.clipcount;
+
+               ret = 1;
+               break;
+       }
        }
 
        return ret;
index 534eaa4d39bc86e18a98a2f05618316a0b35e664..b10f102bbf6f0cf71ce158e8921304a2136ca39a 100644 (file)
@@ -1185,7 +1185,7 @@ struct v4l2_window {
        struct v4l2_rect        w;
        __u32                   field;   /* enum v4l2_field */
        __u32                   chromakey;
-       struct v4l2_clip        __user *clips;
+       struct v4l2_clip        *clips;
        __u32                   clipcount;
        void                    __user *bitmap;
        __u8                    global_alpha;