diff mbox series

[03/11] net: devres: relax devm_register_netdev()

Message ID 20200622100056.10151-4-brgl@bgdev.pl
State Changes Requested
Delegated to: David Miller
Headers show
Series net: improve devres helpers | expand

Commit Message

Bartosz Golaszewski June 22, 2020, 10 a.m. UTC
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This devres helper registers a release callback that only unregisters
the net_device. It works perfectly fine with netdev structs that are
not managed on their own. There's no reason to check this - drop the
warning.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 net/devres.c | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

Comments

Jakub Kicinski June 22, 2020, 10:49 p.m. UTC | #1
On Mon, 22 Jun 2020 12:00:48 +0200 Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> This devres helper registers a release callback that only unregisters
> the net_device. It works perfectly fine with netdev structs that are
> not managed on their own. There's no reason to check this - drop the
> warning.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

I think the reasoning for this suggestion was to catch possible UAF
errors. The netdev doesn't necessarily has to be from devm_alloc_* 
but it has to be part of devm-ed memory or memory which is freed 
after driver's remove callback.

Are there cases in practice where you've seen the netdev not being
devm allocated?
Bartosz Golaszewski June 23, 2020, 9:12 a.m. UTC | #2
wt., 23 cze 2020 o 00:49 Jakub Kicinski <kuba@kernel.org> napisał(a):
>
> On Mon, 22 Jun 2020 12:00:48 +0200 Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This devres helper registers a release callback that only unregisters
> > the net_device. It works perfectly fine with netdev structs that are
> > not managed on their own. There's no reason to check this - drop the
> > warning.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> I think the reasoning for this suggestion was to catch possible UAF
> errors. The netdev doesn't necessarily has to be from devm_alloc_*
> but it has to be part of devm-ed memory or memory which is freed
> after driver's remove callback.
>

Yes I understand that UAF was the concern here, but this limitation is
unnecessary. In its current form devm_register_netdev() only works for
struct net_device allocated with devm_alloc_etherdev(). Meanwhile
calling alloc_netdev() (which doesn't have its devm counterpart yet -
I may look into it shortly), then registering a devm action with
devm_add_action_or_reset() which would free this memory is a perfectly
fine use case. This patch would make it possible.

> Are there cases in practice where you've seen the netdev not being
> devm allocated?

As I said above - alloc_netdev() used by wireless, can, usb etc.
drivers doesn't have a devres variant.

Bartosz
Jakub Kicinski June 23, 2020, 8:16 p.m. UTC | #3
On Tue, 23 Jun 2020 11:12:24 +0200 Bartosz Golaszewski wrote:
> wt., 23 cze 2020 o 00:49 Jakub Kicinski <kuba@kernel.org> napisał(a):
> > On Mon, 22 Jun 2020 12:00:48 +0200 Bartosz Golaszewski wrote:  
> > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > >
> > > This devres helper registers a release callback that only unregisters
> > > the net_device. It works perfectly fine with netdev structs that are
> > > not managed on their own. There's no reason to check this - drop the
> > > warning.
> > >
> > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>  
> >
> > I think the reasoning for this suggestion was to catch possible UAF
> > errors. The netdev doesn't necessarily has to be from devm_alloc_*
> > but it has to be part of devm-ed memory or memory which is freed
> > after driver's remove callback.
> >  
> 
> Yes I understand that UAF was the concern here, but this limitation is
> unnecessary. In its current form devm_register_netdev() only works for
> struct net_device allocated with devm_alloc_etherdev(). Meanwhile
> calling alloc_netdev() (which doesn't have its devm counterpart yet -
> I may look into it shortly),

If resource managed alloc_netdev() is needed devm_alloc_netdev() can
be created, and even reuse devm_free_netdev() so no changes to the
warning are even necessary for such extension.

> then registering a devm action with devm_add_action_or_reset() which
> would free this memory is a perfectly fine use case. This patch would
> make it possible.

alloc_netdev() + devm_add_action makes no sense in the upstream kernel,
just add the appropriate helper, we care little about out of tree code.

> > Are there cases in practice where you've seen the netdev not being
> > devm allocated?  
> 
> As I said above - alloc_netdev() used by wireless, can, usb etc.
> drivers doesn't have a devres variant.
diff mbox series

Patch

diff --git a/net/devres.c b/net/devres.c
index 57a6a88d11f6..1583ccb207c0 100644
--- a/net/devres.c
+++ b/net/devres.c
@@ -46,14 +46,6 @@  static void devm_netdev_release(struct device *dev, void *this)
 	unregister_netdev(res->ndev);
 }
 
-static int netdev_devres_match(struct device *dev, void *this, void *match_data)
-{
-	struct net_device_devres *res = this;
-	struct net_device *ndev = match_data;
-
-	return ndev == res->ndev;
-}
-
 /**
  *	devm_register_netdev - resource managed variant of register_netdev()
  *	@dev: managing device for this netdev - usually the parent device
@@ -61,22 +53,13 @@  static int netdev_devres_match(struct device *dev, void *this, void *match_data)
  *
  *	This is a devres variant of register_netdev() for which the unregister
  *	function will be call automatically when the managing device is
- *	detached. Note: the net_device used must also be resource managed by
- *	the same struct device.
+ *	detached.
  */
 int devm_register_netdev(struct device *dev, struct net_device *ndev)
 {
 	struct net_device_devres *dr;
 	int ret;
 
-	/* struct net_device must itself be managed. For now a managed netdev
-	 * can only be allocated by devm_alloc_etherdev_mqs() so the check is
-	 * straightforward.
-	 */
-	if (WARN_ON(!devres_find(dev, devm_free_netdev,
-				 netdev_devres_match, ndev)))
-		return -EINVAL;
-
 	dr = devres_alloc(devm_netdev_release, sizeof(*dr), GFP_KERNEL);
 	if (!dr)
 		return -ENOMEM;