From 9ff738f93084351ed6e818d4d58679a9e9083a8d Mon Sep 17 00:00:00 2001 From: Rohinthan P Date: Sat, 19 Sep 2026 07:41:09 +0530 Subject: [PATCH] media: v4l2-ctrls: do nothing if controls[0] == NULL in cluster functions The V4L2 control framework is designed to allow drivers to instantiate controls and clusters without checking for errors after each call, checking hdl->error only once at the end. However, if allocating the master control (controls[0]) fails, e.g. due to memory allocation failure, v4l2_ctrl_cluster() triggers a WARNING: ncontrols == 0 || controls[0] == NULL WARNING: drivers/media/v4l2-core/v4l2-ctrls-core.c:2525 at v4l2_ctrl_cluster Additionally, v4l2_ctrl_auto_cluster() attempts to dereference master->minimum without checking if controls[0] is NULL, leading to a NULL pointer dereference when master control creation fails. Update both v4l2_ctrl_cluster() and v4l2_ctrl_auto_cluster() to silently return if controls[0] is NULL, preserving the design that control creation errors are caught at the end when the driver checks hdl->error. Also update function documentation in include/media/v4l2-ctrls.h. Fixes: 71c689dc2e73 ("media: v4l2-ctrls: split up into four source files") Cc: stable@vger.kernel.org Reported-by: syzbot+cf896de36144391bcde1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=cf896de36144391bcde1 Suggested-by: Hans Verkuil Signed-off-by: Rohinthan P Signed-off-by: Hans Verkuil [hverkuil: simplified the v4l2_ctrl_auto_cluster code a bit] --- drivers/media/v4l2-core/v4l2-ctrls-core.c | 12 ++++++++++-- include/media/v4l2-ctrls.h | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 9caca56478d1..661a3a25da52 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -2529,7 +2529,10 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) int i; /* The first control is the master control and it must not be NULL */ - if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) + if (WARN_ON(ncontrols == 0)) + return; + + if (!controls[0]) return; for (i = 0; i < ncontrols; i++) { @@ -2551,8 +2554,13 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, u32 flag = 0; int i; + if (WARN_ON(ncontrols <= 1)) + return; + + if (!master) + return; + v4l2_ctrl_cluster(ncontrols, controls); - WARN_ON(ncontrols <= 1); WARN_ON(manual_val < master->minimum || manual_val > master->maximum); WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl)); master->is_auto = true; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 327976b14d50..cec9217d97ac 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -834,6 +834,9 @@ bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl); * * @ncontrols: The number of controls in this cluster. * @controls: The cluster control array of size @ncontrols. + * + * If controls[0] is NULL, then this function does nothing and just + * returns. */ void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls); @@ -845,6 +848,9 @@ void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls); * @ncontrols: The number of controls in this cluster. * @controls: The cluster control array of size @ncontrols. The first control * must be the 'auto' control (e.g. autogain, autoexposure, etc.) + * + * If controls[0] is NULL, then this function does nothing and just + * returns. * @manual_val: The value for the first control in the cluster that equals the * manual setting. * @set_volatile: If true, then all controls except the first auto control will