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  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Mon, 28 Oct 2019 11:42:23 +0000
From:   John Keeping <john@...anate.com>
To:     linux-usb@...r.kernel.org
Cc:     Felipe Balbi <balbi@...nel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        linux-kernel@...r.kernel.org, John Keeping <john@...anate.com>
Subject: [PATCH v2 1/6] USB: gadget: f_hid: move chardev setup to module init

Lifetime of the objects in the HID gadget is currently tied to the USB
function, which makes it very easy to trigger a use-after-free by
holding a file descriptor on the HID device after deleting the gadget.

As a first step towards fixing this, move the character device
allocation to module initialisation so that we don't have to worry about
when the allocation can be released after closing all of the open
handles on the device.

Note that we also have to move the USB function registration into the
initialisation function in order to avoid having two module_init()
functions.

Signed-off-by: John Keeping <john@...anate.com>
---
v2:
- Switch to DECLARE_USB_FUNCTION and manual function (de)registration to
  fix compiling as a module

 drivers/usb/gadget/function/f_hid.c | 41 ++++++++++++++---------------
 drivers/usb/gadget/function/u_hid.h |  3 ---
 2 files changed, 20 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index f3816a5c861e..e5e18d02b77a 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -1006,11 +1006,7 @@ static void hidg_free_inst(struct usb_function_instance *f)
 	opts = container_of(f, struct f_hid_opts, func_inst);
 
 	mutex_lock(&hidg_ida_lock);
-
 	hidg_put_minor(opts->minor);
-	if (ida_is_empty(&hidg_ida))
-		ghid_cleanup();
-
 	mutex_unlock(&hidg_ida_lock);
 
 	if (opts->report_desc_alloc)
@@ -1023,7 +1019,6 @@ static struct usb_function_instance *hidg_alloc_inst(void)
 {
 	struct f_hid_opts *opts;
 	struct usb_function_instance *ret;
-	int status = 0;
 
 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
 	if (!opts)
@@ -1034,21 +1029,10 @@ static struct usb_function_instance *hidg_alloc_inst(void)
 
 	mutex_lock(&hidg_ida_lock);
 
-	if (ida_is_empty(&hidg_ida)) {
-		status = ghid_setup(NULL, HIDG_MINORS);
-		if (status)  {
-			ret = ERR_PTR(status);
-			kfree(opts);
-			goto unlock;
-		}
-	}
-
 	opts->minor = hidg_get_minor();
 	if (opts->minor < 0) {
 		ret = ERR_PTR(opts->minor);
 		kfree(opts);
-		if (ida_is_empty(&hidg_ida))
-			ghid_cleanup();
 		goto unlock;
 	}
 	config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type);
@@ -1129,11 +1113,11 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
 	return &hidg->func;
 }
 
-DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
+DECLARE_USB_FUNCTION(hid, hidg_alloc_inst, hidg_alloc);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Fabien Chouteau");
 
-int ghid_setup(struct usb_gadget *g, int count)
+static int ghid_setup(void)
 {
 	int status;
 	dev_t dev;
@@ -1145,7 +1129,7 @@ int ghid_setup(struct usb_gadget *g, int count)
 		return status;
 	}
 
-	status = alloc_chrdev_region(&dev, 0, count, "hidg");
+	status = alloc_chrdev_region(&dev, 0, HIDG_MINORS, "hidg");
 	if (status) {
 		class_destroy(hidg_class);
 		hidg_class = NULL;
@@ -1153,13 +1137,25 @@ int ghid_setup(struct usb_gadget *g, int count)
 	}
 
 	major = MAJOR(dev);
-	minors = count;
+	minors = HIDG_MINORS;
+
+	status = usb_function_register(&hidusb_func);
+	if (status)
+		goto fail_unregister;
 
 	return 0;
+
+fail_unregister:
+	unregister_chrdev_region(dev, HIDG_MINORS);
+	class_destroy(hidg_class);
+	hidg_class = NULL;
+	return status;
 }
 
-void ghid_cleanup(void)
+static void ghid_cleanup(void)
 {
+	usb_function_unregister(&hidusb_func);
+
 	if (major) {
 		unregister_chrdev_region(MKDEV(major, 0), minors);
 		major = minors = 0;
@@ -1168,3 +1164,6 @@ void ghid_cleanup(void)
 	class_destroy(hidg_class);
 	hidg_class = NULL;
 }
+
+module_init(ghid_setup);
+module_exit(ghid_cleanup);
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
index 1594bfa312eb..d52acc977c7e 100644
--- a/drivers/usb/gadget/function/u_hid.h
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -33,7 +33,4 @@ struct f_hid_opts {
 	 int				refcnt;
 };
 
-int ghid_setup(struct usb_gadget *g, int count);
-void ghid_cleanup(void);
-
 #endif /* U_HID_H */
-- 
2.23.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