Skip to content

Commit

Permalink
media: dvbdev: prevent the risk of out of memory access
Browse files Browse the repository at this point in the history
[ Upstream commit 972e63e ]

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: 5dd3f30 ("V4L/DVB (9361): Dynamic DVB minor allocation")
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
mchehab authored and gregkh committed Nov 14, 2024
1 parent c776231 commit 1e46167
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions drivers/media/dvb-core/dvbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,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;
Expand Down Expand Up @@ -525,7 +530,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])
break;
if (minor == MAX_DVB_MINORS) {
if (minor >= MAX_DVB_MINORS) {
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
Expand All @@ -540,6 +545,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);
Expand Down

0 comments on commit 1e46167

Please sign in to comment.