Patch "nl80211: fix dumpit error path RTNL deadlocks" has been added to the 4.10-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
nl80211: fix dumpit error path RTNL deadlocks
to the 4.10-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch
and it can be found in the queue-4.10 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
ea90e0dc8cecba6359b481e24d9c37160f6f524fMon Sep 17 00:00:00 2001
From: Johannes Berg <[email protected]>
Date: Wed, 15 Mar 2017 14:26:04 +0100
Subject: nl80211: fix dumpit error path RTNL deadlocks
From: Johannes Berg <[email protected]>
commit ea90e0dc8cecba6359b481e24d9c37160f6f524f upstream.
Sowmini pointed out Dmitry's RTNL deadlock report to me, and it turns out to be perfectly accurate - there are various error paths that miss unlock of the RTNL.
To fix those, change the locking a bit to not be conditional in all those nl80211_prepare_*_dump() functions, but make those require the RTNL to start with, and fix the buggy error paths. This also let me use sparse (by appropriately overriding the rtnl_lock/rtnl_unlock functions) to validate the changes.
--- net/wireless/nl80211.c | 127 +++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 71 deletions(-)
net/wireless/nl80211.c +56 -71
@@ -540,22 +540,18 @@ static int nl80211_prepare_wdev_dump(str {int err; -rtnl_lock (); -if (!cb->args[0 ]) { err =nlmsg_parse (cb->nlh,GENL_HDRLEN + nl80211_fam.hdrsize,genl_family_attrbuf (&nl80211_fam), nl80211_fam.maxattr, nl80211_policy);if (err) - goto out_unlock; +return err; *wdev =__cfg80211_wdev_from_attrs (sock_net (skb->sk),genl_family_attrbuf (&nl80211_fam)); -if (IS_ERR (*wdev)) { - err =PTR_ERR (*wdev); - goto out_unlock; - } +if (IS_ERR (*wdev)) +return PTR_ERR (*wdev); *rdev =wiphy_to_rdev ((*wdev)->wiphy);/* 0 is the first index - add 1 to parse only once */ cb->args[0 ] = (*rdev)->wiphy_idx +1 ;
@@ -565,10 +561,8 @@ static int nl80211_prepare_wdev_dump(strstruct wiphy *wiphy =wiphy_idx_to_wiphy (cb->args[0 ] -1 );struct wireless_dev *tmp; -if (!wiphy) { - err = -ENODEV ; - goto out_unlock; - } +if (!wiphy) +return -ENODEV ; *rdev =wiphy_to_rdev (wiphy); *wdev =NULL ;
@@ -579,21 +573,11 @@ static int nl80211_prepare_wdev_dump(str } } -if (!*wdev) { - err = -ENODEV ; - goto out_unlock; - } +if (!*wdev) +return -ENODEV ; }return 0 ; - out_unlock: -rtnl_unlock (); -return err; -} - -static void nl80211_finish_wdev_dump (struct cfg80211_registered_device *rdev) -{ -rtnl_unlock (); }/* IE validation */
@@ -2599,17 +2583,17 @@ static int nl80211_dump_interface(structint filter_wiphy =-1 ;struct cfg80211_registered_device *rdev;struct wireless_dev *wdev; +int ret;rtnl_lock ();if (!cb->args[2 ]) {struct nl80211_dump_wiphy_state state = { .filter_wiphy =-1 , }; -int ret; ret =nl80211_dump_wiphy_parse (skb, cb, &state);if (ret) -return ret; + goto out_unlock; filter_wiphy = state.filter_wiphy;
@@ -2654,12 +2638,14 @@ static int nl80211_dump_interface(struct wp_idx++; } out: -rtnl_unlock (); - cb->args[0 ] = wp_idx; cb->args[1 ] = if_idx; -return skb->len; + ret = skb->len; + out_unlock: +rtnl_unlock (); + +return ret; }static int nl80211_get_interface (struct sk_buff *skb,struct genl_info *info)
@@ -4398,9 +4384,10 @@ static int nl80211_dump_station(struct sint sta_idx = cb->args[2 ];int err; +rtnl_lock (); err =nl80211_prepare_wdev_dump (skb, cb, &rdev, &wdev);if (err) -return err; + goto out_err;if (!wdev->netdev) { err = -EINVAL ;
@@ -4435,7 +4422,7 @@ static int nl80211_dump_station(struct s cb->args[2 ] = sta_idx; err = skb->len; out_err: -nl80211_finish_wdev_dump (rdev); +rtnl_unlock ();return err; }
@@ -5221,9 +5208,10 @@ static int nl80211_dump_mpath(struct sk_int path_idx = cb->args[2 ];int err; +rtnl_lock (); err =nl80211_prepare_wdev_dump (skb, cb, &rdev, &wdev);if (err) -return err; + goto out_err;if (!rdev->ops->dump_mpath) { err = -EOPNOTSUPP ;
@@ -5256,7 +5244,7 @@ static int nl80211_dump_mpath(struct sk_ cb->args[2 ] = path_idx; err = skb->len; out_err: -nl80211_finish_wdev_dump (rdev); +rtnl_unlock ();return err; }
@@ -5416,9 +5404,10 @@ static int nl80211_dump_mpp(struct sk_buint path_idx = cb->args[2 ];int err; +rtnl_lock (); err =nl80211_prepare_wdev_dump (skb, cb, &rdev, &wdev);if (err) -return err; + goto out_err;if (!rdev->ops->dump_mpp) { err = -EOPNOTSUPP ;
@@ -5451,7 +5440,7 @@ static int nl80211_dump_mpp(struct sk_bu cb->args[2 ] = path_idx; err = skb->len; out_err: -nl80211_finish_wdev_dump (rdev); +rtnl_unlock ();return err; }
@@ -7596,9 +7585,12 @@ static int nl80211_dump_scan(struct sk_bint start = cb->args[2 ], idx =0 ;int err; +rtnl_lock (); err =nl80211_prepare_wdev_dump (skb, cb, &rdev, &wdev); -if (err) +if (err) { +rtnl_unlock ();return err; + }wdev_lock (wdev);spin_lock_bh (&rdev->bss_lock);
@@ -7621,7 +7613,7 @@ static int nl80211_dump_scan(struct sk_bwdev_unlock (wdev); cb->args[2 ] = idx; -nl80211_finish_wdev_dump (rdev); +rtnl_unlock ();return skb->len; }
@@ -7706,9 +7698,10 @@ static int nl80211_dump_survey(struct skint res;bool radio_stats; +rtnl_lock (); res =nl80211_prepare_wdev_dump (skb, cb, &rdev, &wdev);if (res) -return res; + goto out_err;/* prepare_wdev_dump parsed the attributes */ radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS ];
@@ -7749,7 +7742,7 @@ static int nl80211_dump_survey(struct sk cb->args[2 ] = survey_idx; res = skb->len; out_err: -nl80211_finish_wdev_dump (rdev); +rtnl_unlock ();return res; }
@@ -11378,17 +11371,13 @@ static int nl80211_prepare_vendor_dump(svoid *data =NULL ;unsigned int data_len =0 ; -rtnl_lock (); -if (cb->args[0 ]) {/* subtract the 1 again here */ struct wiphy *wiphy =wiphy_idx_to_wiphy (cb->args[0 ] -1 );struct wireless_dev *tmp; -if (!wiphy) { - err = -ENODEV ; - goto out_unlock; - } +if (!wiphy) +return -ENODEV ; *rdev =wiphy_to_rdev (wiphy); *wdev =NULL ;
@@ -11408,23 +11397,19 @@ static int nl80211_prepare_vendor_dump(s err =nlmsg_parse (cb->nlh,GENL_HDRLEN + nl80211_fam.hdrsize, attrbuf, nl80211_fam.maxattr, nl80211_policy);if (err) - goto out_unlock; +return err;if (!attrbuf[NL80211_ATTR_VENDOR_ID ] || - !attrbuf[NL80211_ATTR_VENDOR_SUBCMD ]) { - err = -EINVAL ; - goto out_unlock; - } + !attrbuf[NL80211_ATTR_VENDOR_SUBCMD ]) +return -EINVAL ; *wdev =__cfg80211_wdev_from_attrs (sock_net (skb->sk), attrbuf);if (IS_ERR (*wdev)) *wdev =NULL ; *rdev =__cfg80211_rdev_from_attrs (sock_net (skb->sk), attrbuf); -if (IS_ERR (*rdev)) { - err =PTR_ERR (*rdev); - goto out_unlock; - } +if (IS_ERR (*rdev)) +return PTR_ERR (*rdev); vid =nla_get_u32 (attrbuf[NL80211_ATTR_VENDOR_ID ]); subcmd =nla_get_u32 (attrbuf[NL80211_ATTR_VENDOR_SUBCMD ]);
@@ -11437,19 +11422,15 @@ static int nl80211_prepare_vendor_dump(sif (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)continue ; -if (!vcmd->dumpit) { - err = -EOPNOTSUPP ; - goto out_unlock; - } +if (!vcmd->dumpit) +return -EOPNOTSUPP ; vcmd_idx = i;break ; } -if (vcmd_idx <0 ) { - err = -EOPNOTSUPP ; - goto out_unlock; - } +if (vcmd_idx <0 ) +return -EOPNOTSUPP ;if (attrbuf[NL80211_ATTR_VENDOR_DATA ]) { data =nla_data (attrbuf[NL80211_ATTR_VENDOR_DATA ]);
@@ -11466,9 +11447,6 @@ static int nl80211_prepare_vendor_dump(s/* keep rtnl locked in successful case */ return 0 ; - out_unlock: -rtnl_unlock (); -return err; } static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
@@ -11483,9 +11461,10 @@ static int nl80211_vendor_cmd_dump(strucint err;struct nlattr *vendor_data; +rtnl_lock (); err =nl80211_prepare_vendor_dump (skb, cb, &rdev, &wdev);if (err) -return err; + goto out; vcmd_idx = cb->args[2 ]; data = (void *)cb->args[3 ];
@@ -11494,15 +11473,21 @@ static int nl80211_vendor_cmd_dump(strucif (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |WIPHY_VENDOR_CMD_NEED_NETDEV )) { -if (!wdev) -return -EINVAL ; +if (!wdev) { + err = -EINVAL ; + goto out; + }if (vcmd->flags &WIPHY_VENDOR_CMD_NEED_NETDEV && - !wdev->netdev) -return -EINVAL ; + !wdev->netdev) { + err = -EINVAL ; + goto out; + }if (vcmd->flags &WIPHY_VENDOR_CMD_NEED_RUNNING ) { -if (!wdev_running (wdev)) -return -ENETDOWN ; +if (!wdev_running (wdev)) { + err = -ENETDOWN ; + goto out; + } } }
Patches currently in stable-queue which might be from [email protected] are
queue-4.10/nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch