Skip to content

Commit b802651

Browse files
committed
Merge tag 'media/v6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media fixes from Mauro Carvalho Chehab: "Several fixes for the dvb core and drivers: - fix UAF and null pointer de-reference in DVB core - fix kernel runtime warning for blocking operation in wait_event*() in dvb core - fix write size bug in DVB conditional access core - fix dvb demux continuity counter debug check logic - randconfig build fixes in pvrusb2 and mn88443x - fix memory leak in ttusb-dec - fix netup_unidvb probe-time error check logic - improve error handling in dw2102 if it can't retrieve DVB MAC address" * tag 'media/v6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221 media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*() media: dvb-core: Fix use-after-free due to race at dvb_register_device() media: dvb-core: Fix use-after-free due on race condition at dvb_net media: dvb-core: Fix use-after-free on race condition at dvb_frontend media: mn88443x: fix !CONFIG_OF error by drop of_match_ptr from ID table media: ttusb-dec: fix memory leak in ttusb_dec_exit_dvb() media: dvb_ca_en50221: fix a size write bug media: netup_unidvb: fix irq init by register it at the end of probe media: dvb-usb: dw2102: fix uninit-value in su3000_read_mac_address media: dvb-usb: digitv: fix null-ptr-deref in digitv_i2c_xfer() media: dvb-usb-v2: rtl28xxu: fix null-ptr-deref in rtl28xxu_i2c_xfer media: dvb-usb-v2: ce6230: fix null-ptr-deref in ce6230_i2c_master_xfer() media: dvb-usb-v2: ec168: fix null-ptr-deref in ec168_i2c_xfer() media: dvb-usb: az6027: fix three null-ptr-deref in az6027_i2c_xfer() media: netup_unidvb: fix use-after-free at del_timer() media: dvb_demux: fix a bug for the continuity counter media: pvrusb2: fix DVB_CORE dependency
2 parents 4d6d4c7 + 280a8ab commit b802651

File tree

18 files changed

+293
-59
lines changed

18 files changed

+293
-59
lines changed

drivers/media/dvb-core/dvb_ca_en50221.c

Lines changed: 43 additions & 6 deletions
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)
@@ -187,7 +193,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
187193
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
188194
u8 *ebuf, int ecount);
189195
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
190-
u8 *ebuf, int ecount);
196+
u8 *ebuf, int ecount, int size_write_flag);
191197

192198
/**
193199
* findstr - Safely find needle in haystack.
@@ -370,7 +376,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
370376
ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
371377
if (ret)
372378
return ret;
373-
ret = dvb_ca_en50221_write_data(ca, slot, buf, 2);
379+
ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW);
374380
if (ret != 2)
375381
return -EIO;
376382
ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
@@ -778,11 +784,13 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
778784
* @buf: The data in this buffer is treated as a complete link-level packet to
779785
* be written.
780786
* @bytes_write: Size of ebuf.
787+
* @size_write_flag: A flag on Command Register which says whether the link size
788+
* information will be writen or not.
781789
*
782790
* return: Number of bytes written, or < 0 on error.
783791
*/
784792
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
785-
u8 *buf, int bytes_write)
793+
u8 *buf, int bytes_write, int size_write_flag)
786794
{
787795
struct dvb_ca_slot *sl = &ca->slot_info[slot];
788796
int status;
@@ -817,7 +825,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
817825

818826
/* OK, set HC bit */
819827
status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
820-
IRQEN | CMDREG_HC);
828+
IRQEN | CMDREG_HC | size_write_flag);
821829
if (status)
822830
goto exit;
823831

@@ -1508,7 +1516,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
15081516

15091517
mutex_lock(&sl->slot_lock);
15101518
status = dvb_ca_en50221_write_data(ca, slot, fragbuf,
1511-
fraglen + 2);
1519+
fraglen + 2, 0);
15121520
mutex_unlock(&sl->slot_lock);
15131521
if (status == (fraglen + 2)) {
15141522
written = 1;
@@ -1709,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
17091717

17101718
dprintk("%s\n", __func__);
17111719

1712-
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);
17131729
return -EIO;
1730+
}
17141731

