From bb558c55a5517db1cdf5270870cf4e1f9b912e70 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 16 Nov 2024 16:30:38 +0000 Subject: [PATCH] Revert "genetlink: hold RCU in genlmsg_mcast()" This reverts commit ae53d09f11e52fe75bd173ae2597e47bad8fda5b 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: I62229b26a4fd7dd4141a0342e3b7298ed3ee7942 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 a80be1bd6dec..15ffc8d2ac7b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2130,7 +2130,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 4750e141b78d..6fe3ab5af5c9 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -358,12 +358,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 e27e00cb16c6..a901fd14fe3b 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 ae77a26cb589..3e16527beb91 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1147,11 +1147,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; } @@ -1493,23 +1497,23 @@ problem: 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) @@ -1518,31 +1522,27 @@ 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 8b7d92cb6352..4dcbe6700f53 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17707,8 +17707,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; @@ -18335,8 +18337,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;