[PATCH] \sbus: char: uctrl: Fix use-after-free in uctrl_open

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A race condition may occur if the user physically removes the
uctrl device while calling open().

This is a race condition between uctrl_open() function and
the uctrl_remove() function, which may lead to Use-After-Free.

Therefore, add a kref when open() uctrl driver and decrement
the kref when close() and uctrl_remove() so that the race
condition is not occured.

---------------CPU 0--------------------CPU 1-----------------
                              | p = dev_get_drvdata(&op->dev);
                              | ...
                              | kfree(p); -- (1)
uctrl_get_event_status(global
_driver); — (2)

Signed-off-by: Yoochan Lee <yoochan1026@xxxxxxxxx>
---
 drivers/sbus/char/uctrl.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 05de0ce79cb9..17a8acdfc03a 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -189,6 +189,7 @@ static struct uctrl_driver {
 	int irq;
 	int pending;
 	struct uctrl_status status;
+	struct kref *refcnt;
 } *global_driver;
 
 static void uctrl_get_event_status(struct uctrl_driver *);
@@ -204,12 +205,28 @@ uctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	return 0;
 }
 
+static void uctrl_delete(struct kref *kref)
+{
+	struct uctrl_driver *p = container_of(kref, struct uctrl_driver, refcnt);
+
+	misc_deregister(&uctrl_dev);
+	free_irq(p->irq, p);
+	of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+	kfree(p);
+}
+
+static int uctrl_close(struct inode *inode, struct file *file)
+{
+	kref_put(&global_driver->refcnt, uctrl_delete);
+}
+
 static int
 uctrl_open(struct inode *inode, struct file *file)
 {
 	mutex_lock(&uctrl_mutex);
 	uctrl_get_event_status(global_driver);
 	uctrl_get_external_status(global_driver);
+	kref_get(&global_driver->refcnt);
 	mutex_unlock(&uctrl_mutex);
 	return 0;
 }
@@ -224,6 +241,7 @@ static const struct file_operations uctrl_fops = {
 	.llseek =	no_llseek,
 	.unlocked_ioctl =	uctrl_ioctl,
 	.open =		uctrl_open,
+	.release =	uctrl_close,
 };
 
 static struct miscdevice uctrl_dev = {
@@ -404,10 +422,7 @@ static int uctrl_remove(struct platform_device *op)
 	struct uctrl_driver *p = dev_get_drvdata(&op->dev);
 
 	if (p) {
-		misc_deregister(&uctrl_dev);
-		free_irq(p->irq, p);
-		of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
-		kfree(p);
+		kref_put(&p->refcnt, uctrl_delete);
 	}
 	return 0;
 }
-- 
2.39.0




[Index of Archives]     [Kernel Development]     [DCCP]     [Linux ARM Development]     [Linux]     [Photo]     [Yosemite Help]     [Linux ARM Kernel]     [Linux SCSI]     [Linux x86_64]     [Linux Hams]

  Powered by Linux