media fixes for v6.1-rc3

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmNaSe8ACgkQCF8+vY7k
 4RWc+g//dWz903vryxpRlC2ap7W3Ml9A9KC2NONyR9ryvX71rXaqsVe5/rg4+kKK
 HJ5xbY6cFZVNWWvSEfW2sfNolAwdkEuDem1VDrOIvJRV+1fxCip4frwkD4bhY/V0
 H8I50tgSAtzpTTwEX8w5KHocUYXqtn0T9SX6CA5ll9ijJwVdU2hUZFzUWG2cbx1r
 shSv99HQApflUfD6McwhqFK8r1EpyzKUZypM3zmpSinvEinT+5naV6QBXlLMsO9F
 mmGnQKyOch1a9tTHV9MAojEVN7wTWZbdT7hwwwMP1Fj8zhdt6UqncjK6eaHhbpYd
 WExZEGhN1l+ZDxZZ1kY/VX/pE93uLaq16WkJH6HftiTYjdXpZe6IjBZnJsSIPktO
 BCoEYJfmCmfC/9AkqrM9/TdFBJ3MRgZwfrhZ8j6dcEgvZ5OYpQLOaWIR0cZ0YYPE
 iw+HooXlv3gf1JiMLb8KVFpC4UrD1RU8HfIFD2KaMx1UKUs3NjVzv5g8V+IDUa1i
 ky80MvEXXH6Eg91QNypQEY6EH6G6c2Mk8yVj6WVFWTEC9mqNo/A1egL6DFDKbfZd
 OuP3bl/hjdNU1oQ9ajBq/GurUJQoFtnCie5M2Sqy3gyKfD92F7nufJusfICaPgz7
 SztFKjPcaomLNJl/IH2ALox11+fs2HfTeiCX0zZwun8ddPqOWBM=
 =WXL5
 -----END PGP SIGNATURE-----

Merge tag 'media/v6.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media fixes from Mauro Carvalho Chehab:
 "A bunch of patches addressing issues in the vivid driver and adding
  new checks in V4L2 to validate the input parameters from some ioctls"

* tag 'media/v6.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  media: vivid.rst: loop_video is set on the capture devnode
  media: vivid: set num_in/outputs to 0 if not supported
  media: vivid: drop GFP_DMA32
  media: vivid: fix control handler mutex deadlock
  media: videodev2.h: V4L2_DV_BT_BLANKING_HEIGHT should check 'interlaced'
  media: v4l2-dv-timings: add sanity checks for blanking values
  media: vivid: dev->bitmap_cap wasn't freed in all cases
  media: vivid: s_fbuf: add more sanity checks
This commit is contained in:
Linus Torvalds 2022-10-27 12:21:57 -07:00
commit 7f9a7cd690
7 changed files with 83 additions and 13 deletions

View File

@ -1318,7 +1318,7 @@ instance. This setup would require the following commands:
$ v4l2-ctl -d2 -i2 $ v4l2-ctl -d2 -i2
$ v4l2-ctl -d2 -c horizontal_movement=4 $ v4l2-ctl -d2 -c horizontal_movement=4
$ v4l2-ctl -d1 --overlay=1 $ v4l2-ctl -d1 --overlay=1
$ v4l2-ctl -d1 -c loop_video=1 $ v4l2-ctl -d0 -c loop_video=1
$ v4l2-ctl -d2 --stream-mmap --overlay=1 $ v4l2-ctl -d2 --stream-mmap --overlay=1
And from another console: And from another console:

View File

