Skip to content

Commit 4172385

Browse files
V4belmchehab
authored andcommitted
media: dvb-core: Fix use-after-free due on race condition at dvb_net
A race condition may occur between the .disconnect function, which is called when the device is disconnected, and the dvb_device_open() function, which is called when the device node is open()ed. This results in several types of UAFs. The root cause of this is that you use the dvb_device_open() function, which does not implement a conditional statement that checks 'dvbnet->exit'. So, add 'remove_mutex` to protect 'dvbnet->exit' and use locked_dvb_net_open() function to check 'dvbnet->exit'. [mchehab: fix a checkpatch warning] Link: https://lore.kernel.org/linux-media/[email protected] Signed-off-by: Hyunwoo Kim <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 6769a0b commit 4172385

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

drivers/media/dvb-core/dvb_net.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,23 +1564,51 @@ static long dvb_net_ioctl(struct file *file,
15641564
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
15651565
}
15661566

1567+
static int locked_dvb_net_open(struct inode *inode, struct file *file)
1568+
{
1569+
struct dvb_device *dvbdev = file->private_data;
1570+
struct dvb_net *dvbnet = dvbdev->priv;
1571+
int ret;
1572+
1573+
if (mutex_lock_interruptible(&dvbnet->remove_mutex))
1574+
return -ERESTARTSYS;
1575+
1576+
if (dvbnet->exit) {
1577+
mutex_unlock(&dvbnet->remove_mutex);
1578+
return -ENODEV;
1579+
}
1580+
1581+
ret = dvb_generic_open(inode, file);
1582+
1583+
mutex_unlock(&dvbnet->remove_mutex);
1584+
1585+
return ret;
1586+
}
1587+
15671588
static int dvb_net_close(struct inode *inode, struct file *file)
15681589
{
15691590
struct dvb_device *dvbdev = file->private_data;
15701591
struct dvb_net *dvbnet = dvbdev->priv;
15711592

1593+
mutex_lock(&dvbnet->remove_mutex);
1594+
15721595
dvb_generic_release(inode, file);
15731596

1574-
if(dvbdev->users == 1 && dvbnet->exit == 1)
1597+
if (dvbdev->users == 1 && dvbnet->exit == 1) {
1598+
mutex_unlock(&dvbnet->remove_mutex);
15751599
wake_up(&dvbdev->wait_queue);
1600+
} else {
1601+
mutex_unlock(&dvbnet->remove_mutex);
1602+
}
1603+
15761604
return 0;
15771605
}
15781606

15791607

15801608
static const struct file_operations dvb_net_fops = {
15811609
.owner = THIS_MODULE,
15821610
.unlocked_ioctl = dvb_net_ioctl,
1583-
.open = dvb_generic_open,
1611+
.open = locked_dvb_net_open,
15841612
.release = dvb_net_close,
15851613
.llseek = noop_llseek,
15861614
};
@@ -1599,10 +1627,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
15991627
{
16001628
int i;
16011629

1630+
mutex_lock(&dvbnet->remove_mutex);
16021631
dvbnet->exit = 1;
1632+
mutex_unlock(&dvbnet->remove_mutex);
1633+
16031634
if (dvbnet->dvbdev->users < 1)
16041635
wait_event(dvbnet->dvbdev->wait_queue,
1605-
dvbnet->dvbdev->users==1);
1636+
dvbnet->dvbdev->users == 1);
16061637

16071638
dvb_unregister_device(dvbnet->dvbdev);
16081639

@@ -1621,6 +1652,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
16211652
int i;
16221653

16231654
mutex_init(&dvbnet->ioctl_mutex);
1655+
mutex_init(&dvbnet->remove_mutex);
16241656
dvbnet->demux = dmx;
16251657

16261658
for (i=0; i<DVB_NET_DEVICES_MAX; i++)

include/media/dvb_net.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct net_device;
3939
* @exit: flag to indicate when the device is being removed.
4040
* @demux: pointer to &struct dmx_demux.
4141
* @ioctl_mutex: protect access to this struct.
42+
* @remove_mutex: mutex that avoids a race condition between a callback
43+
* called when the hardware is disconnected and the
44+
* file_operations of dvb_net.
4245
*
4346
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
4447
* devices.
@@ -51,6 +54,7 @@ struct dvb_net {
5154
unsigned int exit:1;
5255
struct dmx_demux *demux;
5356
struct mutex ioctl_mutex;
57+
struct mutex remove_mutex;
5458
};
5559

5660
/**

0 commit comments

Comments
 (0)