17151732
err = dvb_generic_open(inode, file);
17161733
if (err < 0) {
17171734
module_put(ca->pub->owner);
1735+
mutex_unlock(&ca->remove_mutex);
17181736
return err;
17191737
}
17201738

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

17401758
dvb_ca_private_get(ca);
17411759

1760+
mutex_unlock(&ca->remove_mutex);
17421761
return 0;
17431762
}
17441763

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

17591778
dprintk("%s\n", __func__);
17601779

1780+
mutex_lock(&ca->remove_mutex);
1781+
17611782
/* mark the CA device as closed */
17621783
ca->open = 0;
17631784
dvb_ca_en50221_thread_update_delay(ca);
@@ -1768,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
17681789

17691790
dvb_ca_private_put(ca);
17701791

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+
17711799
return err;
17721800
}
17731801

@@ -1891,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
18911919
}
18921920

18931921
mutex_init(&ca->ioctl_mutex);
1922+
mutex_init(&ca->remove_mutex);
18941923

18951924
if (signal_pending(current)) {
18961925
ret = -EINTR;
@@ -1933,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
19331962

19341963
dprintk("%s\n", __func__);
19351964

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+
19361973
/* shutdown the thread if there was one */
19371974
kthread_stop(ca->thread);
19381975

drivers/media/dvb-core/dvb_demux.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
115115

116116
cc = buf[3] & 0x0f;
117117
ccok = ((feed->cc + 1) & 0x0f) == cc;
118-
feed->cc = cc;
119118
if (!ccok) {
120119
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
121120
dprintk_sect_loss("missed packet: %d instead of %d!\n",
122121
cc, (feed->cc + 1) & 0x0f);
123122
}
123+
feed->cc = cc;
124124

125125
if (buf[1] & 0x40) // PUSI ?
126126
feed->peslen = 0xfffa;
@@ -300,7 +300,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
300300

301301
cc = buf[3] & 0x0f;
302302
ccok = ((feed->cc + 1) & 0x0f) == cc;
303-
feed->cc = cc;
304303

305304
if (buf[3] & 0x20) {
306305
/* adaption field present, check for discontinuity_indicator */
@@ -336,6 +335,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
336335
feed->pusi_seen = false;
337336
dvb_dmx_swfilter_section_new(feed);
338337
}
338+
feed->cc = cc;
339339

340340
if (buf[1] & 0x40) {
341341
/* PUSI=1 (is set), section boundary is here */

drivers/media/dvb-core/dvb_frontend.c

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
293293
}
294294

295295
if (events->eventw == events->eventr) {
296-
int ret;
296+
struct wait_queue_entry wait;
297+
int ret = 0;
297298

298299
if (flags & O_NONBLOCK)
299300
return -EWOULDBLOCK;
300301

301-
ret = wait_event_interruptible(events->wait_queue,
302-
dvb_frontend_test_event(fepriv, events));
303-
302+
init_waitqueue_entry(&wait, current);
303+
add_wait_queue(&events->wait_queue, &wait);
304+
while (!dvb_frontend_test_event(fepriv, events)) {
305+
wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
306+
if (signal_pending(current)) {
307+
ret = -ERESTARTSYS;
308+
break;
309+
}
310+
}
311+
remove_wait_queue(&events->wait_queue, &wait);
304312
if (ret < 0)
305313
return ret;
306314
}
@@ -809,15 +817,26 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
809817

810818
dev_dbg(fe->dvb->device, "%s:\n", __func__);
811819

820+
mutex_lock(&fe->remove_mutex);
821+
812822
if (fe->exit != DVB_FE_DEVICE_REMOVED)
813823
fe->exit = DVB_FE_NORMAL_EXIT;
814824
mb();
815825

816-
if (!fepriv->thread)
826+
if (!fepriv->thread) {
827+
mutex_unlock(&fe->remove_mutex);
817828
return;
829+
}
818830

819831
kthread_stop(fepriv->thread);
820832

833+
mutex_unlock(&fe->remove_mutex);
834+
835+
if (fepriv->dvbdev->users < -1) {
836+
wait_event(fepriv->dvbdev->wait_queue,
837+
fepriv->dvbdev->users == -1);
838+
}
839+
821840
sema_init(&fepriv->sem, 1);
822841
fepriv->state = FESTATE_IDLE;
823842

@@ -2761,17 +2780,22 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
27612780
struct dvb_adapter *adapter = fe->dvb;
27622781
int ret;
27632782

2783+
mutex_lock(&fe->remove_mutex);
2784+
27642785
dev_dbg(fe->dvb->device, "%s:\n", __func__);
2765-
if (fe->exit == DVB_FE_DEVICE_REMOVED)
2766-
return -ENODEV;
2786+
if (fe->exit == DVB_FE_DEVICE_REMOVED) {
2787+
ret = -ENODEV;
2788+
goto err_remove_mutex;
2789+
}
27672790

27682791
if (adapter->mfe_shared == 2) {
27692792
mutex_lock(&adapter->mfe_lock);
27702793
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
27712794
if (adapter->mfe_dvbdev &&
27722795
!adapter->mfe_dvbdev->writers) {
27732796
mutex_unlock(&adapter->mfe_lock);
2774-
return -EBUSY;
2797+
ret = -EBUSY;
2798+
goto err_remove_mutex;
27752799
}
27762800
adapter->mfe_dvbdev = dvbdev;
27772801
}
@@ -2794,8 +2818,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
27942818
while (mferetry-- && (mfedev->users != -1 ||
27952819
mfepriv->thread)) {
27962820
if (msleep_interruptible(500)) {
2797-
if (signal_pending(current))
2798-
return -EINTR;
2821+
if (signal_pending(current)) {
2822+
ret = -EINTR;
2823+
goto err_remove_mutex;
2824+
}
27992825
}
28002826
}
28012827

@@ -2807,7 +2833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
28072833
if (mfedev->users != -1 ||
28082834
mfepriv->thread) {
28092835
mutex_unlock(&adapter->mfe_lock);
2810-
return -EBUSY;
2836+
ret = -EBUSY;
2837+
goto err_remove_mutex;
28112838
}
28122839
adapter->mfe_dvbdev = dvbdev;
28132840
}
@@ -2866,6 +2893,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
28662893

