Commit 3758f68c authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab Committed by Zicheng Qu
Browse files

media: dvbdev: prevent the risk of out of memory access

stable inclusion
from stable-v5.10.230
commit a4a17210c03ade1c8d9a9f193a105654b7a05c11
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB5KR8
CVE: CVE-2024-53063

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=a4a17210c03ade1c8d9a9f193a105654b7a05c11



--------------------------------

[ Upstream commit 972e63e895abbe8aa1ccbdbb4e6362abda7cd457 ]

The dvbdev contains a static variable used to store dvb minors.

The behavior of it depends if CONFIG_DVB_DYNAMIC_MINORS is set
or not. When not set, dvb_register_device() won't check for
boundaries, as it will rely that a previous call to
dvb_register_adapter() would already be enforcing it.

On a similar way, dvb_device_open() uses the assumption
that the register functions already did the needed checks.

This can be fragile if some device ends using different
calls. This also generate warnings on static check analysers
like Coverity.

So, add explicit guards to prevent potential risk of OOM issues.

Fixes: 5dd3f307 ("V4L/DVB (9361): Dynamic DVB minor allocation")
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarZicheng Qu <quzicheng@huawei.com>
parent 929a9df3
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -96,10 +96,15 @@ static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
	struct dvb_device *dvbdev;
	unsigned int minor = iminor(inode);

	if (minor >= MAX_DVB_MINORS)
		return -ENODEV;

	mutex_lock(&dvbdev_mutex);
	down_read(&minor_rwsem);
	dvbdev = dvb_minors[iminor(inode)];

	dvbdev = dvb_minors[minor];

	if (dvbdev && dvbdev->fops) {
		int err = 0;
@@ -539,7 +544,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
		if (dvb_minors[minor] == NULL)
			break;
	if (minor == MAX_DVB_MINORS) {
	if (minor >= MAX_DVB_MINORS) {
		if (new_node) {
			list_del (&new_node->list_head);
			kfree(dvbdevfops);
@@ -554,6 +559,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
	}
#else
	minor = nums2minor(adap->num, type, id);
	if (minor >= MAX_DVB_MINORS) {
		dvb_media_device_free(dvbdev);
		list_del(&dvbdev->list_head);
		kfree(dvbdev);
		*pdvbdev = NULL;
		mutex_unlock(&dvbdev_register_lock);
		return ret;
	}
#endif
	dvbdev->minor = minor;
	dvb_minors[minor] = dvb_device_get(dvbdev);