Message ID | 20221203133159.94414-1-mailhol.vincent@wanadoo.fr |
---|---|
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1366552wrr; Sat, 3 Dec 2022 05:34:24 -0800 (PST) X-Google-Smtp-Source: AA0mqf4sZoBRNxq2jpU2woPmPRQaRG0Hve9vFys0DH45bRaLP2X4x+z9vWES/vQAoYjW0mwoWb2X X-Received: by 2002:a05:6a00:1d0b:b0:574:24cc:8aa7 with SMTP id a11-20020a056a001d0b00b0057424cc8aa7mr53830027pfx.45.1670074464622; Sat, 03 Dec 2022 05:34:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670074464; cv=none; d=google.com; s=arc-20160816; b=XPgPVMIY/oqWoardh5emDKSl4+v3HATri6uGb9X+oOCSfGhZRV6zy9+M9axPczpSbL FYaAHOffsAdKyqgRzuHlBb97QOlINtF6b62AzlhNUiyyU1KhjQOpTt2GH5zYjcJk9sRq MJH+1KPdI2bDFYAViyi3+p/+Nw4M/uUjWWI1T+4n2kRdtD2GFyx7rUTS/PY+Ukl3P/fx WQRPIxOCFB9u/2CV+2SgiXHf0sFURVRf4F0Qt7C2hjapysf3M/OI3ROymyJfoK6Pz/qN EnxexUa1wIJLcNU0cUiQNkm5/7rxRSMcWUR98d7qCtovz3/zFv/DBihAdn+8ckEjW21V K6ZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:sender:dkim-signature; bh=Ge/hvb27wH9tqZKTvQJ35IDsoTdlfsfW2RzAv9+gF3w=; b=j8RpffZD41THhthhtMlC/uCqWZ+fHOmQT3Ach1cP4Qj/Ps3DWFT77wKNx7oTUOcMyc YiSMrk4JGp04m1htnfrRRidjeiIq36Ch5K0G1roWXZ/5FMz+/Ra+gu7RrZS1OMC3GxHV y/gJH4e8t6mYraNioDY1khMyXO/u51BEQnGg4pPA+FKJPpRcIfW4ydi0PqewASVAAYFO qmYMh2x9HSzsfvK6qAFYt1ZLnYTCsd3qtifhDyW3b5vjRib353bj++pyD5cCiloekjuA wV73XvJMqcglaQYBCINVbDU8Kt4jvUDuMUZ/koLSTxvDJxNcH83NaefAJ6gsEHlxQfrg vIKw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="k1d/Uab7"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id oe1-20020a17090b394100b0021918bc9a47si9407441pjb.174.2022.12.03.05.34.10; Sat, 03 Dec 2022 05:34:24 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="k1d/Uab7"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229747AbiLCNcV (ORCPT <rfc822;lhua1029@gmail.com> + 99 others); Sat, 3 Dec 2022 08:32:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229555AbiLCNcT (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Sat, 3 Dec 2022 08:32:19 -0500 Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4D5081CB31; Sat, 3 Dec 2022 05:32:18 -0800 (PST) Received: by mail-pl1-x633.google.com with SMTP id a9so7037433pld.7; Sat, 03 Dec 2022 05:32:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:from:to:cc:subject:date:message-id:reply-to; bh=Ge/hvb27wH9tqZKTvQJ35IDsoTdlfsfW2RzAv9+gF3w=; b=k1d/Uab7IlDLX6e5E27qe0CBQhCi8ZjEvPIIa1x/Usq+VKJF6+mnGK0TX8YOHsljsh qjh7BmIzwix8tJ2FT4KpULD2oM7vwMdmRyNK30rZo1j97USnIcNAw621wo580gQswMSQ YwkcC+3xRtYXlyf66EfqIwkimsRZMJXDjP5AEBz8mrxJ/prAO2+NPiD3goVnjiK2i44/ 1gajD9iTICYw+9dBUFlOyiPXoEcrhKBAIMJcI5b9ggoYM2Xmr4WzkDcV5zHeG/2BEwME 5Y8GHBAZLGfXs11By/wtaHn6aTynVdko9MTpNo+7jtEpw717d63USI6tR9gmIpTu/07u 4Ozg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Ge/hvb27wH9tqZKTvQJ35IDsoTdlfsfW2RzAv9+gF3w=; b=ZbHMGi4454YtL26hGmcT+iFZcPE1X65iVF4JLK4hBA8eCFZ7CvRx4oDl6S85tgvx2t dLCw1+PnDGrw/R2wSDOohEfOpwWkghLzwMO/d5H8hRfiiZcqLvVKbFKwrN2a9hCL1JiU XP8jDeZxrk1NiH3mL0esYzfK12y1zBgq1mP/wm9ccfe9E/w+Ns0avlRBqvoIquMObO+l WalPPvdZ16+Wy7S7brkfy0i5WaXP4+ieoU9p3BiXJwI3b1IXX2riK5kcb2zUEjAKOj7S 4joliveYhsZc6kv9KrFVozbym7PdPwoQf56Z7y0Eu7934OkjOyZOSH2svfNFtYFSBUXC B+aA== X-Gm-Message-State: ANoB5pnItWg99W5o36LZiYOxe9yKH08FV/qrx3smFFK/nrxh1JiOOW48 hkkimogVP+9bpyKG+mFuWqg= X-Received: by 2002:a17:902:7885:b0:189:1366:fba7 with SMTP id q5-20020a170902788500b001891366fba7mr58575707pll.45.1670074337649; Sat, 03 Dec 2022 05:32:17 -0800 (PST) Received: from localhost.localdomain (124x33x176x97.ap124.ftth.ucom.ne.jp. [124.33.176.97]) by smtp.gmail.com with ESMTPSA id q12-20020a170902dacc00b00185402cfedesm7414472plx.246.2022.12.03.05.32.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 03 Dec 2022 05:32:17 -0800 (PST) Sender: Vincent Mailhol <vincent.mailhol@gmail.com> From: Vincent Mailhol <mailhol.vincent@wanadoo.fr> To: Marc Kleine-Budde <mkl@pengutronix.de>, linux-can@vger.kernel.org Cc: Wolfgang Grandegger <wg@grandegger.com>, "David S . Miller" <davem@davemloft.net>, Eric Dumazet <edumazet@google.com>, Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>, Frank Jungclaus <frank.jungclaus@esd.eu>, socketcan@esd.eu, Yasushi SHOJI <yashi@spacecubics.com>, =?utf-8?q?Stefan_M=C3=A4tje?= <stefan.maetje@esd.eu>, Hangyu Hua <hbh25y@gmail.com>, Oliver Hartkopp <socketcan@hartkopp.net>, Peter Fink <pfink@christ-es.de>, Jeroen Hofstee <jhofstee@victronenergy.com>, =?utf-8?q?Christoph_M=C3=B6hring?= <cmoehring@christ-es.de>, John Whittington <git@jbrengineering.co.uk>, Vasanth Sadhasivan <vasanth.sadhasivan@samsara.com>, Jimmy Assarsson <extja@kvaser.com>, Anssi Hannula <anssi.hannula@bitwise.fi>, Pavel Skripkin <paskripkin@gmail.com>, Stephane Grosjean <s.grosjean@peak-system.com>, Wolfram Sang <wsa+renesas@sang-engineering.com>, "Gustavo A . R . Silva" <gustavoars@kernel.org>, Julia Lawall <Julia.Lawall@inria.fr>, Dongliang Mu <dzm91@hust.edu.cn>, Sebastian Haas <haas@ems-wuensche.com>, Maximilian Schneider <max@schneidersoft.net>, Daniel Berglund <db@kvaser.com>, Olivier Sobrie <olivier@sobrie.be>, =?utf-8?b?UmVtaWdpdXN6IEtvxYLFgsSFdGFq?= <remigiusz.kollataj@mobica.com>, Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>, Martin Elshuber <martin.elshuber@theobroma-systems.com>, Philipp Tomsich <philipp.tomsich@theobroma-systems.com>, Bernd Krumboeck <b.krumboeck@gmail.com>, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Alan Stern <stern@rowland.harvard.edu>, linux-usb@vger.kernel.org, Vincent Mailhol <mailhol.vincent@wanadoo.fr> Subject: [PATCH 0/8] can: usb: remove all usb_set_intfdata(intf, NULL) in drivers' disconnect() Date: Sat, 3 Dec 2022 22:31:51 +0900 Message-Id: <20221203133159.94414-1-mailhol.vincent@wanadoo.fr> X-Mailer: git-send-email 2.37.4 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751200001939860726?= X-GMAIL-MSGID: =?utf-8?q?1751200001939860726?= |
Series |
can: usb: remove all usb_set_intfdata(intf, NULL) in drivers' disconnect()
|
|
Message
Vincent Mailhol
Dec. 3, 2022, 1:31 p.m. UTC
The core sets the usb_interface to NULL in [1]. Also setting it to NULL in usb_driver::disconnects() is at best useless, at worse risky. Indeed, if a driver set the usb interface to NULL before all actions relying on the interface-data pointer complete, there is a risk of NULL pointer dereference. Typically, this is the case if there are outstanding urbs which have not yet completed when entering disconnect(). If all actions are already completed, doing usb_set_intfdata(intf, NULL) is useless because the core does it at [1]. The first seven patches fix all drivers which set their usb_interface to NULL while outstanding URB might still exists. There is one patch per driver in order to add the relevant "Fixes:" tag to each of them. The last patch removes in bulk the remaining benign calls to usb_set_intfdata(intf, NULL) in etas_es58x and peak_usb. N.B. some other usb drivers outside of the can tree also have the same issue, but this is out of scope of this. [1] function usb_unbind_interface() from drivers/usb/core/driver.c Link: https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/driver.c#L497 Vincent Mailhol (8): can: ems_usb: ems_usb_disconnect(): fix NULL pointer dereference can: esd_usb: esd_usb_disconnect(): fix NULL pointer dereference can: gs_usb: gs_usb_disconnect(): fix NULL pointer dereference can: kvaser_usb: kvaser_usb_disconnect(): fix NULL pointer dereference can: mcba_usb: mcba_usb_disconnect(): fix NULL pointer dereference can: ucan: ucan_disconnect(): fix NULL pointer dereference can: usb_8dev: usb_8dev_disconnect(): fix NULL pointer dereference can: etas_es58x and peak_usb: remove useless call to usb_set_intfdata() drivers/net/can/usb/ems_usb.c | 2 -- drivers/net/can/usb/esd_usb.c | 2 -- drivers/net/can/usb/etas_es58x/es58x_core.c | 1 - drivers/net/can/usb/gs_usb.c | 2 -- drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 2 -- drivers/net/can/usb/mcba_usb.c | 2 -- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 -- drivers/net/can/usb/ucan.c | 2 -- drivers/net/can/usb/usb_8dev.c | 2 -- 9 files changed, 17 deletions(-)
Comments
On 03.12.22 14:31, Vincent Mailhol wrote: > The core sets the usb_interface to NULL in [1]. Also setting it to > NULL in usb_driver::disconnects() is at best useless, at worse risky. Hi, I am afraid there is a major issue with your series of patches. The drivers you are removing this from often have a subsequent check for the data they got from usb_get_intfdata() being NULL. That pattern is taken from drivers like btusb or CDC-ACM, which claim secondary interfaces disconnect() will be called a second time for. In addition, a driver can use setting intfdata to NULL as a flag for disconnect() having proceeded to a point where certain things can no longer be safely done. You need to check for that in every driver you remove this code from and if you decide that it can safely be removed, which is likely, then please also remove checks like this: struct ems_usb *dev = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); if (dev) { unregister_netdev(dev->netdev); Either it can be called a second time, then you need to leave it as is, or the check for NULL is superfluous. But only removing setting the pointer to NULL never makes sense. Regards Oliver
On Mon. 5 Dec. 2022 at 17:39, Oliver Neukum <oneukum@suse.com> wrote: > On 03.12.22 14:31, Vincent Mailhol wrote: > > The core sets the usb_interface to NULL in [1]. Also setting it to > > NULL in usb_driver::disconnects() is at best useless, at worse risky. > > Hi, > > I am afraid there is a major issue with your series of patches. > The drivers you are removing this from often have a subsequent check > for the data they got from usb_get_intfdata() being NULL. ACK, but I do not see the connection. > That pattern is taken from drivers like btusb or CDC-ACM Where does CDC-ACM set *his* interface to NULL? Looking at: https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/class/cdc-acm.c#L1531 I can see that cdc-acm sets acm->control and acm->data to NULL in his disconnect(), but it doesn't set its own usb_interface to NULL. > which claim secondary interfaces disconnect() will be called a second time > for. Are you saying that the disconnect() of those CAN USB drivers is being called twice? I do not see this in the source code. The only caller of usb_driver::disconnect() I can see is: https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/driver.c#L458 > In addition, a driver can use setting intfdata to NULL as a flag > for disconnect() having proceeded to a point where certain things > can no longer be safely done. Any reference that a driver can do that? This pattern seems racy. By the way, I did check all the drivers: * ems_usb: intf is only used in ems_usb_probe() and ems_usb_disconnect() functions. * esd_usb: intf is only used in the esd_usb_probe(), esd_usb_probe_one_net() (which is part of probing), esd_usb_disconnect() and a couple of sysfs functions (which only use intf to get a pointer to struct esd_usb). * gs_usb: intf is used several time but only to retrive struct usb_device. This seems useless, I will sent this patch to remove it: https://lore.kernel.org/linux-can/20221208081142.16936-3-mailhol.vincent@wanadoo.fr/ Aside of that, intf is only used in gs_usb_probe(), gs_make_candev() (which is part of probing) and gs_usb_disconnect() functions. * kvaser_usb: intf is only used in kvaser_usb_probe() and kvaser_usb_disconnect() functions. * mcba_usb: intf is only used in mcba_usb_probe() and mcba_usb_disconnect() functions. * ucan: intf is only used in ucan_probe() and ucan_disconnect(). struct ucan_priv also has a pointer to intf but it is never used. I sent this patch to remove it: https://lore.kernel.org/linux-can/20221208081142.16936-2-mailhol.vincent@wanadoo.fr/ * usb_8dev: intf is only used in usb_8dev_probe() and usb_8dev_disconnect(). With no significant use of intf outside of the probe() and disconnect(), there is definitely no such "use intf as a flag" in any of these drivers. > You need to check for that in every driver > you remove this code from and if you decide that it can safely be removed, What makes you assume that I didn't check this in the first place? Or do you see something I missed? > which is likely, then please also remove checks like this: > > struct ems_usb *dev = usb_get_intfdata(intf); > > usb_set_intfdata(intf, NULL); > > if (dev) { > unregister_netdev(dev->netdev); How is the if (dev) check related? There is no correlation between setting intf to NULL and dev not being NULL. I think dev is never NULL, but I did not assess that dev could not be NULL. > Either it can be called a second time, then you need to leave it > as is, Really?! The first thing disconnect() does is calling usb_get_intfdata(intf) which dereferences intf without checking if it is NULL, c.f.: https://elixir.bootlin.com/linux/v6.0/source/include/linux/usb.h#L265 Then it sets intf to NULL. The second time you call disconnect(), the usb_get_intfdata(intf) would be a NULL pointer dereference. > or the check for NULL is superfluous. But only removing setting > the pointer to NULL never makes sense. Yours sincerely, Vincent Mailhol
On 08.12.22 10:00, Vincent MAILHOL wrote: > On Mon. 5 Dec. 2022 at 17:39, Oliver Neukum <oneukum@suse.com> wrote: >> On 03.12.22 14:31, Vincent Mailhol wrote: Good Morning! > ACK, but I do not see the connection. Well, useless checks are bad. In particular, we should always make it clear whether a pointer may or may not be NULL. That is, I have no problem with what you were trying to do with your patch set. It is a good idea and possibly slightly overdue. The problem is the method. > I can see that cdc-acm sets acm->control and acm->data to NULL in his > disconnect(), but it doesn't set its own usb_interface to NULL. You don't have to, but you can. I was explaining the two patterns for doing so. >> which claim secondary interfaces disconnect() will be called a second time >> for. > > Are you saying that the disconnect() of those CAN USB drivers is being > called twice? I do not see this in the source code. The only caller of > usb_driver::disconnect() I can see is: > > https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/driver.c#L458 If they use usb_claim_interface(), yes it is called twice. Once per interface. That is in the case of ACM once for the originally probed interface and a second time for the claimed interface. But not necessarily in that order, as you can be kicked off an interface via sysfs. Yet you need to cease operations as soon as you are disconnected from any interface. That is annoying because it means you cannot use a refcount. From that stems the widespread use of intfdata as a flag. >> In addition, a driver can use setting intfdata to NULL as a flag >> for disconnect() having proceeded to a point where certain things >> can no longer be safely done. > > Any reference that a driver can do that? This pattern seems racy. Technically that is exactly what drivers that use usb_claim_interface() do. You free everything at the first call and use intfdata as a flag to prevent a double free. The race is prevented by usbcore locking, which guarantees that probe() and disconnect() have mutual exclusion. If you use intfdata in sysfs, yes additional locking is needed. > What makes you assume that I didn't check this in the first place? Or > do you see something I missed? That you did not put it into the changelogs. That reads like the drivers are doing something obsolete or stupid. They do not. They copied something that is necessary only under some circumstances. And that you did not remove the checks. >> which is likely, then please also remove checks like this: >> >> struct ems_usb *dev = usb_get_intfdata(intf); >> >> usb_set_intfdata(intf, NULL); >> >> if (dev) { Here. If you have a driver that uses usb_claim_interface(). You need this check or you unregister an already unregistered netdev. The way this disconnect() method is coded is extremely defensive. Most drivers do not need this check. But it is never wrong in the strict sense. Hence doing a mass removal with a change log that does not say that this driver is using only a single interface hence the check can be dropped to reduce code size is not good. Regards Oliver
On Thu. 8 Dec. 2022 at 20:04, Oliver Neukum <oneukum@suse.com> wrote: > On 08.12.22 10:00, Vincent MAILHOL wrote: > > On Mon. 5 Dec. 2022 at 17:39, Oliver Neukum <oneukum@suse.com> wrote: > >> On 03.12.22 14:31, Vincent Mailhol wrote: > > Good Morning! Good night! (different time zone :)) > > ACK, but I do not see the connection. > Well, useless checks are bad. In particular, we should always > make it clear whether a pointer may or may not be NULL. > That is, I have no problem with what you were trying to do > with your patch set. It is a good idea and possibly slightly > overdue. The problem is the method. > > > I can see that cdc-acm sets acm->control and acm->data to NULL in his > > disconnect(), but it doesn't set its own usb_interface to NULL. > > You don't have to, but you can. I was explaining the two patterns for doing so. > > >> which claim secondary interfaces disconnect() will be called a second time > >> for. > > > > Are you saying that the disconnect() of those CAN USB drivers is being > > called twice? I do not see this in the source code. The only caller of > > usb_driver::disconnect() I can see is: > > > > https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/driver.c#L458 > > If they use usb_claim_interface(), yes it is called twice. Once per > interface. That is in the case of ACM once for the originally probed > interface and a second time for the claimed interface. > But not necessarily in that order, as you can be kicked off an interface > via sysfs. Yet you need to cease operations as soon as you are disconnected > from any interface. That is annoying because it means you cannot use a > refcount. From that stems the widespread use of intfdata as a flag. Thank you for the details! I better understand this part now. > >> In addition, a driver can use setting intfdata to NULL as a flag > >> for disconnect() having proceeded to a point where certain things > >> can no longer be safely done. > > > > Any reference that a driver can do that? This pattern seems racy. > > Technically that is exactly what drivers that use usb_claim_interface() > do. You free everything at the first call and use intfdata as a flag > to prevent a double free. > The race is prevented by usbcore locking, which guarantees that probe() > and disconnect() have mutual exclusion. > If you use intfdata in sysfs, yes additional locking is needed. ACK for the mutual exclusion. My question was about what you said in your previous message: | In addition, a driver can use setting intfdata to NULL as a flag | for *disconnect() having proceeded to a point* where certain things | can no longer be safely done. How do you check that disconnect() has proceeded *to a given point* using intf without being racy? You can check if it has already completed once but not check how far it has proceeded, right? > > What makes you assume that I didn't check this in the first place? Or > > do you see something I missed? > > That you did not put it into the changelogs. > That reads like the drivers are doing something obsolete or stupid. > They do not. They copied something that is necessary only under > some circumstances. > > And that you did not remove the checks. > > >> which is likely, then please also remove checks like this: > >> > >> struct ems_usb *dev = usb_get_intfdata(intf); > >> > >> usb_set_intfdata(intf, NULL); > >> > >> if (dev) { > > Here. If you have a driver that uses usb_claim_interface(). > You need this check or you unregister an already unregistered > netdev. Sorry, but with all my best intentions, I still do not get it. During the second iteration, inft is NULL and: /* equivalent to dev = intf->dev.data. Because intf is NULL, * this is a NULL pointer dereference */ struct ems_usb *dev = usb_get_intfdata(intf); /* OK, intf is already NULL */ usb_set_intfdata(intf, NULL); /* follows a NULL pointer dereference so this is undefined * behaviour */ if (dev) { How is this a valid check that you entered the function for the second time? If intf is the flag, you should check intf, not dev? Something like this: struct ems_usb *dev; if (!intf) return; dev = usb_get_intfdata(intf); /* ... */ I just can not see the connection between intf being NULL and the if (dev) check. All I see is some undefined behaviour, sorry. > The way this disconnect() method is coded is extremely defensive. > Most drivers do not need this check. But it is never > wrong in the strict sense. > > Hence doing a mass removal with a change log that does > not say that this driver is using only a single interface > hence the check can be dropped to reduce code size > is not good. > > Regards > Oliver
On Fri, Dec 09, 2022 at 12:44:51AM +0900, Vincent MAILHOL wrote: > On Thu. 8 Dec. 2022 at 20:04, Oliver Neukum <oneukum@suse.com> wrote: > > >> which is likely, then please also remove checks like this: > > >> > > >> struct ems_usb *dev = usb_get_intfdata(intf); > > >> > > >> usb_set_intfdata(intf, NULL); > > >> > > >> if (dev) { > > > > Here. If you have a driver that uses usb_claim_interface(). > > You need this check or you unregister an already unregistered > > netdev. > > Sorry, but with all my best intentions, I still do not get it. During > the second iteration, inft is NULL and: No, intf is never NULL. Rather, the driver-specific pointer stored in intfdata may be NULL. You seem to be confusing intf with intfdata(intf). > /* equivalent to dev = intf->dev.data. Because intf is NULL, > * this is a NULL pointer dereference */ > struct ems_usb *dev = usb_get_intfdata(intf); So here dev will be NULL when the second interface's disconnect routine runs, because the first time through the routine sets the intfdata to NULL for both interfaces: USB core calls ->disconnect(intf1) disconnect routine sets intfdata(intf1) and intfdata(intf2) both to NULL and handles the disconnection USB core calls ->disconnect(intf2) disconnect routine sees that intfdata(intf2) is already NULL, so it knows that it doesn't need to do anything more. As you can see in this scenario, neither intf1 nor intf2 is ever NULL. > /* OK, intf is already NULL */ > usb_set_intfdata(intf, NULL); > > /* follows a NULL pointer dereference so this is undefined > * behaviour */ > if (dev) { > > How is this a valid check that you entered the function for the second > time? If intf is the flag, you should check intf, not dev? Something > like this: intf is not a flag; it is the argument to the function and is never NULL. The flag is the intfdata. > struct ems_usb *dev; > > if (!intf) > return; > > dev = usb_get_intfdata(intf); > /* ... */ > > I just can not see the connection between intf being NULL and the if > (dev) check. All I see is some undefined behaviour, sorry. Once you get it straightened out in your head, you will understand. Alan Stern
On 08.12.22 16:44, Vincent MAILHOL wrote: > On Thu. 8 Dec. 2022 at 20:04, Oliver Neukum <oneukum@suse.com> wrote: >> On 08.12.22 10:00, Vincent MAILHOL wrote: >>> On Mon. 5 Dec. 2022 at 17:39, Oliver Neukum <oneukum@suse.com> wrote: >>>> On 03.12.22 14:31, Vincent Mailhol wrote: >> >> Good Morning! > > Good night! (different time zone :)) Good evening! > > How do you check that disconnect() has proceeded *to a given point* > using intf without being racy? You can check if it has already > completed once but not check how far it has proceeded, right? You'd use intfdata, which is a pointer stored in intf. But other than that the simplest way would be to use a mutex. Regards Oliver
Hi, Thanks Alan and Oliver for your patience, really appreciated. And sorry that it took me four messages to realize my mistake. I will send a v2 right now.