@ -339,6 +339,28 @@ static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a
return vivid_vid_out_g_fbuf(file, fh, a); return vivid_vid_out_g_fbuf(file, fh, a);
} }
/*
* Only support the framebuffer of one of the vivid instances.
* Anything else is rejected.
*/
bool vivid_validate_fb(const struct v4l2_framebuffer *a)
{
struct vivid_dev *dev;
int i;
for (i = 0; i < n_devs; i++) {
dev = vivid_devs[i];
if (!dev || !dev->video_pbase)
continue;
if ((unsigned long)a->base == dev->video_pbase &&
a->fmt.width <= dev->display_width &&
a->fmt.height <= dev->display_height &&
a->fmt.bytesperline <= dev->display_byte_stride)
return true;
}
return false;
}
static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
@ -920,8 +942,12 @@ static int vivid_detect_feature_set(struct vivid_dev *dev, int inst,
/* how many inputs do we have and of what type? */ /* how many inputs do we have and of what type? */
dev->num_inputs = num_inputs[inst]; dev->num_inputs = num_inputs[inst];
if (node_type & 0x20007) {
if (dev->num_inputs < 1) if (dev->num_inputs < 1)
dev->num_inputs = 1; dev->num_inputs = 1;
} else {
dev->num_inputs = 0;
}
if (dev->num_inputs >= MAX_INPUTS) if (dev->num_inputs >= MAX_INPUTS)
dev->num_inputs = MAX_INPUTS; dev->num_inputs = MAX_INPUTS;
for (i = 0; i < dev->num_inputs; i++) { for (i = 0; i < dev->num_inputs; i++) {
@ -938,8 +964,12 @@ static int vivid_detect_feature_set(struct vivid_dev *dev, int inst,
/* how many outputs do we have and of what type? */ /* how many outputs do we have and of what type? */
dev->num_outputs = num_outputs[inst]; dev->num_outputs = num_outputs[inst];
if (node_type & 0x40300) {
if (dev->num_outputs < 1) if (dev->num_outputs < 1)
dev->num_outputs = 1; dev->num_outputs = 1;
} else {
dev->num_outputs = 0;
}
if (dev->num_outputs >= MAX_OUTPUTS) if (dev->num_outputs >= MAX_OUTPUTS)
dev->num_outputs = MAX_OUTPUTS; dev->num_outputs = MAX_OUTPUTS;
for (i = 0; i < dev->num_outputs; i++) { for (i = 0; i < dev->num_outputs; i++) {

View File

@ -613,4 +613,6 @@ static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
return dev->output_type[dev->output] == HDMI; return dev->output_type[dev->output] == HDMI;
} }
bool vivid_validate_fb(const struct v4l2_framebuffer *a);
#endif #endif

View File

@ -357,7 +357,7 @@ int vivid_fb_init(struct vivid_dev *dev)
int ret; int ret;
dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2; dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2;
dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32); dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL);
if (dev->video_vbase == NULL) if (dev->video_vbase == NULL)
return -ENOMEM; return -ENOMEM;
dev->video_pbase = virt_to_phys(dev->video_vbase); dev->video_pbase = virt_to_phys(dev->video_vbase);

View File

@ -453,6 +453,12 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap); tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
dev->crop_cap = dev->src_rect; dev->crop_cap = dev->src_rect;
dev->crop_bounds_cap = dev->src_rect; dev->crop_bounds_cap = dev->src_rect;
if (dev->bitmap_cap &&
(dev->compose_cap.width != dev->crop_cap.width ||
dev->compose_cap.height != dev->crop_cap.height)) {
vfree(dev->bitmap_cap);
dev->bitmap_cap = NULL;
}
dev->compose_cap = dev->crop_cap; dev->compose_cap = dev->crop_cap;
if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap)) if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
dev->compose_cap.height /= 2; dev->compose_cap.height /= 2;
@ -460,6 +466,14 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev)); tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev));
tpg_update_mv_step(&dev->tpg); tpg_update_mv_step(&dev->tpg);
/*
* We can be called from within s_ctrl, in that case we can't
* modify controls. Luckily we don't need to in that case.
*/
if (keep_controls)
return;
dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV); dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV);
dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV); dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV);
v4l2_ctrl_modify_dimensions(dev->pixel_array, dims); v4l2_ctrl_modify_dimensions(dev->pixel_array, dims);
@ -913,6 +927,8 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
struct vivid_dev *dev = video_drvdata(file); struct vivid_dev *dev = video_drvdata(file);
struct v4l2_rect *crop = &dev->crop_cap; struct v4l2_rect *crop = &dev->crop_cap;
struct v4l2_rect *compose = &dev->compose_cap; struct v4l2_rect *compose = &dev->compose_cap;
unsigned orig_compose_w = compose->width;
unsigned orig_compose_h = compose->height;
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
int ret; int ret;
@ -1029,17 +1045,17 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
s->r.height /= factor; s->r.height /= factor;
} }
v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect);
if (dev->bitmap_cap && (compose->width != s->r.width ||
compose->height != s->r.height)) {
vfree(dev->bitmap_cap);
dev->bitmap_cap = NULL;
}
*compose = s->r; *compose = s->r;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
if (dev->bitmap_cap && (compose->width != orig_compose_w ||
compose->height != orig_compose_h)) {
vfree(dev->bitmap_cap);
dev->bitmap_cap = NULL;
}
tpg_s_crop_compose(&dev->tpg, crop, compose); tpg_s_crop_compose(&dev->tpg, crop, compose);
return 0; return 0;
} }
@ -1276,7 +1292,14 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
return -EINVAL; return -EINVAL;
if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8)
return -EINVAL; return -EINVAL;
if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) if (a->fmt.bytesperline > a->fmt.sizeimage / a->fmt.height)
return -EINVAL;
/*
* Only support the framebuffer of one of the vivid instances.
* Anything else is rejected.
*/
if (!vivid_validate_fb(a))
return -EINVAL; return -EINVAL;
dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base); dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);

View File

@ -161,6 +161,20 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
(bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) || (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
(!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE))) (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
return false; return false;
/* sanity checks for the blanking timings */
if (!bt->interlaced &&
(bt->il_vbackporch || bt->il_vsync || bt->il_vfrontporch))
return false;
if (bt->hfrontporch > 2 * bt->width ||
bt->hsync > 1024 || bt->hbackporch > 1024)
return false;
if (bt->vfrontporch > 4096 ||
bt->vsync > 128 || bt->vbackporch > 4096)
return false;
if (bt->interlaced && (bt->il_vfrontporch > 4096 ||
bt->il_vsync > 128 || bt->il_vbackporch > 4096))
return false;
return fnc == NULL || fnc(t, fnc_handle); return fnc == NULL || fnc(t, fnc_handle);
} }
EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings); EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings);

View File

@ -1601,7 +1601,8 @@ struct v4l2_bt_timings {
((bt)->width + V4L2_DV_BT_BLANKING_WIDTH(bt)) ((bt)->width + V4L2_DV_BT_BLANKING_WIDTH(bt))
#define V4L2_DV_BT_BLANKING_HEIGHT(bt) \ #define V4L2_DV_BT_BLANKING_HEIGHT(bt) \
((bt)->vfrontporch + (bt)->vsync + (bt)->vbackporch + \ ((bt)->vfrontporch + (bt)->vsync + (bt)->vbackporch + \
(bt)->il_vfrontporch + (bt)->il_vsync + (bt)->il_vbackporch) ((bt)->interlaced ? \
((bt)->il_vfrontporch + (bt)->il_vsync + (bt)->il_vbackporch) : 0))
#define V4L2_DV_BT_FRAME_HEIGHT(bt) \ #define V4L2_DV_BT_FRAME_HEIGHT(bt) \
((bt)->height + V4L2_DV_BT_BLANKING_HEIGHT(bt)) ((bt)->height + V4L2_DV_BT_BLANKING_HEIGHT(bt))