Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1361849 > unrolled thread

[PATCH 1/6] drivers/media/dvb-core/en50221: move code to dvb_ca_private_free()

Started byMax Kellermann <max@duempel.org>
First post2016-03-21 14:40 +0100
Last post2016-03-21 14:40 +0100
Articles 3 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH 1/6] drivers/media/dvb-core/en50221: move code to  dvb_ca_private_free() Max Kellermann <max@duempel.org> - 2016-03-21 14:40 +0100
    [PATCH 2/6] drivers/media/dvb-core/en50221: postpone release until  file is closed Max Kellermann <max@duempel.org> - 2016-03-21 14:40 +0100
    [PATCH 6/6] drivers/media/dvb-usb-dvb: postpone kfree(mdev) Max Kellermann <max@duempel.org> - 2016-03-21 14:40 +0100

#1361849 — [PATCH 1/6] drivers/media/dvb-core/en50221: move code to dvb_ca_private_free()

FromMax Kellermann <max@duempel.org>
Date2016-03-21 14:40 +0100
Subject[PATCH 1/6] drivers/media/dvb-core/en50221: move code to dvb_ca_private_free()
Message-ID<rf8dQ-6jL-11@gated-at.bofh.it>
Prepare for postponing the call until all file handles have been
closed.

Signed-off-by: Max Kellermann <max@duempel.org>
---
 drivers/media/dvb-core/dvb_ca_en50221.c |   16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index f82cd1f..e33364c 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -161,6 +161,17 @@ struct dvb_ca_private {
 	struct mutex ioctl_mutex;
 };
 
+static void dvb_ca_private_free(struct dvb_ca_private *ca)
+{
+	dvb_unregister_device(ca->dvbdev);
+	unsigned int i;
+	for (i = 0; i < ca->slot_count; i++) {
+		vfree(ca->slot_info[i].rx_buffer.data);
+	}
+	kfree(ca->slot_info);
+	kfree(ca);
+}
+
 static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
 static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
 static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
@@ -1759,10 +1770,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 
 	for (i = 0; i < ca->slot_count; i++) {
 		dvb_ca_en50221_slot_shutdown(ca, i);
-		vfree(ca->slot_info[i].rx_buffer.data);
 	}
-	kfree(ca->slot_info);
-	dvb_unregister_device(ca->dvbdev);
-	kfree(ca);
+	dvb_ca_private_free(ca);
 	pubca->private = NULL;
 }

[toc] | [next] | [standalone]


#1361850 — [PATCH 2/6] drivers/media/dvb-core/en50221: postpone release until file is closed

FromMax Kellermann <max@duempel.org>
Date2016-03-21 14:40 +0100
Subject[PATCH 2/6] drivers/media/dvb-core/en50221: postpone release until file is closed
Message-ID<rf8dR-6jL-29@gated-at.bofh.it>
In reply to#1361849
Fixes use-after-free bug which occurs when I disconnect my DVB-S
received while VDR is running.

Signed-off-by: Max Kellermann <max@duempel.org>
---
 drivers/media/dvb-core/dvb_ca_en50221.c |   23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index e33364c..dfc686a 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -148,6 +148,9 @@ struct dvb_ca_private {
 	/* Flag indicating if the CA device is open */
 	unsigned int open:1;
 
+	/* Flag indicating if the CA device is released */
+	unsigned int released:1;
+
 	/* Flag indicating the thread should wake up now */
 	unsigned int wakeup:1;
 
@@ -1392,6 +1395,11 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
 	int found = 0;
 	u8 hdr[2];
 
+	if (ca->released) {
+		*result = -ENODEV;
+		return 1;
+	}
+
 	slot = ca->next_read_slot;
 	while ((slot_count < ca->slot_count) && (!found)) {
 		if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
@@ -1595,6 +1603,9 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 
 	err = dvb_generic_release(inode, file);
 
+	if (ca->released)
+		dvb_ca_private_free(ca);
+
 	module_put(ca->pub->owner);
 
 	return err;
@@ -1701,6 +1712,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
 	}
 	init_waitqueue_head(&ca->wait_queue);
 	ca->open = 0;
+	ca->released = 0;
 	ca->wakeup = 0;
 	ca->next_read_slot = 0;
 	pubca->private = ca;
@@ -1765,12 +1777,21 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 
 	dprintk("%s\n", __func__);
 
+	BUG_ON(ca->released);
+
 	/* shutdown the thread if there was one */
 	kthread_stop(ca->thread);
 
 	for (i = 0; i < ca->slot_count; i++) {
 		dvb_ca_en50221_slot_shutdown(ca, i);
 	}
-	dvb_ca_private_free(ca);
+
+	if (ca->open) {
+		ca->released = 1;
+		mb();
+		wake_up_interruptible(&ca->wait_queue);
+	} else
+		dvb_ca_private_free(ca);
+
 	pubca->private = NULL;
 }

[toc] | [prev] | [next] | [standalone]


#1361853 — [PATCH 6/6] drivers/media/dvb-usb-dvb: postpone kfree(mdev)

FromMax Kellermann <max@duempel.org>
Date2016-03-21 14:40 +0100
Subject[PATCH 6/6] drivers/media/dvb-usb-dvb: postpone kfree(mdev)
Message-ID<rf8dS-6jL-39@gated-at.bofh.it>
In reply to#1361849
Fixes use-after-free bug which occurs when I disconnect my DVB-S
received while VDR is running.

Signed-off-by: Max Kellermann <max@duempel.org>
---
 drivers/media/usb/dvb-usb/dvb-usb-dvb.c |   14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 9ddfcab..7859479 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -95,6 +95,12 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 	return dvb_usb_ctrl_feed(dvbdmxfeed, 0);
 }
 
+static void dvb_usb_media_device_release(struct media_device *mdev)
+{
+	media_device_cleanup(mdev);
+	kfree(mdev);
+}
+
 static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap)
 {
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
@@ -113,6 +119,7 @@ static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap)
 	strcpy(mdev->bus_info, udev->devpath);
 	mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
 	mdev->driver_version = LINUX_VERSION_CODE;
+	mdev->release = dvb_usb_media_device_release;
 
 	media_device_init(mdev);
 
@@ -138,10 +145,11 @@ static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap)
 	if (!adap->dvb_adap.mdev)
 		return;
 
-	media_device_unregister(adap->dvb_adap.mdev);
-	media_device_cleanup(adap->dvb_adap.mdev);
-	kfree(adap->dvb_adap.mdev);
+	struct media_device *mdev = adap->dvb_adap.mdev;
 	adap->dvb_adap.mdev = NULL;
+	media_device_unregister(mdev);
+	/* media_device_cleanup() and kfree() will be called by the
+	   callback function dvb_usb_media_device_release() */
 #endif
 }
 

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web