From 38dc270ca093908e056ebb9d1f60ce7b7a654b5e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 21 Nov 2024 23:32:02 +0000 Subject: [PATCH] Revert "genetlink: hold RCU in genlmsg_mcast()" This reverts commit 4af714e82379984974a1b61a5629cdb302673dda which is commit 56440d7ec28d60f8da3bfa09062b3368ff9b16db upstream. It breaks the Android kernel abi and can be brought back in the future in an abi-safe way if it is really needed. Bug: 161946584 Change-Id: I812d261d139e7f73a135c3445b7733b7611c23e0 Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_user.c | 2 +- include/net/genetlink.h | 3 ++- net/l2tp/l2tp_netlink.c | 4 ++-- net/netlink/genetlink.c | 28 ++++++++++++++-------------- net/wireless/nl80211.c | 8 ++++++-- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 2ac973291b1f..c283e45ac300 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1988,7 +1988,7 @@ static int tcmu_netlink_event_send(struct tcmu_dev *udev, } ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, - TCMU_MCGRP_CONFIG); + TCMU_MCGRP_CONFIG, GFP_KERNEL); /* Wait during an add as the listener may not be up yet */ if (ret == 0 || diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 140d0c35ce08..d66f0f397f2e 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -337,12 +337,13 @@ static inline int genlmsg_multicast(const struct genl_family *family, * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself * @group: offset of multicast group in groups array + * @flags: allocation flags * * This function must hold the RTNL or rcu_read_lock(). */ int genlmsg_multicast_allns(const struct genl_family *family, struct sk_buff *skb, u32 portid, - unsigned int group); + unsigned int group, gfp_t flags); /** * genlmsg_unicast - unicast a netlink message diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index f34ca225c219..96eb91be9238 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -115,7 +115,7 @@ static int l2tp_tunnel_notify(struct genl_family *family, NLM_F_ACK, tunnel, cmd); if (ret >= 0) { - ret = genlmsg_multicast_allns(family, msg, 0, 0); + ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); /* We don't care if no one is listening */ if (ret == -ESRCH) ret = 0; @@ -143,7 +143,7 @@ static int l2tp_session_notify(struct genl_family *family, NLM_F_ACK, session, cmd); if (ret >= 0) { - ret = genlmsg_multicast_allns(family, msg, 0, 0); + ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); /* We don't care if no one is listening */ if (ret == -ESRCH) ret = 0; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index fcfbb22a1e34..9fd7ba01b9f8 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1097,11 +1097,15 @@ static int genl_ctrl_event(int event, const struct genl_family *family, if (IS_ERR(msg)) return PTR_ERR(msg); - if (!family->netnsok) + if (!family->netnsok) { genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0, 0, GFP_KERNEL); - else - genlmsg_multicast_allns(&genl_ctrl, msg, 0, 0); + } else { + rcu_read_lock(); + genlmsg_multicast_allns(&genl_ctrl, msg, 0, + 0, GFP_ATOMIC); + rcu_read_unlock(); + } return 0; } @@ -1410,23 +1414,23 @@ static int __init genl_init(void) core_initcall(genl_init); -static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group) +static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, + gfp_t flags) { struct sk_buff *tmp; struct net *net, *prev = NULL; bool delivered = false; int err; - rcu_read_lock(); for_each_net_rcu(net) { if (prev) { - tmp = skb_clone(skb, GFP_ATOMIC); + tmp = skb_clone(skb, flags); if (!tmp) { err = -ENOMEM; goto error; } err = nlmsg_multicast(prev->genl_sock, tmp, - portid, group, GFP_ATOMIC); + portid, group, flags); if (!err) delivered = true; else if (err != -ESRCH) @@ -1435,30 +1439,26 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group) prev = net; } - err = nlmsg_multicast(prev->genl_sock, skb, portid, group, GFP_ATOMIC); - - rcu_read_unlock(); + err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags); if (!err) delivered = true; else if (err != -ESRCH) return err; return delivered ? 0 : -ESRCH; error: - rcu_read_unlock(); - kfree_skb(skb); return err; } int genlmsg_multicast_allns(const struct genl_family *family, struct sk_buff *skb, u32 portid, - unsigned int group) + unsigned int group, gfp_t flags) { if (WARN_ON_ONCE(group >= family->n_mcgrps)) return -EINVAL; group = family->mcgrp_offset + group; - return genlmsg_mcast(skb, portid, group); + return genlmsg_mcast(skb, portid, group, flags); } EXPORT_SYMBOL(genlmsg_multicast_allns); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 71e63cfef4ff..979b1f690bdb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15883,8 +15883,10 @@ void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, genlmsg_end(msg, hdr); + rcu_read_lock(); genlmsg_multicast_allns(&nl80211_fam, msg, 0, - NL80211_MCGRP_REGULATORY); + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); + rcu_read_unlock(); return; @@ -16392,8 +16394,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, genlmsg_end(msg, hdr); + rcu_read_lock(); genlmsg_multicast_allns(&nl80211_fam, msg, 0, - NL80211_MCGRP_REGULATORY); + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); + rcu_read_unlock(); return;