Skip to content

Commit 280a8ab

Browse files
ImV4belmchehab
authored andcommitted
media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221
If the device node of dvb_ca_en50221 is open() and the device is disconnected, a UAF may occur when calling close() on the device node. The root cause is that wake_up() and wait_event() for dvbdev->wait_queue are not implemented. So implement wait_event() function in dvb_ca_en50221_release() and add 'remove_mutex' which prevents race condition for 'ca->exit'. [mchehab: fix a checkpatch warning] Link: https://lore.kernel.org/linux-media/20221121063308.GA33821@ubuntu Signed-off-by: Hyunwoo Kim <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent b8c75e4 commit 280a8ab

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

drivers/media/dvb-core/dvb_ca_en50221.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ struct dvb_ca_private {
151151

152152
/* mutex serializing ioctls */
153153
struct mutex ioctl_mutex;
154+
155+
/* A mutex used when a device is disconnected */
156+
struct mutex remove_mutex;
157+
158+
/* Whether the device is disconnected */
159+
int exit;
154160
};
155161

156162
static void dvb_ca_private_free(struct dvb_ca_private *ca)
@@ -1711,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
17111717

17121718
dprintk("%s\n", __func__);
17131719

1714-
if (!try_module_get(ca->pub->owner))
1720+
mutex_lock(&ca->remove_mutex);
1721+
1722+
if (ca->exit) {
1723+
mutex_unlock(&ca->remove_mutex);
1724+
return -ENODEV;
1725+
}
1726+
1727+
if (!try_module_get(ca->pub->owner)) {
1728+
mutex_unlock(&ca->remove_mutex);
17151729
return -EIO;
1730+
}
17161731

17171732
err = dvb_generic_open(inode, file);
17181733
if (err < 0) {
17191734
module_put(ca->pub->owner);
1735+
mutex_unlock(&ca->remove_mutex);
17201736
return err;
17211737
}
17221738

@@ -1741,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
17411757

17421758
dvb_ca_private_get(ca);
17431759

1760+
mutex_unlock(&ca->remove_mutex);
17441761
return 0;
17451762
}
17461763

@@ -1760,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
17601777

17611778
dprintk("%s\n", __func__);
17621779

1780+
mutex_lock(&ca->remove_mutex);
1781+
17631782
/* mark the CA device as closed */
17641783
ca->open = 0;
17651784
dvb_ca_en50221_thread_update_delay(ca);
@@ -1770,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
17701789

17711790
dvb_ca_private_put(ca);
17721791

1792+
if (dvbdev->users == 1 && ca->exit == 1) {
1793+
mutex_unlock(&ca->remove_mutex);
1794+
wake_up(&dvbdev->wait_queue);
1795+
} else {
1796+
mutex_unlock(&ca->remove_mutex);
1797+
}
1798+
17731799
return err;
17741800
}
17751801

@@ -1893,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
18931919
}
18941920

18951921
mutex_init(&ca->ioctl_mutex);
1922+
mutex_init(&ca->remove_mutex);
18961923

18971924
if (signal_pending(current)) {
18981925
ret = -EINTR;
@@ -1935,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
19351962

19361963
dprintk("%s\n", __func__);
19371964

1965+
mutex_lock(&ca->remove_mutex);
1966+
ca->exit = 1;
1967+
mutex_unlock(&ca->remove_mutex);
1968+
1969+
if (ca->dvbdev->users < 1)
1970+
wait_event(ca->dvbdev->wait_queue,
1971+
ca->dvbdev->users == 1);
1972+
19381973
/* shutdown the thread if there was one */
19391974
kthread_stop(ca->thread);
19401975

0 commit comments

Comments
 (0)