7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Rohinthan P [ Upstream commit 9ff738f93084351ed6e818d4d58679a9e9083a8d ] 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] Signed-off-by: Sasha Levin --- 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 47fb60b1f0c07..6e751a043a210 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -2561,7 +2561,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++) { @@ -2583,8 +2586,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 327976b14d50b..cec9217d97ac6 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 -- 2.53.0