Re: [PATCH v3 8/8] media: subdev: disallow ioctl for saa6588/davinci

From: Laurent Pinchart
Date: Mon Jun 14 2021 - 13:21:28 EST


Hi Arnd,

Thank you for the patch.

On Mon, Jun 14, 2021 at 12:34:09PM +0200, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@xxxxxxxx>
>
> The saa6588_ioctl() function expects to get called from other kernel
> functions with a 'saa6588_command' pointer, but I found nothing stops it
> from getting called from user space instead, which seems rather dangerous.
>
> The same thing happens in the davinci vpbe driver with its VENC_GET_FLD
> command.
>
> As a quick fix, add a separate .command() callback pointer for this
> driver and change the two callers over to that. This change can easily
> get backported to stable kernels if necessary, but since there are only
> two drivers, we may want to eventually replace this with a set of more
> specialized callbacks in the long run.
>
> Fixes: c3fda7f835b0 ("V4L/DVB (10537): saa6588: convert to v4l2_subdev.")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Arnd Bergmann <arnd@xxxxxxxx>

Reviewed-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>

> ---
> drivers/media/i2c/saa6588.c | 4 ++--
> drivers/media/pci/bt8xx/bttv-driver.c | 6 +++---
> drivers/media/pci/saa7134/saa7134-video.c | 6 +++---
> drivers/media/platform/davinci/vpbe_display.c | 2 +-
> drivers/media/platform/davinci/vpbe_venc.c | 6 ++----
> include/media/v4l2-subdev.h | 4 ++++
> 6 files changed, 15 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
> index ecb491d5f2ab..d1e0716bdfff 100644
> --- a/drivers/media/i2c/saa6588.c
> +++ b/drivers/media/i2c/saa6588.c
> @@ -380,7 +380,7 @@ static void saa6588_configure(struct saa6588 *s)
>
> /* ---------------------------------------------------------------------- */
>
> -static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
> +static long saa6588_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
> {
> struct saa6588 *s = to_saa6588(sd);
> struct saa6588_command *a = arg;
> @@ -433,7 +433,7 @@ static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
> /* ----------------------------------------------------------------------- */
>
> static const struct v4l2_subdev_core_ops saa6588_core_ops = {
> - .ioctl = saa6588_ioctl,
> + .command = saa6588_command,
> };
>
> static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
> diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
> index 1f62a9d8ea1d..0e9df8b35ac6 100644
> --- a/drivers/media/pci/bt8xx/bttv-driver.c
> +++ b/drivers/media/pci/bt8xx/bttv-driver.c
> @@ -3179,7 +3179,7 @@ static int radio_release(struct file *file)
>
> btv->radio_user--;
>
> - bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
> + bttv_call_all(btv, core, command, SAA6588_CMD_CLOSE, &cmd);
>
> if (btv->radio_user == 0)
> btv->has_radio_tuner = 0;
> @@ -3260,7 +3260,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
> cmd.result = -ENODEV;
> radio_enable(btv);
>
> - bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
> + bttv_call_all(btv, core, command, SAA6588_CMD_READ, &cmd);
>
> return cmd.result;
> }
> @@ -3281,7 +3281,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
> cmd.instance = file;
> cmd.event_list = wait;
> cmd.poll_mask = res;
> - bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
> + bttv_call_all(btv, core, command, SAA6588_CMD_POLL, &cmd);
>
> return cmd.poll_mask;
> }
> diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
> index 0f9d6b9edb90..374c8e1087de 100644
> --- a/drivers/media/pci/saa7134/saa7134-video.c
> +++ b/drivers/media/pci/saa7134/saa7134-video.c
> @@ -1181,7 +1181,7 @@ static int video_release(struct file *file)
>
> saa_call_all(dev, tuner, standby);
> if (vdev->vfl_type == VFL_TYPE_RADIO)
> - saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
> + saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
> mutex_unlock(&dev->lock);
>
> return 0;
> @@ -1200,7 +1200,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
> cmd.result = -ENODEV;
>
> mutex_lock(&dev->lock);
> - saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
> + saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
> mutex_unlock(&dev->lock);
>
> return cmd.result;
> @@ -1216,7 +1216,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
> cmd.event_list = wait;
> cmd.poll_mask = 0;
> mutex_lock(&dev->lock);
> - saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
> + saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
> mutex_unlock(&dev->lock);
>
> return rc | cmd.poll_mask;
> diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
> index d19bad997f30..bf3c3e76b921 100644
> --- a/drivers/media/platform/davinci/vpbe_display.c
> +++ b/drivers/media/platform/davinci/vpbe_display.c
> @@ -47,7 +47,7 @@ static int venc_is_second_field(struct vpbe_display *disp_dev)
>
> ret = v4l2_subdev_call(vpbe_dev->venc,
> core,
> - ioctl,
> + command,
> VENC_GET_FLD,
> &val);
> if (ret < 0) {
> diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
> index 8caa084e5704..bde241c26d79 100644
> --- a/drivers/media/platform/davinci/vpbe_venc.c
> +++ b/drivers/media/platform/davinci/vpbe_venc.c
> @@ -521,9 +521,7 @@ static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
> return ret;
> }
>
> -static long venc_ioctl(struct v4l2_subdev *sd,
> - unsigned int cmd,
> - void *arg)
> +static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
> {
> u32 val;
>
> @@ -542,7 +540,7 @@ static long venc_ioctl(struct v4l2_subdev *sd,
> }
>
> static const struct v4l2_subdev_core_ops venc_core_ops = {
> - .ioctl = venc_ioctl,
> + .command = venc_command,
> };
>
> static const struct v4l2_subdev_video_ops venc_video_ops = {
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 42aa1f6c7c3f..115b1e41e933 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -162,6 +162,9 @@ struct v4l2_subdev_io_pin_config {
> * @s_gpio: set GPIO pins. Very simple right now, might need to be extended with
> * a direction argument if needed.
> *
> + * @command: called by in-kernel drivers in order to call functions internal
> + * to subdev drivers driver that have a separate callback.
> + *
> * @ioctl: called at the end of ioctl() syscall handler at the V4L2 core.
> * used to provide support for private ioctls used on the driver.
> *
> @@ -193,6 +196,7 @@ struct v4l2_subdev_core_ops {
> int (*load_fw)(struct v4l2_subdev *sd);
> int (*reset)(struct v4l2_subdev *sd, u32 val);
> int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
> + long (*command)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
> long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
> #ifdef CONFIG_COMPAT
> long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);

--
Regards,

Laurent Pinchart