28672894
if (adapter->mfe_shared)
28682895
mutex_unlock(&adapter->mfe_lock);
2896+
2897+
mutex_unlock(&fe->remove_mutex);
28692898
return ret;
28702899

28712900
err3:
@@ -2887,6 +2916,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
28872916
err0:
28882917
if (adapter->mfe_shared)
28892918
mutex_unlock(&adapter->mfe_lock);
2919+
2920+
err_remove_mutex:
2921+
mutex_unlock(&fe->remove_mutex);
28902922
return ret;
28912923
}
28922924

@@ -2897,6 +2929,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
28972929
struct dvb_frontend_private *fepriv = fe->frontend_priv;
28982930
int ret;
28992931

2932+
mutex_lock(&fe->remove_mutex);
2933+
29002934
dev_dbg(fe->dvb->device, "%s:\n", __func__);
29012935

29022936
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -2918,10 +2952,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
29182952
}
29192953
mutex_unlock(&fe->dvb->mdev_lock);
29202954
#endif
2921-
if (fe->exit != DVB_FE_NO_EXIT)
2922-
wake_up(&dvbdev->wait_queue);
29232955
if (fe->ops.ts_bus_ctrl)
29242956
fe->ops.ts_bus_ctrl(fe, 0);
2957+
2958+
if (fe->exit != DVB_FE_NO_EXIT) {
2959+
mutex_unlock(&fe->remove_mutex);
2960+
wake_up(&dvbdev->wait_queue);
2961+
} else {
2962+
mutex_unlock(&fe->remove_mutex);
2963+
}
2964+
2965+
} else {
2966+
mutex_unlock(&fe->remove_mutex);
29252967
}
29262968

29272969
dvb_frontend_put(fe);
@@ -3022,6 +3064,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
30223064
fepriv = fe->frontend_priv;
30233065

30243066
kref_init(&fe->refcount);
3067+
mutex_init(&fe->remove_mutex);
30253068

30263069
/*
30273070
* After initialization, there need to be two references: one

0 commit comments

Comments
 (0)