From patchwork Thu Oct 24 16:45:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210385 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7C8D11575 for ; Thu, 24 Oct 2019 17:05:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5AD7621906 for ; Thu, 24 Oct 2019 17:05:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="C/V0R/MU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410115AbfJXRFQ (ORCPT ); Thu, 24 Oct 2019 13:05:16 -0400 Received: from dougal.metanate.com ([90.155.101.14]:53162 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2410088AbfJXRFP (ORCPT ); Thu, 24 Oct 2019 13:05:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=WeI3FCFsNE1HtrK6jYQxaZQOHZIpKCcPIjwM0XSj0NI=; b=C/V0R/MUeQdPA/QR4pMfSn+0pG EPGql0q8F7wWhh4lkGorFnBQLKOfp4Pkx3helkiEidXsi5walZ1ciGBTRmvqfVvCVNZLNHPIbTXcF hvglhk4OHG3AUFinX2f7uRI4LFbGTwSv9Ti9HDMLCawsABwjAAHkhJgu9mYPvA4VwWxhvEefUxX9b 1+zD2C8tRMSjRdpdXYkaO9SZQOn+wE50lKWByVKPLqWmSt17G7pxtfYw3BK5pDqEkP5RZoj2cBONS NUA2lHVAiN0mx4IFs2wmNYtYHN7/X86+2CA4+42i8kN5pqziaEyxucGnPRGGtmFbNq9OjlbjEB/gS 1nreoq8Q==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgF9-0004oc-DV; Thu, 24 Oct 2019 17:45:47 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 1/6] USB: gadget: f_hid: move chardev setup to module init Date: Thu, 24 Oct 2019 17:45:33 +0100 Message-Id: <20191024164538.3161474-2-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org 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. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 27 +++++++-------------------- drivers/usb/gadget/function/u_hid.h | 3 --- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index f3816a5c861e..e9e45f9eae80 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); @@ -1133,7 +1117,7 @@ DECLARE_USB_FUNCTION_INIT(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,12 +1137,12 @@ int ghid_setup(struct usb_gadget *g, int count) } major = MAJOR(dev); - minors = count; + minors = HIDG_MINORS; return 0; } -void ghid_cleanup(void) +static void ghid_cleanup(void) { if (major) { unregister_chrdev_region(MKDEV(major, 0), minors); @@ -1168,3 +1152,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 */ From patchwork Thu Oct 24 16:45:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210391 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A235B139A for ; Thu, 24 Oct 2019 17:05:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 80CDF20650 for ; Thu, 24 Oct 2019 17:05:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="FlWPxduv" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410076AbfJXRFK (ORCPT ); Thu, 24 Oct 2019 13:05:10 -0400 Received: from dougal.metanate.com ([90.155.101.14]:18348 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2405819AbfJXRFK (ORCPT ); Thu, 24 Oct 2019 13:05:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=mQaqDJfBUJCKU7f6avq0mzD47+ygTkCFs3EjoJcaN+4=; b=FlWPxduvtt9U8hlkrCWU30aFS2 Xb0YnEt4mEuav2Od5AyttpkUw55dCU6CFJm3Zgs+bGhLBRBx0BzMiq6dJ0OVs7IoJysSYCZvY5+HG Z6v5Okdi599VEl+TJL/YcHdr8Q4rUEBSv8fG8wSz6mVC6FAa0CzxrkI7UzLckZyuuE0Isx8AEpuwq h6uow3vlflYQ/kj4s/QZmIui8/ijUo/GxSq3j/gDHZe/5OikLxob/4Ks40QvHAdG/YjJ3giTIvxp4 3UYe45ageLPt04rWFuGxoxJPRK9i5xXptUWkUNUFHSq2cO+fMrQYNg5Km+Q4sws2utg2CHenNtcZ2 zYcfCHDA==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgF9-0004oc-LY; Thu, 24 Oct 2019 17:45:47 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 2/6] USB: gadget: f_hid: switch to IDR for tracking minors Date: Thu, 24 Oct 2019 17:45:34 +0100 Message-Id: <20191024164538.3161474-3-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org In the following commits, we are going to move the cdev allocation up to the module initialisation, and will look up the associated f_hidg structure from the open operation. Start preparing for this by switching from IDA to IDR. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index e9e45f9eae80..838256086bd2 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -24,8 +24,8 @@ static int major, minors; static struct class *hidg_class; -static DEFINE_IDA(hidg_ida); -static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */ +static DEFINE_IDR(hidg_idr); +static DEFINE_MUTEX(hidg_idr_lock); /* protects access to hidg_idr */ /*-------------------------------------------------------------------------*/ /* HID gadget struct */ @@ -851,9 +851,9 @@ static inline int hidg_get_minor(void) { int ret; - ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL); + ret = idr_alloc(&hidg_idr, NULL, 0, 0, GFP_KERNEL); if (ret >= HIDG_MINORS) { - ida_simple_remove(&hidg_ida, ret); + idr_remove(&hidg_idr, ret); ret = -ENODEV; } @@ -996,7 +996,7 @@ static const struct config_item_type hid_func_type = { static inline void hidg_put_minor(int minor) { - ida_simple_remove(&hidg_ida, minor); + idr_remove(&hidg_idr, minor); } static void hidg_free_inst(struct usb_function_instance *f) @@ -1005,9 +1005,9 @@ 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); + mutex_lock(&hidg_idr_lock); hidg_put_minor(opts->minor); - mutex_unlock(&hidg_ida_lock); + mutex_unlock(&hidg_idr_lock); if (opts->report_desc_alloc) kfree(opts->report_desc); @@ -1027,7 +1027,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst; - mutex_lock(&hidg_ida_lock); + mutex_lock(&hidg_idr_lock); opts->minor = hidg_get_minor(); if (opts->minor < 0) { @@ -1038,7 +1038,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type); unlock: - mutex_unlock(&hidg_ida_lock); + mutex_unlock(&hidg_idr_lock); return ret; } From patchwork Thu Oct 24 16:45:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210379 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B1C26139A for ; Thu, 24 Oct 2019 17:05:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8737F21E6F for ; Thu, 24 Oct 2019 17:05:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="D1yvgpRU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410142AbfJXRFV (ORCPT ); Thu, 24 Oct 2019 13:05:21 -0400 Received: from dougal.metanate.com ([90.155.101.14]:54823 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2410129AbfJXRFU (ORCPT ); Thu, 24 Oct 2019 13:05:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=PoG+jqjBMytnM1gatI3jmNtM0gsY06tyPc72yvO/HYg=; b=D1yvgpRULaB1mKyWHCbVFn4c8u cRFTQ1loJE+5qXEMmbcztInnKopFcnS3Vltzi2/alsX4hUcqDlDFZm6zGO0WIrBVJSN3+j4UbG8ri L9pSyO0w7it/0ChxdawH6otOFYETlEia/KoKoUIbdxNF2obJi0KQRBYWXrGl8Y16oztER4ec9lO8j bdbjebvaZ6snehknEJQ01Tzf9XCKc6sUJiHfl7B0HkAcSjUnpSJowoYSJt+hY8S2EY+YfzPLesqoY IN96jN5FgJw+icYkaz3OQFmlrCFqLIR74OoFpNZnVgoy/mAuYnx5j/jOnovH2eS6AhU6RFxCCGB6I 42SVf02Q==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgFA-0004oc-0T; Thu, 24 Oct 2019 17:45:48 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 3/6] USB: gadget: f_hid: find f_hidg by IDR lookup on open Date: Thu, 24 Oct 2019 17:45:35 +0100 Message-Id: <20191024164538.3161474-4-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org As a step towards decoupling the cdev lifetime from f_hidg, lookup the f_hidg structure by minor number from IDR when opening the device. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 838256086bd2..4d20347fe908 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -441,8 +441,14 @@ static int f_hidg_release(struct inode *inode, struct file *fd) static int f_hidg_open(struct inode *inode, struct file *fd) { - struct f_hidg *hidg = - container_of(inode->i_cdev, struct f_hidg, cdev); + struct f_hidg *hidg; + + mutex_lock(&hidg_idr_lock); + hidg = idr_find(&hidg_idr, iminor(inode)); + mutex_unlock(&hidg_idr_lock); + + if (!hidg) + return -ENODEV; fd->private_data = hidg; @@ -827,6 +833,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail_free_descs; + mutex_lock(&hidg_idr_lock); + idr_replace(&hidg_idr, hidg, hidg->minor); + mutex_unlock(&hidg_idr_lock); + device = device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor); if (IS_ERR(device)) { From patchwork Thu Oct 24 16:45:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210387 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 067C7139A for ; Thu, 24 Oct 2019 17:05:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D910621906 for ; Thu, 24 Oct 2019 17:05:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="NwULFx1e" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410105AbfJXRFO (ORCPT ); Thu, 24 Oct 2019 13:05:14 -0400 Received: from dougal.metanate.com ([90.155.101.14]:13807 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2410088AbfJXRFN (ORCPT ); Thu, 24 Oct 2019 13:05:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=gqqO7kvxln6um6tt7UgRTKE7dTS/mPaPHkT0N4qUVrk=; b=NwULFx1eh65Q3mZp0N2VCuJ2hd WlMAjH0Gs7tsvg5RW7FOomoyIw2owTkcoOlycgwJymu9EtCO+h9BBJoFi4GOpSb6ULGbN2C3UUW/c Ei++xzSj5hKzNDH1ZTFMkiXiwk7ejkAF1I5Ukr6/mVaI/f4nAK1DUSVaM+prX/z4zUkBV1C/rqPyL +7m2oaNShmP2Y7QgU1eNqfRl83mwL/t5aOCDtiZhwmASPiAsK4Z1rEjMU/OihXY3SlGu3z+8i+y1w EYtiMAUm23r9QKmTWdAhbPQKX4Zafj3yvnVLR8vJYYbtJxQuWViThB4etwBkIh+VyuGCJZoE540AP iwVrXMKQ==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgFA-0004oc-8O; Thu, 24 Oct 2019 17:45:48 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 4/6] USB: gadget: f_hid: decouple cdev from f_hidg lifetime Date: Thu, 24 Oct 2019 17:45:36 +0100 Message-Id: <20191024164538.3161474-5-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org The character device needs to live until the last file descriptor has been closed (and until after ->release() is called in that case). Change the lifetime of our character devices to match the module, so as to avoid a use-after-free when closing a file descriptor after the gadget function has been deleted. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 45 ++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 4d20347fe908..ee94348b85ef 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -24,6 +24,7 @@ static int major, minors; static struct class *hidg_class; +static struct cdev *hidg_cdev; static DEFINE_IDR(hidg_idr); static DEFINE_MUTEX(hidg_idr_lock); /* protects access to hidg_idr */ @@ -58,7 +59,6 @@ struct f_hidg { struct usb_request *req; int minor; - struct cdev cdev; struct usb_function func; struct usb_ep *in_ep; @@ -827,11 +827,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) INIT_LIST_HEAD(&hidg->completed_out_req); /* create char device */ - cdev_init(&hidg->cdev, &f_hidg_fops); dev = MKDEV(major, hidg->minor); - status = cdev_add(&hidg->cdev, dev, 1); - if (status) - goto fail_free_descs; mutex_lock(&hidg_idr_lock); idr_replace(&hidg_idr, hidg, hidg->minor); @@ -841,13 +837,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) "%s%d", "hidg", hidg->minor); if (IS_ERR(device)) { status = PTR_ERR(device); - goto del; + goto fail_idr_remove; } return 0; -del: - cdev_del(&hidg->cdev); -fail_free_descs: +fail_idr_remove: + mutex_lock(&hidg_idr_lock); + idr_replace(&hidg_idr, NULL, hidg->minor); + mutex_unlock(&hidg_idr_lock); usb_free_all_descriptors(f); fail: ERROR(f->config->cdev, "hidg_bind FAILED\n"); @@ -1071,7 +1068,10 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) struct f_hidg *hidg = func_to_hidg(f); device_destroy(hidg_class, MKDEV(major, hidg->minor)); - cdev_del(&hidg->cdev); + + mutex_lock(&hidg_idr_lock); + idr_replace(&hidg_idr, NULL, hidg->minor); + mutex_unlock(&hidg_idr_lock); usb_free_all_descriptors(f); } @@ -1129,6 +1129,7 @@ MODULE_AUTHOR("Fabien Chouteau"); static int ghid_setup(void) { + struct cdev *cdev = NULL; int status; dev_t dev; @@ -1149,11 +1150,35 @@ static int ghid_setup(void) major = MAJOR(dev); minors = HIDG_MINORS; + status = -ENOMEM; + cdev = cdev_alloc(); + if (!cdev) + goto fail_unregister; + + cdev->owner = THIS_MODULE; + cdev->ops = &f_hidg_fops; + kobject_set_name(&cdev->kobj, "hidg"); + + status = cdev_add(cdev, dev, HIDG_MINORS); + if (status) + goto fail_put; + + hidg_cdev = cdev; return 0; + +fail_put: + kobject_put(&cdev->kobj); +fail_unregister: + unregister_chrdev_region(dev, HIDG_MINORS); + class_destroy(hidg_class); + hidg_class = NULL; + return status; } static void ghid_cleanup(void) { + cdev_del(hidg_cdev); + if (major) { unregister_chrdev_region(MKDEV(major, 0), minors); major = minors = 0; From patchwork Thu Oct 24 16:45:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210383 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AFA43112C for ; Thu, 24 Oct 2019 17:05:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 901D721D7E for ; Thu, 24 Oct 2019 17:05:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="mcsf8BDU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410127AbfJXRFS (ORCPT ); Thu, 24 Oct 2019 13:05:18 -0400 Received: from dougal.metanate.com ([90.155.101.14]:26826 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2410113AbfJXRFR (ORCPT ); Thu, 24 Oct 2019 13:05:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=lt/emEqve1MDsXN2KXFtvpLb9DsysvYyUGYvLNkp2YY=; b=mcsf8BDUrZsbXUMnw8/VOODNpt cKd7svVlnEuCbh1IkBi2vkuJhAKYTezDTzplQft0sq4awiEHsbCQzQG/lw/yPszE8Y3QiLV5146dN FUPk1F50HBsC5S28wRz8Z8H/RfuCAkjrAGYJZ+eDNwCIDXg64gDCgq4z8NIAx3acqeKvlskIfKBhN qkoE3ubX7p9JdHwLGIB+u8m6c1qgfXYo4chzpwF+qTnxE8OTkffIEaUqIisQChua2pX+AIpmIPO1Y 0AmRd/gNFGGoecM0X5yx2wPH/HES0VGso1juuTVnBX0KbllrzzwNKNLJNc/u6gtptNY+hAfJirl8g x15XgrFQ==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgFA-0004oc-GA; Thu, 24 Oct 2019 17:45:48 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 5/6] USB: gadget: f_hid: refcount f_hidg structure Date: Thu, 24 Oct 2019 17:45:37 +0100 Message-Id: <20191024164538.3161474-6-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org f_hidg is referenced by file descriptors opened on /dev/hidgN as well as being the USB gadget function. Since these file descriptors can be kept alive after the gadget function has been deleted, we need to decouple the lifetime of the f_hidg structure from the function. Make f_hidg reference counted so that it remains alive after the gadget function has been deleted if necessary. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index ee94348b85ef..2c3e835962a5 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -58,6 +58,7 @@ struct f_hidg { wait_queue_head_t write_queue; struct usb_request *req; + struct kref kref; int minor; struct usb_function func; @@ -70,6 +71,14 @@ static inline struct f_hidg *func_to_hidg(struct usb_function *f) return container_of(f, struct f_hidg, func); } +static void hidg_release(struct kref *kref) +{ + struct f_hidg *hidg = container_of(kref, struct f_hidg, kref); + + kfree(hidg->report_desc); + kfree(hidg); +} + /*-------------------------------------------------------------------------*/ /* Static descriptors */ @@ -435,6 +444,9 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) static int f_hidg_release(struct inode *inode, struct file *fd) { + struct f_hidg *hidg = fd->private_data; + + kref_put(&hidg->kref, hidg_release); fd->private_data = NULL; return 0; } @@ -445,6 +457,8 @@ static int f_hidg_open(struct inode *inode, struct file *fd) mutex_lock(&hidg_idr_lock); hidg = idr_find(&hidg_idr, iminor(inode)); + if (hidg) + kref_get(&hidg->kref); mutex_unlock(&hidg_idr_lock); if (!hidg) @@ -1056,8 +1070,7 @@ static void hidg_free(struct usb_function *f) hidg = func_to_hidg(f); opts = container_of(f->fi, struct f_hid_opts, func_inst); - kfree(hidg->report_desc); - kfree(hidg); + kref_put(&hidg->kref, hidg_release); mutex_lock(&opts->lock); --opts->refcnt; mutex_unlock(&opts->lock); @@ -1109,6 +1122,8 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) mutex_unlock(&opts->lock); + kref_init(&hidg->kref); + hidg->func.name = "hid"; hidg->func.bind = hidg_bind; hidg->func.unbind = hidg_unbind; From patchwork Thu Oct 24 16:45:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Keeping X-Patchwork-Id: 11210389 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 470A6112C for ; Thu, 24 Oct 2019 17:05:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2615221925 for ; Thu, 24 Oct 2019 17:05:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=metanate.com header.i=@metanate.com header.b="ZgRkNkVx" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2410091AbfJXRFN (ORCPT ); Thu, 24 Oct 2019 13:05:13 -0400 Received: from dougal.metanate.com ([90.155.101.14]:61211 "EHLO metanate.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2405819AbfJXRFM (ORCPT ); Thu, 24 Oct 2019 13:05:12 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=metanate.com; s=stronger; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=sCKa65N8pDZk/BvuYm93WNP3he5hb1vXX9CJBcDMFMo=; b=ZgRkNkVxdM6qxsaIjJ7G34YwPa X5OQB5CdqUqQ17bmonlNjvYGrT1POGv9XnxFRtDdeuU+El3xSfRoQtD6wwh3vnqST12cL+VnqkSac yQhfQY+uJhJoURnimGgjl4Tu9Yq89KDM8kpKHyvrMLah+3SEWasRTlAxulNqE2LoyVwtCXeFQkpMX b9zePA3As8lliLb/bIWzlbJr7/Q/dXVrSY8a8ZpRB9+WPwceO5DY6oEqLHhdzdpSxAVwSnPjg5+Io n+3oCSIcs49FIwnJEBLmrigzDkgtWpt3FjezMXoWiK+DLiHhA8OnrdIrCIuW/4X91IjO4vPMmkn7y D//dEcxw==; Received: from 188-39-28-98.static.enta.net ([188.39.28.98] helo=donbot.corp.numark.com) by email.metanate.com with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1iNgFA-0004oc-O1; Thu, 24 Oct 2019 17:45:48 +0100 From: John Keeping To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, John Keeping Subject: [PATCH 6/6] USB: gadget: f_hid: return ENODEV from read/write after deletion Date: Thu, 24 Oct 2019 17:45:38 +0100 Message-Id: <20191024164538.3161474-7-john@metanate.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024164538.3161474-1-john@metanate.com> References: <20191024164538.3161474-1-john@metanate.com> MIME-Version: 1.0 X-Authenticated: YES Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org If a file descriptor to /dev/hidgN is kept open after the gadget function has been deleted, reading or writing will block indefinitely since no requests will ever be processed. Add a flag to note that the function has been deleted and check this in read & write if there is no other action to take. When setting this flag, also wake up any readers/writers so that they get ENODEV immediately. Signed-off-by: John Keeping --- drivers/usb/gadget/function/f_hid.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 2c3e835962a5..fdb8356e334b 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -59,6 +59,7 @@ struct f_hidg { struct usb_request *req; struct kref kref; + bool deleted; int minor; struct usb_function func; @@ -271,10 +272,14 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, /* wait for at least one buffer to complete */ while (!READ_COND) { spin_unlock_irqrestore(&hidg->read_spinlock, flags); + if (READ_ONCE(hidg->deleted)) + return -ENODEV; + if (file->f_flags & O_NONBLOCK) return -EAGAIN; - if (wait_event_interruptible(hidg->read_queue, READ_COND)) + if (wait_event_interruptible(hidg->read_queue, + READ_COND || READ_ONCE(hidg->deleted))) return -ERESTARTSYS; spin_lock_irqsave(&hidg->read_spinlock, flags); @@ -358,11 +363,14 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, /* write queue */ while (!WRITE_COND) { spin_unlock_irqrestore(&hidg->write_spinlock, flags); + if (READ_ONCE(hidg->deleted)) + return -ENODEV; + if (file->f_flags & O_NONBLOCK) return -EAGAIN; - if (wait_event_interruptible_exclusive( - hidg->write_queue, WRITE_COND)) + if (wait_event_interruptible_exclusive(hidg->write_queue, + WRITE_COND || READ_ONCE(hidg->deleted))) return -ERESTARTSYS; spin_lock_irqsave(&hidg->write_spinlock, flags); @@ -1070,6 +1078,10 @@ static void hidg_free(struct usb_function *f) hidg = func_to_hidg(f); opts = container_of(f->fi, struct f_hid_opts, func_inst); + WRITE_ONCE(hidg->deleted, true); + wake_up(&hidg->read_queue); + wake_up(&hidg->write_queue); + kref_put(&hidg->kref, hidg_release); mutex_lock(&opts->lock); --opts->refcnt;