lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Wed, 2 Jan 2019 23:42:20 +0800
From:   liujian <liujian56@...wei.com>
To:     <gregkh@...uxfoundation.org>, <hamish.martin@...iedtelesis.co.nz>
CC:     <liujian56@...wei.com>, <linux-kernel@...r.kernel.org>
Subject: [PATCH] driver: uio: fix possible memory leak and use-after-free in __uio_register_device

Before device_register, if something goes wrong, we need to manually
 free idev.

In the error handling path, after device_unregister, idev maybe have been
 released, we should not use it anymore.

Signed-off-by: liujian <liujian56@...wei.com>
---
 drivers/uio/uio.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 1313422..5c10fc7 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -413,13 +413,18 @@ static int uio_get_minor(struct uio_device *idev)
 	return retval;
 }
 
-static void uio_free_minor(struct uio_device *idev)
+static void __uio_free_minor(int id)
 {
 	mutex_lock(&minor_lock);
-	idr_remove(&uio_idr, idev->minor);
+	idr_remove(&uio_idr, id);
 	mutex_unlock(&minor_lock);
 }
 
+static void uio_free_minor(struct uio_device *idev)
+{
+	__uio_free_minor(idev->minor);
+}
+
 /**
  * uio_event_notify - trigger an interrupt event
  * @info: UIO device capabilities
@@ -919,6 +924,7 @@ int __uio_register_device(struct module *owner,
 {
 	struct uio_device *idev;
 	int ret = 0;
+	int uio_minor;
 
 	if (!uio_class_registered)
 		return -EPROBE_DEFER;
@@ -940,8 +946,12 @@ int __uio_register_device(struct module *owner,
 	atomic_set(&idev->event, 0);
 
 	ret = uio_get_minor(idev);
-	if (ret)
+	if (ret) {
+		kfree(idev);
 		return ret;
+	}
+
+	uio_minor = idev->minor;
 
 	idev->dev.devt = MKDEV(uio_major, idev->minor);
 	idev->dev.class = &uio_class;
@@ -950,8 +960,11 @@ int __uio_register_device(struct module *owner,
 	dev_set_drvdata(&idev->dev, idev);
 
 	ret = dev_set_name(&idev->dev, "uio%d", idev->minor);
-	if (ret)
-		goto err_device_create;
+	if (ret) {
+		__uio_free_minor(uio_minor);
+		kfree(idev);
+		return ret;
+	}
 
 	ret = device_register(&idev->dev);
 	if (ret)
@@ -987,7 +1000,7 @@ int __uio_register_device(struct module *owner,
 err_uio_dev_add_attributes:
 	device_unregister(&idev->dev);
 err_device_create:
-	uio_free_minor(idev);
+	__uio_free_minor(uio_minor);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(__uio_register_device);
-- 
2.7.4

Powered by blists - more mailing lists