diff mbox series

[net,1/4] ieee802154: Restore initial state on failed device_rename() in cfg802154_switch_netns()

Message ID 20250325141723.499850-2-i.abramov@mt-integration.ru (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Avoid using WARN_ON() on allocation failure in device_rename() | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 7 this patch: 7
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers fail 3 blamed authors not CCed: stefan@datenfreihafen.org alex.aring@gmail.com marcel@holtmann.org; 8 maintainers not CCed: edumazet@google.com pabeni@redhat.com alex.aring@gmail.com miquel.raynal@bootlin.com linux-wpan@vger.kernel.org horms@kernel.org stefan@datenfreihafen.org marcel@holtmann.org
netdev/build_clang fail Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn fail Errors and warnings before: 7 this patch: 7
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 55 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Ivan Abramov March 25, 2025, 2:17 p.m. UTC
Currently, the return value of device_rename() is not checked or acted
upon. There is also a pointless WARN_ON() call in case of an allocation
failure, since it only leads to useless splats caused by deliberate fault
injections.

Since it's possible to roll back the changes made before the
device_rename() call in case of failure, do it.

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 66e5c2672cd1 ("ieee802154: add netns support")
Signed-off-by: Ivan Abramov <i.abramov@mt-integration.ru>
---
 net/ieee802154/core.c | 44 +++++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 20 deletions(-)

Comments

Kuniyuki Iwashima March 25, 2025, 10 p.m. UTC | #1
From: Ivan Abramov <i.abramov@mt-integration.ru>
Date: Tue, 25 Mar 2025 17:17:20 +0300
> Currently, the return value of device_rename() is not checked or acted
> upon. There is also a pointless WARN_ON() call in case of an allocation
> failure, since it only leads to useless splats caused by deliberate fault
> injections.
> 
> Since it's possible to roll back the changes made before the
> device_rename() call in case of failure, do it.
> 
> Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
> 
> Fixes: 66e5c2672cd1 ("ieee802154: add netns support")
> Signed-off-by: Ivan Abramov <i.abramov@mt-integration.ru>
> ---
>  net/ieee802154/core.c | 44 +++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> 
> diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> index 88adb04e4072..f9865eb2c7cf 100644
> --- a/net/ieee802154/core.c
> +++ b/net/ieee802154/core.c
> @@ -233,31 +233,35 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
>  		wpan_dev->netdev->netns_local = true;
>  	}
>  
> -	if (err) {
> -		/* failed -- clean up to old netns */
> -		net = wpan_phy_net(&rdev->wpan_phy);
> -
> -		list_for_each_entry_continue_reverse(wpan_dev,
> -						     &rdev->wpan_dev_list,
> -						     list) {
> -			if (!wpan_dev->netdev)
> -				continue;
> -			wpan_dev->netdev->netns_local = false;
> -			err = dev_change_net_namespace(wpan_dev->netdev, net,
> -						       "wpan%d");
> -			WARN_ON(err);
> -			wpan_dev->netdev->netns_local = true;
> -		}
> +	if (err)
> +		goto errout;
>  
> -		return err;
> -	}
> +	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
>  
> -	wpan_phy_net_set(&rdev->wpan_phy, net);
> +	if (err)
> +		goto errout;
>  
> -	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
> -	WARN_ON(err);
> +	wpan_phy_net_set(&rdev->wpan_phy, net);
>  
>  	return 0;
> +
> +errout:
> +	/* failed -- clean up to old netns */
> +	net = wpan_phy_net(&rdev->wpan_phy);
> +
> +	list_for_each_entry_continue_reverse(wpan_dev,
> +					     &rdev->wpan_dev_list,
> +					     list) {
> +		if (!wpan_dev->netdev)
> +			continue;
> +		wpan_dev->netdev->netns_local = false;
> +		err = dev_change_net_namespace(wpan_dev->netdev, net,
> +					       "wpan%d");
> +		WARN_ON(err);

It's still possible to trigger this with -ENOMEM.

For example, see bitmap_zalloc() in __dev_alloc_name().

Perhaps simply use pr_warn() or net_warn_ratelimited() as do_setlink().

I guess the stack trace from here is not so interesting as it doens't
show where it actually failed.


> +		wpan_dev->netdev->netns_local = true;
> +	}
> +
> +	return err;
>  }
>  
>  void cfg802154_dev_free(struct cfg802154_registered_device *rdev)
> -- 
> 2.39.5
diff mbox series

Patch

diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 88adb04e4072..f9865eb2c7cf 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -233,31 +233,35 @@  int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
 		wpan_dev->netdev->netns_local = true;
 	}
 
-	if (err) {
-		/* failed -- clean up to old netns */
-		net = wpan_phy_net(&rdev->wpan_phy);
-
-		list_for_each_entry_continue_reverse(wpan_dev,
-						     &rdev->wpan_dev_list,
-						     list) {
-			if (!wpan_dev->netdev)
-				continue;
-			wpan_dev->netdev->netns_local = false;
-			err = dev_change_net_namespace(wpan_dev->netdev, net,
-						       "wpan%d");
-			WARN_ON(err);
-			wpan_dev->netdev->netns_local = true;
-		}
+	if (err)
+		goto errout;
 
-		return err;
-	}
+	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
 
-	wpan_phy_net_set(&rdev->wpan_phy, net);
+	if (err)
+		goto errout;
 
-	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
-	WARN_ON(err);
+	wpan_phy_net_set(&rdev->wpan_phy, net);
 
 	return 0;
+
+errout:
+	/* failed -- clean up to old netns */
+	net = wpan_phy_net(&rdev->wpan_phy);
+
+	list_for_each_entry_continue_reverse(wpan_dev,
+					     &rdev->wpan_dev_list,
+					     list) {
+		if (!wpan_dev->netdev)
+			continue;
+		wpan_dev->netdev->netns_local = false;
+		err = dev_change_net_namespace(wpan_dev->netdev, net,
+					       "wpan%d");
+		WARN_ON(err);
+		wpan_dev->netdev->netns_local = true;
+	}
+
+	return err;
 }
 
 void cfg802154_dev_free(struct cfg802154_registered_device *rdev)