Skip to contentSkip to conversation

7.2.9-rc1 review

PATCH In review Greg Kroah-Hartman 12 participants 469 messages Sep 30 – Oct 2 Page 2 of 4

Subsystems (6)
lore
Share & tools
lore
author maintainer
#122 lore raw

PATCH 122/457 ovpn: always unhash old VPN addresses before rehashing

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit b43beccb3713fafada57814b0a652f4a876eb75f ]

ovpn_peer_hash_vpn_ip updates the per-peer VPN address hash entries after userspace changes a peer VPN address. The current code removes an old hash entry only when the new address for that family is not the unspecified address.

When an address is cleared to 0.0.0.0 or ::, its hash node therefore remains linked in the bucket selected by the old address. The address comparison performed during lookup prevents the old address from matching, but the table retains a stale entry until the peer is removed or another address is configured for that family.

Always remove both old VPN address hash entries before conditionally adding the currently configured addresses back. This ensures that a cleared address leaves its hash node unhashed.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/peer.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/net/ovpn/peer.c +4 -6
index 430c6cd48db87..bbd9e17fb0bfa 100644
@@ -994,10 +994,11 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
 	if (hlist_unhashed(&peer->hash_entry_id))
 		return;
 
-	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
-		/* remove potential old hashing */
-		hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+	/* remove potential old hashing */
+	hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+	hlist_nulls_del_init_rcu(&peer->hash_entry_addr6);
 
+	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
 		nhead = ovpn_get_hash_head(peer->ovpn->peers->by_vpn_addr4,
 					   &peer->vpn_addrs.ipv4,
 					   sizeof(peer->vpn_addrs.ipv4));
@@ -1005,9 +1006,6 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
 	}
 
 	if (!ipv6_addr_any(&peer->vpn_addrs.ipv6)) {
-		/* remove potential old hashing */
-		hlist_nulls_del_init_rcu(&peer->hash_entry_addr6);
-
 		nhead = ovpn_get_hash_head(peer->ovpn->peers->by_vpn_addr6,
 					   &peer->vpn_addrs.ipv6,
 					   sizeof(peer->vpn_addrs.ipv6));
Signature · 1 line
2.53.0
author maintainer
#123 lore raw

PATCH 123/457 ovpn: reject duplicate peer VPN addresses

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit d25e885b31a0f2808d936f95c9a558a8a792669b ]

In MP mode, ovpn uses the peer VPN addresses as lookup keys for selecting the peer that should receive an outgoing tunnel packet. However, the netlink peer configuration path does not currently reject duplicate VPN addresses.

If two peers are configured with the same VPN address, both can be inserted in the VPN address hash table and lookups return whichever peer is found first. This makes peer selection ambiguous and dependent on hash insertion order.

Reject peer creation or update when the resulting VPN address is already assigned to another peer. Ignore unspecified addresses because those are not inserted in the VPN address hash tables.

This changes such configurations from being accepted to being rejected, but they have never worked reliably because peer selection is ambiguous.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 37 ++++++++++++++++-----
 drivers/net/ovpn/peer.c    | 67 +++++++++++++++++++++++++++++++++++++-
 drivers/net/ovpn/peer.h    |  6 ++++
 3 files changed, 101 insertions(+), 9 deletions(-)
drivers/net/ovpn/netlink.c +29 -8
index 2ba762082acc1..e23f7d1f49e01 100644
@@ -480,8 +480,10 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 
 int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
 	struct ovpn_priv *ovpn = info->user_ptr[0];
+	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
+	struct in6_addr vpn_addr6;
+	struct in_addr vpn_addr4;
 	struct ovpn_socket *sock;
 	struct ovpn_peer *peer;
 	u32 peer_id;
@@ -528,28 +530,47 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 	rcu_read_unlock();
 
 	spin_lock_bh(&ovpn->lock);
-	ret = ovpn_nl_peer_modify(peer, info, attrs);
-	if (ret < 0) {
-		spin_unlock_bh(&ovpn->lock);
-		ovpn_peer_put(peer);
-		return ret;
+
+	/* reject peer with conflicting VPN address */
+	if (attrs[OVPN_A_PEER_VPN_IPV4]) {
+		vpn_addr4.s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
+		if (ovpn_peer_vpn_addr_conflict4(ovpn, peer, &vpn_addr4))
+			goto addr_conflict;
 	}
+	if (attrs[OVPN_A_PEER_VPN_IPV6]) {
+		vpn_addr6 = nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
+		if (ovpn_peer_vpn_addr_conflict6(ovpn, peer, &vpn_addr6))
+			goto addr_conflict;
+	}
+
+	ret = ovpn_nl_peer_modify(peer, info, attrs);
+	if (ret < 0)
+		goto unlock;
 
 	/* ret == 1 means that VPN IPv4/6 has been modified and rehashing
 	 * is required
 	 */
-	if (ret > 0)
+	if (ret > 0) {
 		ovpn_peer_hash_vpn_ip(peer);
+		ret = 0;
+	}
 	/* if the remote endpoint was updated, the by_transp_addr hash bucket
 	 * also needs to be refreshed, otherwise incoming packets from the new
 	 * remote address would fail the lockless lookup
 	 */
 	if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
 		ovpn_peer_hash_transp_addr(peer);
+
+unlock:
 	spin_unlock_bh(&ovpn->lock);
 	ovpn_peer_put(peer);
 
-	return 0;
+	return ret;
+addr_conflict:
+	NL_SET_ERR_MSG_FMT_MOD(info->extack,
+			       "VPN IP is already assigned to another peer");
+	ret = -EADDRINUSE;
+	goto unlock;
 }
 
 static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info,
drivers/net/ovpn/peer.c +66 -1

85 lines not on this page · raw message

drivers/net/ovpn/peer.h +6 -0
index 063535699ecd8..1879bfb76992d 100644
@@ -164,6 +164,12 @@ struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn,
 struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
 struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
 				       struct sk_buff *skb);
+bool ovpn_peer_vpn_addr_conflict4(struct ovpn_priv *ovpn,
+				  const struct ovpn_peer *peer,
+				  const struct in_addr *addr);
+bool ovpn_peer_vpn_addr_conflict6(struct ovpn_priv *ovpn,
+				  const struct ovpn_peer *peer,
+				  const struct in6_addr *addr);
 void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
 void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
 bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
Signature · 1 line
2.53.0
author maintainer
#124 lore raw

PATCH 124/457 ovpn: reject multipeer peers without VPN addresses

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 025af3a0a892514f9f27f186338ba3d44365547a ]

In MP mode, ovpn uses the peer VPN addresses to select the peer for outgoing tunnel packets. Peer creation currently requires a VPN IPv4 or IPv6 attribute, but it only checks for the presence of the attribute and not for a usable address value.

This allows userspace to create an MP peer with only unspecified VPN addresses, or to update an existing peer so that both VPN address families become unspecified. Such a peer cannot be selected through the VPN address hash tables.

Reject MP peer creation or update when the resulting peer would not have at least one VPN address configured.

This changes such configurations from being accepted to being rejected, but they have never been usable because the peer cannot be selected through the VPN address hash tables.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)
drivers/net/ovpn/netlink.c +30 -6
index e23f7d1f49e01..e9e0f75e04433 100644
@@ -352,8 +352,10 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
 
 int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
+	struct in_addr vpn_addr4 = { .s_addr = htonl(INADDR_ANY) };
+	struct in6_addr vpn_addr6 = IN6ADDR_ANY_INIT;
 	struct ovpn_priv *ovpn = info->user_ptr[0];
+	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
 	struct ovpn_socket *ovpn_sock;
 	struct socket *sock = NULL;
 	struct ovpn_peer *peer;
@@ -377,11 +379,20 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 
 	/* in MP mode VPN IPs are required for selecting the right peer */
-	if (ovpn->mode == OVPN_MODE_MP && !attrs[OVPN_A_PEER_VPN_IPV4] &&
-	    !attrs[OVPN_A_PEER_VPN_IPV6]) {
-		NL_SET_ERR_MSG_FMT_MOD(info->extack,
-				       "VPN IP must be provided in MP mode");
-		return -EINVAL;
+	if (ovpn->mode == OVPN_MODE_MP) {
+		if (attrs[OVPN_A_PEER_VPN_IPV4])
+			vpn_addr4.s_addr =
+				nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
+		if (attrs[OVPN_A_PEER_VPN_IPV6])
+			vpn_addr6 =
+				nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
+
+		if (vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+		    ipv6_addr_any(&vpn_addr6)) {
+			NL_SET_ERR_MSG_FMT_MOD(info->extack,
+					       "at least one VPN IP must be configured in MP mode");
+			return -EINVAL;
+		}
 	}
 
 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
@@ -531,6 +542,9 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 
 	spin_lock_bh(&ovpn->lock);
 
+	vpn_addr4 = peer->vpn_addrs.ipv4;
+	vpn_addr6 = peer->vpn_addrs.ipv6;
+
 	/* reject peer with conflicting VPN address */
 	if (attrs[OVPN_A_PEER_VPN_IPV4]) {
 		vpn_addr4.s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
@@ -543,6 +557,16 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 			goto addr_conflict;
 	}
 
+	/* in MP mode VPN IPs are required for selecting the right peer */
+	if (ovpn->mode == OVPN_MODE_MP &&
+	    vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+	    ipv6_addr_any(&vpn_addr6)) {
+		NL_SET_ERR_MSG_FMT_MOD(info->extack,
+				       "at least one VPN IP must be configured in MP mode");
+		ret = -EINVAL;
+		goto unlock;
+	}
+
 	ret = ovpn_nl_peer_modify(peer, info, attrs);
 	if (ret < 0)
 		goto unlock;
Signature · 1 line
2.53.0
author maintainer
#125 lore raw

PATCH 125/457 ovpn: reject invalid peer VPN addresses

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 5940f3407b78062442cb01f541ef6eed709fc380 ]

In MP mode, ovpn uses peer VPN addresses as lookup keys for selecting the peer that should receive outgoing tunnel packets. The netlink configuration path currently accepts address values that cannot sensibly identify a VPN peer, such as multicast, broadcast or loopback addresses.

Reject invalid peer VPN addresses when creating or updating an MP peer. Keep accepting the unspecified address as the internal unset value, provided that at least one VPN address family remains configured.

Fixes 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
---
 drivers/net/ovpn/netlink.c | 55 +++++++++++++++++++++++++++++---------
 1 file changed, 42 insertions(+), 13 deletions(-)
drivers/net/ovpn/netlink.c +42 -13
index e9e0f75e04433..5432bc2eb8e80 100644
@@ -185,6 +185,39 @@ static sa_family_t ovpn_nl_family_get(struct nlattr *addr4,
 	return AF_UNSPEC;
 }
 
+static int ovpn_nl_peer_check_vpn_addrs(const struct in_addr *addr4,
+					const struct in6_addr *addr6,
+					struct genl_info *info)
+{
+	int addr6_type;
+
+	if (addr4->s_addr == htonl(INADDR_ANY) && ipv6_addr_any(addr6)) {
+		NL_SET_ERR_MSG_MOD(info->extack,
+				   "at least one VPN IP must be configured in MP mode");
+		return -EINVAL;
+	}
+
+	if (ipv4_is_multicast(addr4->s_addr) || ipv4_is_lbcast(addr4->s_addr) ||
+	    ipv4_is_loopback(addr4->s_addr)) {
+		NL_SET_ERR_MSG_MOD(info->extack,
+				   "VPN IPv4 address must be valid unicast or any");
+		return -EADDRNOTAVAIL;
+	}
+
+	if (!ipv6_addr_any(addr6)) {
+		addr6_type = ipv6_addr_type(addr6);
+
+		if (!(addr6_type & IPV6_ADDR_UNICAST) ||
+		    (addr6_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_COMPATv4))) {
+			NL_SET_ERR_MSG_MOD(info->extack,
+					   "VPN IPv6 address must be valid unicast or any");
+			return -EADDRNOTAVAIL;
+		}
+	}
+
+	return 0;
+}
+
 static int ovpn_nl_peer_precheck(struct ovpn_priv *ovpn,
 				 struct genl_info *info,
 				 struct nlattr **attrs)
@@ -387,12 +420,10 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
 			vpn_addr6 =
 				nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
 
-		if (vpn_addr4.s_addr == htonl(INADDR_ANY) &&
-		    ipv6_addr_any(&vpn_addr6)) {
-			NL_SET_ERR_MSG_FMT_MOD(info->extack,
-					       "at least one VPN IP must be configured in MP mode");
-			return -EINVAL;
-		}
+		ret = ovpn_nl_peer_check_vpn_addrs(&vpn_addr4, &vpn_addr6,
+						   info);
+		if (ret < 0)
+			return ret;
 	}
 
 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
@@ -558,13 +589,11 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	/* in MP mode VPN IPs are required for selecting the right peer */
-	if (ovpn->mode == OVPN_MODE_MP &&
-	    vpn_addr4.s_addr == htonl(INADDR_ANY) &&
-	    ipv6_addr_any(&vpn_addr6)) {
-		NL_SET_ERR_MSG_FMT_MOD(info->extack,
-				       "at least one VPN IP must be configured in MP mode");
-		ret = -EINVAL;
-		goto unlock;
+	if (ovpn->mode == OVPN_MODE_MP) {
+		ret = ovpn_nl_peer_check_vpn_addrs(&vpn_addr4, &vpn_addr6,
+						   info);
+		if (ret < 0)
+			goto unlock;
 	}
 
 	ret = ovpn_nl_peer_modify(peer, info, attrs);
Signature · 1 line
2.53.0
author maintainer
#126 lore raw

PATCH 126/457 drm/xe/gt_throttle: Report power brake as a throttle reason on CRI

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sk Anirban <[email protected]>

[ Upstream commit ea4debcd8016f73c5dee3a29250a3d7977f015ef ]

CRI defines bit 5 of the perf limit reasons register as a power brake (PWRBRK) indicator. Add PWRBRK_MASK and a reason_pwrbrk sysfs attribute for CRI in place of reason_ratl.

Fixes 8578e6d0546c ("drm/xe/gt_throttle: Drop individual show functions")
(cherry picked from commit e199c851c0ab608a0ca89e7be1756a1461b41a2c)
---
 drivers/gpu/drm/xe/regs/xe_gt_regs.h | 1 +
 drivers/gpu/drm/xe/xe_gt_throttle.c  | 5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/regs/xe_gt_regs.h +1 -0
index 08251c7a1a4b6..247a736a54aaa 100644
@@ -651,6 +651,7 @@
 #define   MEM_THERMAL_MASK			REG_BIT(2)
 #define   VR_THERMAL_MASK			REG_BIT(3)
 #define   ICCMAX_MASK				REG_BIT(4)
+#define   PWRBRK_MASK				REG_BIT(5)
 #define   SOC_AVG_THERMAL_MASK			REG_BIT(6)
 #define   FASTVMODE_MASK			REG_BIT(7)
 #define   PSYS_PL1_MASK				REG_BIT(12)
drivers/gpu/drm/xe/xe_gt_throttle.c +3 -2
index 1e7e3a31aa698..c0af5484611d1 100644
@@ -39,7 +39,7 @@
  * - ``reason_mem_thermal``: Memory thermal
  * - ``reason_vr_thermal``: VR thermal
  * - ``reason_iccmax``: ICCMAX
- * - ``reason_ratl``: RATL thermal algorithm
+ * - ``reason_pwrbrk``: Power brake
  * - ``reason_soc_avg_thermal``: SoC average temp
  * - ``reason_fastvmode``: VR is hitting FastVMode
  * - ``reason_psys_pl1``: PSYS PL1
@@ -200,6 +200,7 @@ static THROTTLE_ATTR_RO(reason_psys_pl1, PSYS_PL1_MASK);
 static THROTTLE_ATTR_RO(reason_psys_pl2, PSYS_PL2_MASK);
 static THROTTLE_ATTR_RO(reason_p0_freq, P0_FREQ_MASK);
 static THROTTLE_ATTR_RO(reason_psys_crit, PSYS_CRIT_MASK);
+static THROTTLE_ATTR_RO(reason_pwrbrk, PWRBRK_MASK);
 
 static struct attribute *cri_throttle_attrs[] = {
 	/* Common */
@@ -209,12 +210,12 @@ static struct attribute *cri_throttle_attrs[] = {
 	&attr_reason_pl2.attr.attr,
 	&attr_reason_pl4.attr.attr,
 	&attr_reason_prochot.attr.attr,
-	&attr_reason_ratl.attr.attr,
 	/* CRI */
 	&attr_reason_vr_thermal.attr.attr,
 	&attr_reason_soc_thermal.attr.attr,
 	&attr_reason_mem_thermal.attr.attr,
 	&attr_reason_iccmax.attr.attr,
+	&attr_reason_pwrbrk.attr.attr,
 	&attr_reason_soc_avg_thermal.attr.attr,
 	&attr_reason_fastvmode.attr.attr,
 	&attr_reason_psys_pl1.attr.attr,
Signature · 1 line
2.53.0
author maintainer
#127 lore raw

PATCH 127/457 Bluetooth: bnep: fix out-of-bounds reads on short RX/TX frames and control fallthrough

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

[ Upstream commit f0ca020cbb9bb7f3f4ea8ba1dfcf30a282aec91e ]

Fix multiple out-of-bounds reads in Bluetooth BNEP frame processing:

1. In bnep_rx_frame() and bnep_ctrl_frame() (net/bluetooth/bnep/core.c), use pskb_may_pull() to verify the BNEP header, control type byte, filter count, and extension headers exist before reading them, and return 0 after handling BNEP_CONTROL instead of falling through to Ethernet frame submission when no extension headers follow.
2. In bnep_net_xmit() (net/bluetooth/bnep/netdev.c), verify skb->len >= ETH_HLEN with pskb_may_pull() before reading the 14-byte Ethernet header to prevent an out-of-bounds heap read and infoleak on short AF_PACKET TX frames.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by LLM
---
 net/bluetooth/bnep/core.c   | 17 ++++++++++++++++-
 net/bluetooth/bnep/netdev.c |  8 +++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)
net/bluetooth/bnep/core.c +16 -1
index f7d88c33e23e4..ad24d2486665a 100644
@@ -270,9 +270,14 @@ static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
 
 		BT_DBG("type 0x%x len %u", h->type, h->len);
 
+		if (skb->len < h->len) {
+			err = -EILSEQ;
+			break;
+		}
+
 		switch (h->type & BNEP_TYPE_MASK) {
 		case BNEP_EXT_CONTROL:
-			bnep_rx_control(s, skb->data, skb->len);
+			bnep_rx_control(s, skb->data, h->len);
 			break;
 
 		default:
@@ -373,6 +378,11 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 			goto badframe;
 	}
 
+	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	/* Strip 802.1p header */
 	if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
 		if (!skb_pull(skb, 4))
@@ -451,6 +461,11 @@ static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 		goto send;
 	}
 
+	if (skb->len < ETH_HLEN) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	iv[il++] = (struct kvec) { &type, 1 };
 	len++;
 
net/bluetooth/bnep/netdev.c +7 -1
index ee1e39a3daffb..b451ef457741f 100644
@@ -166,6 +166,12 @@ static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
 
 	BT_DBG("skb %p, dev %p", skb, dev);
 
+	if (!pskb_may_pull(skb, ETH_HLEN)) {
+		dev->stats.tx_dropped++;
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
 #ifdef CONFIG_BT_BNEP_MC_FILTER
 	if (bnep_net_mc_filter(skb, s)) {
 		kfree_skb(skb);
@@ -218,7 +224,7 @@ void bnep_net_setup(struct net_device *dev)
 	dev->addr_len = ETH_ALEN;
 
 	ether_setup(dev);
-	dev->min_mtu = 0;
+	dev->min_mtu = ETH_MIN_MTU;
 	dev->max_mtu = ETH_MAX_MTU;
 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	dev->netdev_ops = &bnep_netdev_ops;
Signature · 1 line
2.53.0
author maintainer
#128 lore raw

PATCH 128/457 Bluetooth: btintel_pcie: validate device-supplied DMA indices

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ravindra <[email protected]>

[ Upstream commit 37a11129345337efd6eef8e62b03b6348cd0dd8b ]

In btintel_pcie_msix_rx_handle(), the driver processes RX completion descriptors (urbd1) written by the PCIe device into DMA-coherent memory. urbd1->frbd_tag (a 16-bit field fully controlled by the device firmware via DMA) is used directly as an array index into rxq->bufs[] without any bounds check. rxq->bufs[] has only BTINTEL_PCIE_RX_DESCS_COUNT (64) entries, while frbd_tag can be any value 0-65535. A malicious or malfunctioning device can write an out-of-range frbd_tag, causing the driver to dereference an out-of-bounds data_buf pointer.

Additionally, cr_hia is read from a DMA-shared index array also writable by the device; if the device sets cr_hia >= rxq->count, the while-loop never terminates because cr_tia is wrapped via modulo rxq->count and can never equal an out-of-range cr_hia.

Add bounds validation for cr_hia and frbd_tag in the RX path, and cr_hia in the TX path. Log invalid values with bt_dev_err before returning.

Fixes c2b636b3f788 ("Bluetooth: btintel_pcie: Add support for PCIe transport")
---
 drivers/bluetooth/btintel_pcie.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
drivers/bluetooth/btintel_pcie.c +16 -0
index 3262e950a6bd8..9381895dc3cf0 100644
@@ -1099,6 +1099,11 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
 
 	txq = &data->txq;
 
+	if (cr_hia >= txq->count) {
+		bt_dev_err(data->hdev, "TXQ: invalid cr_hia %u", cr_hia);
+		return;
+	}
+
 	while (cr_tia != cr_hia) {
 		data->tx_wait_done = true;
 		wake_up(&data->tx_wait_q);
@@ -1588,6 +1593,11 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
 
 	rxq = &data->rxq;
 
+	if (cr_hia >= rxq->count) {
+		bt_dev_err(hdev, "RXQ: invalid cr_hia %u", cr_hia);
+		return;
+	}
+
 	/* The firmware sends multiple CD in a single MSI-X and it needs to
 	 * process all received CDs in this interrupt.
 	 */
@@ -1595,6 +1605,12 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
 		urbd1 = &rxq->urbd1s[cr_tia];
 		ipc_print_urbd1(data->hdev, urbd1, cr_tia);
 
+		if (urbd1->frbd_tag >= rxq->count) {
+			bt_dev_err(hdev, "RXQ: invalid frbd_tag %u",
+				   urbd1->frbd_tag);
+			return;
+		}
+
 		buf = &rxq->bufs[urbd1->frbd_tag];
 		if (!buf) {
 			bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d",
Signature · 1 line
2.53.0
author maintainer
#129 lore raw

PATCH 129/457 Bluetooth: RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

[ Upstream commit 6d91041bb38b97e2feb625123cc0529d7b83a0e1 ]

While rfcomm_recv_frame() verifies that skb->len is at least sizeof(*hdr) + 1 (4 bytes: 3-byte header + 1-byte FCS), an RFCOMM frame with an extended 2-byte length field (!__test_ea(hdr->len)) has a 4-byte header plus a 1-byte FCS (5 bytes minimum, sizeof(*hdr) + 2).

When a 4-byte RFCOMM frame with EA == 0 arrives:
1. The initial skb->len < sizeof(*hdr) + 1 check passes (4 < 4 is false).
2. Trimming the FCS byte decrements skb->len to 3.
3. If __check_fcs() succeeds, skb_pull(skb, 4) fails (4 > 3) and returns NULL without advancing skb->data.
4. Because the return value of skb_pull() is ignored, the un-pulled 3-byte struct rfcomm_hdr remains at skb->data and is either queued as application payload via rfcomm_recv_data() or parsed as a multiplexer control command via rfcomm_recv_mcc() on DLCI 0.

Fix this by extending the length check in rfcomm_recv_frame() to also require skb->len >= sizeof(*hdr) + 2 when !__test_ea(hdr->len).

Fixes b230e5bf501c ("Bluetooth: RFCOMM: validate skb length in rfcomm_recv_frame")
Assisted-by LLM
---
 net/bluetooth/rfcomm/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/bluetooth/rfcomm/core.c +2 -1
index 63fa0f542ccf1..3f757198051a2 100644
@@ -1817,7 +1817,8 @@ static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
 		return s;
 	}
 
-	if (skb->len < sizeof(*hdr) + 1) {
+	if (skb->len < sizeof(*hdr) + 1 ||
+	    (!__test_ea(hdr->len) && skb->len < sizeof(*hdr) + 2)) {
 		kfree_skb(skb);
 		return s;
 	}
Signature · 1 line
2.53.0
author maintainer
#130 lore raw

PATCH 130/457 bpf: Reject non-negative offsets in stack_slot_obj_get_spi()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xu Yunxiang <[email protected]>

[ Upstream commit 79a9172f3ab4ad8392c5e5c8944b9b7710ade620 ]

bpf_get_spi() computes (-off - 1) / BPF_REG_SIZE using C division, which truncates toward zero. For off == 0, this produces spi 0, the same index used by the valid stack slot at fp-8.

stack_slot_obj_get_spi() currently checks alignment and the resulting spi bounds, but does not reject the non-negative offset itself. It can therefore validate a PTR_TO_STACK register holding fp+0 against an iterator stored at fp-8 even though the runtime receives the actual fp+0 pointer. An effectful iterator kfunc can then interpret memory outside the BPF stack as iterator state.

Reject non-negative offsets before converting the offset to an spi. All valid stack objects begin at a negative offset from the frame pointer.

Fixes 06accc8779c1 ("bpf: add support for open-coded iterator loops")
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/verifier.c +1 -1
index dc1a9ef32b78e..cb523cc5465dd 100644
@@ -582,7 +582,7 @@ static int stack_slot_obj_get_spi(struct bpf_verifier_env *env, struct bpf_reg_s
 	}
 
 	off = reg->var_off.value;
-	if (off % BPF_REG_SIZE) {
+	if (off >= 0 || off % BPF_REG_SIZE) {
 		verbose(env, "cannot pass in %s at an offset=%d\n", obj_kind, off);
 		return -EINVAL;
 	}
Signature · 1 line
2.53.0
author maintainer
#131 lore raw

PATCH 131/457 octeontx2-af: Fix memory scaling limitation in SR-IOV mode

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ratheesh Kannoth <[email protected]>

[ Upstream commit d06f2ebf67ff2962fe00d687e4f0d4703eb41a12 ]

The original code used DMA_ATTR_FORCE_CONTIGUOUS, which could exhaust the CMA pool when a large number of VFs were requested.

Fix this by switching to the DMA streaming API. This is equivalent on Octeon platforms, which provide full I/O coherency via the SMMU.

Cc Leon Romanovsky <[email protected]>
Fixes 73d33dbc0723 ("octeontx2-af: Use DMA_ATTR_FORCE_CONTIGUOUS attribute in DMA alloc")
---
 .../ethernet/marvell/octeontx2/af/common.h    | 45 ++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/common.h +39 -6
index 779413a383b74..78e42549d9908 100644
@@ -7,6 +7,10 @@
 #ifndef COMMON_H
 #define COMMON_H
 
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
 #include "rvu_struct.h"
 
 #define OTX2_ALIGN			128  /* Align to cacheline */
@@ -44,6 +48,33 @@ struct qmem {
 	u32		qsize;
 };
 
+static inline void *otx2_dma_alloc_coherent(struct device *dev, size_t size,
+					    dma_addr_t *dma_handle)
+{
+	dma_addr_t dma_addr;
+	void *vaddr;
+
+	vaddr = kzalloc(size, GFP_KERNEL);
+	if (!vaddr)
+		return NULL;
+
+	dma_addr = dma_map_single(dev, vaddr, size, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, dma_addr)) {
+		kfree(vaddr);
+		return NULL;
+	}
+
+	*dma_handle = dma_addr;
+	return vaddr;
+}
+
+static inline void otx2_dma_free_coherent(struct device *dev, size_t size,
+					  void *vaddr, dma_addr_t dma_handle)
+{
+	dma_unmap_single(dev, dma_handle, size, DMA_BIDIRECTIONAL);
+	kfree(vaddr);
+}
+
 static inline int qmem_alloc(struct device *dev, struct qmem **q,
 			     int qsize, int entry_sz)
 {
@@ -60,8 +91,11 @@ static inline int qmem_alloc(struct device *dev, struct qmem **q,
 
 	qmem->entry_sz = entry_sz;
 	qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN;
-	qmem->base = dma_alloc_attrs(dev, qmem->alloc_sz, &qmem->iova,
-				     GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
+
+	if (get_order(PAGE_ALIGN(qmem->alloc_sz)) > MAX_PAGE_ORDER)
+		return -ENOMEM;
+
+	qmem->base = otx2_dma_alloc_coherent(dev, qmem->alloc_sz, &qmem->iova);
 	if (!qmem->base)
 		return -ENOMEM;
 
@@ -80,10 +114,9 @@ static inline void qmem_free(struct device *dev, struct qmem *qmem)
 		return;
 
 	if (qmem->base)
-		dma_free_attrs(dev, qmem->alloc_sz,
-			       qmem->base - qmem->align,
-			       qmem->iova - qmem->align,
-			       DMA_ATTR_FORCE_CONTIGUOUS);
+		otx2_dma_free_coherent(dev, qmem->alloc_sz,
+				       qmem->base - qmem->align,
+				       qmem->iova - qmem->align);
 	devm_kfree(dev, qmem);
 }
 
Signature · 1 line
2.53.0
author maintainer
#132 lore raw

PATCH 132/457 ipv6: Prevent rt6_insert_exception() for dying fib6_info.

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit 0346ec2f080b40d95ed05b853bb9226289e75212 ]

Before the cited commit, fib6_nh_flush_exceptions() always set from->exception_bucket_flushed = 1 under rt6_exception_lock to prevent rt6_insert_exception() from inserting a new exception for a dying fib6_info.

The flag was replaced with the FIB6_EXCEPTION_BUCKET_FLUSHED bit stored in nh->rt6i_exception_bucket.

The problem is that now the bit is only set when the bucket is not NULL and fib6_nh_flush_exceptions() is called from fib6_nh_release() after fib6_ref has already reached zero.

If rt6_insert_exception() is called while the target fib6_info is being removed via fib6_purge_rt(), a new exception could be created successfully because rt6_flush_exceptions() no longer sets the bit.

This creates a reference cycle between the fib6_info and the exception route, leaking the fib6_info, its nexthop device, and all per-CPU routes in fib6_nh->rt6i_pcpu, which stalls netdev unregistration.

[   34.680602] unregister_netdevice: waiting for gre6 to become free. Usage count = 68
[   44.920675] unregister_netdevice: waiting for gre6 to become free. Usage count = 68
[   55.176582] unregister_netdevice: waiting for gre6 to become free. Usage count = 68

Let's call fib6_drop_pcpu_from() before rt6_flush_exceptions(), to set fib6_destroying before rt6_exception_lock, and check f6i->fib6_destroying in rt6_insert_exception().

Note that FIB6_EXCEPTION_BUCKET_FLUSHED logic is dead and we can clean it up in net-next.

---
 net/ipv6/ip6_fib.c | 2 +-
 net/ipv6/route.c   | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)
net/ipv6/ip6_fib.c +1 -1
index 7c5daea3f0963..fc3da984a9ab0 100644
@@ -1043,8 +1043,8 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
 	struct fib6_table *table = rt->fib6_table;
 
 	/* Flush all cached dst in exception table */
-	rt6_flush_exceptions(rt);
 	fib6_drop_pcpu_from(rt);
+	rt6_flush_exceptions(rt);
 
 	if (rt->nh) {
 		spin_lock(&rt->nh->lock);
net/ipv6/route.c +5 -0
index ee707e48f4efa..c94ad52d03f24 100644
@@ -1729,6 +1729,11 @@ static int rt6_insert_exception(struct rt6_info *nrt,
 
 	spin_lock_bh(&rt6_exception_lock);
 
+	if (f6i->fib6_destroying) {
+		err = -ENOENT;
+		goto out;
+	}
+
 	bucket = rcu_dereference_protected(nh->rt6i_exception_bucket,
 					  lockdep_is_held(&rt6_exception_lock));
 	if (!bucket) {
Signature · 1 line
2.53.0
author maintainer
#133 lore raw

PATCH 133/457 net: dont require the hwtstamp NDOs when a PHY provides timestamping

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nicolai Buchwitz <[email protected]>

[ Upstream commit 31995571219c8ac30913d9c0dccad033fbb0b3da ]

Removing the legacy ioctl fallback made both hwtstamp NDOs mandatory. A device that only timestamps in its PHY implements neither, so SIOCSHWTSTAMP fails with EOPNOTSUPP before anything looks at the PHY and PTP stops working there.

The check only ever picked the legacy path. That path is gone, so drop it and test where the NDOs are actually called.

SIOCGHWTSTAMP is new here, not restored. The old path went through phy_mii_ioctl(), which only handled SIOCSHWTSTAMP.

Such a device now returns -ENODEV while absent instead of -EOPNOTSUPP, like the ones that do implement the NDOs.

Fixes 5062245a5a7f ("net: remove legacy way to get/set HW timestamp config")
---
 net/core/dev_ioctl.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)
net/core/dev_ioctl.c +9 -16
index a320e264eaaf0..164643140a523 100644
@@ -276,19 +276,18 @@ int dev_get_hwtstamp_phylib(struct net_device *dev,
 	if (phy_is_default_hwtstamp(dev->phydev))
 		return phy_hwtstamp_get(dev->phydev, cfg);
 
+	if (!dev->netdev_ops->ndo_hwtstamp_get)
+		return -EOPNOTSUPP;
+
 	return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
 }
 
 static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
 	struct kernel_hwtstamp_config kernel_cfg = {};
 	struct hwtstamp_config cfg;
 	int err;
 
-	if (!ops->ndo_hwtstamp_get)
-		return -EOPNOTSUPP;
-
 	if (!netif_device_present(dev))
 		return -ENODEV;
 
@@ -359,12 +358,18 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
 	cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
 
 	if (phy_ts && dev->see_all_hwtstamp_requests) {
+		if (!ops->ndo_hwtstamp_get)
+			return -EOPNOTSUPP;
+
 		err = ops->ndo_hwtstamp_get(dev, &old_cfg);
 		if (err)
 			return err;
 	}
 
 	if (!phy_ts || dev->see_all_hwtstamp_requests) {
+		if (!ops->ndo_hwtstamp_set)
+			return -EOPNOTSUPP;
+
 		err = ops->ndo_hwtstamp_set(dev, cfg, extack);
 		if (err) {
 			if (extack->_msg)
@@ -390,7 +395,6 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
 
 static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
 	struct kernel_hwtstamp_config kernel_cfg = {};
 	struct netlink_ext_ack extack = {};
 	struct hwtstamp_config cfg;
@@ -413,9 +417,6 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 		return err;
 	}
 
-	if (!ops->ndo_hwtstamp_set)
-		return -EOPNOTSUPP;
-
 	if (!netif_device_present(dev))
 		return -ENODEV;
 
@@ -441,15 +442,11 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 int generic_hwtstamp_get_lower(struct net_device *dev,
 			       struct kernel_hwtstamp_config *kernel_cfg)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
 	int err;
 
 	if (!netif_device_present(dev))
 		return -ENODEV;
 
-	if (!ops->ndo_hwtstamp_get)
-		return -EOPNOTSUPP;
-
 	netdev_lock_ops(dev);
 	err = dev_get_hwtstamp_phylib(dev, kernel_cfg);
 	netdev_unlock_ops(dev);
@@ -462,15 +459,11 @@ int generic_hwtstamp_set_lower(struct net_device *dev,
 			       struct kernel_hwtstamp_config *kernel_cfg,
 			       struct netlink_ext_ack *extack)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
 	int err;
 
 	if (!netif_device_present(dev))
 		return -ENODEV;
 
-	if (!ops->ndo_hwtstamp_set)
-		return -EOPNOTSUPP;
-
 	netdev_lock_ops(dev);
 	err = dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
 	netdev_unlock_ops(dev);
Signature · 1 line
2.53.0
author maintainer
#134 lore raw

PATCH 134/457 dpll: use exact lookup for reference sync pin id

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ivan Vecera <[email protected]>

[ Upstream commit 7cce782d8327b7291334c4a304cf3fd909a74d9d ]

dpll_pin_ref_sync_state_set() looks up the reference sync pin in the pin->ref_sync_pins xarray, which is keyed by the sync pin's id (see dpll_pin_ref_sync_pair_add() using xa_insert() with ref_sync_pin->id). The pin id to operate on is supplied by userspace via DPLL_A_PIN_ID.

The lookup however used xa_find() with a ULONG_MAX limit, which returns the first present entry with an index greater than or equal to the requested id, not the entry stored exactly at that id. If userspace passes an id that is not paired as a reference sync pin, but another pin with a higher id is present in the xarray, xa_find() silently returns that wrong pin and the subsequent ref_sync_set() operates on it. The request only fails when the given id is larger than every present key.

Use xa_load() for an exact-key lookup instead, mirroring the deletion path in dpll_pin_ref_sync_pair_del().

Fixes 58256a26bfb3 ("dpll: add reference sync get/set")
---
 drivers/dpll/dpll_netlink.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/dpll/dpll_netlink.c +1 -2
index 9e55745e33e4f..9f274c6253c66 100644
@@ -1282,8 +1282,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
 	unsigned long i;
 	int ret;
 
-	ref_sync_pin = xa_find(&pin->ref_sync_pins, &ref_sync_pin_idx,
-			       ULONG_MAX, XA_PRESENT);
+	ref_sync_pin = xa_load(&pin->ref_sync_pins, ref_sync_pin_idx);
 	if (!ref_sync_pin) {
 		NL_SET_ERR_MSG(extack, "reference sync pin not found");
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#135 lore raw

PATCH 135/457 net: usb: sr9700: include receive overhead in the length check

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit c06bde80ae7a7b595732f7cabcb92cf08db9d56a ]

The receive fixup subtracts the Ethernet CRC from the reported packet length, but compares that payload length against the whole remaining receive buffer. The following copy starts after the three-byte header, and the cursor advance consumes both that header and the four-byte CRC.

Require the payload to fit after SR_RX_OVERHEAD before copying it or advancing to the next packet. The loop already ensures that the remaining buffer is larger than the overhead, so the subtraction is safe.

The issue was found by our static-analysis tool.

Fixes c9b37458e956 ("USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700Device Driver Support")
---
 drivers/net/usb/sr9700.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/usb/sr9700.c +2 -1
index 937e6fef3ac6d..50981a28376a5 100644
@@ -355,7 +355,8 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 		/* ignore the CRC length */
 		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
-		if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
+		if (len > ETH_FRAME_LEN || len < 0 ||
+		    len > skb->len - SR_RX_OVERHEAD)
 			return 0;
 
 		/* the last packet of current skb */
Signature · 1 line
2.53.0
author maintainer
#136 lore raw

PATCH 136/457 ipv6: Fix dst leak for uncached routes.

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit be31fe6333f534155e6b408f1ef6d77974bb41aa ]

ip6_route_output_flags(), ip6_rt_put_flags(), and ip6_dst_check() detect an uncached route by list_empty(&rt->dst.rt_uncached), which replaced the static DST_NOCACHE flag check in commit a4c2fd7f7891 ("net: remove DST_NOCACHE flag").

When a device is unregistered, rt6_uncached_list_flush_dev() unlinks uncached routes tied to the device from rt6_uncached_list.

Previously, they were moved to another list with list_move() (__list_del_entry() + list_add()), and since commit 98aa546af5e4 ("inet: remove (struct uncached_list)->quarantine"), the routes are just unlinked with list_del_init().

If list_del_init() runs concurrently, list_empty() evaluates to true; ip6_route_output_flags() calls dst_hold_safe() incorrectly and ip6_rt_put_flags() skips ip6_rt_put(), leaking dst, and thus dev tied via rt->from as well.

The same race is partially fixed by commit 9a6f0c4d5796 ("dst:
fix races in rt6_uncached_list_del() and rt_del_uncached_list()").

Let's check rt6->dst.rt_uncached_list instead.

Note that IPv4 does not have the same issue.

---
 include/net/ip6_route.h | 4 ++--
 net/ipv6/route.c        | 7 ++++---
 2 files changed, 6 insertions(+), 5 deletions(-)
include/net/ip6_route.h +2 -2
index 745ab62154ace..0a6c4ceb95a7a 100644
@@ -101,12 +101,12 @@ static inline struct dst_entry *ip6_route_output(struct net *net,
 }
 
 /* Only conditionally release dst if flags indicates
- * !RT6_LOOKUP_F_DST_NOREF or dst is in uncached_list.
+ * !RT6_LOOKUP_F_DST_NOREF or dst is uncached.
  */
 static inline void ip6_rt_put_flags(struct rt6_info *rt, int flags)
 {
 	if (!(flags & RT6_LOOKUP_F_DST_NOREF) ||
-	    !list_empty(&rt->dst.rt_uncached))
+	    rt->dst.rt_uncached_list)
 		ip6_rt_put(rt);
 }
 
net/ipv6/route.c +4 -3
index c94ad52d03f24..8fddcc631fcb6 100644
@@ -139,6 +139,7 @@ void rt6_uncached_list_add(struct rt6_info *rt)
 {
 	struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
 
+	/* Set once and never cleared: non-NULL marks an uncached route. */
 	rt->dst.rt_uncached_list = ul;
 
 	spin_lock_bh(&ul->lock);
@@ -2726,8 +2727,8 @@ struct dst_entry *ip6_route_output_flags(struct net *net,
 	rcu_read_lock();
 	dst = ip6_route_output_flags_noref(net, sk, fl6, flags);
 	rt6 = dst_rt6_info(dst);
-	/* For dst cached in uncached_list, refcnt is already taken. */
-	if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) {
+	/* For an uncached dst, refcnt is already taken. */
+	if (!rt6->dst.rt_uncached_list && !dst_hold_safe(dst)) {
 		dst = &net->ipv6.ip6_null_entry->dst;
 		dst_hold(dst);
 	}
@@ -2836,7 +2837,7 @@ INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst,
 	from = rcu_dereference(rt->from);
 
 	if (from && (rt->rt6i_flags & RTF_PCPU ||
-	    unlikely(!list_empty(&rt->dst.rt_uncached))))
+	    unlikely(rt->dst.rt_uncached_list)))
 		dst_ret = rt6_dst_from_check(rt, from, cookie);
 	else
 		dst_ret = rt6_check(rt, from, cookie);
Signature · 1 line
2.53.0
author maintainer
#137 lore raw

PATCH 137/457 udp: relocate a connected socket in the 4-tuple hash table on re-connect

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shardul Bankar <[email protected]>

[ Upstream commit 5fd0783b99d4af98f65cd58b56ec203d1d426104 ]

A connected UDP socket that connects again to a different peer is not re-filed in the 4-tuple hash table:

    sk binds to 127.0.0.1:21001
    sk connects to 127.0.0.2:20001	// filed under hash(sk, peer1)
    sk connects to 127.0.0.3:20002	// still filed under hash(sk, peer1)
    packet from 127.0.0.3:20002		// hash(sk, peer2) misses, so the
					// lookup falls back to scoring the
					// hash2 chain for this address
					// and port

udp_lib_hash4() returns early when the socket is already hashed, assuming ->rehash() relocates it. ->rehash() runs from __ip{4,6}_datagram_connect() only while the receive address is unset, which a second connect never is:
the first connect assigns it, whether the socket was bound to a specific address or to the wildcard. commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()") added that early return and named connect(AF_UNSPEC) as the way around it. That workaround does not help a socket with both SOCK_BINDADDR_LOCK and SOCK_BINDPORT_LOCK set, because __udp_disconnect() skips ->rehash() for the first and ->unhash() for the second.

Delivery is correct either way.

Relocate the socket when the hash it is filed under differs from the one requested, which is what commit 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket") did before the early return became unconditional. It is done here under hslot->lock, which that version did not take, to match udp_lib_rehash() and udp_lib_unhash(). hslot2 is unchanged, so hash4_cnt needs no adjustment, as in udp_lib_rehash(). A first connect is unaffected, and IPv6 shares the code.

With 500 sockets on the port, a re-connected socket measured 522,553 pps without this change and 2,055,078 with it. The UDP side was noted as remaining work in [1].

---
 net/ipv4/udp.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
net/ipv4/udp.c +14 -5
index 45e96b7219896..aa095ab833ecd 100644
@@ -616,14 +616,23 @@ void udp_lib_hash4(struct sock *sk, u16 hash)
 	struct net *net = sock_net(sk);
 	struct udp_table *udptable;
 
-	/* Connected udp socket can re-connect to another remote address, which
-	 * will be handled by rehash. Thus no need to redo hash4 here.
+	udptable = net->ipv4.udp_table;
+	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
+
+	/* A connected socket can re-connect to another address. rehash()
+	 * relocates it, but only runs when the local address changes, so a
+	 * socket bound to a specific address would stay filed under the
+	 * previous peer's hash. Move it here.
 	 */
-	if (udp_hashed4(sk))
+	if (udp_hashed4(sk)) {
+		if (udp_sk(sk)->udp_lrpa_hash != hash) {
+			spin_lock_bh(&hslot->lock);
+			udp_rehash4(udptable, sk, hash);
+			spin_unlock_bh(&hslot->lock);
+		}
 		return;
+	}
 
-	udptable = net->ipv4.udp_table;
-	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
 	hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
 	hslot4 = udp_hashslot4(udptable, hash);
 	udp_sk(sk)->udp_lrpa_hash = hash;
Signature · 1 line
2.53.0
author maintainer
#138 lore raw

PATCH 138/457 udp: remove a disconnected socket from the 4-tuple hash table

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shardul Bankar <[email protected]>

[ Upstream commit 9e95b1a94c9c49b4ba722251bbca2759b9c51737 ]

A UDP socket bound to a specific address and port keeps its entry in the 4-tuple hash table after it is disconnected:

    sk binds to 127.0.0.1:21001
    sk connects to 127.0.0.2:20001	// filed in the 4-tuple table
    sk disconnects, connect(AF_UNSPEC)	// still filed, peer now 0.0.0.0:0

__udp_disconnect() takes a socket out of that table only as a side effect of ->rehash() or ->unhash(), and it skips ->rehash() when SOCK_BINDADDR_LOCK is set and ->unhash() when SOCK_BINDPORT_LOCK is set. commit 6996a2d2d0a6 ("udp: Unhash auto-bound connected sk from 4-tuple hash table when disconnected.") fixed the same end state for a wildcard-bound socket, by a path this one does not take.

The entry is counted whether or not anything hits it. hash4_cnt on the hash2 slot stays raised for as long as the socket lives, so udp_has_hash4() keeps sending every packet for that address and port through the 4-tuple lookup first.

On IPv6 it can also be hit. __udp_disconnect() does not clear sk_v6_daddr, so udp_v6_rehash() files the entry under the peer the socket was connected to with a zero dport, and inet6_match() compares that same
field: a datagram from the former peer with a zero source port matches, and source port zero is accepted on receive. On IPv4 the peer is cleared, so a match would need a zero source address as well, which the routing layer rejects as martian. The stale sk_v6_daddr is a separate defect, not addressed here; removing the entry closes this path either way.

The entry can also be relocated. __udp_disconnect() clears sk_bound_dev_if, so a subsequent SO_BINDTODEVICE calls ->rehash(), and because the receive address is still specific udp_lib_rehash() moves the entry instead of removing it, into the bucket that (rcv_saddr, num, 0, 0) hashes to -- a pure function of the address and port, so every socket reaching this state on one address and port collects in one bucket. The bucket cannot be chosen from outside, as udp_ehashfn() is seeded with a per-boot secret. This last one became reachable only with commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()"), which moved the hash4 handling out of a branch a disconnected socket does not take; the stale entry itself dates from the commit in Fixes.

Take the socket out of the table before __udp_disconnect() runs, while it still matches how it was filed. This also reaches the wildcard case ahead of udp_lib_rehash()'s udp_unhash4() branch, leaving that branch unreachable from udp_disconnect(); removing it belongs in net-next. udp_disconnect() and udp_abort() are the only UDP entries into __udp_disconnect(), which is shared with raw, ping and l2tp sockets that are not struct udp_sock:
ping_prot.obj_size is sizeof(struct inet_sock), so udp_hashed4() on one would read past the allocation.

Fixes 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket")
Assisted-by LLM
---
 net/ipv4/udp.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
net/ipv4/udp.c +23 -0
index aa095ab833ecd..59afce196079a 100644
@@ -2193,9 +2193,31 @@ int __udp_disconnect(struct sock *sk, int flags)
 }
 EXPORT_SYMBOL(__udp_disconnect);
 
+/* __udp_disconnect() takes a socket out of the 4-tuple hash table only via
+ * ->rehash() or ->unhash(), and neither runs for a socket bound to a
+ * specific address and port. Remove it here, before its peer is cleared.
+ */
+static void udp_unhash4_on_disconnect(struct sock *sk)
+{
+	struct net *net = sock_net(sk);
+	struct udp_table *udptable;
+	struct udp_hslot *hslot;
+
+	if (!udp_hashed4(sk))
+		return;
+
+	udptable = net->ipv4.udp_table;
+	hslot = udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash);
+
+	spin_lock_bh(&hslot->lock);
+	udp_unhash4(udptable, sk);
+	spin_unlock_bh(&hslot->lock);
+}
+
 int udp_disconnect(struct sock *sk, int flags)
 {
 	lock_sock(sk);
+	udp_unhash4_on_disconnect(sk);
 	__udp_disconnect(sk, flags);
 	release_sock(sk);
 	return 0;
@@ -3107,6 +3129,7 @@ int udp_abort(struct sock *sk, int err)
 
 	sk->sk_err = err;
 	sk_error_report(sk);
+	udp_unhash4_on_disconnect(sk);
 	__udp_disconnect(sk, 0);
 
 out:
Signature · 1 line
2.53.0
author maintainer
#139 lore raw

PATCH 139/457 tg3: clean up PHYLIB resources on probe failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Myeonghun Pak <[email protected]>

[ Upstream commit a92e1a412c53dc0d9ad639e7abf8b3fc70a5b6ad ]

tg3_get_invariants() can register an MDIO bus and connect a PHY for USE_PHYLIB devices. If tg3_init_one() later fails, its common error path releases the mappings and netdev without undoing those PHYLIB resources.

Disconnect the PHY and unregister the MDIO bus before the remaining teardown. Guard PHY cleanup with USE_PHYLIB to match tg3_phy_init(), and call tg3_mdio_fini() unconditionally to match tg3_mdio_init(). The existing IS_CONNECTED and MDIOBUS_INITED flags make both helpers safe when initialization only completed partially.

This issue was identified during our ongoing static-analysis research while reviewing kernel code.

Fixes 158d7abdae85 ("tg3: Add mdio bus registration")
Assisted-by OpenAI:GPT-5.6
---
 drivers/net/ethernet/broadcom/tg3.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/ethernet/broadcom/tg3.c +4 -0
index 73a4b569b03e3..caa7a6caa6e2f 100644
@@ -18047,6 +18047,10 @@ static int tg3_init_one(struct pci_dev *pdev,
 	return 0;
 
 err_out_apeunmap:
+	if (tg3_flag(tp, USE_PHYLIB))
+		tg3_phy_fini(tp);
+	tg3_mdio_fini(tp);
+
 	if (tp->aperegs) {
 		iounmap(tp->aperegs);
 		tp->aperegs = NULL;
Signature · 1 line
2.53.0
author maintainer
#140 lore raw

PATCH 140/457 drm/i915/psr: Clear stale sel fetch enable bits on sel fetch disable

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nemesa Garg <[email protected]>

[ Upstream commit 2777ec9852277a06ae68fee0c4f1a32783e4a999 ]

Selective fetch is dropped while pipe CRC is active, and the planes keep their SEL_FETCH_PLANE_CTL / SEL_FETCH_CUR_CTL enable bit set in hardware over that. A plane disabled while selective fetch is off never gets the bit cleared, as the disable path is guarded by enable_psr2_sel_fetch. Once selective fetch comes back the hardware resumes fetching for a plane that is no longer enabled and keeps its DDB range reserved.

Clear the bits as selective fetch is turned off instead. Atomic check has both the old and the new crtc state, so record the transition there and let the plane and cursor arm paths write the registers to 0 for that commit.

v2: Drop the old_crtc_state->hw.active check. [Jouni]

Fixes b1f5279b5981 ("drm/i915/psr: Move plane sel fetch configuration into plane source files")
Assisted-by Copilot:Claude-Opus-5
(cherry picked from commit a4c0e7f80429eda6990960971aebd4e4b9533cc6)
---
 drivers/gpu/drm/i915/display/intel_cursor.c       |  7 +++++--
 .../gpu/drm/i915/display/intel_display_types.h    |  2 ++
 drivers/gpu/drm/i915/display/intel_psr.c          | 15 +++++++++++++++
 .../gpu/drm/i915/display/skl_universal_plane.c    |  9 ++++-----
 4 files changed, 26 insertions(+), 7 deletions(-)
drivers/gpu/drm/i915/display/intel_cursor.c +5 -2
index 52347668f27d6..dad0e0eb0e0c0 100644
@@ -536,7 +536,8 @@ static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch &&
+	    !crtc_state->clear_psr2_sel_fetch)
 		return;
 
 	intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
@@ -569,8 +570,10 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch) {
+		i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
 		return;
+	}
 
 	if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) {
 		if (crtc_state->enable_psr2_su_region_et) {
drivers/gpu/drm/i915/display/intel_display_types.h +2 -0
index 96422641ae441..18e6b01efd380 100644
@@ -1177,6 +1177,8 @@ struct intel_crtc_state {
 	bool has_sel_update;
 	bool enable_psr2_sel_fetch;
 	bool enable_psr2_su_region_et;
+	/* Drop the stale selective fetch enable bits as selective fetch is turned off */
+	bool clear_psr2_sel_fetch;
 	bool req_psr2_sdp_prior_scanline;
 	bool has_panel_replay;
 	bool link_off_after_as_sdp_when_pr_active;
drivers/gpu/drm/i915/display/intel_psr.c +15 -0
index beaa1d62613db..87128104476a3 100644
@@ -2933,6 +2933,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
 {
 	struct intel_display *display = to_intel_display(state);
+	const struct intel_crtc_state *old_crtc_state =
+		intel_atomic_get_old_crtc_state(state, crtc);
 	struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 	struct intel_plane_state *new_plane_state, *old_plane_state;
 	struct intel_plane *plane;
@@ -2945,6 +2947,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 	bool full_update = false, su_area_changed;
 	int i, ret;
 
+	/*
+	 * Selective fetch is not always usable, for instance it is dropped
+	 * while pipe CRC is active. The planes keep their selective fetch
+	 * enable bit set in hardware over that, and a plane disabled while
+	 * selective fetch is off never gets the bit cleared. Once selective
+	 * fetch comes back the hardware would resume fetching for a plane that
+	 * is no longer enabled and keep its DDB range reserved, so have the
+	 * plane update drop the bit for every plane of the pipe as selective
+	 * fetch is turned off.
+	 */
+	crtc_state->clear_psr2_sel_fetch = old_crtc_state->enable_psr2_sel_fetch &&
+		!crtc_state->enable_psr2_sel_fetch;
+
 	if (!crtc_state->enable_psr2_sel_fetch)
 		return 0;
 
drivers/gpu/drm/i915/display/skl_universal_plane.c +4 -5
index 164b7d61c9a31..3dad2da4c3aaf 100644
@@ -885,7 +885,8 @@ static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
+	if (!crtc_state->enable_psr2_sel_fetch &&
+	    !crtc_state->clear_psr2_sel_fetch)
 		return;
 
 	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
@@ -1634,10 +1635,8 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
 	struct intel_display *display = to_intel_display(plane);
 	enum pipe pipe = plane->pipe;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
-		return;
-
-	if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
+	if (crtc_state->enable_psr2_sel_fetch &&
+	    drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
 		intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
 				   SEL_FETCH_PLANE_CTL_ENABLE);
 	else
Signature · 1 line
2.53.0
author maintainer
#141 lore raw

PATCH 141/457 s390/debug: Do not register views for failed static debug areas

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mikhail Zaslonko <[email protected]>

[ Upstream commit 28e29992b034acffc9342df216c06097825ce610 ]

__REGISTER_STATIC_DEBUG_INFO() calls debug_register_view() unconditionally, even when debug_register_static() has failed. In that case _debug_register() was never reached and id->debugfs_root_entry is still NULL, so debugfs_create_file() places the view file in the debugfs root directory. For sclp_err this leaves a /sys/kernel/debug/hex_ascii file with nothing to indicate which debug log it belongs to.

debug_register_static() is not exported and the macro is its only caller, so let it return an error code and skip the view registration when it fails. No debugfs files are created for such an area then.

Reproduce by booting with s390dbf=sclp_err::100000000. The sclp_err registration fails, no s390dbf/sclp_err/ directory is created, and a hex_ascii file appears in the debugfs root instead.

Fixes d72541f94512 ("s390/debug: add early tracing support")
---
 arch/s390/include/asm/debug.h |  8 ++++++--
 arch/s390/kernel/debug.c      | 12 +++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)
arch/s390/include/asm/debug.h +6 -2
index 39d484c597748..ad438d6352c8e 100644
@@ -460,7 +460,11 @@ static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
 #define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view)	\
 static int __init VNAME(var, reg)(void)					\
 {									\
-	debug_register_static(&var, (pages), (areas));			\
+	int rc;								\
+									\
+	rc = debug_register_static(&var, (pages), (areas));		\
+	if (rc)								\
+		return rc;						\
 	debug_register_view(&var, (view));				\
 	return 0;							\
 }									\
@@ -493,7 +497,7 @@ static debug_info_t __refdata var =					\
 static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
 __REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
 
-void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
+int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
 
 #endif /* MODULE */
 
arch/s390/kernel/debug.c +9 -3
index e06abf1dbc218..d193c6fd1ecc7 100644
@@ -948,8 +948,12 @@ EXPORT_SYMBOL(debug_register);
  *
  * Note: This function is called automatically via an initcall generated by
  *	 DEFINE_STATIC_DEBUG_INFO.
+ *
+ * Return:
+ * - 0 on success
+ * - negative error code on failure
  */
-void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
+int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 {
 	unsigned long flags;
 	debug_info_t *copy;
@@ -957,7 +961,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 	if (!initialized) {
 		pr_err("Tried to register debug feature %s too early\n",
 		       id->name);
-		return;
+		return -EINVAL;
 	}
 
 	debug_get_param(id->name, &id->level, &pages_per_area);
@@ -973,7 +977,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 		id->active_entries = NULL;
 		raw_spin_unlock_irqrestore(&id->lock, flags);
 
-		return;
+		return -ENOMEM;
 	}
 
 	/* Replace static trace area with dynamic copy. */
@@ -991,6 +995,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
 	mutex_lock(&debug_mutex);
 	_debug_register(id);
 	mutex_unlock(&debug_mutex);
+
+	return 0;
 }
 
 /* Remove debugfs entries. */
Signature · 1 line
2.53.0
author maintainer
#142 lore raw

PATCH 142/457 s390/debug: Fix NULL pointer dereference in debug_info_copy()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mikhail Zaslonko <[email protected]>

[ Upstream commit 012bfcd5a51082d5a65f096dfb9ca652b5267965 ]

When debug_register_static() fails, it clears areas, active_pages and active_entries but leaves the area bounds unchanged. Copying such an area, either by opening its view file or via debug_dump(), makes debug_info_copy() dereference the NULL pointers.

Skip the copy loop when the source has no areas.

---
 arch/s390/kernel/debug.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/s390/kernel/debug.c +2 -1
index d193c6fd1ecc7..71c966f4c5d03 100644
@@ -432,7 +432,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
 		debug_info_free(rc);
 	} while (1);
 
-	if (mode == NO_AREAS)
+	/* debug_register_static() failure leaves areas NULL, bounds intact */
+	if (mode == NO_AREAS || !in->areas)
 		goto out;
 
 	for (i = 0; i < in->nr_areas; i++) {
Signature · 1 line
2.53.0
author maintainer
#143 lore raw

PATCH 143/457 net: spacemit: clear TX descriptor on fragment mapping failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Muhammad Bilal <[email protected]>

[ Upstream commit 2d14720beb58870b15a52b236c3ab0be0e06e915 ]

emac_tx_mem_map() writes TX_DESC_0_OWN into the ring descriptor for every slot beyond old_head as soon as that slot's memset()'d local copy is committed with "*tx_desc_addr = tx_desc", i.e. before the buffers for that slot have necessarily all been mapped successfully. If emac_tx_map_frag() then fails on a later fragment, the err_free_skb path calls emac_free_tx_buf() to unmap and drop the skb, but leaves the already-written descriptor memory untouched, and tx_ring->head is never advanced past old_head (the "tx_ring->head = head" store is skipped by the goto).

So a slot between old_head and the rolled-back head can be left with TX_DESC_0_OWN set and buffer_addr_{1,2} pointing at DMA mappings that emac_free_tx_buf() just tore down, while software considers that slot free again. The next successful emac_tx_mem_map() call only rebuilds old_head itself; if the DMA engine auto-advances into the following descriptor once it finishes old_head's packet, it will fetch that stale, already-unmapped address.

emac_tx_clean_desc() already treats emac_free_tx_buf() and clearing the descriptor as a pair when reclaiming completed descriptors; do the same in the mapping failure path.

---
 drivers/net/ethernet/spacemit/k1_emac.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/spacemit/k1_emac.c +3 -0
index f7f16397a2c2a..d641ac26a1e86 100644
@@ -803,6 +803,9 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
 	while (i != head) {
 		emac_free_tx_buf(priv, i);
 
+		tx_desc_addr = &((struct emac_desc *)tx_ring->desc_addr)[i];
+		memset(tx_desc_addr, 0, sizeof(*tx_desc_addr));
+
 		if (++i == tx_ring->total_cnt)
 			i = 0;
 	}
Signature · 1 line
2.53.0
author maintainer
#144 lore raw

PATCH 144/457 net: ethernet: ti: netcp: fix pm_runtime usage counter leak on error

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: bui duc phuc <[email protected]>

[ Upstream commit ac4334522e4ba4a3b6710dd5d4cc98092824b8ca ]

pm_runtime_get_sync() leaves the runtime PM usage counter incremented even when it fails, but the error path in netcp_probe() does not call pm_runtime_put_noidle() to balance it, leaking a reference each time resume fails.

Use pm_runtime_resume_and_get() instead, which automatically drops the usage counter on failure, fixing the leak.

Fixes 84640e27f230 ("net: netcp: Add Keystone NetCP core ethernet driver")
---
 drivers/net/ethernet/ti/netcp_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/ti/netcp_core.c +1 -1
index eb8fc2ed05f45..4f9e20468bbbf 100644
@@ -2225,7 +2225,7 @@ static int netcp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	pm_runtime_enable(&pdev->dev);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0) {
 		dev_err(dev, "Failed to enable NETCP power-domain\n");
 		pm_runtime_disable(&pdev->dev);
Signature · 1 line
2.53.0
author maintainer
#145 lore raw

PATCH 145/457 genetlink: report the real command id for dump-only ops in policy dumps

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <[email protected]>

[ Upstream commit 261e8a37ecbaf462cdf9c336d2b2f5056088401a ]

The op-to-policy map a CTRL_CMD_GETPOLICY dump returns is the only way for userspace to find out which policy index belongs to which command. ctrl_dumppolicy_put_op() tags the nest with doit->cmd, but an op which only has a dumpit has no doit and every path which fills the split ops in zeroes it out, so those entries all claim to be command 0. nlctrl's own CTRL_CMD_GETPOLICY and NETDEV_CMD_QSTATS_GET are both in that group:

[{'family-id': 16, 'op-policy': {'do': 0, 'dump': 0, 'op-id': 3}},
{'family-id': 16, 'op-policy': {'dump': 1, 'op-id': 0}},

ctrl_fill_info() gets this right - it uses the iterator's cmd for CTRL_ATTR_OP_ID - so the two introspection interfaces of the same family contradict each other today.

Pass the command in rather than reconstructing it from doit->cmd | dumpit->cmd inside the helper, both callers already have it.

Fixes 26588edbef60 ("genetlink: support split policies in ctrl_dumppolicy_put_op()")
---
 net/netlink/genetlink.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
net/netlink/genetlink.c +5 -3
index 41d37442f1868..5cc1037d4917e 100644
@@ -1656,7 +1656,7 @@ static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
 }
 
 static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
-				  struct netlink_callback *cb,
+				  struct netlink_callback *cb, u32 cmd,
 				  struct genl_split_ops *doit,
 				  struct genl_split_ops *dumpit)
 {
@@ -1677,7 +1677,7 @@ static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
 	if (!nest_pol)
 		goto err;
 
-	nest_op = nla_nest_start(skb, doit->cmd);
+	nest_op = nla_nest_start(skb, cmd);
 	if (!nest_op)
 		goto err;
 
@@ -1721,7 +1721,8 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 						      &doit, &dumpit)))
 				return -ENOENT;
 
-			if (ctrl_dumppolicy_put_op(skb, cb, &doit, &dumpit))
+			if (ctrl_dumppolicy_put_op(skb, cb, ctx->op,
+						   &doit, &dumpit))
 				return skb->len;
 
 			/* done with the per-op policy index list */
@@ -1730,6 +1731,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 
 		while (ctx->dump_map) {
 			if (ctrl_dumppolicy_put_op(skb, cb,
+						   ctx->op_iter->cmd,
 						   &ctx->op_iter->doit,
 						   &ctx->op_iter->dumpit))
 				return skb->len;
Signature · 1 line
2.53.0
author maintainer
#146 lore raw

PATCH 146/457 net: pcs: xpcs: fix clock reference leak on xpcs_init_clks failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Coia Prant <[email protected]>

[ Upstream commit 9892d71cf0ce3ff3d4fed2d9a3968fd4feb1c918 ]

xpcs_init_clks() takes references with clk_bulk_get_optional() and then enables them with clk_bulk_prepare_enable(). If the enable step fails, the function returns without dropping the references.

xpcs_create() handles the failure through out_free_data, which calls xpcs_free_data() but never xpcs_clear_clks(), so the clk references are leaked.

Add the missing clk_bulk_put() on the enable failure path. The prepare/enable side is already rolled back by clk_bulk_prepare_enable() itself.

Fixes f6bb3e9d98c2 ("net: pcs: xpcs: Add Synopsys DW xPCS platform device driver")
---
 drivers/net/pcs/pcs-xpcs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/pcs/pcs-xpcs.c +3 -1
index 0337e2bcc0125..b415b93d77c15 100644
@@ -1545,8 +1545,10 @@ static int xpcs_init_clks(struct dw_xpcs *xpcs)
 		return dev_err_probe(dev, ret, "Failed to get clocks\n");
 
 	ret = clk_bulk_prepare_enable(DW_XPCS_NUM_CLKS, xpcs->clks);
-	if (ret)
+	if (ret) {
+		clk_bulk_put(DW_XPCS_NUM_CLKS, xpcs->clks);
 		return dev_err_probe(dev, ret, "Failed to enable clocks\n");
+	}
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#147 lore raw

PATCH 147/457 PM: hibernate: Freeze kernel threads after image preallocation

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Schmaus <[email protected]>

[ Upstream commit 41112a787f9182c7f2d27122817861e3f22ef928 ]

Commit 783c81098445 ("PM: hibernate: call preallocate_image() after freeze prepare") moved hibernate_preallocate_memory() after dpm_prepare() so that device drivers have the opportunity to release pinned/unswappable memory during their ->prepare() callback before memory is preallocated for the snapshot image.

However, that commit also placed hibernate_preallocate_memory() after freeze_kernel_threads(). While it was assumed during review that swap I/O submitted via submit_bio() is synchronous and would not depend on frozen kernel threads, this does not hold in practice. Calling hibernate_preallocate_memory() with kernel threads frozen leads to intermittent deadlocks during hibernation.

Inside hibernate_preallocate_memory(), shrink_all_memory() is invoked with .may_writepage = 1 and .may_swap = 1 to aggressively reclaim and swap out pages. Any writeback or swap I/O that relies on freezable kernel threads, block device helpers, or WQ_FREEZABLE workqueues (such as those in storage drivers, device mapper, or filesystems) deadlocks waiting on tasks that are stuck in the refrigerator.

Fix this by reordering hibernation_snapshot():
1. Call dpm_prepare(PMSG_FREEZE) first, allowing device drivers to release pinned resources while kernel threads are still active.
2. Call hibernate_preallocate_memory() second, performing page reclaim and swapout while storage layers, workqueues, and kernel threads are alive.
3. Call freeze_kernel_threads() third, only after all memory preallocation and swap I/O have completed.

Additionally, restore the call to swsusp_free() in the cleanup path so that preallocated image memory is properly freed if freeze_kernel_threads() fails or if TEST_FREEZER is enabled.

---
 kernel/power/hibernate.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)
kernel/power/hibernate.c +14 -12
index d2479c69d71a4..c13f68ab7f6e0 100644
@@ -408,9 +408,18 @@ int hibernation_snapshot(int platform_mode)
 	if (error)
 		goto Close;
 
+	error = dpm_prepare(PMSG_FREEZE);
+	if (error)
+		goto Complete;
+
+	/* Preallocate image memory before freezing kernel threads and shutting down devices. */
+	error = hibernate_preallocate_memory();
+	if (error)
+		goto Complete;
+
 	error = freeze_kernel_threads();
 	if (error)
-		goto Close;
+		goto Cleanup;
 
 	if (hibernation_test(TEST_FREEZER)) {
 
@@ -422,15 +431,6 @@ int hibernation_snapshot(int platform_mode)
 		goto Thaw;
 	}
 
-	error = dpm_prepare(PMSG_FREEZE);
-	if (error)
-		goto Complete;
-
-	/* Preallocate image memory before shutting down devices. */
-	error = hibernate_preallocate_memory();
-	if (error)
-		goto Complete;
-
 	console_suspend_all();
 	pm_restrict_gfp_mask();
 
@@ -464,10 +464,12 @@ int hibernation_snapshot(int platform_mode)
 	platform_end(platform_mode);
 	return error;
 
- Complete:
-	dpm_complete(PMSG_RECOVER);
  Thaw:
 	thaw_kernel_threads();
+ Cleanup:
+	swsusp_free();
+ Complete:
+	dpm_complete(PMSG_RECOVER);
 	goto Close;
 }
 
Signature · 1 line
2.53.0
author maintainer
#148 lore raw

PATCH 148/457 thermal: gov_step_wise: Fix stale mitigation vote with non-zero lower bounds

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Manaf Meethalavalappu Pallikunhi <[email protected]>

[ Upstream commit ec0d89150a9381d591344a9f6f5428655c227a7f ]

When two or more thermal zones bind to a common cooling device and one zone uses a non-zero instance->lower value, there is a bug where the instance holds a stale mitigation vote even after its trip is cleared.

Problem scenario:
- thermal-zone1: Trip at 50°C, cooling-map with lower=0
- thermal-zone2: Trip at 55°C, cooling-map with lower=2
- Both zones share the same cooling device (e.g., CPU)

Issue flow:
1. Both trips trigger, zone1 requests state 5, zone2 also mitigates
2. Zone2 trip clears (temp < 53°C due to hysteresis)
3. When throttle=false and trend=THERMAL_TREND_DROPPING:
- Current code checks: if (cur_state <= instance->lower) return THERMAL_NO_TARGET
- Since cur_state (5) > instance->lower (2),

     it returns instance->lower (2)

- This is the BUG where it returns instance->lower even though trip is cleared
4. Zone2's passive polling stops (tz->passive reaches 0) - no more updates for zone2
5. Zone2's stale vote of 2 persists indefinitely
6. Even when zone1 wants to reduce cooling to state, the cooling device cannot go below state 2 due to zone2's stale vote

When a trip is cleared (throttle == false), always return THERMAL_NO_TARGET instead of instance->lower. Remove the unnecessary check comparing cur_state with instance->lower. Since passive polling is already deactivated when the trip is cleared, the instance should always be deactivated regardless of its current cooling state. This ensures that instances with non-zero lower bounds do not retain stale mitigation votes after their trips are cleared.

---
 drivers/thermal/gov_step_wise.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/thermal/gov_step_wise.c +4 -6
index ea277c466d8d2..4fa4377f0d428 100644
@@ -65,14 +65,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
 				     min(instance->lower + 1, instance->upper),
 				     instance->upper);
 	} else if (trend == THERMAL_TREND_DROPPING) {
-		if (cur_state <= instance->lower)
-			return THERMAL_NO_TARGET;
-
 		/*
-		 * If 'throttle' is false, no mitigation is necessary, so
-		 * request the lower state for this instance.
+		 * If 'throttle' is false, no mitigation is necessary and
+		 * passive polling is already deactivated, so clear this
+		 * instance state by returning THERMAL_NO_TARGET.
 		 */
-		return instance->lower;
+		return THERMAL_NO_TARGET;
 	}
 
 	return instance->target;
Signature · 1 line
2.53.0
author maintainer
#149 lore raw

PATCH 149/457 bpf: Fix bounds check for skb-backed dynptrs

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emil Tsalapatis <[email protected]>

[ Upstream commit ed6eec97b534979dcf28b40c389cee57bd6561d4 ]

The skb_pointer_if_linear() function checks whether a memory region of length len starting at offset off into the skb is in the linear area, and returns a pointer to the region if so. The check currently subtracts between skb_headlen and offset of the check, and since skb_headlen is unsigned the subtraction can underflow. This causes the bounds check to spuriously pass and generate an arbitrary pointer of the form *(skb->data + off).

The only user of this helper is currently skb-backed BPF dynptr code. Returning the wrong pointer leads to the dynptr erroneously being backed with invalid memory.

Ensure the subtraction cannot underflow, and fail the check if it would. Use u64 arithmetic to also prevent overflow when calculating (skb_headlen(skb) - off) since off is unsigned.

---
 include/linux/skbuff.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
include/linux/skbuff.h +4 -1
index f7dd3db9459c6..039f3c38743ca 100644
@@ -4372,7 +4372,10 @@ skb_header_pointer_careful(const struct sk_buff *skb, int offset,
 static inline void * __must_check
 skb_pointer_if_linear(const struct sk_buff *skb, int offset, int len)
 {
-	if (likely(skb_headlen(skb) - offset >= len))
+	unsigned int uoffset = (unsigned int)offset;
+
+	if (likely(uoffset <= skb_headlen(skb) &&
+		   (unsigned int)len <= skb_headlen(skb) - uoffset))
 		return skb->data + offset;
 	return NULL;
 }
Signature · 1 line
2.53.0
author maintainer
#150 lore raw

PATCH 150/457 bpf: Fix bpf_sock context code generation

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emil Tsalapatis <[email protected]>

[ Upstream commit 4a4852376e3a2727ea40e61143d6d7c22bb6dfad ]

Currently, the ctx access code reads the rx_queue_mapping field with either a 4-byte or 2-byte load. The rest of the bits in the register are marked known zero by the verifier. However, the emitted ctx access code places in the register on certain the special value (-1) using BPF_MOV_IMM64, which gets sign-extended to turn on all the bits in the register. By shifting this value right, the program ends up with a value at runtime above what the verifier assumes is possible.

Fix this by ensuring the read value is as wide as the assumed size. Use MOV32 instructions instead of MOV64 instructions to keep the upper bits zero as assumed by the verifier. Also properly report the size of the destination variable (the bpf_sock field, 4 bytes) instead of the source (the socket field, 2 bytes).

---
 net/core/filter.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
net/core/filter.c +4 -3
index 70f19ef093ee1..1acc53dd04efc 100644
@@ -10403,11 +10403,12 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
 				       target_size));
 		*insn++ = BPF_JMP_IMM(BPF_JNE, si->dst_reg, NO_QUEUE_MAPPING,
 				      1);
-		*insn++ = BPF_MOV64_IMM(si->dst_reg, -1);
+		*insn++ = BPF_MOV32_IMM(si->dst_reg, -1);
 #else
-		*insn++ = BPF_MOV64_IMM(si->dst_reg, -1);
-		*target_size = 2;
+		*insn++ = BPF_MOV32_IMM(si->dst_reg, -1);
 #endif
+		*target_size = sizeof_field(struct bpf_sock, rx_queue_mapping);
+
 		break;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#151 lore raw

PATCH 151/457 bpf: Reject pkt arguments in mutating subprogs

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emil Tsalapatis <[email protected]>

[ Upstream commit a6c1edfbe240e4377038a0e1d233ad81fde9a21b ]

The verifier tracks changes in how PTR_TO_PACKET registers' bounds are modified across subprog boundaries. PTR_TO_PACKET registers are actually passed as PTR_TO_MEM, which is assumed valid for the entire call. This is not the case with packet memory, where a pskb_* call may invalidate its memory region.

Reject BPF code that passes PTR_TO_PACKET pointers to subprogs that may mutate a packet. We cannot pass the pointer as a true PTR_TO_PACKET because we would also need to somehow pass the PTR_TO_PACKET_META or PTR_TO_PACKET_END to the subprog. Since we cannot avoid representing the pointer in the subprog as PTR_TO_MEM, only permit it if the subprog is guaranteed not to mutate the packet.

---
 kernel/bpf/verifier.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
kernel/bpf/verifier.c +10 -0
index cb523cc5465dd..ccf735d74dc82 100644
@@ -9264,6 +9264,16 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
 				return ret;
 			if (check_mem_reg(env, reg, argno, arg->mem_size))
 				return -EINVAL;
+			/*
+			 * PTR_TO_PACKET get passed as PTR_TO_MEM, preventing
+			 * us from adjusting bounds tracking info.
+			 */
+			if ((reg_is_pkt_pointer_any(reg) || reg_is_dynptr_slice_pkt(reg)) &&
+			    sub->changes_pkt_data) {
+				bpf_log(log, "%s is a packet pointer, but func#%d may change packet data\n",
+						reg_arg_name(env, argno), subprog);
+				return -EINVAL;
+			}
 			if (!(arg->arg_type & PTR_MAYBE_NULL) &&
 			    (type_may_be_null(reg->type) || bpf_register_is_null(reg))) {
 				bpf_log(log, "%s is expected to be non-NULL\n",
Signature · 1 line
2.53.0
author maintainer
#152 lore raw

PATCH 152/457 bpf, sockmap: Reject max_entries > INT_MAX in sock_map_alloc

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhao Gongyi <[email protected]>

[ Upstream commit 814a81c842bd88f6bd8a4ce550d560df071a5d03 ]

sock_map_alloc() only rejects max_entries == 0 and otherwise allows any u32 value. sock_map_free() then walks the sks[] array with a signed int iterator:

	int i;
	for (i = 0; i < stab->map.max_entries; i++)
		struct sock **psk = &stab->sks[i];

When a SOCKMAP is created with max_entries = 0xffffffff (UINT_MAX), the allocation of 32 GiB can succeed on large-memory hosts. During free the counter reaches 0x80000000, wraps to INT_MIN, is sign-extended by movslq and turned into a ~16 GiB negative offset from stab->sks, pointing far below the allocation.

The faulting access is an xchg() write in sock_map_free(). Without KASAN, the same out-of-bounds write can fault on an unmapped vmalloc page or corrupt an unrelated allocation if that vmalloc address is populated. On a KASAN kernel with CONFIG_KASAN_VMALLOC=y, the shadow check for that address hits an unmapped shadow page and oopses first:

  BUG: unable to handle page fault for address: fffff521b59c5a00
  RIP: 0010:kasan_check_range+0x107/0x190
  Call Trace:
   sock_map_free+0x93/0x190
   map_create+0x68d/0xb30
   __sys_bpf+0x21e/0x2e70

Vmcore confirmed stab->map.max_entries == 0xffffffff, stab->sks == 0xffffc911ace2d000, and the faulting address sks + (s64)INT_MIN * 8 exactly at 0xffffc90dace2d000. The same buggy path is reached on the normal close()/bpf_map_free_deferred() path whenever such a map is destroyed.

sock_map_alloc() used to bound its allocation size through bpf_map_charge_init(), but the bound was dropped when rlimit-based memory accounting was removed. Reject max_entries > INT_MAX at creation time so the signed iterator in sock_map_free() never sees a value that would overflow.

Triggered by syzkaller and reproduced on both a 6.6-based KASAN kernel and the upstream v7.3-rc2 kernel.

Fixes 0d2c4f964050 ("bpf: Eliminate rlimit-based memory accounting for sockmap and sockhash maps")
---
 net/core/sock_map.c | 1 +
 1 file changed, 1 insertion(+)
net/core/sock_map.c +1 -0
index 9efbd8ca7db83..09d20318a0eae 100644
@@ -41,6 +41,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 	struct bpf_stab *stab;
 
 	if (attr->max_entries == 0 ||
+	    attr->max_entries > INT_MAX ||
 	    attr->key_size    != 4 ||
 	    (attr->value_size != sizeof(u32) &&
 	     attr->value_size != sizeof(u64)) ||
Signature · 1 line
2.53.0
author maintainer
#153 lore raw

PATCH 153/457 firewire: cdev: fix back-transition for iso_resource_auto client resource

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Takashi Sakamoto <[email protected]>

[ Upstream commit c6b51091cafff9ce6c03c1416aa13864d17ab97c ]

The todo member of iso_resource_auto structure represents the state of the client resource and normally transitions in the following order:

    ISO_RES_AUTO_ALLOC -> ISO_RES_AUTO_REALLOC -> ISO_RES_AUTO_DEALLOC

However, concurrent access from the work item and the file descriptor release function can cause the state to transition backwards from ISO_RES_AUTO_DEALLOC to ISO_RES_AUTO_REALLOC.

Prevent the back-transition by checking the current state before updating it in the work item.

Fixes fcabbf40fae5 ("firewire: core: move allocation/reallocation paths into specific branch after isoc resource management in cdev")
---
 drivers/firewire/core-cdev.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/firewire/core-cdev.c +4 -2
index e49d8a58be09e..664952a67a11a 100644
@@ -1397,8 +1397,10 @@ static void iso_resource_auto_work(struct work_struct *work)
 		} else {
 			// Transit from allocation to reallocation, except if the client requested
 			// deallocation in the meantime.
-			scoped_guard(spinlock_irq,  &client->lock)
-				r->todo = ISO_RES_AUTO_REALLOC;
+			scoped_guard(spinlock_irq,  &client->lock) {
+				if (r->todo == ISO_RES_AUTO_ALLOC)
+					r->todo = ISO_RES_AUTO_REALLOC;
+			}
 
 			if (channel >= 0)
 				r->params.channels_mask = BIT_ULL(channel);
Signature · 1 line
2.53.0
author maintainer
#154 lore raw

PATCH 154/457 net/mlx5: Bridge, dont fail switchdev events of sibling eswitch ports

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bernardo Soares <[email protected]>

[ Upstream commit 35e6f970f553954d92ba20afa885139a8e7dd0d7 ]

mlx5 registers the bridge offload switchdev notifiers once per eswitch instance, but the notifier chains are global, so every instance sees every event and must filter out the ones that aren't its own. The existing filter, mlx5_esw_bridge_dev_same_hw(), only checks that the event netdevice sits on the same HCA - intentional for merged eswitch, where one bridge can span representors of several eswitches on one HCA - but same-HCA doesn't mean the instance actually has that port:
peer ports are only created reactively from NETDEV_CHANGEUPPER, so an instance brought up after a sibling PF's port was already enslaved has none. The port object and attribute handlers claim the event anyway once same-HW passes, then fail the port lookup and return -EINVAL, which gets reported to user space even though the owning instance already handled it (e.g. "bridge vlan add ... RTNETLINK answers:
Invalid argument"). Fix by filtering on the tracked port instead.

The same gap exists in the generic recursive lower-device walk used by attribute changes on a bridge with more than one representor enslaved
directly: mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get() is entered with the bridge master netdevice, falls through to its generic netdev_for_each_lower_dev() loop, and returns as soon as the recursion into any one lower device yields a non-NULL rep - the underlying base case, mlx5_esw_bridge_rep_vport_num_vhca_id_get(), only checks mlx5_esw_bridge_dev_same_hw(), not ownership by the calling instance's br_offloads. mlx5_esw_bridge_lag_rep_get(), used for the LAG-master case, already filters on mlx5_esw_bridge_dev_same_esw() per candidate and so cannot select a sibling's rep; it is not the source of this bug. On a merged-eswitch HCA with a bridge spanning representors of more than one eswitch instance directly, the walk can return a sibling's rep instead of continuing to the one the calling instance actually owns, so the attribute change fails the same way as above. Fix by checking mlx5_esw_bridge_port_exists() at the point each rep is picked, same as the previous fix did for the notifier filter.

Fixes c358ea1741bc ("net/mlx5: Bridge, allow merged eswitch connectivity")
Cc Vlad Buslov <[email protected]>
Cc Saeed Mahameed <[email protected]>
---
 .../mellanox/mlx5/core/en/rep/bridge.c        | 45 +++++++++++++++----
 .../ethernet/mellanox/mlx5/core/esw/bridge.c  |  6 +++
 .../ethernet/mellanox/mlx5/core/esw/bridge.h  |  2 +
 3 files changed, 44 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c +36 -9
index baac38bece14a..4b7b0a0fc2b2f 100644
@@ -85,9 +85,16 @@ mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct m
 	struct net_device *lower_dev;
 	struct list_head *iter;
 
-	if (netif_is_lag_master(dev) || mlx5e_eswitch_rep(dev))
-		return mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, esw, vport_num,
-								 esw_owner_vhca_id);
+	if (netif_is_lag_master(dev) || mlx5e_eswitch_rep(dev)) {
+		struct net_device *rep;
+
+		rep = mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, esw, vport_num,
+								esw_owner_vhca_id);
+		if (rep && !mlx5_esw_bridge_port_exists(*vport_num, *esw_owner_vhca_id,
+							esw->br_offloads))
+			return NULL;
+		return rep;
+	}
 
 	netdev_for_each_lower_dev(dev, lower_dev, iter) {
 		struct net_device *rep;
@@ -104,6 +111,28 @@ mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct m
 	return NULL;
 }
 
+static bool mlx5_esw_bridge_rep_port_lookup(struct net_device *dev,
+					    struct mlx5_esw_bridge_offloads *br_offloads,
+					    u16 *vport_num, u16 *esw_owner_vhca_id)
+{
+	if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, vport_num,
+						       esw_owner_vhca_id))
+		return false;
+
+	return mlx5_esw_bridge_port_exists(*vport_num, *esw_owner_vhca_id, br_offloads);
+}
+
+static bool mlx5_esw_bridge_lower_rep_port_lookup(struct net_device *dev,
+						  struct mlx5_esw_bridge_offloads *br_offloads,
+						  u16 *vport_num, u16 *esw_owner_vhca_id)
+{
+	if (!mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev, br_offloads->esw, vport_num,
+							     esw_owner_vhca_id))
+		return false;
+
+	return mlx5_esw_bridge_port_exists(*vport_num, *esw_owner_vhca_id, br_offloads);
+}
+
 static bool mlx5_esw_bridge_is_local(struct net_device *dev, struct net_device *rep,
 				     struct mlx5_eswitch *esw)
 {
@@ -218,8 +247,7 @@ mlx5_esw_bridge_port_obj_add(struct net_device *dev,
 	u16 vport_num, esw_owner_vhca_id;
 	int err;
 
-	if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
-						       &esw_owner_vhca_id))
+	if (!mlx5_esw_bridge_rep_port_lookup(dev, br_offloads, &vport_num, &esw_owner_vhca_id))
 		return 0;
 
 	port_obj_info->handled = true;
@@ -251,8 +279,7 @@ mlx5_esw_bridge_port_obj_del(struct net_device *dev,
 	const struct switchdev_obj_port_mdb *mdb;
 	u16 vport_num, esw_owner_vhca_id;
 
-	if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
-						       &esw_owner_vhca_id))
+	if (!mlx5_esw_bridge_rep_port_lookup(dev, br_offloads, &vport_num, &esw_owner_vhca_id))
 		return 0;
 
 	port_obj_info->handled = true;
@@ -283,8 +310,8 @@ mlx5_esw_bridge_port_obj_attr_set(struct net_device *dev,
 	u16 vport_num, esw_owner_vhca_id;
 	int err = 0;
 
-	if (!mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num,
-							     &esw_owner_vhca_id))
+	if (!mlx5_esw_bridge_lower_rep_port_lookup(dev, br_offloads, &vport_num,
+						   &esw_owner_vhca_id))
 		return 0;
 
 	port_attr_info->handled = true;
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +6 -0
index 87b5fd3495945..ac90ccda12722 100644
@@ -1686,6 +1686,12 @@ int mlx5_esw_bridge_vport_peer_unlink(struct net_device *br_netdev, u16 vport_nu
 					    extack);
 }
 
+bool mlx5_esw_bridge_port_exists(u16 vport_num, u16 esw_owner_vhca_id,
+				 struct mlx5_esw_bridge_offloads *br_offloads)
+{
+	return mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads);
+}
+
 int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, u16 flags,
 				  struct mlx5_esw_bridge_offloads *br_offloads,
 				  struct netlink_ext_ack *extack)
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h +2 -0
index d6f5391619930..a4e59cc210894 100644
@@ -80,6 +80,8 @@ int mlx5_esw_bridge_vlan_proto_set(u16 vport_num, u16 esw_owner_vhca_id, u16 pro
 				   struct mlx5_esw_bridge_offloads *br_offloads);
 int mlx5_esw_bridge_mcast_set(u16 vport_num, u16 esw_owner_vhca_id, bool enable,
 			      struct mlx5_esw_bridge_offloads *br_offloads);
+bool mlx5_esw_bridge_port_exists(u16 vport_num, u16 esw_owner_vhca_id,
+				 struct mlx5_esw_bridge_offloads *br_offloads);
 int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, u16 flags,
 				  struct mlx5_esw_bridge_offloads *br_offloads,
 				  struct netlink_ext_ack *extack);
Signature · 1 line
2.53.0
author maintainer
#155 lore raw

PATCH 155/457 net/mlx5: Bridge, dont fail unlink of untracked/unsupported peer ports

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bernardo Soares <[email protected]>

[ Upstream commit 2e51097c982b7b22382fda3202ba29f0ea33e8c0 ]

mlx5_esw_bridge_vport_unlink() returns -EINVAL when the port isn't tracked by this instance's br_offloads. This is reachable on a sibling instance that registered its notifier after the port was already
enslaved: it never saw the NETDEV_CHANGEUPPER link event, so peer_link() never created a peer port for it, but it does see the later unlink event and fails. Return 0 instead, and give mlx5_esw_bridge_vport_peer_unlink() the same merged_eswitch capability guard peer_link() already has, since without it peer_link() likewise never creates a port to unlink.

This also matters beyond the -EINVAL itself:
mlx5_esw_bridge_switchdev_port_event() runs on the per-netns netdev_chain, and notifier_from_errno(-EINVAL) sets NOTIFY_STOP_MASK, which call_netdevice_notifiers_info() checks to stop calling further listeners on that chain - so the old -EINVAL silently dropped the event for any listener registered later on the same chain, even though none of it was visible to user space since __netdev_upper_dev_unlink() discards the return value.

Fixes c358ea1741bc ("net/mlx5: Bridge, allow merged eswitch connectivity")
---
 drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +5 -4
index ac90ccda12722..b4cf3c5ac0dde 100644
@@ -1649,10 +1649,8 @@ int mlx5_esw_bridge_vport_unlink(struct net_device *br_netdev, u16 vport_num,
 	int err;
 
 	port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads);
-	if (!port) {
-		NL_SET_ERR_MSG_MOD(extack, "Port is not attached to any bridge");
-		return -EINVAL;
-	}
+	if (!port)
+		return 0;
 	if (port->bridge->ifindex != br_netdev->ifindex) {
 		NL_SET_ERR_MSG_MOD(extack, "Port is attached to another bridge");
 		return -EINVAL;
@@ -1682,6 +1680,9 @@ int mlx5_esw_bridge_vport_peer_unlink(struct net_device *br_netdev, u16 vport_nu
 				      struct mlx5_esw_bridge_offloads *br_offloads,
 				      struct netlink_ext_ack *extack)
 {
+	if (!MLX5_CAP_ESW(br_offloads->esw->dev, merged_eswitch))
+		return 0;
+
 	return mlx5_esw_bridge_vport_unlink(br_netdev, vport_num, esw_owner_vhca_id, br_offloads,
 					    extack);
 }
Signature · 1 line
2.53.0
author maintainer
#156 lore raw

PATCH 156/457 sctp: hold asoc or transport before mod_timer() in timer handlers

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit cae23ae3f7887a1cf8a75da38edcebeef695040f ]

Take the association or transport reference before rearming a timer in the timer handlers.

The existing code calls mod_timer() before taking the reference needed by the rearmed timer without holding the sock lock. This creates a race with timer cleanup: if the timer is deleted after mod_timer() returns but before the reference is taken, the cleanup path can drop the timer's reference and destroy the transport or association. The timer handler then takes a reference on the already freed object and eventually drops it, causing a refcount underflow.

Hold the object before mod_timer() and drop the reference if mod_timer() reports that the timer was already pending in timer handlers. Apply the same ordering to the proto-unreachable path, which can rearm a transport timer outside the timer handlers without holding the sock lock.

---
 net/sctp/input.c         |  7 ++++---
 net/sctp/sm_sideeffect.c | 37 ++++++++++++++++++++++---------------
 2 files changed, 26 insertions(+), 18 deletions(-)
net/sctp/input.c +4 -3
index 864741fae4187..9494cfa51106c 100644
@@ -436,9 +436,10 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
 		if (timer_pending(&t->proto_unreach_timer))
 			return;
 		else {
-			if (!mod_timer(&t->proto_unreach_timer,
-						jiffies + (HZ/20)))
-				sctp_transport_hold(t);
+			sctp_transport_hold(t);
+			if (mod_timer(&t->proto_unreach_timer,
+				      jiffies + (HZ / 20)))
+				sctp_transport_put(t);
 		}
 	} else {
 		struct net *net = sock_net(sk);
net/sctp/sm_sideeffect.c +22 -15
index 0d99b7e8c082f..35f540fb15fc1 100644
@@ -244,8 +244,9 @@ void sctp_generate_t3_rtx_event(struct timer_list *t)
 		pr_debug("%s: sock is busy\n", __func__);
 
 		/* Try again later.  */
-		if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->T3_rtx_timer, jiffies + (HZ / 20)))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
@@ -280,8 +281,9 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
 			 timeout_type);
 
 		/* Try again later.  */
-		if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20)))
-			sctp_association_hold(asoc);
+		sctp_association_hold(asoc);
+		if (mod_timer(&asoc->timers[timeout_type], jiffies + (HZ / 20)))
+			sctp_association_put(asoc);
 		goto out_unlock;
 	}
 
@@ -378,8 +380,9 @@ void sctp_generate_heartbeat_event(struct timer_list *t)
 		pr_debug("%s: sock is busy\n", __func__);
 
 		/* Try again later.  */
-		if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->hb_timer, jiffies + (HZ / 20)))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
@@ -388,8 +391,9 @@ void sctp_generate_heartbeat_event(struct timer_list *t)
 	timeout = sctp_transport_timeout(transport);
 	if (elapsed < timeout) {
 		elapsed = timeout - elapsed;
-		if (!mod_timer(&transport->hb_timer, jiffies + elapsed))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->hb_timer, jiffies + elapsed))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
@@ -422,9 +426,10 @@ void sctp_generate_proto_unreach_event(struct timer_list *t)
 		pr_debug("%s: sock is busy\n", __func__);
 
 		/* Try again later.  */
-		if (!mod_timer(&transport->proto_unreach_timer,
-				jiffies + (HZ/20)))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->proto_unreach_timer,
+			      jiffies + (HZ / 20)))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
@@ -458,8 +463,9 @@ void sctp_generate_reconf_event(struct timer_list *t)
 		pr_debug("%s: sock is busy\n", __func__);
 
 		/* Try again later.  */
-		if (!mod_timer(&transport->reconf_timer, jiffies + (HZ / 20)))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->reconf_timer, jiffies + (HZ / 20)))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
@@ -495,8 +501,9 @@ void sctp_generate_probe_event(struct timer_list *t)
 		pr_debug("%s: sock is busy\n", __func__);
 
 		/* Try again later.  */
-		if (!mod_timer(&transport->probe_timer, jiffies + (HZ / 20)))
-			sctp_transport_hold(transport);
+		sctp_transport_hold(transport);
+		if (mod_timer(&transport->probe_timer, jiffies + (HZ / 20)))
+			sctp_transport_put(transport);
 		goto out_unlock;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#157 lore raw

PATCH 157/457 net: stmmac: selftests: Support running selftests on DSA conduits

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit d68acbf93531abdb5b02b21994cd4c15a3c95b42 ]

Most stmmac selftests rely on dev_add_pack() to add custom handlers, that validate the packets sent to ourselves through MAC loopback.

However, when the stmmac-driven interface is a DSA CPU conduit, all frames that are received have ETH_P_XDSA as a protocol, even though they don't actually contain any tag as they come from the loopback and not the switch.

This will prevent any incoming packet to match our packet handlers.

Let's register a ETH_P_ALL packet handler when we detect that we're a DSA conduit, and use a proxy packet handler to filter the h_proto.

As this allows external frames to be received through our .func(), the packet handler is added after the dev->addr field is populated in our selftest attributes.

Note that we may still receive incoming packets from the switch, but these frames shouldn't interfere with the very specific frames used for selftests, and stmmac selftests in general aren't safe against external traffic interferences.

This was validated on a WPQ864 devkit for IPQ8064, that has the SoC connected to a QCA8k switch.

The ARP offload's packet handler is left alone, this feature is just not implemented in stmmac and due for removal.

---
 .../stmicro/stmmac/stmmac_selftests.c         | 89 +++++++++++++++----
 1 file changed, 71 insertions(+), 18 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +71 -18
index f97f32369e903..a65eac55323af 100644
@@ -13,6 +13,7 @@
 #include <linux/ip.h>
 #include <linux/phy.h>
 #include <linux/udp.h>
+#include <net/dsa.h>
 #include <net/pkt_cls.h>
 #include <net/pkt_sched.h>
 #include <net/tcp.h>
@@ -238,6 +239,9 @@ struct stmmac_test_priv {
 	struct stmmac_packet_attrs *packet;
 	struct packet_type pt;
 	struct completion comp;
+	__be16 packet_type;
+	int (*func)(struct sk_buff *skb, struct net_device *ndev,
+		    struct packet_type *pt, struct net_device *orig_ndev);
 	int double_vlan;
 	int vlan_id;
 	int ok;
@@ -317,6 +321,50 @@ static int stmmac_test_loopback_validate(struct sk_buff *skb,
 	return 0;
 }
 
+static int stmmac_sft_filter(struct sk_buff *skb, struct net_device *ndev,
+			     struct packet_type *pt,
+			     struct net_device *orig_ndev)
+{
+	struct stmmac_test_priv *tpriv = pt->af_packet_priv;
+	struct ethhdr *hdr = eth_hdr(skb);
+	int ret = 0;
+
+	if (hdr->h_proto == tpriv->packet_type) {
+		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+		if (nskb)
+			ret = tpriv->func(nskb, ndev, pt, orig_ndev);
+	}
+
+	kfree_skb(skb);
+	return ret;
+}
+
+static void stmmac_sft_add_pack(struct packet_type *pt)
+{
+	struct stmmac_test_priv *tpriv = pt->af_packet_priv;
+
+	if (netdev_uses_dsa(tpriv->pt.dev)) {
+		tpriv->packet_type = tpriv->pt.type;
+		tpriv->func = tpriv->pt.func;
+
+		/* DSA conduit will report ETH_P_XDSA, so our packet handler
+		 * won't match. Let's register a ETH_P_ALL match and filter
+		 * manually in stmmac_sft_filter.
+		 */
+		tpriv->pt.type = htons(ETH_P_ALL);
+		tpriv->pt.func = stmmac_sft_filter;
+		tpriv->pt.ignore_outgoing = true;
+	}
+
+	dev_add_pack(pt);
+}
+
+static void stmmac_sft_remove_pack(struct packet_type *pt)
+{
+	dev_remove_pack(pt);
+}
+
 static int __stmmac_test_loopback(struct stmmac_priv *priv,
 				  struct stmmac_packet_attrs *attr)
 {
@@ -338,7 +386,7 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
 	tpriv->packet = attr;
 
 	if (!attr->dont_wait)
-		dev_add_pack(&tpriv->pt);
+		stmmac_sft_add_pack(&tpriv->pt);
 
 	skb = stmmac_test_get_udp_skb(priv, attr);
 	if (!skb) {
@@ -361,7 +409,7 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
 
 cleanup:
 	if (!attr->dont_wait)
-		dev_remove_pack(&tpriv->pt);
+		stmmac_sft_remove_pack(&tpriv->pt);
 	kfree(tpriv);
 	return ret;
 }
@@ -787,7 +835,7 @@ static int stmmac_test_flowctrl(struct stmmac_priv *priv)
 	tpriv->pt.func = stmmac_test_flowctrl_validate;
 	tpriv->pt.dev = priv->dev;
 	tpriv->pt.af_packet_priv = tpriv;
-	dev_add_pack(&tpriv->pt);
+	stmmac_sft_add_pack(&tpriv->pt);
 
 	/* Compute minimum number of packets to make FIFO full */
 	pkt_count = rx_fifo_size;
@@ -843,7 +891,7 @@ static int stmmac_test_flowctrl(struct stmmac_priv *priv)
 cleanup:
 	dev_mc_del(priv->dev, paddr);
 	dev_set_promiscuity(priv->dev, -1);
-	dev_remove_pack(&tpriv->pt);
+	stmmac_sft_remove_pack(&tpriv->pt);
 	kfree(tpriv);
 	return ret;
 }
@@ -948,18 +996,20 @@ static int __stmmac_test_vlanfilt(struct stmmac_priv *priv)
 	 * HASH values.
 	 */
 	tpriv->vlan_id = 0x123;
-	dev_add_pack(&tpriv->pt);
 
 	ret = vlan_vid_add(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id);
 	if (ret)
 		goto cleanup;
 
+	attr.vlan = 1;
+	attr.dst = priv->dev->dev_addr;
+	attr.sport = 9;
+	attr.dport = 9;
+
+	stmmac_sft_add_pack(&tpriv->pt);
+
 	for (i = 0; i < 4; i++) {
-		attr.vlan = 1;
 		attr.vlan_id_out = tpriv->vlan_id + i;
-		attr.dst = priv->dev->dev_addr;
-		attr.sport = 9;
-		attr.dport = 9;
 
 		skb = stmmac_test_get_udp_skb(priv, &attr);
 		if (!skb) {
@@ -986,9 +1036,9 @@ static int __stmmac_test_vlanfilt(struct stmmac_priv *priv)
 	}
 
 vlan_del:
+	stmmac_sft_remove_pack(&tpriv->pt);
 	vlan_vid_del(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id);
 cleanup:
-	dev_remove_pack(&tpriv->pt);
 	kfree(tpriv);
 	return ret;
 }
@@ -1042,18 +1092,20 @@ static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
 	 * HASH values.
 	 */
 	tpriv->vlan_id = 0x123;
-	dev_add_pack(&tpriv->pt);
 
 	ret = vlan_vid_add(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id);
 	if (ret)
 		goto cleanup;
 
+	attr.vlan = 2;
+	attr.dst = priv->dev->dev_addr;
+	attr.sport = 9;
+	attr.dport = 9;
+
+	stmmac_sft_add_pack(&tpriv->pt);
+
 	for (i = 0; i < 4; i++) {
-		attr.vlan = 2;
 		attr.vlan_id_out = tpriv->vlan_id + i;
-		attr.dst = priv->dev->dev_addr;
-		attr.sport = 9;
-		attr.dport = 9;
 
 		skb = stmmac_test_get_udp_skb(priv, &attr);
 		if (!skb) {
@@ -1080,9 +1132,9 @@ static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
 	}
 
 vlan_del:
+	stmmac_sft_remove_pack(&tpriv->pt);
 	vlan_vid_del(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id);
 cleanup:
-	dev_remove_pack(&tpriv->pt);
 	kfree(tpriv);
 	return ret;
 }
@@ -1313,7 +1365,6 @@ static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
 	tpriv->pt.af_packet_priv = tpriv;
 	tpriv->packet = &attr;
 	tpriv->vlan_id = 0x123;
-	dev_add_pack(&tpriv->pt);
 
 	ret = vlan_vid_add(priv->dev, htons(proto), tpriv->vlan_id);
 	if (ret)
@@ -1321,6 +1372,8 @@ static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
 
 	attr.dst = priv->dev->dev_addr;
 
+	stmmac_sft_add_pack(&tpriv->pt);
+
 	skb = stmmac_test_get_udp_skb(priv, &attr);
 	if (!skb) {
 		ret = -ENOMEM;
@@ -1338,9 +1391,9 @@ static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
 	ret = tpriv->ok ? 0 : -ETIMEDOUT;
 
 vlan_del:
+	stmmac_sft_remove_pack(&tpriv->pt);
 	vlan_vid_del(priv->dev, htons(proto), tpriv->vlan_id);
 cleanup:
-	dev_remove_pack(&tpriv->pt);
 	kfree(tpriv);
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#158 lore raw

PATCH 158/457 net: stmmac: selftests: Validate EEE based on the actual LPI timer value

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit c8c1795aa8106293020a836d01e127e98f442925 ]

The EEE selftest is a 2-step test :
- It validates that we enter in LPI mode with the irq_tx_path_in_lpi_mode_n counter
- It then validates that we exit LPI when sending a frame, with the irq_tx_path_exit_lpi_mode_n counter.

The current state of the test lacks 2 main things :

- We don't know exactly when was the previous frame sent (it's from the previous selftest)

- The timeout is hardcoded, while the LPI is entered after a user-configurable delay. On top of that, the timeout loop uses a pre-decrement iterator (--retries) that actually only iterate nine times, so 900ms while the default LPI value is 1 second.

Let's therefore make it more deterministic :

- Send a frame at the beginning of the test
- Wait for more than the lpi timer value, we timeout after about twice the value,
- Then send another frame, and verify that we do go out of LPI, also with a timeout.

As LPI timer can get pretty high, bail out if LPI timer is over 5 seconds.

Note that the test's goal isn't to validate the LPI timer value itself, only that we enter/leave LPI mode.

---
 .../stmicro/stmmac/stmmac_selftests.c         | 44 ++++++++++++++++---
 1 file changed, 37 insertions(+), 7 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +37 -7
index a65eac55323af..045d644ae50b5 100644
@@ -31,6 +31,7 @@ struct stmmachdr {
 			      sizeof(struct stmmachdr))
 #define STMMAC_TEST_PKT_MAGIC	0xdeadcafecafedeadULL
 #define STMMAC_LB_TIMEOUT	msecs_to_jiffies(200)
+#define STMMAC_SFT_MAX_LPI	(5 * USEC_PER_SEC)
 
 struct stmmac_packet_attrs {
 	int vlan;
@@ -482,12 +483,16 @@ static int stmmac_test_mmc(struct stmmac_priv *priv)
 static int stmmac_test_eee(struct stmmac_priv *priv)
 {
 	struct stmmac_extra_stats *initial, *final;
-	int retries = 10;
+	unsigned long timeout, max_duration;
 	int ret;
 
 	if (!priv->dma_cap.eee || !priv->eee_active)
 		return -EOPNOTSUPP;
 
+	/* Bail out if the configured LPI timer is too long */
+	if (priv->tx_lpi_timer > STMMAC_SFT_MAX_LPI)
+		return -EOPNOTSUPP;
+
 	initial = kzalloc_obj(*initial);
 	if (!initial)
 		return -ENOMEM;
@@ -498,14 +503,21 @@ static int stmmac_test_eee(struct stmmac_priv *priv)
 		goto out_free_initial;
 	}
 
+	/* Snapshot stats, we want to count the in_lpi events. We may enter
+	 * LPI just after the packet was sent.
+	 */
 	memcpy(initial, &priv->xstats, sizeof(*initial));
 
+	/* Send a frame, then wait to enter LPI */
 	ret = stmmac_test_mac_loopback(priv);
 	if (ret)
 		goto out_free_final;
 
+	max_duration = usecs_to_jiffies(2 * priv->tx_lpi_timer);
+
 	/* We have no traffic in the line so, sooner or later it will go LPI */
-	while (--retries) {
+	timeout = jiffies + max_duration;
+	while (!time_after(jiffies, timeout)) {
 		memcpy(final, &priv->xstats, sizeof(*final));
 
 		if (final->irq_tx_path_in_lpi_mode_n >
@@ -514,20 +526,38 @@ static int stmmac_test_eee(struct stmmac_priv *priv)
 		msleep(100);
 	}
 
-	if (!retries) {
+	memcpy(final, &priv->xstats, sizeof(*final));
+	if (final->irq_tx_path_in_lpi_mode_n <=
+	    initial->irq_tx_path_in_lpi_mode_n) {
 		ret = -ETIMEDOUT;
 		goto out_free_final;
 	}
 
-	if (final->irq_tx_path_in_lpi_mode_n <=
-	    initial->irq_tx_path_in_lpi_mode_n) {
-		ret = -EINVAL;
+	/* Re-snapshot, as we want to measure exit_lpi events. We should be
+	 * in LPI right now.
+	 */
+	memcpy(initial, &priv->xstats, sizeof(*initial));
+
+	/* TX something so we go out of LPI */
+	ret = stmmac_test_mac_loopback(priv);
+	if (ret)
 		goto out_free_final;
+
+	/* Wait for the exit LPI interrupt */
+	timeout = jiffies + max_duration;
+	while (!time_after(jiffies, timeout)) {
+		memcpy(final, &priv->xstats, sizeof(*final));
+
+		if (final->irq_tx_path_exit_lpi_mode_n >
+		    initial->irq_tx_path_exit_lpi_mode_n)
+			break;
+		msleep(100);
 	}
 
+	memcpy(final, &priv->xstats, sizeof(*final));
 	if (final->irq_tx_path_exit_lpi_mode_n <=
 	    initial->irq_tx_path_exit_lpi_mode_n) {
-		ret = -EINVAL;
+		ret = -ETIMEDOUT;
 		goto out_free_final;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#159 lore raw

PATCH 159/457 net: stmmac: selftests: Check the dev->features for S-TAG offload testing

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit ba804b23d76d278ee475b8427fa7c5623ce5e270 ]

The S-TAG offload insertion incorrectly checks the dvlan (double vlan) DMA cap, which is different than S-TAG support. Use NETIF_F_HW_VLAN_STAG_TX to check if the feature is supported instead.

Note that this flag isn't set in stmmac yet, but contrary to ARP offload, this is a feature that has a chance to get there eventually so let's leave the selftest here for now. It'll report -EOPNOTSUPP in the meantime.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +1 -1
index 045d644ae50b5..53bb911b69ffb 100644
@@ -1435,7 +1435,7 @@ static int stmmac_test_vlanoff(struct stmmac_priv *priv)
 
 static int stmmac_test_svlanoff(struct stmmac_priv *priv)
 {
-	if (!priv->dma_cap.dvlan)
+	if (!(priv->dev->features & NETIF_F_HW_VLAN_STAG_TX))
 		return -EOPNOTSUPP;
 	return stmmac_test_vlanoff_common(priv, true);
 }
Signature · 1 line
2.53.0
author maintainer
#160 lore raw

PATCH 160/457 net: stmmac: selftests: Capture all packets for vlan checks

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit 960db6f65788c21249ea04a947d5c01e38d19294 ]

While we use vlan_vid_add to trigger the tag filtering machinery in the driver, there's no netdev associated to the VLAN. This causes the skb to arrive with empty skb->vlan_tci fields, as the packet is marked OTHERHOST in __netif_receive_skb_core(), and we fail our validation.

Let's use the proxy mechanism introduced for DSA, that registers a ETH_P_ALL packet handler that runs earlier, before the vlan netdev lookup, then filters for the correct ethertype before passing an skb clone to our validation function.

As we may receive external frames with the right tag from the outside, let's move the address check in the vlan validation function earlier.

---
 .../stmicro/stmmac/stmmac_selftests.c         | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +13 -6
index 53bb911b69ffb..b3b05a7753335 100644
@@ -243,6 +243,7 @@ struct stmmac_test_priv {
 	__be16 packet_type;
 	int (*func)(struct sk_buff *skb, struct net_device *ndev,
 		    struct packet_type *pt, struct net_device *orig_ndev);
+	bool capture_all;
 	int double_vlan;
 	int vlan_id;
 	int ok;
@@ -345,13 +346,15 @@ static void stmmac_sft_add_pack(struct packet_type *pt)
 {
 	struct stmmac_test_priv *tpriv = pt->af_packet_priv;
 
-	if (netdev_uses_dsa(tpriv->pt.dev)) {
+	if (netdev_uses_dsa(tpriv->pt.dev) || tpriv->capture_all) {
 		tpriv->packet_type = tpriv->pt.type;
 		tpriv->func = tpriv->pt.func;
 
 		/* DSA conduit will report ETH_P_XDSA, so our packet handler
 		 * won't match. Let's register a ETH_P_ALL match and filter
-		 * manually in stmmac_sft_filter.
+		 * manually in stmmac_sft_filter. This is also useful for
+		 * VLAN tests, to capture packets otherwise marked as
+		 * OTHERHOST.
 		 */
 		tpriv->pt.type = htons(ETH_P_ALL);
 		tpriv->pt.func = stmmac_sft_filter;
@@ -963,6 +966,11 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
 		goto out;
 	if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
 		goto out;
+
+	ehdr = (struct ethhdr *)skb_mac_header(skb);
+	if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->dst))
+		goto out;
+
 	if (tpriv->vlan_id) {
 		if (skb->vlan_proto != htons(proto))
 			goto out;
@@ -974,10 +982,6 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
 		}
 	}
 
-	ehdr = (struct ethhdr *)skb_mac_header(skb);
-	if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->dst))
-		goto out;
-
 	ihdr = ip_hdr(skb);
 	if (tpriv->double_vlan)
 		ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
@@ -1019,6 +1023,7 @@ static int __stmmac_test_vlanfilt(struct stmmac_priv *priv)
 	tpriv->pt.dev = priv->dev;
 	tpriv->pt.af_packet_priv = tpriv;
 	tpriv->packet = &attr;
+	tpriv->capture_all = true;
 
 	/*
 	 * As we use HASH filtering, false positives may appear. This is a
@@ -1115,6 +1120,7 @@ static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
 	tpriv->pt.dev = priv->dev;
 	tpriv->pt.af_packet_priv = tpriv;
 	tpriv->packet = &attr;
+	tpriv->capture_all = true;
 
 	/*
 	 * As we use HASH filtering, false positives may appear. This is a
@@ -1395,6 +1401,7 @@ static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
 	tpriv->pt.af_packet_priv = tpriv;
 	tpriv->packet = &attr;
 	tpriv->vlan_id = 0x123;
+	tpriv->capture_all = true;
 
 	ret = vlan_vid_add(priv->dev, htons(proto), tpriv->vlan_id);
 	if (ret)
Signature · 1 line
2.53.0
author maintainer
#161 lore raw

PATCH 161/457 net: stmmac: dwmac4: Use the correct bufzise when the len is exactly 8K

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit b42e7012773a0e81e97a2dda6ef907f5147a6658 ]

DMA bufsize selection isn't made on the MTU but the actual frame length, so including the L2 header. On DWMAC4, if the len is exactly BUF_SIZE_8KiB, the next larger size is incorrectly selected.

Lets fix the comparison and while at it, rename the parameter from len to mtu.

Fixes c3efed5ad1b0 ("net: stmmac: Enable dwmac4 jumbo frame more than 8KiB").
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 4 ++--
 drivers/net/ethernet/stmicro/stmmac/hwif.h         | 2 +-
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c    | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +2 -2
index 2994df41ec2c4..c6a8f8d735015 100644
@@ -474,11 +474,11 @@ static void dwmac4_set_sarc(struct dma_desc *p, u32 sarc_type)
 					  sarc_type));
 }
 
-static int set_16kib_bfsize(int mtu)
+static int set_16kib_bfsize(int len)
 {
 	int ret = 0;
 
-	if (unlikely(mtu >= BUF_SIZE_8KiB))
+	if (unlikely(len > BUF_SIZE_8KiB))
 		ret = BUF_SIZE_16KiB;
 	return ret;
 }
drivers/net/ethernet/stmicro/stmmac/hwif.h +1 -1
index 9314bcb85c221..857f7562c6c6d 100644
@@ -540,7 +540,7 @@ struct stmmac_mode_ops {
 	bool (*is_jumbo_frm)(unsigned int len, bool enh_desc);
 	int (*jumbo_frm)(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
 			 int csum);
-	int (*set_16kib_bfsize)(int mtu);
+	int (*set_16kib_bfsize)(int len);
 	void (*init_desc3)(struct dma_desc *p);
 	void (*refill_desc3)(struct stmmac_rx_queue *rx_q, struct dma_desc *p);
 	void (*clean_desc3)(struct stmmac_tx_queue *tx_q, struct dma_desc *p);
drivers/net/ethernet/stmicro/stmmac/ring_mode.c +2 -2
index 78fc6aa5bbe95..dd796cb74419e 100644
@@ -123,10 +123,10 @@ static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
 		p->des3 = 0;
 }
 
-static int set_16kib_bfsize(int mtu)
+static int set_16kib_bfsize(int len)
 {
 	int ret = 0;
-	if (unlikely(mtu > BUF_SIZE_8KiB))
+	if (unlikely(len > BUF_SIZE_8KiB))
 		ret = BUF_SIZE_16KiB;
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#162 lore raw

PATCH 162/457 net: stmmac: size the RX buffers from the frame length, not the MTU

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit b8a26d46c0a4254f8bfe143681adb9d18d020299 ]

When picking the buffsize to use based on the MTU, we shouldn't check only the MTU value, but also :
- ETH_HLEN for the L2 header,
- up to 2 VLAN tags,
- the FCS,

The default bufsize is 1536 bytes, which is enough to contain all the above so this hasn't surfaced before, but the addition of NET_IP_ALIGN to the start of buffer address tripped the Jumbo selftest, leading to this discovery.

With that, we don't need the '>=' checks on the buffer len, we can use more consistent comparison operators in stmmac_set_bfsize.

Fixes 286a83721720 ("stmmac: add CHAINED descriptor mode support (V4)")
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +11 -9
index 5f717f02c3c01..9c4d92a19f2c0 100644
@@ -1536,17 +1536,17 @@ static unsigned int stmmac_rx_offset(struct stmmac_priv *priv)
 	return NET_SKB_PAD + NET_IP_ALIGN;
 }
 
-static int stmmac_set_bfsize(int mtu)
+static int stmmac_set_bfsize(int len)
 {
 	int ret;
 
-	if (mtu >= BUF_SIZE_8KiB)
+	if (len > BUF_SIZE_8KiB)
 		ret = BUF_SIZE_16KiB;
-	else if (mtu >= BUF_SIZE_4KiB)
+	else if (len > BUF_SIZE_4KiB)
 		ret = BUF_SIZE_8KiB;
-	else if (mtu >= BUF_SIZE_2KiB)
+	else if (len > BUF_SIZE_2KiB)
 		ret = BUF_SIZE_4KiB;
-	else if (mtu > DEFAULT_BUFSIZE)
+	else if (len > DEFAULT_BUFSIZE)
 		ret = BUF_SIZE_2KiB;
 	else
 		ret = DEFAULT_BUFSIZE;
@@ -4063,7 +4063,7 @@ static struct stmmac_dma_conf *
 stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu)
 {
 	struct stmmac_dma_conf *dma_conf;
-	int bfsize, ret;
+	int bfsize, len, ret;
 	u8 chan;
 
 	dma_conf = kzalloc_obj(*dma_conf);
@@ -4073,13 +4073,15 @@ stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	/* Returns 0 or BUF_SIZE_16KiB if mtu > 8KiB and dwmac4 or ring mode */
-	bfsize = stmmac_set_16kib_bfsize(priv, mtu);
+	len = mtu + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN;
+
+	/* Returns 0 or BUF_SIZE_16KiB if len > 8KiB and dwmac4 or ring mode */
+	bfsize = stmmac_set_16kib_bfsize(priv, len);
 	if (bfsize < 0)
 		bfsize = 0;
 
 	if (bfsize < BUF_SIZE_16KiB)
-		bfsize = stmmac_set_bfsize(mtu);
+		bfsize = stmmac_set_bfsize(len);
 
 	dma_conf->dma_buf_sz = bfsize;
 	/* Chose the tx/rx size from the already defined one in the
Signature · 1 line
2.53.0
author maintainer
#163 lore raw

PATCH 163/457 net: stmmac: selftests: Account for alignment shift on dwmac1000 for Jumbo test

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maxime Chevallier <[email protected]>

[ Upstream commit c4ac6e94eb9423126bda907a7f2933284f7450ff ]

On dwmac1000, we currently only support single-descriptor frames. The Jumbo test started failing when NET_IP_ALIGN was added to align the IP header, as this tests tries to send the biggest possible frame.

On dwmac1000 the DMA transfer is aligned on 4-bytes, so adding a 2-byte shift at the start-of-buffer address means it takes a whole extra 4-byte DMA burst to receive the Jumbo packet, causing it to spill over the next descriptor.

This doesn't seem to happen on dwmac4 and xgmac that appear to correctly handle unaligned xfers (only tested on dwmac4)

Let's account for that in the Jumbo test, reduce the size of our big packet by the align size.

Fixes 23680bf5f8c6 ("net: stmmac: restore NET_IP_ALIGN in the RX DMA offset")
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +3 -0
index b3b05a7753335..75647992cbb44 100644
@@ -1809,6 +1809,9 @@ static int __stmmac_test_jumbo(struct stmmac_priv *priv, u16 queue)
 	struct stmmac_packet_attrs attr = { };
 	int size = priv->dma_conf.dma_buf_sz;
 
+	if (!dwmac_is_xmac(priv->plat->core_type))
+		size -= NET_IP_ALIGN;
+
 	attr.dst = priv->dev->dev_addr;
 	attr.max_size = size - ETH_FCS_LEN;
 	attr.queue_mapping = queue;
Signature · 1 line
2.53.0
author maintainer
#164 lore raw

PATCH 164/457 eth: fbnic: Avoid rounding zero ring sizes

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Björn Töpel <[email protected]>

[ Upstream commit 0160953d8eec75c3c55562158c46442ff1fd410b ]

roundup_pow_of_two() is undefined for zero. ethtool permits a zero ring size to reach the driver, where the minimum-size check should reject it.

Leave zero unchanged while rounding nonzero ring sizes. The minimum-size check then rejects zero deterministically without changing the established behavior for other values.

---
 drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +9 -4
index 423f179c9d475..76e9a545bb165 100644
@@ -313,6 +313,11 @@ fbnic_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
 	kernel_ring->hds_thresh = fbn->hds_thresh;
 }
 
+static u32 fbnic_ring_size_pow2(u32 size)
+{
+	return size ? roundup_pow_of_two(size) : 0;
+}
+
 static void fbnic_set_rings(struct fbnic_net *fbn,
 			    struct ethtool_ringparam *ring,
 			    struct kernel_ethtool_ringparam *kernel_ring)
@@ -334,10 +339,10 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
 	struct fbnic_net *clone;
 	int err;
 
-	ring->rx_pending	= roundup_pow_of_two(ring->rx_pending);
-	ring->rx_mini_pending	= roundup_pow_of_two(ring->rx_mini_pending);
-	ring->rx_jumbo_pending	= roundup_pow_of_two(ring->rx_jumbo_pending);
-	ring->tx_pending	= roundup_pow_of_two(ring->tx_pending);
+	ring->rx_pending	= fbnic_ring_size_pow2(ring->rx_pending);
+	ring->rx_mini_pending	= fbnic_ring_size_pow2(ring->rx_mini_pending);
+	ring->rx_jumbo_pending	= fbnic_ring_size_pow2(ring->rx_jumbo_pending);
+	ring->tx_pending	= fbnic_ring_size_pow2(ring->tx_pending);
 
 	/* These are absolute minimums allowing the device and driver to operate
 	 * but not necessarily guarantee reasonable performance. Settings below
Signature · 1 line
2.53.0
author maintainer
#165 lore raw

PATCH 165/457 net/sched: fix potential stack infoleak in em_text_dump()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bernard Ladenthin <[email protected]>

[ Upstream commit 9c572a83037a7dcd653ba3a9cc468c16b857d0c9 ]

em_text_dump() allocates struct tcf_em_text on the stack without zeroing it. strscpy() writes the algorithm name and a NUL terminator into conf.algo[], leaving the remaining bytes uninitialised. nla_put_nohdr() then copies the full struct to the netlink response.

KMSAN on Linux 7.2-rc6 reports two kernel-infoleak splats from this path, one triggered via "tc filter show" and one via a raw RTM_GETTFILTER dump:

  BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x1c9/0x2620
    nla_put_nohdr+0x83/0x130
    em_text_dump+0x291/0x550
  Local variable conf created at: em_text_dump+0x5d/0x550
  Bytes 168-179 of 199 are uninitialized

I am not certain whether this constitutes a real security problem in
practice: the test was conducted in a controlled KMSAN environment and the leaked stack bytes may or may not carry sensitive data on actual production kernels. I am reporting it because KMSAN flagged it as a kernel-infoleak and the fix is straightforward. I can provide a userspace reproducer on request.

The original code used strncpy() which zero-pads to the destination size. Commit b04202d6065c ("net/sched: replace strncpy with strscpy") replaced it with strscpy(), which does not pad, creating this condition. Zero-initialising the struct closes it.

Fixes b04202d6065c ("net/sched: replace strncpy with strscpy")
Assisted-by Claude:claude-sonnet-4-6 [KMSAN]
---
 net/sched/em_text.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/em_text.c +1 -1
index 343f1aebeec2a..4132f8c3c5fc9 100644
@@ -113,7 +113,7 @@ static void em_text_destroy(struct tcf_ematch *m)
 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
 {
 	struct text_match *tm = EM_TEXT_PRIV(m);
-	struct tcf_em_text conf;
+	struct tcf_em_text conf = {};
 
 	strscpy(conf.algo, tm->config->ops->name);
 	conf.from_offset = tm->from_offset;
Signature · 1 line
2.53.0
author maintainer
#166 lore raw

PATCH 166/457 bpf: Reject dev-bound-only programs on other devices

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Weiming Shi <[email protected]>

[ Upstream commit 6db1ce73e9853f533eb7f413f14ba00f8ec6f80d ]

__bpf_offload_dev_match() falls back to comparing offdev pointers after an exact netdev mismatch. Bound-only programs normally have NULL offdevs, so unrelated netdevs compare equal. A bound-only program on an offload-registered netdev can instead inherit a real offdev and match a sibling port. With CAP_BPF and CAP_NET_ADMIN, a caller can use bpf(BPF_LINK_CREATE) with a different target ifindex to run metadata kfuncs specialized for the bound driver on the target driver's xdp_buff. Running a veth-bound program on tun reads beyond tun's bare stack xdp_buff as a veth_xdp_buff.

  Oops: general protection fault, probably for non-canonical address
  KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
  RIP: 0010:veth_xdp_rx_timestamp (drivers/net/veth.c:1673)
  Call Trace:
   ...
   tun_build_skb (drivers/net/tun.c:1739)
   tun_get_user (drivers/net/tun.c:1856)
   tun_chr_write_iter (drivers/net/tun.c:2091)
   vfs_write (fs/read_write.c:595 fs/read_write.c:687)
   ksys_write (fs/read_write.c:739)
   do_syscall_64 (arch/x86/entry/syscall_64.c:84)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
  Kernel panic - not syncing: Fatal exception in interrupt

Restrict non-offloaded programs to exact netdev matches and retain the shared-offdev fallback only for genuinely offloaded multi-port programs.

---
 kernel/bpf/offload.c | 2 ++
 1 file changed, 2 insertions(+)
kernel/bpf/offload.c +2 -0
index 0d6f5569588c3..d855399812eec 100644
@@ -698,6 +698,8 @@ static bool __bpf_offload_dev_match(struct bpf_prog *prog,
 		return false;
 	if (offload->netdev == netdev)
 		return true;
+	if (!bpf_prog_is_offloaded(prog->aux))
+		return false;
 
 	ondev1 = bpf_offload_find_netdev(offload->netdev);
 	ondev2 = bpf_offload_find_netdev(netdev);
Signature · 1 line
2.53.0
author maintainer
#167 lore raw

PATCH 167/457 nfc: nfcmrvl: validate helper command length before pull

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit 686f942332b1667f13f3b8d6a2f50bcfbf42e277 ]

The firmware download receive path removes the NCI data header and reads the helper command before validating the remaining packet length. A short frame can therefore reach the data access before the malformed packet is rejected.

Validate the complete helper command length before stripping the NCI data header.

Fixes 3194c6870158 ("NFC: nfcmrvl: add firmware download support")
---
 drivers/nfc/nfcmrvl/fw_dnld.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/nfc/nfcmrvl/fw_dnld.c +8 -3
index 2b8f401d8fd7a..8b9d5257320dc 100644
@@ -263,9 +263,14 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv,
 		 * B8..N: payload
 		 */
 
-		/* Remove NCI HDR */
-		skb_pull(skb, 3);
-		if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) {
+		if (skb->len != NCI_DATA_HDR_SIZE + 5) {
+			nfc_err(priv->dev, "bad command");
+			return -EINVAL;
+		}
+
+		/* Remove NCI header */
+		skb_pull(skb, NCI_DATA_HDR_SIZE);
+		if (skb->data[0] != HELPER_CMD_PACKET_FORMAT) {
 			nfc_err(priv->dev, "bad command");
 			return -EINVAL;
 		}
Signature · 1 line
2.53.0
author maintainer
#168 lore raw

PATCH 168/457 nfc: st21nfca: validate received frame size

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit a653c01ce447f10c36b901646888c0330363af4f ]

st21nfca_hci_i2c_repack() trims a received frame at its EOF marker before removing byte stuffing. It then assumes the truncated frame contains the LLC header and two CRC bytes, and it unconditionally reads the byte after an escape marker.

A malformed frame can place EOF immediately after the start marker or can end its data portion with an escape marker. The former leaves too few bytes for check_crc(), while the latter makes the unstuffing loop read past the current skb length.

Require the minimum framing bytes both before and after unstuffing. Use separate input and output cursors while removing byte stuffing, and reject an escape marker without its encoded byte. This keeps malformed frames within the received frame boundary before CRC processing.

Fixes 3096e25a3e40 ("NFC: st21nfca: Fix incorrect byte stuffing revocation")
---
 drivers/nfc/st21nfca/i2c.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/nfc/st21nfca/i2c.c +19 -10
index aa5f4922b6b04..11ba4fb498283 100644
@@ -289,27 +289,36 @@ static int check_crc(u8 *buf, int buflen)
  */
 static int st21nfca_hci_i2c_repack(struct sk_buff *skb)
 {
-	int i, j, r, size;
+	int read, write, r, size;
 
-	if (skb->len < 1 || (skb->len > 1 && skb->data[1] != 0))
+	if (skb->len < ST21NFCA_FRAME_HEADROOM ||
+	    !IS_START_OF_FRAME(skb->data))
 		return -EBADMSG;
 
 	size = get_frame_size(skb->data, skb->len);
 	if (size > 0) {
+		if (size < ST21NFCA_FRAME_HEADROOM + 2)
+			return -EBADMSG;
+
 		skb_trim(skb, size);
 		/* remove ST21NFCA byte stuffing for upper layer */
-		for (i = 1, j = 0; i < skb->len; i++) {
-			if (skb->data[i + j] ==
+		for (read = 1, write = 1; read < skb->len;) {
+			if (skb->data[read] ==
 					(u8) ST21NFCA_ESCAPE_BYTE_STUFFING) {
-				skb->data[i] = skb->data[i + j + 1]
-						| ST21NFCA_BYTE_STUFFING_MASK;
-				i++;
-				j++;
+				if (read + 1 == skb->len)
+					return -EBADMSG;
+
+				skb->data[write++] = skb->data[read + 1]
+						     | ST21NFCA_BYTE_STUFFING_MASK;
+				read += 2;
+			} else {
+				skb->data[write++] = skb->data[read++];
 			}
-			skb->data[i] = skb->data[i + j];
 		}
 		/* remove byte stuffing useless byte */
-		skb_trim(skb, i - j);
+		skb_trim(skb, write);
+		if (skb->len < ST21NFCA_FRAME_HEADROOM + 2)
+			return -EBADMSG;
 		/* remove ST21NFCA_SOF_EOF from head */
 		skb_pull(skb, 1);
 
Signature · 1 line
2.53.0
author maintainer
#169 lore raw

PATCH 169/457 nfc: llcp: Fix list corruption / refcount desync in nfc_llcp_recv_dm()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aldo Ariel Panzardo <[email protected]>

[ Upstream commit bf1460acdf8cf5a07c819f59785d40f20d113099 ]

nfc_llcp_recv_dm() handles DM(NOBOUND)/DM(REJ) for a socket that is still linked on local->connecting_sockets: it looks the socket up with nfc_llcp_connecting_sock_get(), sets sk->sk_state = LLCP_CLOSED and returns, without taking the socket lock and without unlinking the socket from the connecting_sockets list.

llcp_sock_release() selects the list to unlink from by sk_state: a socket in LLCP_CONNECTING is unlinked from connecting_sockets, otherwise from the sockets list. Because recv_dm left the socket physically on connecting_sockets but in the LLCP_CLOSED state, release() takes the else branch and calls nfc_llcp_sock_unlink(&local->sockets, sk). That runs sk_del_node_init() while holding sockets.lock, i.e. it removes the socket from the connecting_sockets hlist under the wrong lock. A concurrent connect() linking another socket onto connecting_sockets under connecting_sockets.lock then mutates the same hlist unserialized, which corrupts the list and desyncs the sk_add_node()/sk_del_node_init() sock_hold()/__sock_put() pairing. An unprivileged local process holding LLCP sockets, with the DM supplied by the remote peer over an established LLCP link, can drive this to leak kernel sockets without bound (the mis-decrement goes through the non-freeing __sock_put() path, so the object is never released), leading to memory exhaustion / DoS.

This is the same class of bug that was fixed in the sibling handler nfc_llcp_recv_cc() by commit b493ea2765cc ("nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc()"); recv_dm did not receive the equivalent fix.

Fix it the same way: take lock_sock(), re-check that the socket is still hashed (release() may have won the race), and for the NOBOUND/REJ case unlink it from connecting_sockets before moving it to LLCP_CLOSED. The unlink drops the connecting_sockets membership reference via sk_del_node_init(), leaving the socket unhashed, so the later nfc_llcp_sock_unlink() in llcp_sock_release() becomes a no-op and no double put occurs.

---
 net/nfc/llcp_core.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
net/nfc/llcp_core.c +25 -0
index cac1b5487064d..bd6361e2efa4f 100644
@@ -1251,6 +1251,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local,
 	struct nfc_llcp_sock *llcp_sock;
 	struct sock *sk;
 	u8 dsap, ssap, reason;
+	bool connecting = false;
 
 	dsap = nfc_llcp_dsap(skb);
 	ssap = nfc_llcp_ssap(skb);
@@ -1262,6 +1263,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local,
 	case LLCP_DM_NOBOUND:
 	case LLCP_DM_REJ:
 		llcp_sock = nfc_llcp_connecting_sock_get(local, dsap);
+		connecting = true;
 		break;
 
 	default:
@@ -1276,10 +1278,33 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local,
 
 	sk = &llcp_sock->sk;
 
+	lock_sock(sk);
+
+	/* Check if socket was destroyed whilst waiting for the lock */
+	if (!sk_hashed(sk)) {
+		release_sock(sk);
+		nfc_llcp_sock_put(llcp_sock);
+		return;
+	}
+
+	/*
+	 * For DM(NOBOUND)/DM(REJ) the socket is still linked on the
+	 * connecting_sockets list.  Unlink it here, under the socket lock,
+	 * before moving it to LLCP_CLOSED: llcp_sock_release() selects the
+	 * list to unlink from by sk_state, so leaving a connecting socket
+	 * in the CLOSED state would make it unlink from the wrong list and
+	 * corrupt the connecting_sockets list / desync the socket refcount.
+	 * This mirrors nfc_llcp_recv_cc().
+	 */
+	if (connecting)
+		nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+
 	sk->sk_err = ENXIO;
 	sk->sk_state = LLCP_CLOSED;
 	sk->sk_state_change(sk);
 
+	release_sock(sk);
+
 	nfc_llcp_sock_put(llcp_sock);
 }
 
Signature · 1 line
2.53.0
author maintainer
#170 lore raw

PATCH 170/457 selftests: nci: Correct pthread_create return value check

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lei Zhu <[email protected]>

[ Upstream commit 3d8afc5243ea2ee803d98e69eb4a01748167ac1b ]

The pthread_create() functions returns 0 on success and a positive value on failure. Modify the return value check to correctly detect failure cases.

Fixes 72696bd8a09d ("selftests: nci: Extract the start/stop discovery function")
---
 tools/testing/selftests/nci/nci_dev.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
tools/testing/selftests/nci/nci_dev.c +7 -5
index 312f84ee0444f..c053f5cf2745d 100644
@@ -438,7 +438,7 @@ FIXTURE_SETUP(NCI)
 	else
 		rc = pthread_create(&thread_t, NULL, virtual_dev_open,
 				    (void *)&self->virtual_nci_fd);
-	ASSERT_GT(rc, -1);
+	ASSERT_EQ(rc, 0);
 
 	rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
 			       NFC_CMD_DEV_UP, self->dev_idex);
@@ -509,7 +509,7 @@ FIXTURE_TEARDOWN(NCI)
 			rc = pthread_create(&thread_t, NULL, virtual_deinit,
 					    (void *)&self->virtual_nci_fd);
 
-		ASSERT_GT(rc, -1);
+		ASSERT_EQ(rc, 0);
 		rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
 				       NFC_CMD_DEV_DOWN, self->dev_idex);
 		EXPECT_EQ(rc, 0);
@@ -590,7 +590,7 @@ int start_polling(int dev_idx, int proto, int virtual_fd, int sd, int fid, int p
 
 	rc = pthread_create(&thread_t, NULL, virtual_poll_start,
 			    (void *)&virtual_fd);
-	if (rc < 0)
+	if (rc)
 		return rc;
 
 	rc = send_cmd_mt_nla(sd, fid, pid, NFC_CMD_START_POLL, 2, nla_start_poll_type,
@@ -610,7 +610,7 @@ int stop_polling(int dev_idx, int virtual_fd, int sd, int fid, int pid)
 
 	rc = pthread_create(&thread_t, NULL, virtual_poll_stop,
 			    (void *)&virtual_fd);
-	if (rc < 0)
+	if (rc)
 		return rc;
 
 	rc = send_cmd_with_idx(sd, fid, pid,
@@ -830,6 +830,8 @@ int disconnect_tag(int nfc_sock, int virtual_fd)
 
 	status = pthread_create(&thread_t, NULL, virtual_deactivate_proc,
 				(void *)&virtual_fd);
+	if (status)
+		return status;
 
 	close(nfc_sock);
 	pthread_join(thread_t, (void **)&status);
@@ -874,7 +876,7 @@ TEST_F(NCI, deinit)
 	else
 		rc = pthread_create(&thread_t, NULL, virtual_deinit,
 				    (void *)&self->virtual_nci_fd);
-	ASSERT_GT(rc, -1);
+	ASSERT_EQ(rc, 0);
 
 	rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
 			       NFC_CMD_DEV_DOWN, self->dev_idex);
Signature · 1 line
2.53.0
author maintainer
#171 lore raw

PATCH 171/457 nfc: llcp: Fix race condition in accept_queue lifecycle

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lee Jones <[email protected]>

[ Upstream commit c3eef2f988a3db9690369d7cef9a3344dd9788d3 ]

In nfc_llcp_socket_release(), sockets and listener accept queues are walked under the local sockets rwlock and bh_lock_sock(). However, bh_lock_sock() does not synchronise against process-context lock_sock() held by nfc_llcp_accept_dequeue() during accept(). Because socket_release() does not check sock_owned_by_user(), both paths can concurrently unlink and release the same child socket, resulting in use-after-free or a NULL pointer dereference of child->parent in nfc_llcp_accept_unlink().

Fix this synchronisation race by having nfc_llcp_socket_release() use process-context lock_sock() instead of bh_lock_sock():

1. Pop sockets from the local sockets list under the write lock using nfc_llcp_sock_list_pop() so lock_sock() can be acquired without holding the rwlock.

2. Because lock_sock() can sleep, defer the final release of the nfc_llcp_local structure to a workqueue (release_work). This avoids a sleeping-in-atomic bug when the last local reference is dropped from softirq context. Additionally, hold a single device reference on local from registration until final destruction.

3. In nfc_llcp_local_get(), use kref_get_unless_zero() to prevent resurrecting a local object whose teardown has been scheduled.

4. In llcp_sock_accept(), verify that the listener socket state is still LLCP_LISTEN after waking from schedule_timeout() to prevent hangs if the listener is closed concurrently.

5. When unlinking unaccepted child sockets during listener release, unlink them from local->sockets, call sock_orphan(), and drop their initial sk_alloc creation reference via sock_put().

6. Make nfc_llcp_accept_unlink() idempotent by guarding parent access with a NULL check.

Fixes 50b78b2a6500 ("NFC: Fix sleeping in atomic when releasing socket")
---
 net/nfc/llcp.h      |   1 +
 net/nfc/llcp_core.c | 125 +++++++++++++++++++++++++++-----------------
 net/nfc/llcp_sock.c |  49 ++++++++++++-----
 3 files changed, 116 insertions(+), 59 deletions(-)
net/nfc/llcp.h +1 -0
index d8345ed57c954..23ae7a0112d37 100644
@@ -91,6 +91,7 @@ struct nfc_llcp_local {
 	struct hlist_head pending_sdreqs;
 	struct timer_list sdreq_timer;
 	struct work_struct sdreq_timeout_work;
+	struct work_struct release_work;
 	u8 sdreq_next_tid;
 
 	/* sockets array */
net/nfc/llcp_core.c +78 -47

217 lines not on this page · raw message

net/nfc/llcp_sock.c +37 -12

87 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#172 lore raw

PATCH 172/457 selftests: nci: Fix uninitialized family ID on missing attribute

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chaithanya Lagisetty <[email protected]>

[ Upstream commit eda518d2cdb6074a0bcdfa06af291616bcb5c421 ]

get_family_id() walks the generic netlink CTRL_CMD_GETFAMILY reply looking for the CTRL_ATTR_FAMILY_ID attribute and returns the parsed value in the local variable "id". If the reply does not carry that attribute, the parsing loop never assigns "id" and the function returns an indeterminate stack value, which the caller stores in self->fid and uses for subsequent netlink requests.

Initialize "id" to 0 so a missing attribute yields a deterministic (invalid) family ID instead of a garbage value.

---
 tools/testing/selftests/nci/nci_dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/nci/nci_dev.c +1 -1
index c053f5cf2745d..23fd38acfcf42 100644
@@ -182,7 +182,7 @@ static int get_family_id(int sd, __u32 pid, __u32 *event_group)
 	} ans;
 	struct nlattr *na;
 	int resp_len;
-	__u16 id;
+	__u16 id = 0;
 	int len;
 	int rc;
 
Signature · 1 line
2.53.0
author maintainer
#173 lore raw

PATCH 173/457 selftests/nci: Fix out-of-bounds store on thread join

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chris Gellermann <[email protected]>

[ Upstream commit 6be581aeffc215bfc77939cd59902b0dbc4af23e ]

The NCI test collects the exit status of its helper threads by passing the address of an int to pthread_join():

	int status;
	...
	pthread_join(thread_t, (void **) &status);

pthread_join() stores a void pointer to the memory location. On 64-bit systems, a void pointer is wider than an int, so the store overruns the 4 bytes of space allocated on the stack for the integer and corrupts the adjacent stack. On our CHERI system, this caused a fault due to a capability bounds violation.

Fix this by introducing a helper that joins a thread through a void pointer and converts the result back to an integer, which is what the helper threads return.

While here, also fix the logic in disconnect_tag() if the helper thread creation failed. Previously, it would have joined a thread that was never created when pthread_create() failed.

---
 tools/testing/selftests/nci/nci_dev.c | 31 +++++++++++++++++----------
 1 file changed, 20 insertions(+), 11 deletions(-)
tools/testing/selftests/nci/nci_dev.c +20 -11
index 23fd38acfcf42..07427fa42888d 100644
@@ -8,6 +8,7 @@
 
 #include <stdlib.h>
 #include <errno.h>
+#include <stdint.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
@@ -87,6 +88,16 @@ struct msgtemplate {
 	char buf[MAX_MSG_SIZE];
 };
 
+static int join_thread_status(pthread_t thread)
+{
+	void *thread_ret = NULL;
+
+	if (pthread_join(thread, &thread_ret))
+		return -1;
+
+	return (int)(intptr_t)thread_ret;
+}
+
 static int create_nl_socket(void)
 {
 	int fd;
@@ -444,7 +455,7 @@ FIXTURE_SETUP(NCI)
 			       NFC_CMD_DEV_UP, self->dev_idex);
 	EXPECT_EQ(rc, 0);
 
-	pthread_join(thread_t, (void **)&status);
+	status = join_thread_status(thread_t);
 	ASSERT_EQ(status, 0);
 	self->open_state = true;
 }
@@ -514,7 +525,7 @@ FIXTURE_TEARDOWN(NCI)
 				       NFC_CMD_DEV_DOWN, self->dev_idex);
 		EXPECT_EQ(rc, 0);
 
-		pthread_join(thread_t, (void **)&status);
+		status = join_thread_status(thread_t);
 		ASSERT_EQ(status, 0);
 	}
 
@@ -585,7 +596,6 @@ int start_polling(int dev_idx, int proto, int virtual_fd, int sd, int fid, int p
 	void *nla_start_poll_data[2] = {&dev_idx, &proto};
 	int nla_start_poll_len[2] = {4, 4};
 	pthread_t thread_t;
-	int status;
 	int rc;
 
 	rc = pthread_create(&thread_t, NULL, virtual_poll_start,
@@ -598,14 +608,12 @@ int start_polling(int dev_idx, int proto, int virtual_fd, int sd, int fid, int p
 	if (rc != 0)
 		return rc;
 
-	pthread_join(thread_t, (void **)&status);
-	return status;
+	return join_thread_status(thread_t);
 }
 
 int stop_polling(int dev_idx, int virtual_fd, int sd, int fid, int pid)
 {
 	pthread_t thread_t;
-	int status;
 	int rc;
 
 	rc = pthread_create(&thread_t, NULL, virtual_poll_stop,
@@ -618,8 +626,7 @@ int stop_polling(int dev_idx, int virtual_fd, int sd, int fid, int pid)
 	if (rc != 0)
 		return rc;
 
-	pthread_join(thread_t, (void **)&status);
-	return status;
+	return join_thread_status(thread_t);
 }
 
 TEST_F(NCI, start_poll)
@@ -834,8 +841,10 @@ int disconnect_tag(int nfc_sock, int virtual_fd)
 		return status;
 
 	close(nfc_sock);
-	pthread_join(thread_t, (void **)&status);
-	return status;
+	if (status)
+		return -1;
+
+	return join_thread_status(thread_t);
 }
 
 TEST_F(NCI, t4t_tag_read)
@@ -882,7 +891,7 @@ TEST_F(NCI, deinit)
 			       NFC_CMD_DEV_DOWN, self->dev_idex);
 	EXPECT_EQ(rc, 0);
 
-	pthread_join(thread_t, (void **)&status);
+	status = join_thread_status(thread_t);
 	self->open_state = 0;
 	ASSERT_EQ(status, 0);
 
Signature · 1 line
2.53.0
author maintainer
#174 lore raw

PATCH 174/457 nfc: virtual_ncidev: Add missing ioctl compat handler

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chris Gellermann <[email protected]>

[ Upstream commit 51814683e28fc64eceb415962376956c3cfc75a7 ]

The compat handler for ioctls to the virtual nci device is missing. So, nci-specific ioctls of a compat task return with -1 and errno set to ENOTTY. Add a handler.

The handling of an ioctl() call of a compat task to get the index of virtual nci device (IOCTL_GET_NCIDEV_IDX) lands in the default case of the ioctl compat handler (see fs/ioctl.c):

COMPAT_SYSCALL_DEFINE3(ioctl, ...)

{
	...
	default:
       		error = do_vfs_ioctl(fd_file(f), fd, cmd, ...);
		if (error != -ENOIOCTLCMD)
			break;

		if (fd_file(f)->f_op->compat_ioctl)
			error = fd_file(f)->f_op->compat_ioctl(fd_file(f), cmd, arg);
		if (error == -ENOIOCTLCMD)
			error = -ENOTTY;
	...
}

There, do_vfs_ioctl() returns -ENOIOCTLCMD and compat_ioctl is not set for virtual_ncidev_fops, i.e. f_op->compat_ioctl == NULL. So, the ioctl() syscall returns with -1 and errno set to ENOTTY to the compat task.

To fix this, use the compat_ptr_ioctl helper for compat handling here. It shall be used for ioctls that "either ignore the argument or pass a pointer to a compatible data type". The driver's sole ioctl takes a user void pointer and copies nfc_dev->idx to it, a 4-byte integer across all ABIs.

This issue has been found by running the nci_dev kernel selftest as rv64 binary on top of a CHERI kernel, where the ioctl() ends up in the ioctl compat handler, similar to a 32-bit application on top of a 64-bit kernel.

---
 drivers/nfc/virtual_ncidev.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/nfc/virtual_ncidev.c +2 -1
index 8eeb447ac96e9..e51c647b27ebe 100644
@@ -195,7 +195,8 @@ static const struct file_operations virtual_ncidev_fops = {
 	.write = virtual_ncidev_write,
 	.open = virtual_ncidev_open,
 	.release = virtual_ncidev_close,
-	.unlocked_ioctl = virtual_ncidev_ioctl
+	.unlocked_ioctl = virtual_ncidev_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
 };
 
 static struct miscdevice miscdev = {
Signature · 1 line
2.53.0
author maintainer
#175 lore raw

PATCH 175/457 nfc: llcp: fix sdreq TLV list leak on parse/alloc/send failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cong Nguyen <[email protected]>

[ Upstream commit 66f4300206b82b0b143ef0d9be90cd8d29f23a47 ]

nfc_genl_llc_sdreq() builds a list of TLV nodes while walking nested netlink attrs, but 3 error paths (nested-attr parse failure, TLV alloc ENOMEM, nfc_llcp_send_snl_sdreq() failure) all skip freeing what was already queued.

Route them through a new free_list label, mirroring the SDRES path in the same file which already does this. Harmless on the success path too -- send_snl_sdreq() drains the list as it moves nodes, so it's already empty by the time free_list runs.

Fixes d9b8d8e19b07 ("NFC: llcp: Service Name Lookup netlink interface")
Assisted-by Claude:claude-opus-4
---
 net/nfc/netlink.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
net/nfc/netlink.c +5 -2
index 0c58824cb150d..224bdfa2dd0dc 100644
@@ -1181,7 +1181,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
 
 		if (rc != 0) {
 			rc = -EINVAL;
-			goto put_local;
+			goto free_list;
 		}
 
 		if (!sdp_attrs[NFC_SDP_ATTR_URI])
@@ -1200,7 +1200,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
 		sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
 		if (sdreq == NULL) {
 			rc = -ENOMEM;
-			goto put_local;
+			goto free_list;
 		}
 
 		tlvs_len += sdreq->tlv_len;
@@ -1215,6 +1215,9 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
 
 	rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
 
+free_list:
+	nfc_llcp_free_sdp_tlv_list(&sdreq_list);
+
 put_local:
 	nfc_llcp_local_put(local);
 
Signature · 1 line
2.53.0
author maintainer
#176 lore raw

PATCH 176/457 nfc: st21nfca: validate ISO15693 inventory length

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit 7f2ea5ed588c03d481f0301e6c3d4240132383fb ]

The ISO15693 inventory helper removes a two-byte prefix without checking that it exists, then accepts a one-byte remainder before reading data[1] as the DSFID.

Require the prefix and at least two remaining bytes before copying the UID data and reading the DSFID.

Fixes 7974728094d3 ("NFC: st21nfca: Add ISO15693 Reader/Writer support")
---
 drivers/nfc/st21nfca/core.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/nfc/st21nfca/core.c +1 -3
index fd39a05c96222..34d797a29d21b 100644
@@ -577,9 +577,7 @@ static int st21nfca_get_iso15693_inventory(struct nfc_hci_dev *hdev,
 	if (r < 0)
 		goto exit;
 
-	skb_pull(inventory_skb, 2);
-
-	if (inventory_skb->len == 0 ||
+	if (!skb_pull(inventory_skb, 2) || inventory_skb->len < 2 ||
 	    inventory_skb->len > NFC_ISO15693_UID_MAXSIZE) {
 		r = -EPROTO;
 		goto exit;
Signature · 1 line
2.53.0
author maintainer
#177 lore raw

PATCH 177/457 nfc: llcp: fix -ENOMEM on connect with zero-length service name

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ömer Mete Kaya <[email protected]>

[ Upstream commit c04981e42d94f39c1dba965cc462a046e946a6c5 ]

When service_name_len is 0, kmemdup() returns ZERO_SIZE_PTR which passes the NULL check, causing nfc_llcp_send_connect() to attempt building a zero-length service name TLV and fail with -ENOMEM.

Fix by setting service_name to NULL directly when service_name_len is 0.

---
 net/nfc/llcp_sock.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)
net/nfc/llcp_sock.c +10 -6
index ce6875eb58fbc..1e5ee4bcde684 100644
@@ -759,12 +759,16 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr_unsized *_addr
 	llcp_sock->service_name_len = min_t(unsigned int,
 					    addr->service_name_len,
 					    NFC_LLCP_MAX_SERVICE_NAME);
-	llcp_sock->service_name = kmemdup(addr->service_name,
-					  llcp_sock->service_name_len,
-					  GFP_KERNEL);
-	if (!llcp_sock->service_name) {
-		ret = -ENOMEM;
-		goto sock_llcp_release;
+	if (llcp_sock->service_name_len == 0) {
+		llcp_sock->service_name = NULL;
+	} else {
+		llcp_sock->service_name = kmemdup(addr->service_name,
+						  llcp_sock->service_name_len,
+						  GFP_KERNEL);
+		if (!llcp_sock->service_name) {
+			ret = -ENOMEM;
+			goto sock_llcp_release;
+		}
 	}
 
 	nfc_llcp_sock_link(&local->connecting_sockets, sk);
Signature · 1 line
2.53.0
author maintainer
#178 lore raw

PATCH 178/457 nfc: llcp: fix WKS SAP hijacking via prefix match in nfc_llcp_wks_sap()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ömer Mete Kaya <[email protected]>

[ Upstream commit 408cff6bd60636df201274d320edfdfde9ed41db ]

nfc_llcp_wks_sap() compares only service_name_len bytes, so a short service_name like "u" matches longer WKS strings like "urn:nfc:sn:snep". Fix by requiring exact length match before strncmp().

---
 net/nfc/llcp_core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/nfc/llcp_core.c +2 -1
index 23553e7426ec2..fc267533a67f2 100644
@@ -369,7 +369,8 @@ static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len)
 		if (wks[sap] == NULL)
 			continue;
 
-		if (strncmp(wks[sap], service_name, service_name_len) == 0)
+		if (strlen(wks[sap]) == service_name_len &&
+		    !strncmp(wks[sap], service_name, service_name_len))
 			return sap;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#179 lore raw

PATCH 179/457 nfc: llcp: fix slab-out-of-bounds reads when logging service names

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ömer Mete Kaya <[email protected]>

[ Upstream commit 7dcf371a35632f035baf77bcf2c129165f772ce4 ]

nfc_llcp_wks_sap() and nfc_llcp_build_sdreq_tlv() pass non-null- terminated strings to pr_debug() using the %s format specifier. The buffers are allocated via kmemdup() or come from netlink attributes and are not guaranteed to be null-terminated, causing __dynamic_pr_debug() to read beyond the allocated region:

  KASAN: slab-out-of-bounds Read in __dynamic_pr_debug

Fix both call sites by using %.*s with the explicit length to limit the output to the actual length of the string.

---
 net/nfc/llcp_commands.c | 2 +-
 net/nfc/llcp_core.c     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
net/nfc/llcp_commands.c +1 -1
index ca89fe967d6a2..80a00938c8696 100644
@@ -135,7 +135,7 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, const char *uri,
 {
 	struct nfc_llcp_sdp_tlv *sdreq;
 
-	pr_debug("uri: %s, len: %zu\n", uri, uri_len);
+	pr_debug("uri: %.*s, len: %zu\n", (int)uri_len, uri, uri_len);
 
 	/* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */
 	if (WARN_ON_ONCE(uri_len > U8_MAX - 4))
net/nfc/llcp_core.c +1 -1
index fc267533a67f2..10665b2089873 100644
@@ -358,7 +358,7 @@ static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len)
 {
 	int sap, num_wks;
 
-	pr_debug("%s\n", service_name);
+	pr_debug("%.*s\n", (int)service_name_len, service_name);
 
 	if (service_name == NULL)
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#180 lore raw

PATCH 180/457 nfc: pn533: fix OOB read in pn533_acr122_is_rx_frame_valid()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Deepanshu Kartikey <[email protected]>

[ Upstream commit b61732f47316d45f27706db7812950145d3327b5 ]

frame->ccid.datalen is read directly from the USB response frame and used, unchecked, as an index into frame->data[]. A malicious or malfunctioning device can set this field to an arbitrary value, causing the driver to read far outside the received buffer.

Bound ccid.datalen against the maximum possible ACR122 frame size before using it. This replaces the existing datalen == 0 check, since datalen < 2 already covers that case and additionally rejects datalen == 1, which would still underflow the "datalen - 2" offset used below.

Fixes 9815c7cf22da ("NFC: pn533: Separate physical layer from the core implementation")
Reported-by [email protected]
Assisted-by LLM
---
 drivers/nfc/pn533/usb.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/nfc/pn533/usb.c +3 -1
index efb07f944fce2..972eaac09e592 100644
@@ -319,7 +319,9 @@ static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
 	if (frame->ccid.type != 0x83)
 		return false;
 
-	if (!frame->ccid.datalen)
+	if (frame->ccid.datalen < 2 ||
+	    frame->ccid.datalen > PN533_ACR122_FRAME_MAX_PAYLOAD_LEN +
+	    PN533_ACR122_RX_FRAME_TAIL_LEN)
 		return false;
 
 	if (frame->data[frame->ccid.datalen - 2] == 0x63)
Signature · 1 line
2.53.0
author maintainer
#181 lore raw

PATCH 181/457 net/sched: act_gate: budget the per-entry list in get_fill_size

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Victor Nogueira <[email protected]>

[ Upstream commit cfa165cbfbed9d0f4bbc22fef4309f595a3ab187 ]

tcf_gate_get_fill_size returns only the TCA_GATE_PARMS size, but tcf_gate_dump also emits three 64-bit timestamps, the clock id, flags, priority and the variable-length TCA_GATE_ENTRY_LIST nest. The per-entry nest is unbounded: parse_gate_list places no cap on the number of sched-entries, so a gate with many entries can push the real dump well past the skb that tca_get_fill allocates from this size.

RTM_NEWACTION then fails the add-notify with -EINVAL while the action is already committed to the IDR, and a subsequent RTM_GETACTION on the installed gate also returns -EINVAL because its dump no longer fits.

Fix this by accounting for the missing fields in tcf_gate_get_fill_size along with all elements in the entries list.

Note that sizing the reply from the action lets an oversized gate install cleanly for the first time: with the input unbounded by parse_gate_list, the sized skb can now grow well above NLMSG_GOODSIZE per netlink request (a transient GFP_KERNEL allocation reachable only with namespace-local CAP_NET_ADMIN). Overload from a malicious netns admin is hardening material, not net, per the discussion at
https://lore.kernel.org/netdev/[email protected]/;
a follow-up patch for net-next will cap the sched-entry count.

---
 net/sched/act_gate.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)
net/sched/act_gate.c +29 -1
index fdbfcaa3e2ab9..a3c96519936ba 100644
@@ -681,7 +681,35 @@ static void tcf_gate_stats_update(struct tc_action *a, u64 bytes, u64 packets,
 
 static size_t tcf_gate_get_fill_size(const struct tc_action *act)
 {
-	return nla_total_size(sizeof(struct tc_gate));
+	struct tcf_gate *gact = to_gate(act);
+	const struct tcf_gate_params *p;
+	struct tcfg_gate_entry *entry;
+	size_t size = nla_total_size(sizeof(struct tc_gate)) /* TCA_GATE_PARMS */
+		+ 3 * nla_total_size_64bit(sizeof(u64)) /* TCA_GATE_BASE_TIME
+							 * TCA_GATE_CYCLE_TIME
+							 * TCA_GATE_CYCLE_TIME_EXT
+							 */
+		+ nla_total_size(sizeof(s32)) /* TCA_GATE_CLOCKID */
+		+ nla_total_size(sizeof(u32)) /* TCA_GATE_FLAGS */
+		+ nla_total_size(sizeof(s32)) /* TCA_GATE_PRIORITY */
+		+ nla_total_size(0); /* TCA_GATE_ENTRY_LIST */
+	/* TCA_GATE_TM is budgeted by tcf_action_shared_attrs_size() */
+
+	rcu_read_lock();
+	p = rcu_dereference(gact->param);
+	if (p) {
+		list_for_each_entry_rcu(entry, &p->entries, list)
+			/* TCA_GATE_ONE_ENTRY nest and its attributes */
+			size += nla_total_size(0)
+				+ nla_total_size(sizeof(u32)) /* TCA_GATE_ENTRY_INDEX */
+				+ nla_total_size(0) /* TCA_GATE_ENTRY_GATE */
+				+ nla_total_size(sizeof(u32)) /* TCA_GATE_ENTRY_INTERVAL */
+				+ nla_total_size(sizeof(s32)) /* TCA_GATE_ENTRY_MAX_OCTETS */
+				+ nla_total_size(sizeof(s32)); /* TCA_GATE_ENTRY_IPV */
+	}
+	rcu_read_unlock();
+
+	return size;
 }
 
 static void tcf_gate_entry_destructor(void *priv)
Signature · 1 line
2.53.0
author maintainer
#182 lore raw

PATCH 182/457 net: bcmgenet: stop Tx NAPI before disabling the queues

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nicolai Buchwitz <[email protected]>

[ Upstream commit 7e87508b5c4d81210d0a736ed01962e52f5c4c56 ]

bcmgenet_netif_stop() and the Wake-on-LAN branch of bcmgenet_suspend() both disable the Tx queues first and stop Tx NAPI several steps later. A completion in flight calls netif_tx_wake_queue() in between, and nothing stops the queue again, so a transmit can reach the rings after they have been freed.

Close is safe because dev_deactivate_many() stops the qdisc first. bcmgenet_suspend() does not, so stop Tx NAPI before the queues on both paths.

KASAN on a Raspberry Pi CM4, driven from an MTU change because suspend freezes user space before the callback runs:

  BUG: KASAN: use-after-free in bcmgenet_xmit+0x17f8/0x2258
  Write of size 8 at addr ffffff8055844a68 by task ksoftirqd/0/14
   bcmgenet_xmit+0x17f8/0x2258
   dev_hard_start_xmit+0x13c/0x588
   sch_direct_xmit+0x108/0x340
   __dev_queue_xmit+0x1190/0x3848
Fixes 254f3239dd07 ("net: bcmgenet: revise suspend/resume")
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +4 -2
index b916080f4ff17..ca62041efecd7 100644
@@ -3441,6 +3441,8 @@ static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 
+	/* Stop completion polling before it can wake a stopped queue */
+	bcmgenet_disable_tx_napi(priv);
 	netif_tx_disable(dev);
 
 	/* Disable MAC receive */
@@ -3455,7 +3457,6 @@ static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy)
 	/* Disable MAC transmit. TX DMA disabled must be done before this */
 	umac_enable_set(priv, CMD_TX_EN, false);
 
-	bcmgenet_disable_tx_napi(priv);
 	bcmgenet_disable_rx_napi(priv);
 	bcmgenet_intr_disable(priv);
 
@@ -4320,6 +4321,8 @@ static int bcmgenet_suspend(struct device *d)
 	netif_device_detach(dev);
 
 	if (device_may_wakeup(d) && priv->wolopts) {
+		/* Stop completion polling before it can wake a stopped queue */
+		bcmgenet_disable_tx_napi(priv);
 		netif_tx_disable(dev);
 
 		/* Suspend non-wake Rx data flows */
@@ -4348,7 +4351,6 @@ static int bcmgenet_suspend(struct device *d)
 			netdev_warn(priv->dev,
 				    "Timed out while disabling TX DMA\n");
 
-		bcmgenet_disable_tx_napi(priv);
 		bcmgenet_disable_rx_napi(priv);
 		disable_irq(priv->irq1);
 		bcmgenet_tx_reclaim_all(dev);
Signature · 1 line
2.53.0
author maintainer
#183 lore raw

PATCH 183/457 veth: manage XDP program pointers during channel resize

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <[email protected]>

[ Upstream commit 7104a370714346b667712913dc16abf14bbc97ed ]

veth_set_channels() tears down XDP resources for removed RX queues without clearing rq->xdp_prog. If the program is then detached or replaced, those queues keep the old pointer after bpf_prog_put(). A later channel increase can re-enable NAPI and run the freed program.

  BUG: unable to handle page fault for address: ffffc90000256048
  Oops: Oops: 0000 [#1] SMP KASAN NOPTI
  RIP: veth_xdp_rcv_skb (include/linux/filter.h:779
                         include/net/xdp.h:696 drivers/net/veth.c:820)
  Call Trace:
   veth_xdp_rcv (drivers/net/veth.c:941)
   veth_poll (drivers/net/veth.c:986)
   __napi_poll (net/core/dev.c:7787)
   net_rx_action (net/core/dev.c:7850 net/core/dev.c:8007)
   handle_softirqs (kernel/softirq.c:645)
  Kernel panic - not syncing: Fatal exception in interrupt
---
 drivers/net/veth.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/veth.c +2 -0
index 6ab84c837a332..2780b2dd073d1 100644
@@ -1053,6 +1053,7 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
 	for (i = start; i < end; i++) {
 		struct veth_rq *rq = &priv->rq[i];
 
+		rcu_assign_pointer(rq->xdp_prog, priv->_xdp_prog);
 		napi_enable(&rq->xdp_napi);
 		rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
 	}
@@ -1087,6 +1088,7 @@ static void veth_napi_del_range(struct net_device *dev, int start, int end)
 
 		rcu_assign_pointer(priv->rq[i].napi, NULL);
 		napi_disable(&rq->xdp_napi);
+		rcu_assign_pointer(rq->xdp_prog, NULL);
 		__netif_napi_del(&rq->xdp_napi);
 	}
 	synchronize_net();
Signature · 1 line
2.53.0
author maintainer
#184 lore raw

PATCH 184/457 net: skbuff: fix pull-bound underflow in skb_checksum_setup_ipv6()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shihuang Liu <[email protected]>

[ Upstream commit 3b4e0b0c008a8c1b474730248cd5b873026c74bd ]

skb_maybe_pull_tail() subtracts skb_headlen(skb) from the unsigned max argument and passes the result to __pskb_pull_tail() as a signed int. The function does not ensure that max is at least skb_headlen(skb).

This can happen while parsing IPv6 extension headers when an skb already has a linear area larger than MAX_IPV6_HDR_LEN. Once the parser needs data beyond the linear area, max - skb_headlen(skb) wraps and is converted to a negative delta. __pskb_pull_tail() then passes that negative length to skb_copy_bits(), where it can become a very large copy length.

Pass the requested length itself as the pull bound at the three extension-header call sites, so the delta can no longer go negative.

Fixes 1431fb31ecba ("xen-netback: fix fragment detection in checksum setup")
---
 net/core/skbuff.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
net/core/skbuff.c +6 -3
index c485be081aeaa..89ee7907e4996 100644
@@ -5965,7 +5965,8 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
 			err = skb_maybe_pull_tail(skb,
 						  off +
 						  sizeof(struct ipv6_opt_hdr),
-						  MAX_IPV6_HDR_LEN);
+						  off +
+						  sizeof(struct ipv6_opt_hdr));
 			if (err < 0)
 				goto out;
 
@@ -5980,7 +5981,8 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
 			err = skb_maybe_pull_tail(skb,
 						  off +
 						  sizeof(struct ip_auth_hdr),
-						  MAX_IPV6_HDR_LEN);
+						  off +
+						  sizeof(struct ip_auth_hdr));
 			if (err < 0)
 				goto out;
 
@@ -5995,7 +5997,8 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
 			err = skb_maybe_pull_tail(skb,
 						  off +
 						  sizeof(struct frag_hdr),
-						  MAX_IPV6_HDR_LEN);
+						  off +
+						  sizeof(struct frag_hdr));
 			if (err < 0)
 				goto out;
 
Signature · 1 line
2.53.0
author maintainer
#185 lore raw

PATCH 185/457 vrf: Stop corrupting skb->csum when capturing CHECKSUM_COMPLETE packets

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ido Schimmel <[email protected]>

[ Upstream commit ab7aa05c06ae340e5c7530bb78fa8d23794e460b ]

The VRF device is an Ethernet device but it can have non-Ethernet ports such as IP tunnels. Before the cited commit, capturing packets from such ports on the VRF device resulted in these packets being detected as malformed since they lack an Ethernet header.

The cited commit fixed it by pushing a dummy Ethernet header to such packets before the capture and pulling it afterwards. In the case of CHECKSUM_COMPLETE packets it also updated skb->csum with the checksum of the dummy Ethernet header. This is wrong as skb->csum should not include the checksum of the Ethernet header ("checksum of the _whole_ packet as seen by netif_rx()").

This also means that L4 protocols receive a corrupted skb->csum and potentially drop the packet, as is the case with UDP packets whose checksum was completed by software.

Fix by removing the unnecessary call to skb_postpush_rcsum().

---
 drivers/net/vrf.c | 2 --
 1 file changed, 2 deletions(-)
drivers/net/vrf.c +0 -2
index 46209917ae4d6..bae0b69cf894c 100644
@@ -1175,8 +1175,6 @@ static int vrf_prepare_mac_header(struct sk_buff *skb,
 	skb->protocol = eth->h_proto;
 	skb->pkt_type = PACKET_HOST;
 
-	skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
-
 	skb_pull_inline(skb, ETH_HLEN);
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#186 lore raw

PATCH 186/457 net: dsa: mv88e6xxx: 88E6191X and 88E6193X have no PTP

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nicolo Giuliani <[email protected]>

[ Upstream commit 6b491af01aa5c0633a580e3b11bc7277adc903b2 ]

The 88E6191X and 88E6193X are 6393 family devices that share mv88e6393x_ops with the 88E6393X and are marked as ptp_support. Marvell's UMSD driver describes both as parts without AVB (88E6193X: "BGA package - No AVB, No Routing, No Cut-through"), and the register access confirms it on an 88E6193X: the whole indirect AVB register space behind Global 2 registers 0x16 and 0x17 reads zero, for every port, block and address, with the 6390 and with the 6352 command encoding. Writes to the TAI registers, including the clock period register and the TAI global configuration register, read back as zero.

Since commit 7e3c18097a70 ("net: dsa: mv88e6xxx: read cycle counter period from hardware") the PTP setup reads the TAI clock period, so the switch fails to probe:

mv88e6xxx ...: unexpected cycle counter period of 0 ps

Add mv88e6191x_ops, a copy of mv88e6393x_ops without avb_ops and ptp_ops, use it for the 88E6191X and the 88E6193X and stop setting ptp_support for them. The 88E6393X is unchanged.

Tested on an 88E6193X (Sophos XGS 107w): the switch probes and the ports work. I do not have an 88E6191X, it is changed because UMSD describes it the same way.

Fixes de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family")
---
 drivers/net/dsa/mv88e6xxx/chip.c | 68 ++++++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 4 deletions(-)
drivers/net/dsa/mv88e6xxx/chip.c +64 -4
index 7f68a0c558026..a4a8c7e11bf4f 100644
@@ -5639,6 +5639,68 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
 	.pcs_ops = &mv88e6390_pcs_ops,
 };
 
+static const struct mv88e6xxx_ops mv88e6191x_ops = {
+	/* MV88E6XXX_FAMILY_6393 without AVB and PTP: 6191X and 6193X */
+	.irl_init_all = mv88e6390_g2_irl_init_all,
+	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
+	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
+	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+	.phy_read = mv88e6xxx_g2_smi_phy_read_c22,
+	.phy_write = mv88e6xxx_g2_smi_phy_write_c22,
+	.phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45,
+	.phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45,
+	.port_set_link = mv88e6xxx_port_set_link,
+	.port_sync_link = mv88e6xxx_port_sync_link,
+	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
+	.port_tag_remap = mv88e6390_port_tag_remap,
+	.port_set_policy = mv88e6393x_port_set_policy,
+	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
+	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
+	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
+	.port_set_ether_type = mv88e6393x_port_set_ether_type,
+	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
+	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+	.port_pause_limit = mv88e6390_port_pause_limit,
+	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+	.port_get_cmode = mv88e6352_port_get_cmode,
+	.port_set_cmode = mv88e6393x_port_set_cmode,
+	.port_setup_message_port = mv88e6xxx_setup_message_port,
+	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
+	.port_enable_tcam = mv88e6xxx_port_enable_tcam,
+	.stats_snapshot = mv88e6390_g1_stats_snapshot,
+	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
+	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
+	.stats_get_strings = mv88e6320_stats_get_strings,
+	.stats_get_stat = mv88e6390_stats_get_stat,
+	/* .set_cpu_port is missing because this family does not support a global
+	 * CPU port, only per port CPU port which is set via
+	 * .port_set_upstream_port method.
+	 */
+	.set_egress_port = mv88e6393x_set_egress_port,
+	.watchdog_ops = &mv88e6393x_watchdog_ops,
+	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
+	.pot_clear = mv88e6xxx_g2_pot_clear,
+	.hardware_reset_pre = mv88e6xxx_g2_eeprom_wait,
+	.hardware_reset_post = mv88e6xxx_g2_eeprom_wait,
+	.reset = mv88e6352_g1_reset,
+	.rmu_disable = mv88e6390_g1_rmu_disable,
+	.atu_get_hash = mv88e6165_g1_atu_get_hash,
+	.atu_set_hash = mv88e6165_g1_atu_set_hash,
+	.vtu_getnext = mv88e6390_g1_vtu_getnext,
+	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
+	.stu_getnext = mv88e6390_g1_stu_getnext,
+	.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
+	.serdes_get_lane = mv88e6393x_serdes_get_lane,
+	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
+	/* TODO: serdes stats */
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.phylink_get_caps = mv88e6393x_phylink_get_caps,
+	.pcs_ops = &mv88e6393x_pcs_ops,
+	.tcam_ops = &mv88e6393_tcam_ops,
+};
+
 static const struct mv88e6xxx_ops mv88e6393x_ops = {
 	/* MV88E6XXX_FAMILY_6393 */
 	.irl_init_all = mv88e6390_g2_irl_init_all,
@@ -6163,8 +6225,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.atu_move_port_mask = 0x1f,
 		.pvt = true,
 		.multi_chip = true,
-		.ptp_support = true,
-		.ops = &mv88e6393x_ops,
+		.ops = &mv88e6191x_ops,
 	},
 
 	[MV88E6193X] = {
@@ -6190,8 +6251,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.atu_move_port_mask = 0x1f,
 		.pvt = true,
 		.multi_chip = true,
-		.ptp_support = true,
-		.ops = &mv88e6393x_ops,
+		.ops = &mv88e6191x_ops,
 	},
 
 	[MV88E6220] = {
Signature · 1 line
2.53.0
author maintainer
#187 lore raw

PATCH 187/457 net: mdio: realtek-rtl9300: fix RTL931x C22 extended page selection

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jonas Jelonek <[email protected]>

[ Upstream commit 89a8a1eef2d441b7825a6c0116ce817235a7ffe6 ]

The RTL931x indirect access engine has a separate nine-bit extended page field. The driver leaves it at zero, and otto_emdio_run_cmd() therefore programs extended page zero for every Clause 22 transaction. This overrides page selection made through PHY register 30, causing accesses to private PHY pages to hit extended page zero instead.

Set the field to its 0x1ff "do not change" value for RTL931x Clause 22 reads and writes. This preserves extended page selection made through PHY register 30 and restores access to its private register pages.

Fixes 5ebdcac59aff ("net: mdio: realtek-rtl9300: Add support for RTL931x")
---
 drivers/net/mdio/mdio-realtek-rtl9300.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/net/mdio/mdio-realtek-rtl9300.c +6 -0
index afd52a1cd7f83..9ce2b78075320 100644
@@ -88,6 +88,8 @@
 #define RTL9310_SMI_INDRT_ACCESS_BC_PHYID_CTRL	0x0c14
 #define   RTL9310_BC_PORT_ID			GENMASK(10, 5)
 #define RTL9310_SMI_INDRT_ACCESS_CTRL_1		0x0c04
+#define   RTL9310_SMI_INDRT_EXT_PAGE		GENMASK(8, 0)
+#define   RTL9310_SMI_INDRT_EXT_PAGE_NO_CHANGE	0x1ff
 #define RTL9310_SMI_INDRT_ACCESS_CTRL_2_LOW	0x0c08
 #define RTL9310_SMI_INDRT_ACCESS_CTRL_2_HIGH	0x0c0c
 #define RTL9310_SMI_INDRT_ACCESS_CTRL_3		0x0c10 /* I/O fields flipped */
@@ -325,6 +327,8 @@ static int otto_emdio_9310_read_c22(struct mii_bus *bus, int port, int regnum, u
 		.broadcast	= FIELD_PREP(RTL9310_BC_PORT_ID, port),
 		.c22_data	= FIELD_PREP(RTL9310_PHY_CTRL_REG_ADDR, regnum) |
 				  FIELD_PREP(RTL9310_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)),
+		.ext_page	= FIELD_PREP(RTL9310_SMI_INDRT_EXT_PAGE,
+					     RTL9310_SMI_INDRT_EXT_PAGE_NO_CHANGE),
 	};
 
 	return otto_emdio_read_cmd(bus, RTL9310_PHY_CTRL_TYPE_C22, &cmd_data,
@@ -337,6 +341,8 @@ static int otto_emdio_9310_write_c22(struct mii_bus *bus, int port, int regnum,
 	struct otto_emdio_cmd_regs cmd_data = {
 		.c22_data	= FIELD_PREP(RTL9310_PHY_CTRL_REG_ADDR, regnum) |
 				  FIELD_PREP(RTL9310_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)),
+		.ext_page	= FIELD_PREP(RTL9310_SMI_INDRT_EXT_PAGE,
+					     RTL9310_SMI_INDRT_EXT_PAGE_NO_CHANGE),
 		.io_data	= FIELD_PREP(RTL9310_PHY_CTRL_INDATA, value),
 		.port_mask_high	= (u32)(BIT_ULL(port) >> 32),
 		.port_mask_low	= (u32)(BIT_ULL(port)),
Signature · 1 line
2.53.0
author maintainer
#188 lore raw

PATCH 188/457 bpf: Fix immediate JMP JEQ/JNE on MIPS32

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Almbladh <[email protected]>

[ Upstream commit db762fd96be225bd06161c9631160c755d891693 ]

An addu instruction was emitted instead of addiu, causing the immediate value 1 to be interpreted as register $at. This made the comparison result invalid when the immediate operand was negative. Note that $at is mapped to BPF_REG_AX, which is used for constant blinding.

Fix the instruction to use the immediate form.

Found with test_bpf on MIPS32r1 emulated by QEMU.

Fixes eb63cfcd2ee8 ("mips, bpf: Add eBPF JIT for 32-bit MIPS")
---
 arch/mips/net/bpf_jit_comp32.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/net/bpf_jit_comp32.c +1 -1
index 40a878b672f5d..15a2a153dc873 100644
@@ -1111,7 +1111,7 @@ static void emit_jmp_i64(struct jit_context *ctx,
 			emit(ctx, xor, tmp, lo(dst), tmp);
 		}
 		if (imm < 0) { /* Compare sign extension */
-			emit(ctx, addu, MIPS_R_T9, hi(dst), 1);
+			emit(ctx, addiu, MIPS_R_T9, hi(dst), 1);
 			emit(ctx, or, tmp, tmp, MIPS_R_T9);
 		} else {       /* Compare zero extension */
 			emit(ctx, or, tmp, tmp, hi(dst));
Signature · 1 line
2.53.0
author maintainer
#189 lore raw

PATCH 189/457 bpf: Fix BSWAP 32 and 16 on MIPS64

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Almbladh <[email protected]>

[ Upstream commit 8110ba09777873443db286b3cbb89b0e6311c554 ]

The 16/32-bit byteswap implementations for MIPS64r1 and earlier do not have an explicit zero extension afterwards. The input is first sign-extended to 64 bits, and the byteswap sequence can then leave the result sign-extended depending on the value of the low bits.

Add the missing zero-extension.

Found with test_bpf on MIPS64r1 emulated by QEMU.

Fixes fbc802de6b10 ("mips, bpf: Add new eBPF JIT for 64-bit MIPS")
---
 arch/mips/net/bpf_jit_comp64.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/mips/net/bpf_jit_comp64.c +1 -2
index fa7e9aa37f498..6681ccac9dd9e 100644
@@ -305,8 +305,7 @@ static void emit_bswap_r64(struct jit_context *ctx, u8 dst, u32 width)
 	case 16:
 		emit_sext(ctx, dst, dst);
 		emit_bswap_r(ctx, dst, width);
-		if (cpu_has_mips64r2 || cpu_has_mips64r6)
-			emit_zext(ctx, dst);
+		emit_zext(ctx, dst);
 		break;
 	}
 	clobber_reg(ctx, dst);
Signature · 1 line
2.53.0
author maintainer
#190 lore raw

PATCH 190/457 tg3: use random MAC address when tg3_get_device_address fails

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ivan Delalande <[email protected]>

[ Upstream commit 4eb3f195ef08c5acaed87958297e41cc49588dde ]

Some of the tg3 NICs we use (BCM57762) reset the SRAM MAC address to the placeholder address on link flaps, tg3_chip_reset, etc. We've typically fixed it from userspace, but since e4c00ba7274b ("tg3: replace placeholder MAC address with device property") was merged, tg3 just fails probe as we don't have a way to get it through the generic device_get_mac_address infrastructure as fallback on our systems.

Make the driver assign a random address in this condition instead of being fatal for probe. Set deferred_probe_reason through dev_warn_probe if the address isn't yet available from the provider.

---
 drivers/net/ethernet/broadcom/tg3.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/net/ethernet/broadcom/tg3.c +7 -4
index caa7a6caa6e2f..8b6806a79edff 100644
@@ -17915,11 +17915,14 @@ static int tg3_init_one(struct pci_dev *pdev,
 
 	err = tg3_get_device_address(tp, addr);
 	if (err) {
-		dev_err(&pdev->dev,
-			"Could not obtain valid ethernet address, aborting\n");
-		goto err_out_apeunmap;
+		dev_warn_probe(&pdev->dev, err,
+			       "Could not obtain a valid ethernet address\n");
+		if (err == -EPROBE_DEFER)
+			goto err_out_apeunmap;
+		eth_hw_addr_random(dev);
+	} else {
+		eth_hw_addr_set(dev, addr);
 	}
-	eth_hw_addr_set(dev, addr);
 
 	intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW;
 	rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW;
Signature · 1 line
2.53.0
author maintainer
#191 lore raw

PATCH 191/457 net: stmmac: clear stale buf->page after recycling on skb build failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lorenzo Bianconi <[email protected]>

[ Upstream commit 0a7822e34a0bfde31b194ac3da3253e5032b44cc ]

In stmmac_rx(), when napi_build_skb() fails the descriptor page is recycled back to the page pool with page_pool_recycle_direct(), but buf->page is left pointing at the recycled page, unlike every other consumption site in the function which clears the pointer after handing the page away.

With the stale pointer stmmac_rx_refill() skips the replacement allocation and programs the already-recycled page back into the RX descriptor.

Clear buf->page on the napi_build_skb() failure path to keep the buffer lifecycle consistent with the other consumption sites.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -0
index 9c4d92a19f2c0..29025eb416987 100644
@@ -5885,6 +5885,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
 			if (!skb) {
 				page_pool_recycle_direct(rx_q->page_pool,
 							 buf->page);
+				buf->page = NULL;
 				rx_dropped++;
 				count++;
 				goto drain_data;
Signature · 1 line
2.53.0
author maintainer
#192 lore raw

PATCH 192/457 net: ipv6: keep room for the mac header in dst_dev_overhead()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yuya Kusakabe <[email protected]>

[ Upstream commit 87cd6b717e4069dca34e0866e57eaeb44d3b173e ]

The seg6, ioam6 and rpl lwtunnels size their skb_cow_head() request as the length they are about to push plus dst_dev_overhead(), then push the new headers and rebuild the mac header below them with skb_mac_header_rebuild(). That rebuild needs skb->mac_len of headroom, but dst_dev_overhead() leaves LL_RESERVED_SPACE() of the egress device, 16 bytes for plain Ethernet.

Where the mac header is longer than that, as it is on ingress through a VLAN device with reorder_hdr off, the rebuild runs out of room:
skb_set_mac_header(skb, -skb->mac_len) computes a negative offset, stores it unchecked in the u16 skb->mac_header, and the memmove that follows writes skb->mac_len bytes about 64 KB past skb->head. Forwarding plain ping6 traffic through such a device reproduces it on all five seg6 encapsulation modes and on the rpl and ioam6 inline paths; skb->mac_header comes back as 65534 on a 704-byte head.

Return the larger of the two. The helper already returns skb->mac_len when it has no dst, so this only makes the other branch agree, and it covers every caller rather than each call site in turn.

Fixes 40475b63761a ("net: ipv6: seg6_iptunnel: mitigate 2-realloc issue")
Fixes dce525185bc9 ("net: ipv6: ioam6_iptunnel: mitigate 2-realloc issue")
Fixes 985ec6f5e623 ("net: ipv6: rpl_iptunnel: mitigate 2-realloc issue")
---
 include/net/dst.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
include/net/dst.h +2 -1
index 307073eae7f83..dbedfe72e1fd1 100644
@@ -455,7 +455,8 @@ static inline unsigned int dst_dev_overhead(struct dst_entry *dst,
 					    struct sk_buff *skb)
 {
 	if (likely(dst))
-		return LL_RESERVED_SPACE(dst->dev);
+		return max_t(unsigned int, skb->mac_len,
+			     LL_RESERVED_SPACE(dst->dev));
 
 	return skb->mac_len;
 }
Signature · 1 line
2.53.0
author maintainer
#193 lore raw

PATCH 193/457 net: bcmgenet: fix 64-bit RTNL stats reading in ethtool on 32-bit systems

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Fainelli <[email protected]>

[ Upstream commit 0e2bec77ea62895416600c90588f593516572bca ]

When bcmgenet was converted to 64-bit statistics, STAT_RTNL members were switched to point into struct rtnl_link_stats64, whose fields are 64-bit (__u64) regardless of architecture.

However, bcmgenet_get_ethtool_stats() retained a legacy check:
if (sizeof(unsigned long) != sizeof(u32) &&

      s->stat_sizeof == sizeof(unsigned long))

On 32-bit systems, sizeof(unsigned long) == sizeof(u32), causing this condition to evaluate to false. As a result, 64-bit RTNL stats fields were read via *(u32 *)p. On 32-bit Big-Endian systems (such as MIPS BE), this reads the high 32 bits and returns 0 until the counter exceeds 4GB; on 32-bit Little-Endian systems (such as 32-bit ARM), the value is truncated to 32 bits.

Fix this by checking if s->stat_sizeof == sizeof(u64) so 64-bit fields are always read as 64-bit values.

---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +2 -3
index ca62041efecd7..47a6c073c8d94 100644
@@ -1346,9 +1346,8 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev,
 				p = (char *)&stats64;
 
 			p += s->stat_offset;
-			if (sizeof(unsigned long) != sizeof(u32) &&
-				s->stat_sizeof == sizeof(unsigned long))
-				data[i] = *(unsigned long *)p;
+			if (s->stat_sizeof == sizeof(u64))
+				data[i] = *(u64 *)p;
 			else
 				data[i] = *(u32 *)p;
 		}
Signature · 1 line
2.53.0
author maintainer
#194 lore raw

PATCH 194/457 net: bcmgenet: initialize u64 stats seq counter for all queues

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Fainelli <[email protected]>

[ Upstream commit 3aeaa609fda19c09d5298c9fedaaa3b6229601b5 ]

bcmgenet_gstrings_stats statically defines ethtool statistics for queues 0 through GENET_MAX_MQ_CNT (4). However, bcmgenet_probe() only initialized the u64_stats_sync seq counter up to priv->hw_params->rx_queues and priv->hw_params->tx_queues.

Since priv->hw_params->rx_queues is 0 across all hardware versions (and priv->hw_params->tx_queues is 0 on GENET V1), rings 1..4 have uninitialized u64_stats_sync structures. When ethtool -S is run on 32-bit kernels, bcmgenet_get_ethtool_stats() reads stats from rx_rings[1..4], causing lockdep warnings due to the uninitialized sequence counters.

Initialize the sequence counters for all GENET_MAX_MQ_CNT + 1 queues.

Fixes ffc2c8c4a714 ("net: bcmgenet: Initialize u64 stats seq counter")
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +2 -2
index 47a6c073c8d94..2ab37bb031ed2 100644
@@ -4135,10 +4135,10 @@ static int bcmgenet_probe(struct platform_device *pdev)
 		priv->rx_rings[i].rx_max_coalesced_frames = 1;
 
 	/* Initialize u64 stats seq counter for 32bit machines */
-	for (i = 0; i <= priv->hw_params->rx_queues; i++)
+	for (i = 0; i <= GENET_MAX_MQ_CNT; i++) {
 		u64_stats_init(&priv->rx_rings[i].stats64.syncp);
-	for (i = 0; i <= priv->hw_params->tx_queues; i++)
 		u64_stats_init(&priv->tx_rings[i].stats64.syncp);
+	}
 
 	/* libphy will determine the link state */
 	netif_carrier_off(dev);
Signature · 1 line
2.53.0
author maintainer
#195 lore raw

PATCH 195/457 net: bcmgenet: do not skip WoL power up on GENET V1

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Fainelli <[email protected]>

[ Upstream commit cbbc1aee7776c7fa1d89e6cb963a23e58c495dca ]

bcmgenet_power_up() had an early check for bcmgenet_has_ext(priv) before dispatching by power mode. GENET V1 does not have the EXT block (unlike GENET V2+), which causes bcmgenet_power_up() to immediately return 0.

As a consequence, when waking up from GENET_POWER_WOL_MAGIC on GENET V1, bcmgenet_wol_power_up_cfg() is never invoked to disable the WoL clock, clear wake event masks, and restore normal PHY and MAC operations.

Move the bcmgenet_has_ext() checks to the GENET_POWER_PASSIVE and GENET_POWER_CABLE_SENSE cases where the EXT registers are actually accessed, allowing GENET_POWER_WOL_MAGIC cleanup to execute on all hardware versions.

---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +8 -5
index 2ab37bb031ed2..07032e4193ea1 100644
@@ -1762,13 +1762,12 @@ static int bcmgenet_power_up(struct bcmgenet_priv *priv,
 	int ret = 0;
 	u32 reg;
 
-	if (!bcmgenet_has_ext(priv))
-		return ret;
-
-	reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-
 	switch (mode) {
 	case GENET_POWER_PASSIVE:
+		if (!bcmgenet_has_ext(priv))
+			break;
+
+		reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
 		reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS |
 			 EXT_ENERGY_DET_MASK);
 		if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) {
@@ -1792,8 +1791,12 @@ static int bcmgenet_power_up(struct bcmgenet_priv *priv,
 		break;
 
 	case GENET_POWER_CABLE_SENSE:
+		if (!bcmgenet_has_ext(priv))
+			break;
+
 		/* enable APD */
 		if (!GENET_IS_V5(priv)) {
+			reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
 			reg |= EXT_PWR_DN_EN_LD;
 			bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
 		}
Signature · 1 line
2.53.0
author maintainer
#196 lore raw

PATCH 196/457 net: bcmgenet: validate Ethernet address in bcmgenet_set_mac_addr

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Fainelli <[email protected]>

[ Upstream commit 273941c85fc2632cd3e56ddff737b9245de7697d ]

bcmgenet_set_mac_addr() did not check whether the provided MAC address is a valid Ethernet address before applying it. Userspace could configure an invalid address (such as all zeroes or a multicast address) while the interface is down.

Add a call to is_valid_ether_addr() and return -EADDRNOTAVAIL if the MAC address is not valid.

---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +3 -0
index 07032e4193ea1..011376a1678a1 100644
@@ -3635,6 +3635,9 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p)
 	if (netif_running(dev))
 		return -EBUSY;
 
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
 	eth_hw_addr_set(dev, addr->sa_data);
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#197 lore raw

PATCH 197/457 net: bcmgenet: mask DMA_TIMEOUT_MASK when reading DMA_RING0_TIMEOUT

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Fainelli <[email protected]>

[ Upstream commit d64e277b955be4506931802837499b62c8f3968a ]

bcmgenet_get_coalesce() reads DMA_RING0_TIMEOUT to calculate rx_coalesce_usecs without masking out bits outside DMA_TIMEOUT_MASK (16 bits). If upper bits are non-zero or contain status/flags, the computed value of rx_coalesce_usecs returned to userspace via ethtool becomes corrupted.

Mask the register read with DMA_TIMEOUT_MASK before computing the timeout in microseconds.

Fixes 4a29645bfe6c ("net: bcmgenet: Implement RX coalescing control knobs")
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +2 -1
index 011376a1678a1..21668e41b6964 100644
@@ -852,7 +852,8 @@ static int bcmgenet_get_coalesce(struct net_device *dev,
 	ec->rx_max_coalesced_frames =
 		bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH);
 	ec->rx_coalesce_usecs =
-		bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000;
+		(bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) &
+		 DMA_TIMEOUT_MASK) * 8192 / 1000;
 
 	for (i = 0; i <= priv->hw_params->rx_queues; i++) {
 		ring = &priv->rx_rings[i];
Signature · 1 line
2.53.0
author maintainer
#198 lore raw

PATCH 198/457 ip_gre: Reject enabling collect metadata through changelink

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xuanqiang Luo <[email protected]>

[ Upstream commit a3f315be9d30eeb6938d11fa17fd4b32d52f7c42 ]

ipgre_netlink_parms() can enable collect_md on an existing GRE, GRETAP or ERSPAN device. Unlike newlink, changelink does not enforce metadata tunnel uniqueness. Converting a non-metadata device can therefore replace the metadata receive entry for another device of the same type in the same netns. Deleting either device then clears the shared entry, breaking metadata receive lookup for the surviving device.

If parameter validation fails after collect_md is set, deleting the modified device can also clear an entry it never owned.

Reject enabling metadata mode in both changelink callbacks before any encapsulation or tunnel parameters are modified. Allow requests that repeat the metadata attribute on an existing metadata device.

---
 net/ipv4/ip_gre.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
net/ipv4/ip_gre.c +12 -0
index 0ba1e94e9012c..384c02b9700b8 100644
@@ -1460,6 +1460,12 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
 	if (!rtnl_dev_link_net_capable(dev, t->net))
 		return -EPERM;
 
+	if (data && data[IFLA_GRE_COLLECT_METADATA] && !t->collect_md) {
+		NL_SET_ERR_MSG(extack,
+			       "Enabling collect_md on an existing device is not supported");
+		return -EOPNOTSUPP;
+	}
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
@@ -1492,6 +1498,12 @@ static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
 	if (!rtnl_dev_link_net_capable(dev, t->net))
 		return -EPERM;
 
+	if (data && data[IFLA_GRE_COLLECT_METADATA] && !t->collect_md) {
+		NL_SET_ERR_MSG(extack,
+			       "Enabling collect_md on an existing device is not supported");
+		return -EOPNOTSUPP;
+	}
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
Signature · 1 line
2.53.0
author maintainer
#199 lore raw

PATCH 199/457 vxlan: use one headroom snapshot for neighbour replies

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sanghyun Park <[email protected]>

[ Upstream commit 481506a756dcd828ef42391cb08f38d8d96d38fc ]

vxlan_na_create() samples LL_RESERVED_SPACE() to size the reply skb and then samples it again to reserve headroom. A concurrent vxlan_changelink() can update needed_headroom between the two reads, creating a TOCTOU race. The second value can exceed the allocation and make the Ethernet header write out of bounds.

The race is reproducible on the unpatched kernel. It occurred when vxlan_na_create() generated a neighbour reply while vxlan_changelink() changed the link headroom. KASAN caught a four-byte write two bytes beyond a 704-byte skbuff_small_head allocation.

Snapshot the headroom once and use that value for both allocation and reservation.

Fixes 4b29dba9c085 ("vxlan: fix nonfunctional neigh_reduce()")
---
 drivers/net/vxlan/vxlan_core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +4 -2
index e045e1ee9e594..c4bcaadba471d 100644
@@ -1958,13 +1958,15 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
 	struct ipv6hdr *pip6;
 	u8 *daddr;
 	int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+	int headroom;
 	int ns_olen;
 	int i, len;
 
 	if (dev == NULL || !pskb_may_pull(request, request->len))
 		return NULL;
 
-	len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+	headroom = LL_RESERVED_SPACE(dev);
+	len = headroom + sizeof(struct ipv6hdr) +
 		sizeof(*na) + na_olen + dev->needed_tailroom;
 	reply = alloc_skb(len, GFP_ATOMIC);
 	if (reply == NULL)
@@ -1972,7 +1974,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
 
 	reply->protocol = htons(ETH_P_IPV6);
 	reply->dev = dev;
-	skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
+	skb_reserve(reply, headroom);
 	skb_push(reply, sizeof(struct ethhdr));
 	skb_reset_mac_header(reply);
 
Signature · 1 line
2.53.0
author maintainer
#200 lore raw

PATCH 200/457 net: xps: reject an out of range traffic class

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Norbert Szetei <[email protected]>

[ Upstream commit 4da3b7b8b50f3e2fde54a4c18a82a8e3f6223910 ]

Only the entries below dev->num_tc are valid in dev->tc_to_txq[], and dev->prio_tc_map[] may only name classes below it. netdev_set_num_tc() lowers dev->num_tc without touching either array.

netdev_txq_to_tc() walks all TC_MAX_QUEUE slots and netdev_get_prio_tc_map() returns the entry as it stands, so a leftover entry is handed out as a traffic class >= dev->num_tc. Taking that class from netdev_txq_to_tc(), __netif_set_xps_queue() rejects only a negative one and indexes an XPS map sized for dev->num_tc classes:

	tci = j * num_tc + tc;
	RCU_INIT_POINTER(new_dev_maps->attr_map[tci], map);

attr_map[] holds nr_ids * num_tc entries and j runs over the ids named in the mask, so a class that is not below num_tc pushes tci past the end of the map for the last ids and the store overruns it.

Any caller that lowers num_tc leaves such entries behind, and mqprio_destroy() tears down with netdev_set_num_tc(dev, 0) rather than netdev_reset_tc(). After mqprio with 8 classes then 1, tc_to_txq[1..7] still describe txq 1..7. The splat is from an XPS write to txq 2 on a veth with 8 rx queues: attr_map[] has 8 * 1 entries, tci = j + 2, and j == 6 stores one past the end of the 88-byte map:

  BUG: KASAN: slab-out-of-bounds in __netif_set_xps_queue (net/core/dev.c:2954)
  Write of size 8 at addr ffff88813016bc58 by task xps_oob/634
   __netif_set_xps_queue (net/core/dev.c:2954)
   xps_rxqs_store (net/core/net-sysfs.c:1880)
   netdev_queue_attr_store (net/core/net-sysfs.c:1390)
  Allocated by task 634:
   __kmalloc_noprof (mm/slub.c:5439)
   __netif_set_xps_queue (net/core/dev.c:2937)
  The buggy address is located 0 bytes to the right of
   allocated 88-byte region [ffff88813016bc00, ffff88813016bc58)

Reject a class the map has no room for.

Fixes 184c449f91fe ("net: Add support for XPS with QoS via traffic classes")
---
 net/core/dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/dev.c +1 -1
index 65cdaf0c81f71..a48958a3f76c1 100644
@@ -2897,7 +2897,7 @@ int __netif_set_xps_queue(struct net_device *dev, const unsigned long *mask,
 		dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev;
 
 		tc = netdev_txq_to_tc(dev, index);
-		if (tc < 0)
+		if (tc < 0 || tc >= num_tc)
 			return -EINVAL;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#201 lore raw

PATCH 201/457 drm/imagination: clamp freelist reconstruction requests

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit 45585c3aa285854face65293acc95eff73063d6d ]

The firmware reconstruction count controls accesses to the request's fixed freelist ID array and the copy into the fixed response array. Neither access currently bounds the count to those protocol arrays.

Clamp the count to the request capacity, which is shared by the response layout, and use that count consistently for reconstruction and response publication. Keep the firmware recovery exchange instead of dropping an oversized request without a response, as discussed with the firmware maintainer.

The issue was found by our static-analysis tool.

Fixes 6eedddab733b ("drm/imagination: Implement free list and HWRT create and destroy ioctls")
Assisted-by gpt 5
---
 drivers/gpu/drm/imagination/pvr_free_list.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/gpu/drm/imagination/pvr_free_list.c +12 -3
index e85cac83834c6..faf5e586d8dc1 100644
@@ -8,6 +8,7 @@
 #include "pvr_vm.h"
 
 #include <drm/drm_gem.h>
+#include <drm/drm_print.h>
 #include <linux/slab.h>
 #include <linux/xarray.h>
 #include <uapi/drm/pvr_drm.h>
@@ -612,13 +613,21 @@ pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev,
 	};
 	struct rogue_fwif_freelists_reconstruction_data *resp =
 		&resp_cmd.cmd_data.free_lists_reconstruction_data;
+	u32 count = min_t(u32, req->freelist_count,
+			  ARRAY_SIZE(req->freelist_ids));
 
-	for (u32 i = 0; i < req->freelist_count; i++)
+	if (count != req->freelist_count) {
+		drm_warn_once(from_pvr_device(pvr_dev),
+			      "Requested reconstruction of %u freelists, limiting to %u\n",
+			      req->freelist_count, count);
+	}
+
+	for (u32 i = 0; i < count; i++)
 		pvr_free_list_reconstruct(pvr_dev, req->freelist_ids[i]);
 
-	resp->freelist_count = req->freelist_count;
+	resp->freelist_count = count;
 	memcpy(resp->freelist_ids, req->freelist_ids,
-	       req->freelist_count * sizeof(resp->freelist_ids[0]));
+	       count * sizeof(resp->freelist_ids[0]));
 
 	WARN_ON(pvr_kccb_send_cmd(pvr_dev, &resp_cmd, NULL));
 }
Signature · 1 line
2.53.0
author maintainer
#202 lore raw

PATCH 202/457 bonding: crypto offload enabled, non-offload slave failover, rekey failed

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: David Dai <[email protected]>

[ Upstream commit 00efbbd40bd5fd92c67b7cf1aab8904fa59a96f6 ]

Create a bonding device (i.e. bond0) in active-backup mode, 2 slaves. Active slave: offload capable interface (i.e. eth1), primary interface. Backup slave: non-offload capable interface(i.e. eth2). Configure strongswan service swantl.conf child SA "hw_offload = crypto" Start strongswan service
IPSec Crytpo Offload is enabled on top of bond0. i.e.
ip xfrm state |grep offload
crypto offload parameters: dev bond0 dir out mode crypto crypto offload parameters: dev bond0 dir in mode crypto

Active slave eth1 takes adavantage of IPSec Crypto Offload capability.

If active slave eth1 is down for any reason (i.e. eth1 link down):
ip link set down dev eth1
non-offload capable interface eth2 failover to becomes active slave. The existing SAs can continue use software IPsec after failover. Traffic still keeps going properly.

However if eth1 link had not recovered yet, strongswan service does new child SA rekey, or uses swanctl command to do new child SA rekey, it will fail because active slave eth2 doesn't support crypto offload. In bond_ipsec_add_sa routine, it returns -EINVAL now, which is treated as fatal error by xfrm_dev_state_add routine in kernel xfrm.

To make the non-offload active slave survive the child SA rekey, need to make bond_ipsec_add_sa routine returns -EOPNOTSUPP instead when active slave doesn't support IPsec Crypto offload, the xfrm will gracefully fallback to create new SA using Software IPsec. Network traffic can keep going.

After offload capable interface eth1 link is up, becomes active slave, next time strongswan child SA rekey will create a new SA which enables crypto offload again.

Fixes 18cb261afd7b ("bonding: support hardware encryption offload to slaves")
---
 drivers/net/bonding/bond_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/bonding/bond_main.c +1 -1
index 6ea46a617ee60..34c5bbbed9aee 100644
@@ -490,7 +490,7 @@ static int bond_ipsec_add_sa(struct net_device *bond_dev,
 	    !real_dev->xfrmdev_ops->xdo_dev_state_add ||
 	    netif_is_bond_master(real_dev)) {
 		NL_SET_ERR_MSG_MOD(extack, "Slave does not support ipsec offload");
-		err = -EINVAL;
+		err = -EOPNOTSUPP;
 		goto out;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#203 lore raw

PATCH 203/457 macsec: initialize SecY before registering the netdevice

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Haseeb Malik <[email protected]>

[ Upstream commit c2de369c5c5b8599ca10fd5ca8d11fcd845c1331 ]

Creating a MACsec device with MAC offload over an LRO-capable lower device triggers a warning in rtmsg_ifinfo_build_skb() when IPv4 forwarding is enabled by default.

register_netdevice() invokes inetdev_init(), which disables LRO and emits a NETDEV_FEAT_CHANGE notification. This reaches macsec_fill_info() before macsec_add_dev() initializes the SecY. key_len is still zero, so macsec_fill_info() returns -EMSGSIZE and trips the WARN_ON in rtmsg_ifinfo_build_skb(), even though the skb has enough space.

Even without the warning, notifications during registration can report uninitialized SecY attributes, including the SCI. This ordering has existed since the driver was introduced.

Initialize the SecY and apply the new-link attributes before registration. Move MAC address inheritance into macsec_newlink() so the SCI can also be initialized before registration-time notifications report it. Move the per-CPU statistics and metadata destination allocation into ndo_init(), and release partial allocations on failure.

---
 drivers/net/macsec.c | 84 +++++++++++++++++++++++---------------------
 1 file changed, 43 insertions(+), 41 deletions(-)
drivers/net/macsec.c +43 -41
index ee0e2eb7dbc61..e4871cd765790 100644
@@ -3539,6 +3539,22 @@ static int macsec_dev_init(struct net_device *dev)
 	if (err)
 		return err;
 
+	err = -ENOMEM;
+	macsec->stats = netdev_alloc_pcpu_stats(struct pcpu_secy_stats);
+	if (!macsec->stats)
+		goto destroy_gro_cells;
+
+	macsec->secy.tx_sc.stats =
+		netdev_alloc_pcpu_stats(struct pcpu_tx_sc_stats);
+	if (!macsec->secy.tx_sc.stats)
+		goto free_secy_stats;
+
+	macsec->secy.tx_sc.md_dst = metadata_dst_alloc(0, METADATA_MACSEC,
+						       GFP_KERNEL);
+	if (!macsec->secy.tx_sc.md_dst)
+		goto free_tx_sc_stats;
+	macsec->secy.tx_sc.md_dst->u.macsec_info.sci = macsec->secy.sci;
+
 	macsec_inherit_tso_max(dev);
 
 	dev->hw_features = real_dev->hw_features & MACSEC_OFFLOAD_FEATURES;
@@ -3551,8 +3567,6 @@ static int macsec_dev_init(struct net_device *dev)
 
 	macsec_set_head_tail_room(dev);
 
-	if (is_zero_ether_addr(dev->dev_addr))
-		eth_hw_addr_inherit(dev, real_dev);
 	if (is_zero_ether_addr(dev->broadcast))
 		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
 
@@ -3560,6 +3574,14 @@ static int macsec_dev_init(struct net_device *dev)
 	netdev_hold(real_dev, &macsec->dev_tracker, GFP_KERNEL);
 
 	return 0;
+
+free_tx_sc_stats:
+	free_percpu(macsec->secy.tx_sc.stats);
+free_secy_stats:
+	free_percpu(macsec->stats);
+destroy_gro_cells:
+	gro_cells_destroy(&macsec->gro_cells);
+	return err;
 }
 
 static void macsec_dev_uninit(struct net_device *dev)
@@ -4114,26 +4136,11 @@ static sci_t dev_to_sci(struct net_device *dev, __be16 port)
 	return make_sci(dev->dev_addr, port);
 }
 
-static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
+static void macsec_init_secy(struct net_device *dev, sci_t sci, u8 icv_len)
 {
 	struct macsec_dev *macsec = macsec_priv(dev);
 	struct macsec_secy *secy = &macsec->secy;
 
-	macsec->stats = netdev_alloc_pcpu_stats(struct pcpu_secy_stats);
-	if (!macsec->stats)
-		return -ENOMEM;
-
-	secy->tx_sc.stats = netdev_alloc_pcpu_stats(struct pcpu_tx_sc_stats);
-	if (!secy->tx_sc.stats)
-		return -ENOMEM;
-
-	secy->tx_sc.md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
-	if (!secy->tx_sc.md_dst)
-		/* macsec and secy percpu stats will be freed when unregistering
-		 * net_device in macsec_free_netdev()
-		 */
-		return -ENOMEM;
-
 	if (sci == MACSEC_UNDEF_SCI)
 		sci = dev_to_sci(dev, MACSEC_PORT_ES);
 
@@ -4147,15 +4154,12 @@ static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
 	secy->xpn = DEFAULT_XPN;
 
 	secy->sci = sci;
-	secy->tx_sc.md_dst->u.macsec_info.sci = sci;
 	secy->tx_sc.active = true;
 	secy->tx_sc.encoding_sa = DEFAULT_ENCODING_SA;
 	secy->tx_sc.encrypt = DEFAULT_ENCRYPT;
 	secy->tx_sc.send_sci = DEFAULT_SEND_SCI;
 	secy->tx_sc.end_station = false;
 	secy->tx_sc.scb = false;
-
-	return 0;
 }
 
 static struct lock_class_key macsec_netdev_addr_lock_key;
@@ -4218,6 +4222,24 @@ static int macsec_newlink(struct net_device *dev,
 	if (rx_handler && rx_handler != macsec_handle_frame)
 		return -EBUSY;
 
+	if (is_zero_ether_addr(dev->dev_addr))
+		eth_hw_addr_inherit(dev, real_dev);
+
+	if (data && data[IFLA_MACSEC_SCI])
+		sci = nla_get_sci(data[IFLA_MACSEC_SCI]);
+	else if (data && data[IFLA_MACSEC_PORT])
+		sci = dev_to_sci(dev, nla_get_be16(data[IFLA_MACSEC_PORT]));
+	else
+		sci = dev_to_sci(dev, MACSEC_PORT_ES);
+
+	/* Registration can notify listeners before returning. */
+	macsec_init_secy(dev, sci, icv_len);
+	if (data) {
+		err = macsec_changelink_common(dev, data);
+		if (err)
+			return err;
+	}
+
 	err = register_netdevice(dev);
 	if (err < 0)
 		return err;
@@ -4230,31 +4252,11 @@ static int macsec_newlink(struct net_device *dev,
 	if (err < 0)
 		goto unregister;
 
-	/* need to be already registered so that ->init has run and
-	 * the MAC addr is set
-	 */
-	if (data && data[IFLA_MACSEC_SCI])
-		sci = nla_get_sci(data[IFLA_MACSEC_SCI]);
-	else if (data && data[IFLA_MACSEC_PORT])
-		sci = dev_to_sci(dev, nla_get_be16(data[IFLA_MACSEC_PORT]));
-	else
-		sci = dev_to_sci(dev, MACSEC_PORT_ES);
-
 	if (rx_handler && sci_exists(real_dev, sci)) {
 		err = -EBUSY;
 		goto unlink;
 	}
 
-	err = macsec_add_dev(dev, sci, icv_len);
-	if (err)
-		goto unlink;
-
-	if (data) {
-		err = macsec_changelink_common(dev, data);
-		if (err)
-			goto del_dev;
-	}
-
 	/* If h/w offloading is available, propagate to the device */
 	if (macsec_is_offloaded(macsec)) {
 		const struct macsec_ops *ops;
Signature · 1 line
2.53.0
author maintainer
#204 lore raw

PATCH 204/457 net/sched: act_ife: validate metadata length before decoding

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fang Xieyan <[email protected]>

[ Upstream commit d6ec384c87cc851cfd13bb18c99ce351ccee6192 ]

skbmark_decode(), skbprio_decode() and skbtcindex_decode() read fixed-size values from the TLV payload without validating its length.

A malformed IFE frame can declare a shorter payload, causing the decoders to consume bytes beyond the declared metadata value:

[TLV type=IFE_META_SKBMARK len=4]
-> dlen == 0, but decode reads 4 bytes

The decoder may therefore set skb metadata from unintended input.

Validate the payload length before decoding and return -EINVAL for invalid lengths. Read the values with get_unaligned_be32() and get_unaligned_be16(), as TLV payloads are not guaranteed to be aligned. Teach tcf_ife_decode() to log a decoder error separately from an unknown metaid; both are counted as overlimits and decoding continues with the remaining metadata.

The metadata length issue was found by an automated audit of the IFE decode path at v6.18-rc7 and reproduced with a userspace sanitizer model of the decode path. Compile-tested on x86_64 with defconfig and NET_ACT_IFE=y: act_ife.o and the three act_meta_*.o build warning-free.

Fixes 084e2f6566d2 ("Support to encoding decoding skb mark on IFE action")
Fixes 200e10f46936 ("Support to encoding decoding skb prio on IFE action")
Fixes 408fbc22ef1e ("net sched ife action: Introduce skb tcindex metadata encap decap")
Assisted-by Hawkeye:GLM-5.3-flash
Assisted-by Qoder:Qwen3.8-Max
---
 net/sched/act_ife.c             | 17 ++++++++++++-----
 net/sched/act_meta_mark.c       |  6 ++++--
 net/sched/act_meta_skbprio.c    |  6 ++++--
 net/sched/act_meta_skbtcindex.c |  6 ++++--
 4 files changed, 24 insertions(+), 11 deletions(-)
net/sched/act_ife.c +12 -5
index 9cea71fc1db3d..2afd68983ece4 100644
@@ -737,6 +737,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
 		u8 *curr_data;
 		u16 mtype;
 		u16 dlen;
+		int ret;
 
 		curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype,
 						&dlen, NULL);
@@ -745,13 +746,19 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
 			return TC_ACT_SHOT;
 		}
 
-		if (find_decode_metaid(skb, p, mtype, dlen, curr_data)) {
-			/* abuse overlimits to count when we receive metadata
-			 * but dont have an ops for it
+		ret = find_decode_metaid(skb, p, mtype, dlen, curr_data);
+		if (ret < 0) {
+			/* abuse overlimits to count metadata we cannot
+			 * decode: no ops for it, or the decoder rejected it
 			 */
-			pr_info_ratelimited("Unknown metaid %d dlen %d\n",
-					    mtype, dlen);
 			qstats_cpu_overlimit_inc(ife->common.cpu_qstats);
+
+			if (ret == -ENOENT)
+				pr_info_ratelimited("Unknown metaid %d dlen %d\n",
+						    mtype, dlen);
+			else
+				pr_info_ratelimited("Failed to decode metaid %d dlen %d err %d\n",
+						    mtype, dlen, ret);
 		}
 	}
 
net/sched/act_meta_mark.c +4 -2
index ea0573cb8b2d6..e2f61b22bf0f8 100644
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <linux/unaligned.h>
 #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -28,9 +29,10 @@ static int skbmark_encode(struct sk_buff *skb, void *skbdata,
 
 static int skbmark_decode(struct sk_buff *skb, void *data, u16 len)
 {
-	u32 ifemark = *(u32 *)data;
+	if (len != sizeof(u32))
+		return -EINVAL;
 
-	skb->mark = ntohl(ifemark);
+	skb->mark = get_unaligned_be32(data);
 	return 0;
 }
 
net/sched/act_meta_skbprio.c +4 -2
index 2df3133ce5adc..5cdb57931eab4 100644
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <linux/unaligned.h>
 #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -33,9 +34,10 @@ static int skbprio_encode(struct sk_buff *skb, void *skbdata,
 
 static int skbprio_decode(struct sk_buff *skb, void *data, u16 len)
 {
-	u32 ifeprio = *(u32 *)data;
+	if (len != sizeof(u32))
+		return -EINVAL;
 
-	skb->priority = ntohl(ifeprio);
+	skb->priority = get_unaligned_be32(data);
 	return 0;
 }
 
net/sched/act_meta_skbtcindex.c +4 -2
index 44547caead469..8803710c09058 100644
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <linux/unaligned.h>
 #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -28,9 +29,10 @@ static int skbtcindex_encode(struct sk_buff *skb, void *skbdata,
 
 static int skbtcindex_decode(struct sk_buff *skb, void *data, u16 len)
 {
-	u16 ifetc_index = *(u16 *)data;
+	if (len != sizeof(u16))
+		return -EINVAL;
 
-	skb->tc_index = ntohs(ifetc_index);
+	skb->tc_index = get_unaligned_be16(data);
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#205 lore raw

PATCH 205/457 net: emac: move setting of netops to fix crash

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Lamparter <[email protected]>

[ Upstream commit 7c9f391ec89cb621d7af375ace2eb9a6248e5b9d ]

fixes the following crash on driver initialization:

|BUG: Kernel NULL pointer dereference on read at 0x00000158
|Faulting instruction address: 0xc0566b40
|Oops: Kernel access of bad area, sig: 11 [#1]
|BE PAGE_SIZE=4K  PowerPC 44x Platform
|Modules linked in:
|CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Tainted: GW 7.3.0-rc3+ #1
|Tainted: [W]=WARN
|Hardware name: MyBook Live APM821XX 0x12c41c83 PowerPC 44x Platform
|NIP:  c0566b40 LR: c05648f8 CTR: c04c1e9c
|REGS: c1053a20 TRAP: 0300   Tainted: GW  (7.3.0-rc3+)
|MSR:  0002b000 <CE,EE,FP,ME>  CR: 24008808  XER: 00000000
|DEAR: 00000158 ESR: 00000000
|GPR00: c05648f8 c1053b10 c1063600 c1030000 c5ab3000 00000000 [...]
|GPR08: 00000002 00000000 00000000 c1053b40 84002808 00000000 [...]
|GPR16: cfffd210 00000002 c0beafcc cfffc960 00000000 c1030644 [...]
|GPR24: c0beafbc c1037000 00000000 0000000a 00000000 c1030000 [...]
|NIP [c0566b40] phy_link_topo_add_phy+0x2c/0x1d0
|LR [c05648f8] phy_attach_direct+0x1a4/0x368
|Call Trace:
|[c1053b10] [c0811e04] klist_put+0x54/0xb4 (unreliable)
|[c1053b40] [c05648f8] phy_attach_direct+0x1a4/0x368
|[c1053b70] [c0564ae8] phy_connect_direct+0x2c/0x60
|[c1053b90] [c056c7a8] of_phy_connect+0x50/0x74
|[c1053bc0] [c0572a88] emac_probe+0xd50/0x119c
|[c1053c90] [c04cb770] platform_probe+0x74/0xa4
|[c1053cb0] [c04c8f08] really_probe+0x120/0x2b0
|[c1053cd0] [c04c9254] __driver_probe_device+0x1bc/0x1fc
|[c1053d00] [c04c9334] driver_probe_device+0x38/0xa8
|[c1053d30] [c04c9560] __driver_attach+0xf4/0x10c
|[c1053d50] [c04c6af8] bus_for_each_dev+0x68/0xd0
|[c1053d90] [c04c7c34] bus_add_driver+0xcc/0x1ec
|[c1053dc0] [c04c9f6c] driver_register+0xcc/0x110
|[c1053de0] [c0aa3f40] emac_init+0x1c4/0x200

This bug showed up starting with v7.3-rc1. At the NIP in phy_link_topo_add_phy() is a netdev_need_ops_lock() check.
This was added by the following
commit ded86da4bbb7 ("net: ethtool: relax ethnl_req_get_phydev() locking assertion")

The bug shows up because at the time of_phy_connect() was called, the netdev_ops were *not yet* determined. My fix is to move the code that sets netdev_ops+commac.ops+ethtool_ops further up as emac_init_config() derives that by looking at the device-tree and sets the required dev->phy_mode accordingly.

During review, the Sashiko bot's AI stated that the commac assignment became a dead store. Great catch! To keep the original behavior as-is, one mentioned option "set dev->commac.ops = &emac_commac_ops only in the non-gige case?" sounded like a great plan. So the dev->commac.ops assignment for the non-gige-case moves into the else block.

This patch was tested on a WD MyBook Live (RGMII). the device now works again.

---
 drivers/net/ethernet/ibm/emac/core.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/net/ethernet/ibm/emac/core.c +9 -7
index 1d46cf6c2c127..e7043523457c1 100644
@@ -3044,6 +3044,15 @@ static int emac_probe(struct platform_device *ofdev)
 	if (err)
 		goto err_gone;
 
+	if (emac_phy_supports_gige(dev->phy_mode)) {
+		ndev->netdev_ops = &emac_gige_netdev_ops;
+		dev->commac.ops = &emac_commac_sg_ops;
+	} else {
+		ndev->netdev_ops = &emac_netdev_ops;
+		dev->commac.ops = &emac_commac_ops;
+	}
+	ndev->ethtool_ops = &emac_ethtool_ops;
+
 	dev->emacp = devm_platform_ioremap_resource(ofdev, 0);
 	if (IS_ERR(dev->emacp)) {
 		err = PTR_ERR(dev->emacp);
@@ -3076,7 +3085,6 @@ static int emac_probe(struct platform_device *ofdev)
 		dev->mdio_instance = platform_get_drvdata(dev->mdio_dev);
 
 	/* Register with MAL */
-	dev->commac.ops = &emac_commac_ops;
 	dev->commac.dev = dev;
 	dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan);
 	dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan);
@@ -3144,12 +3152,6 @@ static int emac_probe(struct platform_device *ofdev)
 		ndev->features |= ndev->hw_features | NETIF_F_RXCSUM;
 	}
 	ndev->watchdog_timeo = 5 * HZ;
-	if (emac_phy_supports_gige(dev->phy_mode)) {
-		ndev->netdev_ops = &emac_gige_netdev_ops;
-		dev->commac.ops = &emac_commac_sg_ops;
-	} else
-		ndev->netdev_ops = &emac_netdev_ops;
-	ndev->ethtool_ops = &emac_ethtool_ops;
 
 	/* MTU range: 46 - 1500 or whatever is in OF */
 	ndev->min_mtu = EMAC_MIN_MTU;
Signature · 1 line
2.53.0
author maintainer
#206 lore raw

PATCH 206/457 bpf: Zero-fill other CPUs when BPF_F_CPU creates a per-cpu hash element

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Donggeun Yoo <[email protected]>

[ Upstream commit c3a66e5f5bab3912e9f84223c5a982bf4333d5a1 ]

pcpu_init_value() initializes the per-cpu area of a newly created [lru_]percpu_hash element. The area is recycled, so when the value comes from a BPF program (onallcpus == false) it writes the running CPU's slot and zeroes the rest.

bpf_percpu_hash_update() passes onallcpus == true, which delegates to pcpu_copy_value(). pcpu_copy_value() writes only the CPU named in map_flags when BPF_F_CPU is set, so on the create path the other slots keep the recycled element's values:

  update(k1, 0xdeadc0de, BPF_F_ALL_CPUS)  every CPU holds 0xdeadc0de
  delete(k1)                              element back on the freelist
  update(k2, 0xc0ffee, BPF_F_CPU | 0)     creates, writes CPU 0 only
  lookup(k2)                              CPU 0 0xc0ffee, rest 0xdeadc0de

Zero-fill the other CPUs on that arm too.

Fixes c6936161fd55 ("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_hash and lru_percpu_hash maps")
---
 kernel/bpf/hashtab.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
kernel/bpf/hashtab.c +7 -4
index 5117447ac291b..61ef6191f79ad 100644
@@ -1055,14 +1055,17 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
 	/* When not setting the initial value on all cpus, zero-fill element
 	 * values for other cpus. Otherwise, bpf program has no way to ensure
 	 * known initial values for cpus other than current one
-	 * (onallcpus=false always when coming from bpf prog).
+	 * (onallcpus=false always when coming from bpf prog,
+	 *  map_flags & BPF_F_CPU when coming from syscall but setting
+	 *  only one cpu).
 	 */
-	if (!onallcpus) {
-		int current_cpu = raw_smp_processor_id();
+	if (!onallcpus || (map_flags & BPF_F_CPU)) {
+		int init_cpu = (map_flags & BPF_F_CPU) ? map_flags >> 32 :
+			       raw_smp_processor_id();
 		int cpu;
 
 		for_each_possible_cpu(cpu) {
-			if (cpu == current_cpu)
+			if (cpu == init_cpu)
 				copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value);
 			else /* Since elem is preallocated, we cannot touch special fields */
 				zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu));
Signature · 1 line
2.53.0
author maintainer
#207 lore raw

PATCH 207/457 net: dsa: mt7530: fix NULL dereference on unbind of MT7531 and MT7621

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Sviridkin <[email protected]>

[ Upstream commit c2cdef41e0b4d8ed23a5b41e6ad4e64594e055e4 ]

The core and io supplies are only requested for ID_MT7530: both the devm_regulator_get() in probe and the regulator_enable() in mt7530_setup() are guarded by the switch id, but mt7530_remove() disables them unconditionally. On an MT7621 or an MT7531 both pointers are still NULL from devm_kzalloc(), so rmmod or a sysfs unbind calls regulator_disable() on NULL.

Fixes ddda1ac116c8 ("net: dsa: mt7530: support the 7530 switch on the Mediatek MT7621 SoC")
---
 drivers/net/dsa/mt7530-mdio.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/net/dsa/mt7530-mdio.c +11 -9
index 784dd58a71589..de42f70afcfa1 100644
@@ -227,15 +227,17 @@ mt7530_remove(struct mdio_device *mdiodev)
 	if (!priv)
 		return;
 
-	ret = regulator_disable(priv->core_pwr);
-	if (ret < 0)
-		dev_err(priv->dev,
-			"Failed to disable core power: %d\n", ret);
-
-	ret = regulator_disable(priv->io_pwr);
-	if (ret < 0)
-		dev_err(priv->dev, "Failed to disable io pwr: %d\n",
-			ret);
+	if (priv->id == ID_MT7530) {
+		ret = regulator_disable(priv->core_pwr);
+		if (ret < 0)
+			dev_err(priv->dev,
+				"Failed to disable core power: %d\n", ret);
+
+		ret = regulator_disable(priv->io_pwr);
+		if (ret < 0)
+			dev_err(priv->dev, "Failed to disable io pwr: %d\n",
+				ret);
+	}
 
 	mt7530_remove_common(priv);
 
Signature · 1 line
2.53.0
author maintainer
#208 lore raw

PATCH 208/457 net: dsa: mt7530: leave the MDIO IRQ mappings to regmap-irq

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Sviridkin <[email protected]>

[ Upstream commit 0d80ba0a204c6a16bd7778b50de578dff107c0fe ]

mt7530_remove_common() disposes the per-PHY interrupt mappings from .remove, but the regmap-irq chip that owns the domain is devm-registered, so its parent interrupt is only freed once .remove has returned. The switch's own regmap-irq thread can therefore still dispatch on a mapping that is already gone: irq_find_mapping() returns 0, irq_to_desc() returns NULL and handle_nested_irq() locks desc->lock without checking it. The attached PHYs have not given those interrupts back yet either, which the kernel warns about a moment before the fault.

regmap_del_irq_chip() disposes the same mappings itself, after freeing the parent interrupt and before removing the domain, so there is nothing left for the driver to do here. Until it runs the descriptors stay alive, and a late dispatch on one of them is harmless: dsa_unregister_switch() has freed the PHY handlers by then, so handle_nested_irq() finds no action and returns.

Fixes 254f6b272e3b ("dsa: mt7530: Utilize REGMAP_IRQ for interrupt handling")
---
 drivers/net/dsa/mt7530.c | 3 ---
 1 file changed, 3 deletions(-)
drivers/net/dsa/mt7530.c +0 -3
index 56ee8dc34f518..93dba4498c420 100644
@@ -3539,9 +3539,6 @@ EXPORT_SYMBOL_GPL(mt7530_probe_common);
 void
 mt7530_remove_common(struct mt7530_priv *priv)
 {
-	if (priv->irq_domain)
-		mt7530_free_mdio_irq(priv);
-
 	dsa_unregister_switch(priv->ds);
 
 	mutex_destroy(&priv->reg_mutex);
Signature · 1 line
2.53.0
author maintainer
#209 lore raw

PATCH 209/457 tcp: fix use-after-free of retransmit_skb_hint in tcp_send_synack()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yilin Zhang <[email protected]>

[ Upstream commit fe99bbeee5c5dbd3abc30721a8079ced59649d97 ]

When tcp_send_synack() replaces the cloned SYN skb at the head of the retransmit queue with a copy, it frees the original with tcp_rtx_queue_unlink_and_free() and only repairs tp->highest_sack. tp->retransmit_skb_hint keeps pointing at the freed skbuff_fclone_cache object.

The dangling hint is read in tcp_verify_retransmit_hint() and used as the root of the rbtree walk in tcp_xmit_retransmit_queue(). An unprivileged TFO client (sendmsg(MSG_FASTOPEN)) can arm the hint with an attacker-supplied ICMP fragmentation-needed message, after which a simultaneous open frees the armed SYN skb:

  BUG: KASAN: slab-use-after-free in tcp_mark_skb_lost (net/ipv4/tcp_input.c:1316)
  Read of size 4 at addr ffff88800604d928 by task swapper/1/0
  Call Trace:
   tcp_mark_skb_lost (net/ipv4/tcp_input.c:1316)
   tcp_simple_retransmit (net/ipv4/tcp_input.c:3158)
   tcp_v4_err (net/ipv4/tcp_ipv4.c:587)

Sync the hint to the copy.

---
 net/ipv4/tcp_output.c | 3 +++
 1 file changed, 3 insertions(+)
net/ipv4/tcp_output.c +3 -0
index f72a6b1fe749b..0b89b624af8ed 100644
@@ -3886,6 +3886,7 @@ void tcp_send_active_reset(struct sock *sk, enum sk_rst_reason reason)
  */
 int tcp_send_synack(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 
 	skb = tcp_rtx_queue_head(sk);
@@ -3903,6 +3904,8 @@ int tcp_send_synack(struct sock *sk)
 			if (!nskb)
 				return -ENOMEM;
 			INIT_LIST_HEAD(&nskb->tcp_tsorted_anchor);
+			if (skb == tp->retransmit_skb_hint)
+				tp->retransmit_skb_hint = nskb;
 			tcp_highest_sack_replace(sk, skb, nskb);
 			tcp_rtx_queue_unlink_and_free(skb, sk);
 			__skb_header_release(nskb);
Signature · 1 line
2.53.0
author maintainer
#210 lore raw

PATCH 210/457 net: phylink: record the PHY only once bringup cannot fail

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Sviridkin <[email protected]>

[ Upstream commit a940003f44e7e441c228151dd212642152700ec8 ]

phylink_bringup_phy() stores the PHY in pl->phydev before its last fallible step: on a MAC whose phylink ops implement LPI, phy_eee_rx_clock_stop() can fail with a real MDIO error. The callers unwind with phy_detach(), which knows nothing about pl->phydev, so a pointer to a PHY that is no longer attached outlives the failed connect.

What that costs depends on how the caller got here. phylink_connect_phy() goes through phylink_attach_phy(), which refuses to attach while pl->phydev is set, turning a transient MDIO error into a permanent -EBUSY. The SFP path is worse than that: sfp_sm_probe_phy() answers the failure with phy_device_remove() and phy_device_free(), and it assigns sfp->mod_phy only past that error return, so nothing clears pl->phydev and it is left pointing at a freed phy_device that phylink_resolve() and the ethtool helpers go on reading. phylink_fwnode_phy_connect() has no such check, so a later connect overwrites the stale pointer and hides the problem. A disconnect does
not: phylink_disconnect_phy() hands that pointer to phy_disconnect(), and the second phy_detach() on the same PHY drops references the first one already released.

Found while making a DSA port survive a PHY whose driver arrives after the switch probes: keeping the port across a failed connect and retrying is what makes this window reachable.

Publish the pointer after the last call that can fail instead of unwinding it afterwards. Nothing between the two points reads pl->phydev, and the registration that follows cannot fail:
phy_request_interrupt() falls back to polling on its own. The PHY-side state keeps the order it had, so no MDIO operation moves relative to another.

---
 drivers/net/phy/phylink.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/net/phy/phylink.c +17 -3
index 27fd9aa2027a4..3477e1104a43a 100644
@@ -2131,7 +2131,6 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
 	mutex_lock(&pl->phydev_mutex);
 	mutex_lock(&phy->lock);
 	mutex_lock(&pl->state_mutex);
-	pl->phydev = phy;
 	pl->phy_state.interface = interface;
 	pl->phy_state.pause = MLO_PAUSE_NONE;
 	pl->phy_state.speed = SPEED_UNKNOWN;
@@ -2198,10 +2197,25 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
 			ret = 0;
 	}
 
-	if (ret == 0 && phy_interrupt_is_valid(phy))
+	if (ret)
+		return ret;
+
+	/* Nothing below can fail, so the PHY can be recorded now. Doing it
+	 * here rather than above keeps a failed bringup from leaving
+	 * pl->phydev pointing at a PHY the caller is about to detach.
+	 */
+	mutex_lock(&pl->phydev_mutex);
+	mutex_lock(&phy->lock);
+	mutex_lock(&pl->state_mutex);
+	pl->phydev = phy;
+	mutex_unlock(&pl->state_mutex);
+	mutex_unlock(&phy->lock);
+	mutex_unlock(&pl->phydev_mutex);
+
+	if (phy_interrupt_is_valid(phy))
 		phy_request_interrupt(phy);
 
-	return ret;
+	return 0;
 }
 
 static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
Signature · 1 line
2.53.0
author maintainer
#211 lore raw

PATCH 211/457 net: wangxun: implement soft quiesce for PCIe error recovery

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiawen Wu <[email protected]>

[ Upstream commit c023e9769de94cb7b7897297e71f50b0f436c473 ]

Function wx_soft_quiesce() provide a lightweight shutdown path during PCIe error recovery. It avoids MMIO-dependent operations in PCIe error status.

Waiting for the service task to complete may unnecessarily delay PCIe error recovery, especially if the work item is already blocked by the hardware failure that triggered AER. So the service task is not explicitly cancelled in quiesce path. As a measure to block the service task, the checking of WX_STATE_DOWN and WX_STATE_RESETTING is added at the entry of relevant work item.

Stable-dep-of: 3173cba11701 ("net: libwx: fix races in Tx timestamp handling")

---
 drivers/net/ethernet/wangxun/libwx/wx_lib.c   | 18 +++++++++++++
 drivers/net/ethernet/wangxun/libwx/wx_lib.h   |  1 +
 drivers/net/ethernet/wangxun/libwx/wx_ptp.c   | 27 +++++++++++++++++++
 drivers/net/ethernet/wangxun/libwx/wx_ptp.h   |  1 +
 .../net/ethernet/wangxun/txgbe/txgbe_main.c   | 16 +++++++++++
 5 files changed, 63 insertions(+)
drivers/net/ethernet/wangxun/libwx/wx_lib.c +18 -0
index 5d99e870de5ef..7e2ae41a321e1 100644
@@ -3348,5 +3348,23 @@ void wx_service_timer(struct timer_list *t)
 }
 EXPORT_SYMBOL(wx_service_timer);
 
+void wx_soft_quiesce(struct wx *wx)
+{
+	if (!netif_running(wx->netdev) ||
+	    test_and_set_bit(WX_STATE_DOWN, wx->state))
+		return;
+
+	pci_clear_master(wx->pdev);
+	netif_tx_stop_all_queues(wx->netdev);
+	netif_carrier_off(wx->netdev);
+	netif_tx_disable(wx->netdev);
+	wx_napi_disable_all(wx);
+	wx_ptp_quiesce(wx);
+
+	clear_bit(WX_FLAG_NEED_DO_RESET, wx->flags);
+	timer_delete_sync(&wx->service_timer);
+}
+EXPORT_SYMBOL(wx_soft_quiesce);
+
 MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
 MODULE_LICENSE("GPL");
drivers/net/ethernet/wangxun/libwx/wx_lib.h +1 -0
index aed6ea8cf0d64..11bd79985e171 100644
@@ -41,5 +41,6 @@ void wx_set_ring(struct wx *wx, u32 new_tx_count,
 void wx_service_event_schedule(struct wx *wx);
 void wx_service_event_complete(struct wx *wx);
 void wx_service_timer(struct timer_list *t);
+void wx_soft_quiesce(struct wx *wx);
 
 #endif /* _WX_LIB_H_ */
drivers/net/ethernet/wangxun/libwx/wx_ptp.c +27 -0
index 1165518d55225..4708e7f3958f7 100644
@@ -321,6 +321,9 @@ static long wx_ptp_do_aux_work(struct ptp_clock_info *ptp)
 	struct wx *wx = container_of(ptp, struct wx, ptp_caps);
 	int ts_done;
 
+	if (!test_bit(WX_STATE_PTP_RUNNING, wx->state))
+		return HZ;
+
 	ts_done = wx_ptp_tx_hwtstamp_work(wx);
 
 	wx_ptp_overflow_check(wx);
@@ -836,6 +839,30 @@ void wx_ptp_stop(struct wx *wx)
 }
 EXPORT_SYMBOL(wx_ptp_stop);
 
+void wx_ptp_quiesce(struct wx *wx)
+{
+	if (!test_and_clear_bit(WX_STATE_PTP_RUNNING, wx->state))
+		return;
+
+	clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags);
+
+	if (wx->ptp_clock)
+		ptp_cancel_worker_sync(wx->ptp_clock);
+
+	if (wx->ptp_tx_skb) {
+		dev_kfree_skb_any(wx->ptp_tx_skb);
+		wx->ptp_tx_skb = NULL;
+	}
+	clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state);
+
+	if (wx->ptp_clock) {
+		ptp_clock_unregister(wx->ptp_clock);
+		wx->ptp_clock = NULL;
+		dev_info(&wx->pdev->dev, "removed PHC on %s\n", wx->netdev->name);
+	}
+}
+EXPORT_SYMBOL(wx_ptp_quiesce);
+
 /**
  * wx_ptp_rx_hwtstamp - utility function which checks for RX time stamp
  * @wx: pointer to wx struct
drivers/net/ethernet/wangxun/libwx/wx_ptp.h +1 -0
index 50db90a6e3ee6..ad2f824875d51 100644
@@ -10,6 +10,7 @@ void wx_ptp_reset(struct wx *wx);
 void wx_ptp_init(struct wx *wx);
 void wx_ptp_suspend(struct wx *wx);
 void wx_ptp_stop(struct wx *wx);
+void wx_ptp_quiesce(struct wx *wx);
 void wx_ptp_rx_hwtstamp(struct wx *wx, struct sk_buff *skb);
 int wx_hwtstamp_get(struct net_device *dev,
 		    struct kernel_hwtstamp_config *cfg);
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +16 -0
index c277863baf67a..00123c0e3f222 100644
@@ -93,12 +93,24 @@ static void txgbe_module_detection_subtask(struct wx *wx)
 {
 	int err;
 
+	if (test_bit(WX_STATE_DOWN, wx->state) ||
+	    test_bit(WX_STATE_RESETTING, wx->state))
+		return;
+
 	if (!test_and_clear_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags))
 		return;
 
 	/* wait for SFF module ready */
 	msleep(200);
 
+	/* Re-check state to avoid racing with down/reset paths.
+	 * Module identification is deferred to the next up event,
+	 * so it is safe to bail out here.
+	 */
+	if (test_bit(WX_STATE_DOWN, wx->state) ||
+	    test_bit(WX_STATE_RESETTING, wx->state))
+		return;
+
 	err = txgbe_identify_module(wx);
 	if (err == -ENODEV)
 		set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
@@ -106,6 +118,10 @@ static void txgbe_module_detection_subtask(struct wx *wx)
 
 static void txgbe_link_config_subtask(struct wx *wx)
 {
+	if (test_bit(WX_STATE_DOWN, wx->state) ||
+	    test_bit(WX_STATE_RESETTING, wx->state))
+		return;
+
 	if (!test_and_clear_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags))
 		return;
 
Signature · 1 line
2.53.0
author maintainer
#212 lore raw

PATCH 212/457 net: libwx: fix races in Tx timestamp handling

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiawen Wu <[email protected]>

[ Upstream commit 3173cba1170131816972ed2b6185cb970ba8b747 ]

wx->ptp_tx_skb is shared between the Tx path, the PTP auxiliary worker and the timestamp cleanup paths. The WX_STATE_PTP_TX_IN_PROGRESS bit prevents multiple Tx paths from submitting timestamp requests, but does not serialize the worker against cleanup.

As a result, wx_ptp_clear_tx_timestamp() can free an skb after wx_ptp_tx_hwtstamp_work() has obtained its pointer. The worker may then pass the freed skb to skb_tstamp_tx() and release the same reference again.

The cleanup path may also clear the in-progress bit while the worker is still processing the old skb. This allows the Tx path to publish a new skb which the worker can subsequently overwrite with NULL, leaking its reference.

Add a dedicated spinlock to protect publication and consumption of the Tx timestamp skb. Detach the skb and clear the in-progress bit while holding the lock, then deliver the timestamp and release the skb after dropping it. Use the same locked cleanup in the quiesce path, but keep the detach there free of register accesses: quiesce runs during PCIe error recovery, where MMIO is not reliable, and it deliberately did not touch the device before. The lock is taken with interrupts disabled, because netpoll can call ndo_start_xmit() with hard interrupts already off.

When handling a Tx DMA mapping failure, keep the transmit path reference until after comparing the skb under the lock. This prevents skb address reuse from making the error path mistake a newer timestamp request for the failed one.

---
 drivers/net/ethernet/wangxun/libwx/wx_hw.c   |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_lib.c  |  47 ++++--
 drivers/net/ethernet/wangxun/libwx/wx_ptp.c  | 142 +++++++++++++------
 drivers/net/ethernet/wangxun/libwx/wx_type.h |   2 +
 4 files changed, 132 insertions(+), 60 deletions(-)
drivers/net/ethernet/wangxun/libwx/wx_hw.c +1 -0
index 260e14d5d5412..9119c931b3a3f 100644
@@ -2517,6 +2517,7 @@ int wx_sw_init(struct wx *wx)
 	}
 
 	spin_lock_init(&wx->hw_stats_lock);
+	spin_lock_init(&wx->ptp_tx_lock);
 	mutex_init(&wx->reset_lock);
 	bitmap_zero(wx->state, WX_STATE_NBITS);
 	bitmap_zero(wx->flags, WX_PF_FLAGS_NBITS);
drivers/net/ethernet/wangxun/libwx/wx_lib.c +34 -13

77 lines not on this page · raw message

drivers/net/ethernet/wangxun/libwx/wx_ptp.c +95 -47

203 lines not on this page · raw message

drivers/net/ethernet/wangxun/libwx/wx_type.h +2 -0
index 0520288d18ab9..e63a1666d8ed1 100644
@@ -1413,6 +1413,8 @@ struct wx {
 	unsigned long last_overflow_check;
 	unsigned long last_rx_ptp_check;
 	unsigned long ptp_tx_start;
+	/* protects ptp_tx_skb, ptp_tx_start and the in-progress state bit */
+	spinlock_t ptp_tx_lock;
 	seqlock_t hw_tc_lock; /* seqlock for ptp */
 	struct cyclecounter hw_cc;
 	struct timecounter hw_tc;
Signature · 1 line
2.53.0
author maintainer
#213 lore raw

PATCH 213/457 nfp: hold IPsec RX state under the XArray lock

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sang-Hoon Choi <[email protected]>

[ Upstream commit 1a983a4e14c635c40354be110cd9a1a5c94e01e6 ]

nfp_net_ipsec_rx() drops the XArray lock before taking a reference to the xfrm_state it found. The delete path can erase the entry and drop the last state reference in that interval. RX can then try to increment a zero refcount after the state has been queued for destruction.

The driver queues firmware invalidation asynchronously; the delete path does not wait for the command to complete or drain pending RX processing.

The XFRM garbage collector waits for an RCU grace period before freeing the state. That delays reclamation but does not make acquiring a reference from zero valid.

Take the xfrm_state reference before releasing the XArray lock so xa_erase() cannot run between lookup and reference acquisition.

Fixes 57f273adbcd4 ("nfp: add framework to support ipsec offloading")
---
 drivers/net/ethernet/netronome/nfp/crypto/ipsec.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/netronome/nfp/crypto/ipsec.c +2 -1
index 9e7c285eaa6bc..960d7513aa8dd 100644
@@ -625,11 +625,12 @@ int nfp_net_ipsec_rx(struct nfp_meta_parsed *meta, struct sk_buff *skb)
 
 	xa_lock(&nn->xa_ipsec);
 	x = xa_load(&nn->xa_ipsec, saidx);
+	if (x)
+		xfrm_state_hold(x);
 	xa_unlock(&nn->xa_ipsec);
 	if (!x)
 		return -EINVAL;
 
-	xfrm_state_hold(x);
 	sp->xvec[sp->len++] = x;
 	sp->olen++;
 	xo = xfrm_offload(skb);
Signature · 1 line
2.53.0
author maintainer
#214 lore raw

PATCH 214/457 net/rds: size a connections path set by the transport it ends up with

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Allison Henderson <[email protected]>

[ Upstream commit ba3d1f480c7a3fba963e7867ad6cc557c197acbc ]

__rds_conn_create() computes npaths from the caller's transport before it decides whether a connection to one of the host's own addresses is to be handled by the loopback transport instead. That substitution is what an RDS/TCP socket sending to a local address gets, and after it the path init loop still runs for the TCP transport's RDS_MPATH_WORKERS paths and allocates an ordered workqueue for each, while rds_loop_conn_alloc() only ever provides transport data for path 0.

rds_conn_destroy() sizes its teardown from c_trans, by then the loopback transport, so it visits path 0 only - and rds_conn_path_destroy() would skip the other paths anyway, since it returns before destroy_workqueue() for a path without transport data. kfree(c_path) then drops the last pointers to seven workqueues. That repeats for every such connection, on every netns teardown or module unload, and every distinct local destination address is a separate connection.

Recompute npaths once the transport is final, so that creation and destruction agree on the set of paths. The c_path array stays sized for the caller's transport; the unused entries are freed with it.

Fixes 4716af3897e9 ("net/rds: Give each connection path its own workqueue")
---
 net/rds/connection.c | 6 ++++++
 1 file changed, 6 insertions(+)
net/rds/connection.c +6 -0
index b6c4beb50eaf0..c752a8623cfca 100644
@@ -276,6 +276,12 @@ static struct rds_connection *__rds_conn_create(struct net *net,
 
 	conn->c_trans = trans;
 
+	/* The transport may just have been swapped for loopback; size the
+	 * set of paths - which is also what rds_conn_destroy() tears down
+	 * again - by the transport the connection actually uses.
+	 */
+	npaths = (trans->t_mp_capable ? RDS_MPATH_WORKERS : 1);
+
 	init_waitqueue_head(&conn->c_hs_waitq);
 	for (i = 0; i < npaths; i++) {
 		__rds_conn_path_init(conn, &conn->c_path[i],
Signature · 1 line
2.53.0
author maintainer
#215 lore raw

PATCH 215/457 net/smc: fix UAF on lgr list traversal in smcr_port_err()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sidraya Jayagond <[email protected]>

[ Upstream commit 61cb282fe97b3b0ba32ca09417a693162bf4ae3f ]

smcr_port_err() traverses smc_lgr_list.list without holding smc_lgr_list.lock, allowing a concurrent smc_lgr_terminate_sched() to free an lgr while it is still being dereferenced.

Hold smc_lgr_list.lock across the traversal. Update smc_ib_gid_check() to call smcr_port_err() after releasing the lock.

Fixes 541afa10c126 ("net/smc: add smcr_port_err() and smcr_link_down() processing")
---
 net/smc/smc_core.c |  2 ++
 net/smc/smc_ib.c   | 10 ++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)
net/smc/smc_core.c +2 -0
index 04aedd957543a..9974149659c2f 100644
@@ -1849,6 +1849,7 @@ void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport)
 	struct smc_link_group *lgr, *n;
 	int i;
 
+	spin_lock_bh(&smc_lgr_list.lock);
 	list_for_each_entry_safe(lgr, n, &smc_lgr_list.list, list) {
 		if (strncmp(smcibdev->pnetid[ibport - 1], lgr->pnet_id,
 			    SMC_MAX_PNETID_LEN))
@@ -1863,6 +1864,7 @@ void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport)
 				smcr_link_down_cond_sched(lnk);
 		}
 	}
+	spin_unlock_bh(&smc_lgr_list.lock);
 }
 
 static void smc_link_down_work(struct work_struct *work)
net/smc/smc_ib.c +8 -2
index 9bb495707445e..daaa8a72da90f 100644
@@ -333,6 +333,7 @@ static bool smc_ib_check_link_gid(u8 gid[SMC_GID_SIZE], bool smcrv2,
 static void smc_ib_gid_check(struct smc_ib_device *smcibdev, u8 ibport)
 {
 	struct smc_link_group *lgr;
+	bool stale_gid = false;
 	int i;
 
 	spin_lock_bh(&smc_lgr_list.lock);
@@ -348,11 +349,16 @@ static void smc_ib_gid_check(struct smc_ib_device *smcibdev, u8 ibport)
 				continue;
 			if (!smc_ib_check_link_gid(lgr->lnk[i].gid,
 						   lgr->smc_version == SMC_V2,
-						   smcibdev, ibport))
-				smcr_port_err(smcibdev, ibport);
+						   smcibdev, ibport)) {
+				stale_gid = true;
+				goto out;
+			}
 		}
 	}
+out:
 	spin_unlock_bh(&smc_lgr_list.lock);
+	if (stale_gid)
+		smcr_port_err(smcibdev, ibport);
 }
 
 static int smc_ib_remember_port_attr(struct smc_ib_device *smcibdev, u8 ibport)
Signature · 1 line
2.53.0
author maintainer
#216 lore raw

PATCH 216/457 tipc: Fix a data race on mon->peer_cnt in mon_timeout()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ginger Li <[email protected]>

[ Upstream commit 8e1937fed6738460554ec123c64839e2445e7d53 ]

mon_timeout() evaluates dom_size(mon->peer_cnt) before it takes mon->lock, while mon->peer_cnt is updated under that lock by tipc_mon_add_peer() and tipc_mon_remove_peer(). The value can therefore be stale, and the decision whether the local domain has to be recomputed can be based on an outdated member count.

Read mon->peer_cnt inside the write_lock_bh(&mon->lock) protected region.

Fixes 35c55c9877f8 ("tipc: add neighbor monitoring framework")
---
 net/tipc/monitor.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/tipc/monitor.c +2 -1
index a94b9b36a7008..1a438e312d66b 100644
@@ -632,9 +632,10 @@ static void mon_timeout(struct timer_list *t)
 {
 	struct tipc_monitor *mon = timer_container_of(mon, t, timer);
 	struct tipc_peer *self;
-	int best_member_cnt = dom_size(mon->peer_cnt) - 1;
+	int best_member_cnt;
 
 	write_lock_bh(&mon->lock);
+	best_member_cnt = dom_size(mon->peer_cnt) - 1;
 	self = mon->self;
 	if (self && (best_member_cnt != self->applied)) {
 		mon_update_local_domain(mon);
Signature · 1 line
2.53.0
author maintainer
#217 lore raw

PATCH 217/457 net: ethernet: stmmac: dwmac-rk: fix bulk clock leak when the PHY clock fails

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Coia Prant <[email protected]>

[ Upstream commit 8db67bb6a1fffa4df68fbbc22e39943aeeff9178 ]

gmac_clk_enable() enables the bulk clocks first and then the optional PHY clock. If clk_prepare_enable() on the PHY clock fails, the function returns without rolling back the bulk clocks, and bsp_priv->clk_enabled stays false, so the later gmac_clk_enable(bsp_priv, false) becomes a no-op and the bulk clock references are leaked.

Add the missing clk_bulk_disable_unprepare() on that failure path.

---
 drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +4 -1
index 8d7042e689261..72bdbcb5e863a 100644
@@ -1162,8 +1162,11 @@ static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
 				return ret;
 
 			ret = clk_prepare_enable(bsp_priv->clk_phy);
-			if (ret)
+			if (ret) {
+				clk_bulk_disable_unprepare(bsp_priv->num_clks,
+							   bsp_priv->clks);
 				return ret;
+			}
 
 			rk_configure_io_clksel(bsp_priv);
 			rk_ungate_rmii_clock(bsp_priv);
Signature · 1 line
2.53.0
author maintainer
#218 lore raw

PATCH 218/457 net: flush skb_defer_nodes in dev_cpu_dead()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 06e3f54e8b22040ada01a28343badf1990b4dd7d ]

When a CPU goes offline, dev_cpu_dead() drains its softnet queues (completion_queue, output_queue, poll_list, process_queue, and input_pkt_queue), but leaves net_hotdata.skb_defer_nodes untouched.

If oldcpu goes offline while holding pending skbs in its skb_defer_nodes lists (e.g. below the sysctl_skb_defer_max >> 1 IPI threshold, or if the IPI races with CPU teardown), those skbs remain stranded until oldcpu is brought back online. If any of these skbs hold page_pool fragments, page_pool_destroy() will stall indefinitely waiting for inflight pages to be returned when a netdev or driver is torn down while oldcpu is offline.

Additionally, if smp_call_function_single_async() fails in kick_defer_list_purge() because the target CPU went offline, reset defer_ipi_scheduled to 0 so future IPI kicks are not blocked when the CPU comes back online.

Also, if oldcpu was the last online CPU on its NUMA node, drain that node's slot across all CPUs so no skbs deferred from that node remain stranded on idle remote CPUs (or if the node itself is subsequently offlined).

Finally, in skb_attempt_defer_free(), re-check cpu_online(cpu) and whether the caller migrated CPUs after llist_add(), flushing the node list if so, to close the preemption TOCTOU race against CPU/node teardown.

Fixes 68822bdf76f1 ("net: generalize skb freeing deferral to per-cpu lists")
Fixes 5628f3fe3b16 ("net: add NUMA awareness to skb_attempt_defer_free()")
Cc Kris Pan <[email protected]>
---
 net/core/dev.c    | 47 +++++++++++++++++++++++++++++++++++------------
 net/core/dev.h    |  2 ++
 net/core/skbuff.c | 12 +++++++++---
 3 files changed, 46 insertions(+), 15 deletions(-)
net/core/dev.c +35 -12
index a48958a3f76c1..55e1f4045d2c6 100644
@@ -5370,7 +5370,8 @@ void kick_defer_list_purge(unsigned int cpu)
 		backlog_unlock_irq_restore(sd, flags);
 
 	} else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) {
-		smp_call_function_single_async(cpu, &sd->defer_csd);
+		if (smp_call_function_single_async(cpu, &sd->defer_csd))
+			WRITE_ONCE(sd->defer_ipi_scheduled, 0);
 	}
 }
 
@@ -6894,25 +6895,35 @@ bool napi_complete_done(struct napi_struct *n, int work_done)
 }
 EXPORT_SYMBOL(napi_complete_done);
 
-static void skb_defer_free_flush(void)
+static void __skb_defer_free_flush(struct skb_defer_node *sdn, int budget)
 {
 	struct llist_node *free_list;
 	struct sk_buff *skb, *next;
+
+	if (llist_empty(&sdn->defer_list))
+		return;
+	atomic_long_set(&sdn->defer_count, 0);
+	free_list = llist_del_all(&sdn->defer_list);
+
+	llist_for_each_entry_safe(skb, next, free_list, ll_node) {
+		prefetch(next);
+		napi_consume_skb(skb, budget);
+	}
+}
+
+void skb_defer_node_flush(struct skb_defer_node *sdn)
+{
+	__skb_defer_free_flush(sdn, 0);
+}
+
+static void skb_defer_free_flush(void)
+{
 	struct skb_defer_node *sdn;
 	int node;
 
 	for_each_node(node) {
 		sdn = this_cpu_ptr(net_hotdata.skb_defer_nodes) + node;
-
-		if (llist_empty(&sdn->defer_list))
-			continue;
-		atomic_long_set(&sdn->defer_count, 0);
-		free_list = llist_del_all(&sdn->defer_list);
-
-		llist_for_each_entry_safe(skb, next, free_list, ll_node) {
-			prefetch(next);
-			napi_consume_skb(skb, 1);
-		}
+		__skb_defer_free_flush(sdn, 1);
 	}
 }
 
@@ -12773,6 +12784,7 @@ static int dev_cpu_dead(unsigned int oldcpu)
 	struct sk_buff **list_skb;
 	struct sk_buff *skb;
 	unsigned int cpu;
+	int node;
 	struct softnet_data *sd, *oldsd, *remsd = NULL;
 
 	local_irq_disable();
@@ -12833,6 +12845,17 @@ static int dev_cpu_dead(unsigned int oldcpu)
 		rps_input_queue_head_incr(oldsd);
 	}
 
+	for_each_node(node)
+		skb_defer_node_flush(per_cpu_ptr(net_hotdata.skb_defer_nodes,
+						 oldcpu) + node);
+	node = cpu_to_node(oldcpu);
+	if (node_possible(node) &&
+	    !cpumask_intersects(cpumask_of_node(node), cpu_online_mask)) {
+		for_each_possible_cpu(cpu)
+			skb_defer_node_flush(per_cpu_ptr(net_hotdata.skb_defer_nodes,
+							 cpu) + node);
+	}
+
 	return 0;
 }
 
net/core/dev.h +2 -0
index b757faead4d1a..04fb0e9a571e0 100644
@@ -399,6 +399,8 @@ static inline void napi_assert_will_not_race(const struct napi_struct *napi)
 	WARN_ON(READ_ONCE(napi->list_owner) != -1);
 }
 
+struct skb_defer_node;
+void skb_defer_node_flush(struct skb_defer_node *sdn);
 void kick_defer_list_purge(unsigned int cpu);
 
 int dev_set_hwtstamp_phylib(struct net_device *dev,
net/core/skbuff.c +9 -3
index 89ee7907e4996..39102b3660034 100644
@@ -7348,8 +7348,8 @@ void skb_attempt_defer_free(struct sk_buff *skb)
 	struct skb_defer_node *sdn;
 	unsigned long defer_count;
 	unsigned int defer_max;
+	int cpu, my_cpu;
 	bool kick;
-	int cpu;
 
 	if (static_branch_unlikely(&skb_defer_disable_key))
 		goto nodefer;
@@ -7359,7 +7359,8 @@ void skb_attempt_defer_free(struct sk_buff *skb)
 		goto nodefer;
 
 	cpu = skb->alloc_cpu;
-	if (cpu == raw_smp_processor_id() ||
+	my_cpu = raw_smp_processor_id();
+	if (cpu == my_cpu ||
 	    WARN_ON_ONCE(cpu >= nr_cpu_ids) ||
 	    !cpu_online(cpu)) {
 nodefer:	kfree_skb_napi_cache(skb);
@@ -7370,7 +7371,7 @@ nodefer:	kfree_skb_napi_cache(skb);
 	DEBUG_NET_WARN_ON_ONCE(skb->destructor);
 	DEBUG_NET_WARN_ON_ONCE(skb_nfct(skb));
 
-	sdn = per_cpu_ptr(net_hotdata.skb_defer_nodes, cpu) + numa_node_id();
+	sdn = per_cpu_ptr(net_hotdata.skb_defer_nodes, cpu) + cpu_to_node(my_cpu);
 
 	defer_max = READ_ONCE(net_hotdata.sysctl_skb_defer_max);
 	defer_count = atomic_long_inc_return(&sdn->defer_count);
@@ -7380,6 +7381,11 @@ nodefer:	kfree_skb_napi_cache(skb);
 
 	llist_add(&skb->ll_node, &sdn->defer_list);
 
+	if (unlikely(!cpu_online(cpu) || my_cpu != raw_smp_processor_id())) {
+		skb_defer_node_flush(sdn);
+		return;
+	}
+
 	/* Send an IPI every time queue reaches half capacity. */
 	kick = (defer_count - 1) == (defer_max >> 1);
 
Signature · 1 line
2.53.0
author maintainer
#219 lore raw

PATCH 219/457 gve: DQO: fix header length used by gve_can_send_tso() for UDP GSO

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 83769c23fb1879edc916a526ba424285033baf2d ]

gve_can_send_tso() computes how many buffers each segment of a GSO packet would span, and for this it needs the length of the headers that the device replicates in front of every segment.

It unconditionally uses skb_tcp_all_headers(), which reads the doff field of the TCP header. SKB_GSO_UDP_L4 packets have no TCP header:
tcp_hdrlen() then reads one byte of the UDP payload, and header_len can be anything in [0, 60] instead of the transport offset plus the eight bytes of the UDP header that gve_prep_tso() programs into the TSO context descriptor.

A wrong header length shifts all the segment boundaries computed in the loop, so the number of buffers per segment can be over or under estimated. In the first case, GSO is needlessly disabled for this packet by gve_features_check_dqo() and the stack has to segment it. In the second case, the driver hands the device a packet whose segments span more than GVE_TX_MAX_DATA_DESCS buffers.

Use the UDP header length for SKB_GSO_UDP_L4 packets, matching what gve_prep_tso() does.

---
 drivers/net/ethernet/google/gve/gve_tx_dqo.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/ethernet/google/gve/gve_tx_dqo.c +7 -1
index 80ab0a449ff54..0f6f7c5dbb2e0 100644
@@ -918,13 +918,19 @@ static bool gve_can_send_tso(const struct sk_buff *skb)
 {
 	const int max_bufs_per_seg = GVE_TX_MAX_DATA_DESCS - 1;
 	const struct skb_shared_info *shinfo = skb_shinfo(skb);
-	const int header_len = skb_tcp_all_headers(skb);
 	const int gso_size = shinfo->gso_size;
 	int cur_seg_num_bufs;
 	int prev_frag_size;
 	int cur_seg_size;
+	int header_len;
 	int i;
 
+	/* Must match the header length programmed by gve_prep_tso(). */
+	if (skb_is_gso_tcp(skb))
+		header_len = skb_tcp_all_headers(skb);
+	else
+		header_len = skb_transport_offset(skb) + sizeof(struct udphdr);
+
 	cur_seg_size = skb_headlen(skb) - header_len;
 	prev_frag_size = skb_headlen(skb);
 	cur_seg_num_bufs = cur_seg_size > 0;
Signature · 1 line
2.53.0
author maintainer
#220 lore raw

PATCH 220/457 gve: fix TX drop when GSO MSS is too small for hw

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eddie Phillips <[email protected]>

[ Upstream commit 3b430ea6234087957b0d3cd181e3116722b59819 ]

The device has a strict requirement that the minimum MSS (gso_size) for TSO/GSO packets must be at least 88 bytes. If a packet below this threshold is pushed to the hardware, it can cause hardware to silently drop the packet, leading to increased latency and retransmissions.

Currently, this is validated too late in the transmit pipeline (gve_prep_tso), leading to silent drops.

Fix this by moving the validation into the .ndo_features_check callback (gve_features_check_dqo). If we detect a GSO packet with a gso_size smaller than GVE_TX_MIN_TSO_MSS_DQO, we clear the GSO feature flags for this packet.

---
 drivers/net/ethernet/google/gve/gve_tx_dqo.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)
drivers/net/ethernet/google/gve/gve_tx_dqo.c +3 -11
index 0f6f7c5dbb2e0..e5fe17b047981 100644
@@ -577,17 +577,6 @@ static int gve_prep_tso(struct sk_buff *skb)
 	int header_len;
 	int err;
 
-	/* Note: HW requires MSS (gso_size) to be <= 9728 and the total length
-	 * of the TSO to be <= 262143.
-	 *
-	 * However, we don't validate these because:
-	 * - Hypervisor enforces a limit of 9K MTU
-	 * - Kernel will not produce a TSO larger than 64k
-	 */
-
-	if (unlikely(shinfo->gso_size < GVE_TX_MIN_TSO_MSS_DQO))
-		return -1;
-
 	/* Needed because we will modify header. */
 	err = skb_cow_head(skb, 0);
 	if (err < 0)
@@ -925,6 +914,9 @@ static bool gve_can_send_tso(const struct sk_buff *skb)
 	int header_len;
 	int i;
 
+	if (unlikely(gso_size < GVE_TX_MIN_TSO_MSS_DQO))
+		return false;
+
 	/* Must match the header length programmed by gve_prep_tso(). */
 	if (skb_is_gso_tcp(skb))
 		header_len = skb_tcp_all_headers(skb);
Signature · 1 line
2.53.0
author maintainer
#221 lore raw

PATCH 221/457 gve: DQO: reject TSO packets with an out of range MSS

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 296c83b5ccc808c080865eb20fd7a477b0355bb7 ]

gve_prep_tso() notes that the device requires the MSS to be <= 9728, but does not enforce it, assuming the 9K MTU enforced by the hypervisor and the 64KB limit on TSO sizes are enough.

This does not hold for packets that were not generated locally. A guest behind a tap, or any packet socket user, can provide an arbitrary gso_size in virtio_net_hdr. Layer 2 forwarding does not check the MTU for GSO packets (is_skb_forwardable()), and gso_features_check() only bounds skb->len and gso_segs, never gso_size.

Such a packet reaches gve_tx_fill_tso_ctx_desc(), which puts gso_size into the mss field of the TSO context descriptor. This field is 14 bits wide, so a gso_size of 16384 is silently turned into an MSS of zero.

Drop these packets from gve_prep_tso(), and make sure that gve_features_check_dqo() leaves their GSO bits alone: skb_segment() splits at gso_size regardless of the MTU, so falling back to software segmentation would give the device non TSO packets bigger than the 9728 bytes it supports.

Note that the device can still be given oversized non TSO packets when the stack segments in software for other reasons, for instance after TSO has been disabled with ethtool. This is a generic issue, because the MTU check is skipped for GSO packets in the forwarding path, and is addressed separately.

---
 .../net/ethernet/google/gve/gve_desc_dqo.h    |  5 ++++
 drivers/net/ethernet/google/gve/gve_tx_dqo.c  | 26 ++++++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)
drivers/net/ethernet/google/gve/gve_desc_dqo.h +5 -0
index f7786b03c7444..d2c86c8eeae2a 100644
@@ -14,6 +14,11 @@
 #define GVE_TX_MAX_HDR_SIZE_DQO 255
 #define GVE_TX_MIN_TSO_MSS_DQO 88
 
+/* HW limit. This also has to fit in the 14 bits of the mss field of
+ * struct gve_tx_tso_context_desc_dqo.
+ */
+#define GVE_TX_MAX_TSO_MSS_DQO 9728
+
 #ifndef __LITTLE_ENDIAN_BITFIELD
 #error "Only little endian supported"
 #endif
drivers/net/ethernet/google/gve/gve_tx_dqo.c +25 -1
index e5fe17b047981..616c1921aebea 100644
@@ -577,6 +577,20 @@ static int gve_prep_tso(struct sk_buff *skb)
 	int header_len;
 	int err;
 
+	/* Note: HW requires the total length of the TSO to be <= 262143,
+	 * this is enforced by netif_set_tso_max_size().
+	 *
+	 * MSS (gso_size) can not be trusted: packets forwarded from a tap or
+	 * injected by a packet socket can carry an arbitrary value, while the
+	 * mss field of the TSO context descriptor is only 14 bits wide.
+	 *
+	 * A too big MSS is dropped here instead of being rejected from
+	 * gve_features_check_dqo(), because software segmentation would
+	 * produce packets larger than the device can send.
+	 */
+	if (unlikely(shinfo->gso_size > GVE_TX_MAX_TSO_MSS_DQO))
+		return -1;
+
 	/* Needed because we will modify header. */
 	err = skb_cow_head(skb, 0);
 	if (err < 0)
@@ -964,7 +978,17 @@ netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
 					 struct net_device *dev,
 					 netdev_features_t features)
 {
-	if (skb_is_gso(skb) && !gve_can_send_tso(skb))
+	if (!skb_is_gso(skb))
+		return features;
+
+	/* Keep the GSO bits for a too big MSS, so that gve_prep_tso() drops
+	 * the packet: software segmentation would give packets larger than
+	 * the device can send.
+	 */
+	if (skb_shinfo(skb)->gso_size > GVE_TX_MAX_TSO_MSS_DQO)
+		return features;
+
+	if (!gve_can_send_tso(skb))
 		return features & ~NETIF_F_GSO_MASK;
 
 	return features;
Signature · 1 line
2.53.0
author maintainer
#222 lore raw

PATCH 222/457 llc: fix skb UAF and leaks on llc_mac_hdr_init() failure

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 72f9dd522f8d6c5a00be9695c7bb74631eb5069e ]

In llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(), if llc_mac_hdr_init() fails, kfree_skb(skb) is called instead of kfree_skb(nskb). This leaks the newly allocated nskb, reads from the freed skb via LLC_I_GET_NR(pdu), and double-frees skb when llc_conn_state_process() drops its reference.

In llc_sap_action_send_xid_r() and llc_sap_action_send_test_r(), nskb is leaked if llc_mac_hdr_init() returns an error.

Free nskb in all three error paths.

---
 net/llc/llc_c_ac.c | 2 +-
 net/llc/llc_s_ac.c | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)
net/llc/llc_c_ac.c +1 -1
index 724ecd741d4cf..1aa7fe28acddb 100644
@@ -437,7 +437,7 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
 		if (likely(!rc))
 			llc_conn_send_pdu(sk, nskb);
 		else
-			kfree_skb(skb);
+			kfree_skb(nskb);
 	}
 	if (rc) {
 		nr = LLC_I_GET_NR(pdu);
net/llc/llc_s_ac.c +4 -0
index 98deee5603735..831998211b52e 100644
@@ -121,6 +121,8 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
 	rc = llc_mac_hdr_init(nskb, mac_sa, mac_da);
 	if (likely(!rc))
 		rc = dev_queue_xmit(nskb);
+	else
+		kfree_skb(nskb);
 out:
 	return rc;
 }
@@ -170,6 +172,8 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
 	rc = llc_mac_hdr_init(nskb, mac_sa, mac_da);
 	if (likely(!rc))
 		rc = dev_queue_xmit(nskb);
+	else
+		kfree_skb(nskb);
 out:
 	return rc;
 }
Signature · 1 line
2.53.0
author maintainer
#223 lore raw

PATCH 223/457 bridge: check llc_mac_hdr_init() return value in br_send_bpdu()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit ac704ff08e511c87643799c385f55ecd69b85e03 ]

If llc_mac_hdr_init() fails (for instance if the port device type does not support LLC or dev_hard_header() fails), br_send_bpdu() should drop the skb instead of resetting the mac header to the LLC payload and transmitting a malformed frame.

---
 net/bridge/br_stp_bpdu.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
net/bridge/br_stp_bpdu.c +4 -1
index 74ec42ba1e7d0..21d092f5acbb8 100644
@@ -52,7 +52,10 @@ static void br_send_bpdu(struct net_bridge_port *p,
 			    LLC_SAP_BSPAN, LLC_PDU_CMD);
 	llc_pdu_init_as_ui_cmd(skb);
 
-	llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
+	if (llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr)) {
+		kfree_skb(skb);
+		return;
+	}
 
 	skb_reset_mac_header(skb);
 
Signature · 1 line
2.53.0
author maintainer
#224 lore raw

PATCH 224/457 net/sched: sch_teql: fix shadowed err in __teql_resolve()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 907b978e82cb4c1c245fc2985bb27c5d5c88c8f6 ]

__teql_resolve() declares an inner 'int err;' inside the 'if (neigh_event_send(n, skb_res) == 0)' block, shadowing the outer 'int err = 0;'. As a result, a negative return from dev_hard_header() is written to the inner variable and __teql_resolve() still returns 0.

Remove the shadowed variable and set the outer err to -EINVAL when dev_hard_header() returns a negative error.

---
 net/sched/sch_teql.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
net/sched/sch_teql.c +2 -5
index 9e52afc2d9808..409ce50cc0dbc 100644
@@ -265,14 +265,11 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
 	}
 
 	if (neigh_event_send(n, skb_res) == 0) {
-		int err;
 		char haddr[MAX_ADDR_LEN];
 
 		neigh_ha_snapshot(haddr, n, dev);
-		err = dev_hard_header(skb, dev, ntohs(skb_protocol(skb, false)),
-				      haddr, NULL, skb->len);
-
-		if (err < 0)
+		if (dev_hard_header(skb, dev, ntohs(skb_protocol(skb, false)),
+				    haddr, NULL, skb->len) < 0)
 			err = -EINVAL;
 	} else {
 		err = (skb_res == NULL) ? -EAGAIN : 1;
Signature · 1 line
2.53.0
author maintainer
#225 lore raw

PATCH 225/457 vlan: ensure sufficient headroom in vlan_dev_hard_header()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit cd5dd68267c4238795fadaf02b3575ca3f8a6500 ]

Callers that only reserve ETH_HLEN or less (such as llc_alloc_frame()), or skbs allocated before dynamic device/headroom changes (e.g. toggling VLAN_FLAG_REORDER_HDR or bonding/team switching slaves), can reach vlan_dev_hard_header() with insufficient headroom and trigger skb_under_panic().

Use skb_cow_head() in vlan_dev_hard_header() when VLAN_FLAG_REORDER_HDR is not set to ensure sufficient headroom for the VLAN header(s) and the underlying device hard header.

Use READ_ONCE() to read dev->hard_header_len and dev->needed_headroom as they can be updated concurrently under RTNL (e.g. in vlan_transfer_features()) while vlan_dev_hard_header() runs locklessly on the transmit path. Also avoid LL_RESERVED_SPACE(dev) here so that the extra HH_DATA_MOD alignment padding does not trigger unnecessary pskb_expand_head() reallocations on inner stacked VLAN devices after the outer VLAN header has been pushed.

---
 net/8021q/vlan_dev.c | 5 +++++
 1 file changed, 5 insertions(+)
net/8021q/vlan_dev.c +5 -0
index 2859cbac3f266..c949c6a829456 100644
@@ -55,6 +55,11 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 	int rc;
 
 	if (!(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
+		unsigned int hlen = READ_ONCE(dev->hard_header_len) +
+				    READ_ONCE(dev->needed_headroom);
+
+		if (skb_cow_head(skb, hlen) < 0)
+			return -ENOMEM;
 		vhdr = skb_push(skb, VLAN_HLEN);
 
 		vlan_tci = vlan->vlan_id;
Signature · 1 line
2.53.0
author maintainer
#226 lore raw

PATCH 226/457 ovl: fix UAF in ovl_do_mkdir() debug print

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Amir Goldstein <[email protected]>

[ Upstream commit ae146bc1abdeb4607abf2975b858c053024e8ac1 ]

ovl_do_mkdir() prints the input dentry with %pd after vfs_mkdir(). Since commit fe497f0759e0 ("VFS: change vfs_mkdir() to unlock on failure."), vfs_mkdir() calls end_creating() on the input dentry on failure and may replace it on success, so the post-call %pd can use-after-free the dentry when CONFIG_OVERLAY_FS_DEBUG is enabled.

Print the dentry before the call and only the result afterward.

---
 fs/overlayfs/overlayfs.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
fs/overlayfs/overlayfs.h +3 -1
index b75df37f70ac3..3fea90fe37c75 100644
@@ -254,8 +254,10 @@ static inline struct dentry *ovl_do_mkdir(struct ovl_fs *ofs,
 {
 	struct dentry *ret;
 
+	/* vfs_mkdir() drops @dentry on failure and may replace it on success */
+	pr_debug("mkdir(%pd2, 0%o)\n", dentry, mode);
 	ret = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, NULL);
-	pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(ret));
+	pr_debug("...mkdir = %i\n", PTR_ERR_OR_ZERO(ret));
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#227 lore raw

PATCH 227/457 autofs: fix sbi->pipe file reference leak in autofs_kill_sb()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

[ Upstream commit aa5e44b29ffe4eaa08cc2237fd65bc2596bc023e ]

When autofs_fill_super() fails before clearing AUTOFS_SBI_CATATONIC (for example, when find_get_pid() fails on an invalid pgrp mount option, or when an fs_context is closed before mounting), deactivate_locked_super() invokes autofs_kill_sb() -> autofs_catatonic_mode(sbi).

Because AUTOFS_SBI_CATATONIC is still set in sbi->flags, autofs_catatonic_mode() returns early without calling fput(sbi->pipe), permanently leaking the pipe struct file reference.

Explicitly release sbi->pipe in autofs_kill_sb() if it is still non-NULL after autofs_catatonic_mode().

---
 fs/autofs/inode.c | 4 ++++
 1 file changed, 4 insertions(+)
fs/autofs/inode.c +4 -0
index 6b15a3717ba7e..066c16f2ea569 100644
@@ -51,6 +51,10 @@ void autofs_kill_sb(struct super_block *sb)
 	if (sbi) {
 		/* Free wait queues, close pipe */
 		autofs_catatonic_mode(sbi);
+		if (sbi->pipe) {
+			fput(sbi->pipe);
+			sbi->pipe = NULL;
+		}
 		put_pid(sbi->oz_pgrp);
 	}
 
Signature · 1 line
2.53.0
author maintainer
#228 lore raw

PATCH 228/457 perf/x86/intel: Ensure KVM guest PEBS path doesnt set unwanted PERF_GLOBAL_CTRL bits

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

[ Upstream commit cec38d5c098a350dcf084d345025136ade7e6d1e ]

When reinstating PEBS counters into PERF_GLOBAL_CTRL for a KVM guest, mask the value with perf's desired/original PERF_GLOBAL_CTRL value to ensure KVM doesn't unintentionally set reserved bits in PERF_GLOBAL_CTRL. E.g. if the guest's PEBS_ENABLE value had bit 63, "Enable Precise Store", set, then using the raw guest PEBS value would propagate bit 63 to the guest's PERF_GLOBAL_CTRL value (which thankfully would be a failed VM-Entry, not a VMX Abort).

The only reason this bug isn't reachable is because KVM doesn't support "Enable Precise Store" (which is probably a KVM bug?), i.e. bit 63 can't be set in kvm_pmu->pebs_enable and thus not in arr[pebs_enable].guest. In other words, this _should_ be a glorified NOP in the current code base.

Fixes c59a1f106f5c ("KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS")
---
 arch/x86/events/intel/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/events/intel/core.c +1 -1
index 24c1f40595449..cf39dd2111cb9 100644
@@ -5361,7 +5361,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 		arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask;
 		arr[global_ctrl].guest &= ~kvm_pmu->host_cross_mapped_mask;
 		/* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */
-		arr[global_ctrl].guest |= arr[pebs_enable].guest;
+		arr[global_ctrl].guest |= intel_ctrl & arr[pebs_enable].guest;
 	}
 
 	return arr;
Signature · 1 line
2.53.0
author maintainer
#229 lore raw

PATCH 229/457 perf/x86/intel: Dont write PEBS_ENABLED on host<=>guest xfers if CPU has PEBS isolation, to fix stuck PEBS_ENABLED

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

[ Upstream commit 4b64dbdc5861477f148e13d1ed127e7fe7182e4f ]

When filling the list of MSRs to be loaded by KVM on VM-Enter and VM-Exit, *never* insert an entry for PEBS_ENABLED if the CPU properly isolates PEBS events, in which case disabling counters via PERF_GLOBAL_CTRL is sufficient to prevent unwanted PEBS events in the guest (or host). Because perf loads PEBS_ENABLE with the unfiltered cpu_hw_events.pebs_enabled, i.e. with both host and guest masks, there is no need to load different values for the guest versus host, perf+KVM can and should simply control which counters are enabled/disabled via PERF_GLOBAL_CTRL.

Avoiding touching PEBS_ENABLED "fixes" a bug where PEBS_ENABLED can end up with "stuck" bits if a PEBS event is throttled between generating the list and actually entering the guest (Intel CPUs can't arbtitrarily block NMIs). Fixes in quotes because leaving PEBS_ENABLED as-is doesn't fix the underlying problem of perf (via PMIs) being able to modify state after the perf<=>KVM handoff.

But not writing PEBS_ENABLED is desirable no matter what, as stating the obvious, leaving PEBS_ENABLED as-is avoids three MSR writes on every VMX
transition: one each on entry/exit, and one more explicit WRMSR to zero PEBS_ENABLED before VM-Entry (KVM assumes the only reason PEBS_ENABLED is in the load list is if the CPU lacks PEBS isolation and thus needs a quiescent period).

Opportunistically add comments to (better) explain the rules for generating the set of PEBS counters that will be active while the guest is running, along with a FIXME for the suspected hack-a-fix where perf disables guest PEBS if _any_ PEBS event is configured to count in the host (commit 854250329c02 ("KVM: x86/pmu: Disable guest PEBS temporarily in two rare situations") doesn't explain the motivation, at all).

Fixes c59a1f106f5c ("KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS")
---
 arch/x86/events/intel/core.c | 55 ++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 18 deletions(-)
arch/x86/events/intel/core.c +37 -18
index cf39dd2111cb9..b927f0e88e7fc 100644
@@ -5294,12 +5294,15 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 	struct kvm_pmu *kvm_pmu = (struct kvm_pmu *)data;
 	u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl);
 	u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable;
-	int global_ctrl, pebs_enable;
+	u64 guest_pebs_mask;
+	int global_ctrl;
 
 	/*
 	 * In addition to obeying exclude_guest/exclude_host, remove bits being
 	 * used for PEBS when running a guest, because PEBS writes to virtual
-	 * addresses (not physical addresses).
+	 * addresses (not physical addresses).  If the guest wants to utilize
+	 * PEBS, and PEBS can be safely enabled in the guest, bits for the guest's
+	 * PEBS-enabled counters will be OR'd back in as appropriate.
 	 */
 	*nr = 0;
 	global_ctrl = (*nr)++;
@@ -5346,24 +5349,40 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 		};
 	}
 
-	pebs_enable = (*nr)++;
-	arr[pebs_enable] = (struct perf_guest_switch_msr){
-		.msr = MSR_IA32_PEBS_ENABLE,
-		.host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask,
-		.guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable,
-	};
+	/*
+	 * Restrict guest PEBS events to counters that (a) perf supports, (b)
+	 * the guest wants to use for PEBS, (c) are not excluded from counting
+	 * in the guest, and (d) _are_ excluded from counting in the host.
+	 */
+	guest_pebs_mask = pebs_mask & intel_ctrl & kvm_pmu->pebs_enable &
+			  ~cpuc->intel_ctrl_host_mask &
+			  cpuc->intel_ctrl_guest_mask;
 
-	if (arr[pebs_enable].host) {
-		/* Disable guest PEBS if host PEBS is enabled. */
-		arr[pebs_enable].guest = 0;
-	} else {
-		/* Disable guest PEBS thoroughly for cross-mapped PEBS counters. */
-		arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask;
-		arr[global_ctrl].guest &= ~kvm_pmu->host_cross_mapped_mask;
-		/* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */
-		arr[global_ctrl].guest |= intel_ctrl & arr[pebs_enable].guest;
-	}
+	/*
+	 * Disable counters where the guest PMC is different than the host PMC
+	 * being used on behalf of the guest, as the PEBS record includes
+	 * PERF_GLOBAL_STATUS, i.e. the guest will see overflow status for the
+	 * wrong counter(s).
+	 */
+	guest_pebs_mask &= ~kvm_pmu->host_cross_mapped_mask;
+
+	/*
+	 * FIXME: Allow guest and host usage of PEBS events to co-exist instead
+	 *        of disabling guest PEBS entirely if the host is using PEBS.
+	 *        What exactly goes wrong if guest and host are using PEBS is
+	 *        unknown.
+	 */
+	if (pebs_mask & ~cpuc->intel_ctrl_guest_mask)
+		guest_pebs_mask = 0;
 
+	/*
+	 * Do NOT mess with PEBS_ENABLED.  As above, disabling counters via
+	 * PERF_GLOBAL_CTRL is sufficient, and loading a stale PEBS_ENABLED,
+	 * e.g. on VM-Exit, can put the system in a bad state.  Simply enable
+	 * counters in PERF_GLOBAL_CTRL, as perf load PEBS_ENABLED with the
+	 * full value, i.e. perf *also* relies on PERF_GLOBAL_CTRL.
+	 */
+	arr[global_ctrl].guest |= guest_pebs_mask;
 	return arr;
 }
 
Signature · 1 line
2.53.0
author maintainer
#230 lore raw

PATCH 230/457 perf/x86/intel: Dont pointlessly context switch DS_AREA (and PEBS config) if PEBS is unused

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

[ Upstream commit d06260e99eb93d2942b7af4ccd789eb8a6c829d3 ]

When filling the list of MSRs to be loaded by KVM on VM-Enter and VM-Exit, load the guest values for DS_AREA and (conditionally) MSR_PEBS_DATA_CFG if and only if PEBS will be active in the guest, i.e. only if a PEBS record may be generated while running the guest. As shown by the !pebs_ept path, it's perfectly safe to run with the host's DS_AREA, so long as PEBS-enabled counters are disabled via PERF_GLOBAL_CTRL.

Omitting DS_AREA and MSR_PEBS_DATA_CFG when PEBS is unused saves two MSR writes per MSR on each VMX transition, i.e. eliminates two/four pointless MSR writes on each VMX roundtrip when PEBS isn't being used by the guest.

Fixes c59a1f106f5c ("KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS")
---
 arch/x86/events/intel/core.c | 39 +++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 14 deletions(-)
arch/x86/events/intel/core.c +25 -14
index b927f0e88e7fc..b9d7fdf6c6585 100644
@@ -5332,23 +5332,14 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 		return arr;
 	}
 
+	/*
+	 * If the guest won't use PEBS or the CPU doesn't support PEBS in the
+	 * guest, then there's nothing more to do as disabling PMCs via
+	 * PERF_GLOBAL_CTRL is sufficient on CPUs with guest/host isolation.
+	 */
 	if (!kvm_pmu || !x86_pmu.pebs_ept)
 		return arr;
 
-	arr[(*nr)++] = (struct perf_guest_switch_msr){
-		.msr = MSR_IA32_DS_AREA,
-		.host = (unsigned long)cpuc->ds,
-		.guest = kvm_pmu->ds_area,
-	};
-
-	if (x86_pmu.intel_cap.pebs_baseline) {
-		arr[(*nr)++] = (struct perf_guest_switch_msr){
-			.msr = MSR_PEBS_DATA_CFG,
-			.host = cpuc->active_pebs_data_cfg,
-			.guest = kvm_pmu->pebs_data_cfg,
-		};
-	}
-
 	/*
 	 * Restrict guest PEBS events to counters that (a) perf supports, (b)
 	 * the guest wants to use for PEBS, (c) are not excluded from counting
@@ -5375,6 +5366,26 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 	if (pebs_mask & ~cpuc->intel_ctrl_guest_mask)
 		guest_pebs_mask = 0;
 
+	/*
+	 * Context switch DS_AREA and PEBS_DATA_CFG if and only if PEBS will be
+	 * active in the guest; if no records will be generated while the guest
+	 * is running, then simply keep the host values resident in hardware.
+	 */
+	arr[(*nr)++] = (struct perf_guest_switch_msr){
+		.msr = MSR_IA32_DS_AREA,
+		.host = (unsigned long)cpuc->ds,
+		.guest = guest_pebs_mask ? kvm_pmu->ds_area : (unsigned long)cpuc->ds,
+	};
+
+	if (x86_pmu.intel_cap.pebs_baseline) {
+		arr[(*nr)++] = (struct perf_guest_switch_msr){
+			.msr = MSR_PEBS_DATA_CFG,
+			.host = cpuc->active_pebs_data_cfg,
+			.guest = guest_pebs_mask ? kvm_pmu->pebs_data_cfg :
+						   cpuc->active_pebs_data_cfg,
+		};
+	}
+
 	/*
 	 * Do NOT mess with PEBS_ENABLED.  As above, disabling counters via
 	 * PERF_GLOBAL_CTRL is sufficient, and loading a stale PEBS_ENABLED,
Signature · 1 line
2.53.0
author maintainer
#231 lore raw

PATCH 231/457 perf/x86/intel: Make @data a mandatory param for intel_guest_get_msrs()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

[ Upstream commit a391618e1d563f099e4c2a704f45d08329ccdf7c ]

Drop "support" for passing a NULL @data/@kvm_pmu param when getting guest MSRs. KVM, the only in-tree user, unconditionally passes a non-NULL pointer, and carrying code that suggests @data may be NULL is confusing, e.g. incorrectly implies that there are scenarios where KVM doesn't pass a PMU context.

---
 arch/x86/events/intel/core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/events/intel/core.c +4 -4
index b9d7fdf6c6585..41134233fc512 100644
@@ -5333,11 +5333,11 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
 	}
 
 	/*
-	 * If the guest won't use PEBS or the CPU doesn't support PEBS in the
-	 * guest, then there's nothing more to do as disabling PMCs via
-	 * PERF_GLOBAL_CTRL is sufficient on CPUs with guest/host isolation.
+	 * If the CPU doesn't support PEBS in the guest, then there's nothing
+	 * more to do as disabling PMCs via PERF_GLOBAL_CTRL is sufficient on
+	 * CPUs with guest/host isolation.
 	 */
-	if (!kvm_pmu || !x86_pmu.pebs_ept)
+	if (!x86_pmu.pebs_ept)
 		return arr;
 
 	/*
Signature · 1 line
2.53.0
author maintainer
#232 lore raw

PATCH 232/457 perf/x86/intel: Delete dead NVL PEBS data-source initcall

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dapeng Mi <[email protected]>

[ Upstream commit 858b37ca19d3f695f7fa94cd14be5a856fd8e7d7 ]

Nova Lake now uses the OMR data-source table for PEBS data-source decoding and no longer depends on the legacy static pebs_data_source[] mapping.

Remove the dead intel_pmu_pebs_data_source_lnl() initialization call for NVL.

Fixes c847a208f43b ("perf/x86/intel: Add core PMU support for Novalake")
---
 arch/x86/events/intel/core.c | 2 --
 1 file changed, 2 deletions(-)
arch/x86/events/intel/core.c +0 -2
index 41134233fc512..689acaeeabada 100644
@@ -8785,8 +8785,6 @@ __init int intel_pmu_init(void)
 		/* Initialize Atom core specific PerfMon capabilities.*/
 		pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
 		intel_pmu_init_arw(&pmu->pmu);
-
-		intel_pmu_pebs_data_source_lnl();
 		break;
 
 	default:
Signature · 1 line
2.53.0
author maintainer
#233 lore raw

PATCH 233/457 perf/core: Fix a refcount leak in attach_perf_ctx_data()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Namhyung Kim <[email protected]>

[ Upstream commit cca4980630b3c7a85f53cb43c6018184ce5d4e37 ]

The attach_perf_ctx_data() can race on global and !global cases. The global case is protected by global_ctx_data_rwsem and shares a single reference count using perf_ctx_data.global field.

But when it races with !global case, it may miss to set the global field and result in a reference count leak.

CPU1 CPU2
----------------------------------------------------------------
attach_task_ctx_data(.global=1) attach_task_ctx_data(.global=0)

   cd1 = alloc_perf_ctx_data();          cd2 = alloc_perf_ctx_data();
                                         //    { .global = 0, .refcount = 1 };

                                         try_cmpxchg(); // success,
                                         // task->perf_ctx_data = cd2
   try_cmpxhg(); // fail; old = cd2
   refcount_inc_not_zero(&old->refcount); // success
     // old.refcount = 2

free_perf_ctx_data(cd1);

Then later detach_global_ctx_data() will see the data but it's not marked as global, so it won't call detach_task_ctx_data().

Fixes 506e64e710ff ("perf: attach/detach PMU specific data")
Assisted-by Sashiko.dev:Gemini-3.1-pro
---
 kernel/events/core.c | 2 ++
 1 file changed, 2 insertions(+)
kernel/events/core.c +2 -0
index 60e60809bedc7..866c595321868 100644
@@ -5454,6 +5454,8 @@ attach_task_ctx_data(struct task_struct *task, struct kmem_cache *ctx_cache,
 		}
 
 		if (refcount_inc_not_zero(&old->refcount)) {
+			if (global)
+				old->global = true;
 			free_perf_ctx_data(cd); /* unused */
 			return 0;
 		}
Signature · 1 line
2.53.0
author maintainer
#234 lore raw

PATCH 234/457 perf/core: Fill branch entries with a single assignment

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Puranjay Mohan <[email protected]>

[ Upstream commit 24b620729e53d978b3e425f55bc66efd3bab1f59 ]

perf_clear_branch_entry_bitfields() clears the bitfields of struct perf_branch_entry one by one and leaves from/to alone, since callers overwrite those straight away. The list has to be kept in sync with the struct by hand and has already fallen behind: new_type and priv were added to perf_branch_entry and never added here.

Only BRBE writes those two, and neither for every record. brbe_set_perf_entry_type() leaves new_type alone for a branch type it does not recognise, and priv is not set for source-only records. arm_pmuv3.c allocates the per-CPU branch stack with kmalloc(), so such a record reaches userspace with whatever the slot held: uninitialised kmalloc() data on the first pass over the buffer, the previous record's values after that. Nothing under arch/x86/events/ writes either field, so only arm64 is affected.

Assign the whole entry at each site instead. Everything not named is then zero, and there is no list to keep in sync. The bitfields add up to exactly 64 bits, so the struct has no padding to leave undefined.

perf_clear_branch_entry_bitfields() has no callers left, so remove it. perf_entry_from_brbe_regset() assigns an empty literal instead, since it fills from/to conditionally. PERF_BR_SPEC_NA is 0, so dropping the explicit spec assignment changes nothing.

Fixes b190bc4ac9e6 ("perf: Extend branch type classification")
Fixes 5402d25aa571 ("perf: Capture branch privilege information")
---
 arch/x86/events/amd/brs.c   |  9 +++--
 arch/x86/events/amd/lbr.c   | 16 ++++-----
 arch/x86/events/intel/lbr.c | 65 ++++++++++++++++++++-----------------
 drivers/perf/arm_brbe.c     |  2 +-
 include/linux/perf_event.h  | 17 ----------
 5 files changed, 48 insertions(+), 61 deletions(-)
arch/x86/events/amd/brs.c +4 -5
index dc564688f3d73..54b13faba116c 100644
@@ -343,11 +343,10 @@ void amd_brs_drain(void)
 		if (!amd_brs_match_plm(event, from, to))
 			continue;
 
-		perf_clear_branch_entry_bitfields(br+nr);
-
-		br[nr].from = from;
-		br[nr].to   = to;
-
+		br[nr] = (struct perf_branch_entry){
+			.from	= from,
+			.to	= to,
+		};
 		nr++;
 	}
 empty:
arch/x86/events/amd/lbr.c +8 -8
index 9d9c961989d51..a55646fcb8465 100644
@@ -184,13 +184,6 @@ void amd_pmu_lbr_read(void)
 		    entry.to.split.reserved)
 			continue;
 
-		perf_clear_branch_entry_bitfields(br + out);
-
-		br[out].from	= sign_ext_branch_ip(entry.from.split.ip);
-		br[out].to	= sign_ext_branch_ip(entry.to.split.ip);
-		br[out].mispred	= entry.from.split.mispredict;
-		br[out].predicted = !br[out].mispred;
-
 		/*
 		 * Set branch speculation information using the status of
 		 * the valid and spec bits.
@@ -208,7 +201,14 @@ void amd_pmu_lbr_read(void)
 		 * speculative and took the correct path
 		 */
 		idx = (entry.to.split.valid << 1) | entry.to.split.spec;
-		br[out].spec = lbr_spec_map[idx];
+
+		br[out] = (struct perf_branch_entry){
+			.from		= sign_ext_branch_ip(entry.from.split.ip),
+			.to		= sign_ext_branch_ip(entry.to.split.ip),
+			.mispred	= entry.from.split.mispredict,
+			.predicted	= !entry.from.split.mispredict,
+			.spec		= lbr_spec_map[idx],
+		};
 		out++;
 	}
 
arch/x86/events/intel/lbr.c +35 -30

89 lines not on this page · raw message

drivers/perf/arm_brbe.c +1 -1
index ba554e0c846c4..254be4da8ae29 100644
@@ -604,7 +604,7 @@ static bool perf_entry_from_brbe_regset(int index, struct perf_branch_entry *ent
 		return false;
 
 	brbinf = bregs.brbinf;
-	perf_clear_branch_entry_bitfields(entry);
+	*entry = (struct perf_branch_entry){ };
 	if (brbe_record_is_complete(brbinf)) {
 		entry->from = bregs.brbsrc;
 		entry->to = bregs.brbtgt;
include/linux/perf_event.h +0 -17
index 48d851fbd8ea5..310681cccb50a 100644
@@ -1467,23 +1467,6 @@ static inline u32 perf_sample_data_size(struct perf_sample_data *data,
 	return size;
 }
 
-/*
- * Clear all bitfields in the perf_branch_entry.
- * The to and from fields are not cleared because they are
- * systematically modified by caller.
- */
-static inline void perf_clear_branch_entry_bitfields(struct perf_branch_entry *br)
-{
-	br->mispred	= 0;
-	br->predicted	= 0;
-	br->in_tx	= 0;
-	br->abort	= 0;
-	br->cycles	= 0;
-	br->type	= 0;
-	br->spec	= PERF_BR_SPEC_NA;
-	br->reserved	= 0;
-}
-
 extern void perf_output_sample(struct perf_output_handle *handle,
 			       struct perf_event_header *header,
 			       struct perf_sample_data *data,
Signature · 1 line
2.53.0
author maintainer
#235 lore raw

PATCH 235/457 sched/core: Account PSI IRQ time to the execution context, not the scheduling context

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhan Xusheng <[email protected]>

[ Upstream commit a0bb6fac53fa7cf1cadb487b43d4c9276a6b82e3 ]

psi_account_irqtime() has two callers which share rq->psi_irq_time, and they disagree about the context: __schedule() passes the outgoing rq->curr, sched_tick() passes rq->donor. Under proxy execution the donor is blocked on a mutex while rq->curr burns the CPU.

The tick charges PSI_IRQ_FULL to the donor's cgroup and advances the timestamp, so the call from __schedule() then finds delta <= 0 and charges nothing. The delta is not counted twice, it lands on the wrong cgroup.

Pass rq->curr, which is what the call read before commit af0c8b2bf67b ("sched: Split scheduler and execution contexts") renamed 'curr' to 'donor' across sched_tick(). Without CONFIG_SCHED_PROXY_EXEC the two rq members are a union, so this only changes anything where that option is set, and it depends on EXPERT.

Fixes af0c8b2bf67b ("sched: Split scheduler and execution contexts")
---
 kernel/sched/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/core.c +1 -1
index 3d6c55598726f..c104562638e33 100644
@@ -5802,7 +5802,7 @@ void sched_tick(void)
 	curr = rq->curr;
 	donor = rq->donor;
 
-	psi_account_irqtime(rq, donor, NULL);
+	psi_account_irqtime(rq, curr, NULL);
 
 	update_rq_clock(rq);
 	hw_pressure = arch_scale_hw_pressure(cpu_of(rq));
Signature · 1 line
2.53.0
author maintainer
#236 lore raw

PATCH 236/457 mptcp: return sk_wait_data() errors from recvmsg()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mark Amirkan <[email protected]>

[ Upstream commit 60404266ef3e0a1cd8f7a164060e0c83efb72f4b ]

Commit 581302298524 ("mptcp: error out earlier on disconnect") made mptcp_recvmsg() stop when sk_wait_data() returns an error. The error is stored in err, but the function then jumps to a path which returns copied. When no data was copied, recvmsg() therefore returns zero and reports a false EOF.

Store the result in copied, which is the value returned by the function. This also keeps the usual partial-read result when data was copied before the error.

A recvmsg() blocked in one thread reproduces the issue when another thread disconnects the same MPTCP socket with connect(AF_UNSPEC). Before this change recvmsg() returns zero; afterwards it returns -EPIPE.

---
 net/mptcp/protocol.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/mptcp/protocol.c +1 -1
index 49c46498af960..de6f289a6e14e 100644
@@ -2401,7 +2401,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
 		mptcp_cleanup_rbuf(msk, copied);
 		err = sk_wait_data(sk, &timeo, last);
 		if (err < 0) {
-			err = copied ? : err;
+			copied = copied ? : err;
 			goto out_err;
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#237 lore raw

PATCH 237/457 drm/pagemap: dma-unmap pages before handling migration errors

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Matthew Brost <[email protected]>

[ Upstream commit 9e6372ec2a3990662ae0a67f56ac0aee19848d5b ]

drm_pagemap_migrate_unmap_pages() relies on the pages array to determine which pages require DMA unmapping. However, drm_pagemap_migration_unlock_put_pages() clears the array as part of its cleanup, leaving drm_pagemap_migrate_unmap_pages() with no valid page information if it is called afterward.

Call drm_pagemap_migrate_unmap_pages() before drm_pagemap_migration_unlock_put_pages() so the pages array remains valid during DMA unmapping.

Fixes f86ad0ed620c ("drm/gpusvm, drm/pagemap: Move migration functionality to drm_pagemap")
---
 drivers/gpu/drm/drm_pagemap.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/drm_pagemap.c +6 -6
index 89e1ddff84dd2..a0546955d0b9f 100644
@@ -1368,13 +1368,13 @@ int drm_pagemap_evict_to_ram(struct drm_pagemap_devmem *devmem_allocation)
 		goto err_finalize;
 
 err_finalize:
+	drm_pagemap_migrate_unmap_pages(devmem_allocation->dev, pagemap_addr, dst, npages,
+					DMA_FROM_DEVICE, &state);
 	if (err)
 		drm_pagemap_migration_unlock_put_pages(npages, dst);
 	migrate_device_pages(src, dst, npages);
 	drm_pagemap_retire_migrated_pages(src, npages);
 	migrate_device_finalize(src, dst, npages);
-	drm_pagemap_migrate_unmap_pages(devmem_allocation->dev, pagemap_addr, dst, npages,
-					DMA_FROM_DEVICE, &state);
 
 err_free:
 	kvfree(buf);
@@ -1494,15 +1494,15 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas,
 		goto err_finalize;
 
 err_finalize:
+	if (dev)
+		drm_pagemap_migrate_unmap_pages(dev, pagemap_addr, migrate.dst,
+						npages, DMA_FROM_DEVICE,
+						&state);
 	if (err)
 		drm_pagemap_migration_unlock_put_pages(npages, migrate.dst);
 	migrate_vma_pages(&migrate);
 	drm_pagemap_retire_migrated_pages(migrate.src, npages);
 	migrate_vma_finalize(&migrate);
-	if (dev)
-		drm_pagemap_migrate_unmap_pages(dev, pagemap_addr, migrate.dst,
-						npages, DMA_FROM_DEVICE,
-						&state);
 err_free:
 	kvfree(buf);
 err_out:
Signature · 1 line
2.53.0
author maintainer
#238 lore raw

PATCH 238/457 vlan: require the MAC header to be present in __vlan_insert_inner_tag()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xiang Mei <[email protected]>

commit ab888242fce4f16f6c4d4c6ec53939ad36aa3b3a upstream.

__vlan_insert_inner_tag() only guarantees head room via skb_cow_head(), never that mac_len bytes of MAC header are present. Its ETH_HLEN wrappers - __vlan_insert_tag() under skb_vlan_push(), and vlan_insert_tag() under validate_xmit_vlan() on the generic transmit path - therefore rewrite the first 16 bytes at skb->data: a 12-byte memmove plus two 2-byte stores at +12 and +14. No caller supplies the bound, while the pop helpers use skb_ensure_writable()/pskb_may_pull().

An IFF_TUN device has hard_header_len == 0, so packet_snd() accepts a one-byte AF_PACKET/SOCK_RAW frame. The first vlan push only sets a hwaccel tag; the next - clsact "action vlan push" or bpf_skb_vlan_push() - enters the helper with skb->len still 1. The head comes from skbuff_small_head without __GFP_ZERO, so each push drags bytes from beyond skb->tail into the frame. After three the one-byte send leaves as 13 bytes carrying 11 bytes of uninitialised slab:

0000: 5a b3 62 12 80 88 ff ff 00 b3 62 12 81

           `------------------------------'

only 0x5a was sent; the rest is slab, here the top 56 bits of a linear-map address

Require the MAC header the helper rewrites to be present, so such a frame is dropped rather than transmitted.

---
 include/linux/if_vlan.h |    3 +++
 1 file changed, 3 insertions(+)
include/linux/if_vlan.h +3 -0
@@ -365,6 +365,9 @@ static inline int __vlan_insert_inner_ta
 	const u8 meta_len = mac_len > ETH_TLEN ? skb_metadata_len(skb) : 0;
 	struct vlan_ethhdr *veth;
 
+	if (unlikely(!pskb_may_pull(skb, mac_len)))
+		return -EINVAL;
+
 	if (skb_cow_head(skb, meta_len + VLAN_HLEN) < 0)
 		return -ENOMEM;
 
author maintainer
#239 lore raw

PATCH 239/457 x86/mce: Fix hardware debug register corruption on task migration

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Masami Hiramatsu (Google) <[email protected]>

commit b8d1d5b63a8ef532038eebd9d97d406860385668 upstream.

In exc_machine_check_user(), local_db_save() and local_db_restore() are invoked in the outer entry stubs (DEFINE_IDTENTRY_MCE_USER, DEFINE_FREDENTRY_MCE, and DEFINE_IDTENTRY_RAW), surrounding exc_machine_check_user().

However, exc_machine_check_user() calls irqentry_exit_to_user_mode(), which handles pending thread work and may schedule() if TIF_NEED_RESCHED is set. If the task migrates to another CPU during schedule(), local_db_restore() runs on the new CPU with the dr7 state saved from the old CPU. This corrupts the new CPU's DR7 hardware debug register and leaves the old CPU's DR7 disabled. In short, local_db_save() and local_db_restore() pair must be run on the same CPU.

To fix this, move local_db_save() and local_db_restore() inside exc_machine_check_user() and exc_machine_check_kernel(). In exc_machine_check_user(), DR7 is saved and restored strictly around do_machine_check() to avoid schedule() during migration. In exc_machine_check_kernel(), local_db_save() is called at the entry point to prevent early memory accesses from triggering nested #DB exceptions, and restored on all exits.

---
 arch/x86/kernel/cpu/mce/core.c |   27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)
arch/x86/kernel/cpu/mce/core.c +10 -17
@@ -2108,6 +2108,9 @@ bool filter_mce(struct mce *m)
 static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
 {
 	irqentry_state_t irq_state;
+	unsigned long dr7;
+
+	dr7 = local_db_save();
 
 	WARN_ON_ONCE(user_mode(regs));
 
@@ -2116,20 +2119,26 @@ static __always_inline void exc_machine_
 	 * mce_check_crashing_cpu() for details.
 	 */
 	if (mca_cfg.initialized && mce_check_crashing_cpu())
-		return;
+		goto out;
 
 	irq_state = irqentry_nmi_enter(regs);
 
 	do_machine_check(regs);
 
 	irqentry_nmi_exit(regs, irq_state);
+out:
+	local_db_restore(dr7);
 }
 
 static __always_inline void exc_machine_check_user(struct pt_regs *regs)
 {
+	unsigned long dr7;
+
 	irqentry_enter_from_user_mode(regs);
 
+	dr7 = local_db_save();
 	do_machine_check(regs);
+	local_db_restore(dr7);
 
 	irqentry_exit_to_user_mode(regs);
 }
@@ -2138,21 +2147,13 @@ static __always_inline void exc_machine_
 /* MCE hit kernel mode */
 DEFINE_IDTENTRY_MCE(exc_machine_check)
 {
-	unsigned long dr7;
-
-	dr7 = local_db_save();
 	exc_machine_check_kernel(regs);
-	local_db_restore(dr7);
 }
 
 /* The user mode variant. */
 DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
 {
-	unsigned long dr7;
-
-	dr7 = local_db_save();
 	exc_machine_check_user(regs);
-	local_db_restore(dr7);
 }
 
 #ifdef CONFIG_X86_FRED
@@ -2169,28 +2170,20 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_che
  */
 DEFINE_FREDENTRY_MCE(exc_machine_check)
 {
-	unsigned long dr7;
-
-	dr7 = local_db_save();
 	if (user_mode(regs))
 		exc_machine_check_user(regs);
 	else
 		exc_machine_check_kernel(regs);
-	local_db_restore(dr7);
 }
 #endif
 #else
 /* 32bit unified entry point */
 DEFINE_IDTENTRY_RAW(exc_machine_check)
 {
-	unsigned long dr7;
-
-	dr7 = local_db_save();
 	if (user_mode(regs))
 		exc_machine_check_user(regs);
 	else
 		exc_machine_check_kernel(regs);
-	local_db_restore(dr7);
 }
 #endif
 
author maintainer
#240 lore raw

PATCH 240/457 x86/PCI: Disable enhanced atomics on AMD NBIO 7.7 and 7.11

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mario Limonciello <[email protected]>

commit 4fde448225123442c5796f54b7a4400e2d3cbaf6 upstream.

Multiple users report data corruption during 64-bit DMA transfers on systems with AMD NBIO 7.7 and 7.11 controllers.

This occurs when BIOS enables AMD "enhanced atomic operations" on PCIe Root Ports. When enhanced atomics are enabled, any 64-bit DMA access may be corrupted.

Disable enhanced atomics using SMN for NBIO 7.7 and 7.11 based models.

---
 arch/x86/pci/fixup.c |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)
arch/x86/pci/fixup.c +99 -0
@@ -886,6 +886,105 @@ static void quirk_clear_strap_no_soft_re
 	}
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0);
+
+/*
+ * Enhanced atomic operations can cause corruption with 64-bit DMA
+ * on these devices.
+ */
+#define RX_ENH_ATOMIC_EN		BIT(8)
+
+static const u32 nbio_7_7_pcie_smn_addrs[] = {
+	0x111401d0,
+	0x111411d0,
+	0x111421d0,
+	0x111431d0,
+	0x111441d0,
+	0x112401d0,
+	0x112411d0,
+	0x112421d0,
+	0x112431d0,
+	0x112441d0,
+	0x112451d0,
+	0x113401d0,
+	0x114401d0,
+};
+
+static const u32 nbio_7_11_pcie_smn_addrs[] = {
+	0x112401d0,
+	0x112411d0,
+	0x112421d0,
+	0x112431d0,
+	0x112441d0,
+	0x112451d0,
+	0x113401d0,
+	0x113411d0,
+	0x113421d0,
+	0x113431d0,
+	0x113441d0,
+	0x113451d0,
+};
+
+static void quirk_amd_nbio_enhanced_atomic(struct pci_dev *host_bridge,
+					   const u32 *smn_addrs,
+					   size_t nr_smn_addrs)
+{
+	bool changed = false;
+	size_t i;
+	u32 data;
+	int ret;
+
+	for (i = 0; i < nr_smn_addrs; i++) {
+		ret = amd_smn_read(0, smn_addrs[i], &data);
+		if (ret)
+			continue;
+		if (!(data & RX_ENH_ATOMIC_EN))
+			continue;
+		data = data & ~RX_ENH_ATOMIC_EN;
+		ret = amd_smn_write(0, smn_addrs[i], data);
+		if (ret)
+			continue;
+		if (changed)
+			continue;
+		ret = amd_smn_read(0, smn_addrs[i], &data);
+		if (ret)
+			continue;
+		if (data & RX_ENH_ATOMIC_EN)
+			continue;
+		changed = true;
+	}
+
+	if (changed)
+		pci_info(host_bridge, "enhanced atomics disabled\n");
+}
+
+static void quirk_amd_nbio_7_7_disable_enhanced_atomic(struct pci_dev *dev)
+{
+	quirk_amd_nbio_enhanced_atomic(dev, nbio_7_7_pcie_smn_addrs,
+				       ARRAY_SIZE(nbio_7_7_pcie_smn_addrs));
+}
+
+static void quirk_amd_nbio_7_11_disable_enhanced_atomic(struct pci_dev *dev)
+{
+	quirk_amd_nbio_enhanced_atomic(dev, nbio_7_11_pcie_smn_addrs,
+				       ARRAY_SIZE(nbio_7_11_pcie_smn_addrs));
+}
+
+/* Phoenix, Hawk Point (NBIO 7.7) */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x14E8,
+			quirk_amd_nbio_7_7_disable_enhanced_atomic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x14E8,
+			quirk_amd_nbio_7_7_disable_enhanced_atomic);
+
+/* Strix, Krackan, Strix Halo (NBIO 7.11) */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1507,
+			quirk_amd_nbio_7_11_disable_enhanced_atomic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1507,
+			quirk_amd_nbio_7_11_disable_enhanced_atomic);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1122,
+			quirk_amd_nbio_7_11_disable_enhanced_atomic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1122,
+			quirk_amd_nbio_7_11_disable_enhanced_atomic);
+
 #endif
 
 /*
author maintainer
#241 lore raw

PATCH 241/457 x86/sev: Make vTPM SVSM calls preemption-safe

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Melody Wang <[email protected]>

commit 6c43c72748fffd29dec15cd1f31e9a32949bc437 upstream.

Two functions in the SVSM vTPM guest implementation do not disable preemption when fetching the SVSM Calling Area Address (CAA).

The SVSM CAA is a per-CPU structure. When a thread is preempted and migrated to a different CPU after fetching the per-CPU CAA, the SVSM call will execute on the new CPU with the original CPU's CAA. Which is wrong.

Move the CAA fetching operation inside svsm_perform_call_protocol() which disables interrupts around the SVSM call and thus runs preemption-safe.

---
 arch/x86/coco/sev/svsm.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
arch/x86/coco/sev/svsm.c +8 -2
@@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct sv
 
 	flags = native_local_irq_save();
 
+	/*
+	 * 'caa' is a per-CPU variable. To avoid using a stale or incorrect
+	 * 'caa' if the task is preempted or migrated to another CPU after it
+	 * is fetched, always fetch 'caa' and then issue the SVSM call with
+	 * interrupts disabled. This ensures the correct 'caa' is used.
+	 */
+	call->caa = svsm_get_caa();
+
 	ghcb = __sev_get_ghcb(&state);
 
 	do {
@@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffe
 {
 	struct svsm_call call = {};
 
-	call.caa = svsm_get_caa();
 	call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD);
 	call.rcx = __pa(buffer);
 
@@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)
 	if (!snp_vmpl)
 		return false;
 
-	call.caa = svsm_get_caa();
 	call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY);
 
 	if (svsm_perform_call_protocol(&call))
author maintainer
#242 lore raw

PATCH 242/457 vsock: ignore empty child namespace mode writes

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aldo Ariel Panzardo <[email protected]>

commit 2ec28c09b320ba241bea8a70ee5cb9ccf4a099e8 upstream.

__vsock_net_mode_string() returns success without updating new_mode when the transfer length is zero. Its caller then reads the uninitialized enum and may permanently store a stack-derived value in the write-once child mode.

Return before calling __vsock_net_mode_string() when *lenp is zero so that the helper is never invoked with nothing to parse and new_mode is never read uninitialized. This also prevents an empty write from locking the current mode.

---
 net/vmw_vsock/af_vsock.c |    3 +++
 1 file changed, 3 insertions(+)
net/vmw_vsock/af_vsock.c +3 -0
@@ -2873,6 +2873,9 @@ static int vsock_net_child_mode_string(c
 
 	net = container_of(table->data, struct net, vsock.child_ns_mode);
 
+	if (!*lenp)
+		return 0;
+
 	ret = __vsock_net_mode_string(table, write, buffer, lenp, ppos,
 				      vsock_net_child_mode(net), &new_mode);
 	if (ret)
author maintainer
#243 lore raw

PATCH 243/457 virtio_net: copy zerocopy frags in start_xmit without NAPI

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Willem de Bruijn <[email protected]>

commit 07e1a9408b6c2f9d0cfb757b67dabb52da7a32b2 upstream.

Virtio-net without NAPI frees completed skbs lazily on the next start_xmit. Senders waiting for in-flight zerocopy buffers can deadlock if they cannot transmit more packets, as then no completed packets will be freed.

When !use_napi, virtio-net already calls skb_orphan to avoid waiting up for transmitted skbs to be freed. For zerocopy packets that require deep copying on orphan (i.e. those that do not set SKBFL_DONT_ORPHAN, such as PACKET_TX_RING), call skb_orphan_frags before orphaning to release the buffers.

This fixes the tpacket_snd slot reuse bug on skb_orphan for virtio-net, and prevents PACKET_TX_RING from running out of slots.

This fix also touches vhost_net zerocopy packets, which also do not set SKBFL_DONT_ORPHAN. This is fine: vhost_net packets only encounter virtio-net in nested virtualization, and only if napi_tx is explicitly disabled (it has been default-enabled since Linux 4.12). In that rare case, copying the frags is desirable anyway to prevent holding guest descriptors pinned across unbounded intervals.

This is a prerequisite for the next patch, which converts PACKET_TX_RING to standard zerocopy completion. Without this patch first, a bounded ring sender can stall indefinitely behind a virtio-net virtqueue that cannot reclaim.

---
 drivers/net/virtio_net.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/net/virtio_net.c +9 -0
@@ -3349,6 +3349,14 @@ static netdev_tx_t start_xmit(struct sk_
 	else
 		virtqueue_disable_cb(sq->vq);
 
+	if (!use_napi &&
+	    unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) {
+		DEV_STATS_INC(dev, tx_dropped);
+		dev_kfree_skb_any(skb);
+		kick = !xmit_more || netif_xmit_stopped(txq);
+		goto kick_vq;
+	}
+
 	/* timestamp packet in software */
 	skb_tx_timestamp(skb);
 
@@ -3381,6 +3389,7 @@ static netdev_tx_t start_xmit(struct sk_
 
 	kick = use_napi ? __netdev_tx_sent_queue(txq, skb->len, xmit_more) :
 			  !xmit_more || netif_xmit_stopped(txq);
+kick_vq:
 	if (kick) {
 		if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
 			u64_stats_update_begin(&sq->stats.syncp);
author maintainer
#244 lore raw

PATCH 244/457 tipc: reject invalid and unexpected GRP_ACK_MSG to prevent bc_ackers underflow

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

commit 99cc2a62e07a44a22254d7beca9ef1f8ad886d0d upstream.

Commit 48a5fe38772b ("tipc: fix bc_ackers underflow on duplicate GRP_ACK_MSG") rejected duplicate/stale ACKs in tipc_group_proto_rcv() by returning early when less_eq(acked, m->bc_acked).

However, that check remains incomplete in two ways:

1. When grp->bc_ackers is zero (e.g. on a quiet group, when replicast ACKs were not requested, or after all expected members have already acknowledged), an unexpected GRP_ACK_MSG with acked > m->bc_acked passes less_eq() and unconditionally decrements grp->bc_ackers. Because bc_ackers is a u16, this wraps to 65535, causing tipc_group_bc_cong() to permanently report congestion and blocking all future group broadcasts on the socket.

2. During an active broadcast round (grp->bc_ackers > 0), the sender transmits packet S and advances grp->bc_snd_nxt to S + 1. Receivers increment their expected counter to S + 1 upon consuming packet S, so the only valid ACK value for the current round is strictly acked == grp->bc_snd_nxt.

However, tipc_group_update_bc_members() initializes each member's m->bc_acked to prev = grp->bc_snd_nxt - 1 (S - 1 before increment). This leaves a 2-sequence gap (S - 1 to S + 1) in sequence space. An incoming ACK is therefore neither rejected as duplicate nor prevented from decrementing grp->bc_ackers if an unexpected or stale value (such as S) is received. A member sending acked = S followed by acked = S + 1 could decrement grp->bc_ackers twice in the same round, prematurely clearing bc_ackers or underflowing it.

Fix this by:
- Dropping GRP_ACK_MSG immediately if grp->bc_ackers is zero.
- Requiring acked == grp->bc_snd_nxt and rejecting duplicates where m->bc_acked == acked. Because replicast broadcast rounds are strictly sequential, only grp->bc_snd_nxt can be acknowledged, and each member can acknowledge at most once per round.

Note that a related pre-existing issue in tipc_group_delete_member() (where grp->bc_ackers decrementing to zero upon member departure does not restore *grp->open or trigger a socket wakeup) will be addressed in a separate patch.

Fixes 48a5fe38772b ("tipc: fix bc_ackers underflow on duplicate GRP_ACK_MSG")
Fixes 2f487712b893 ("tipc: guarantee that group broadcast doesn't bypass group unicast")
---
 net/tipc/group.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/tipc/group.c +2 -2
@@ -797,10 +797,10 @@ void tipc_group_proto_rcv(struct tipc_gr
 		tipc_group_open(m, usr_wakeup);
 		return;
 	case GRP_ACK_MSG:
-		if (!m)
+		if (!m || !grp->bc_ackers)
 			return;
 		acked = msg_grp_bc_acked(hdr);
-		if (less_eq(acked, m->bc_acked))
+		if (acked != grp->bc_snd_nxt || m->bc_acked == acked)
 			return;
 		m->bc_acked = acked;
 		if (--grp->bc_ackers)
author maintainer
#245 lore raw

PATCH 245/457 tcp: prevent collapsing skbs across boundary in rtx queue

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Willem de Bruijn <[email protected]>

commit fc6d80eb504458d6416b75a94188b268c95c6533 upstream.

tcp_write_collapse_fence() sets TCP_SKB_CB(skb)->eor = 1 on tcp_write_queue_tail(sk) to prevent skbs queued after a switch to device encryption from being collapsed into earlier skbs.

The fence is a no-op if all earlier data has already been transmitted when the switch happens: sk->sk_write_queue is empty. The not yet acknowledged earlier skbs wait in sk->tcp_rtx_queue with eor 0.

On a subsequent retransmit or SACK shift, tcp_retrans_try_collapse() or tcp_shift_skb_data() can then merge an skb queued after the switch into one queued before it.

Both users of the fence are affected:

- psp: devices only encrypt skbs with skb->decrypted set. The merged skb keeps decrypted = 0 from the earlier skb, so merged data sent after psp_sock_assoc_set_tx() is retransmitted in cleartext.

- tls device offload: the merged skb straddles the start marker set in tls_set_device_offload(). The software fallback (fill_sg_in() returns -EINVAL) and the mlx5, nfp and funeth drivers cannot handle such an skb and drop it. Every retransmit rebuilds the same skb, so the connection stalls.

Fix this in two places, for defense in depth:

1. Fall back to tcp_rtx_queue_tail(sk) in tcp_write_collapse_fence() when tcp_write_queue_tail(sk) is NULL.

2. Check !skb_cmp_decrypted(to, from) in tcp_skb_can_collapse(), as tcp_skb_can_collapse_rx() does on receive. skb_shift(), which both collapse paths call, already has a DEBUG_NET_WARN_ON_ONCE() for this condition.

---
 include/net/tcp.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/net/tcp.h +2 -2
@@ -1232,9 +1232,9 @@ static inline bool tcp_skb_can_collapse_
 static inline bool tcp_skb_can_collapse(const struct sk_buff *to,
 					const struct sk_buff *from)
 {
-	/* skb_cmp_decrypted() not needed, use tcp_write_collapse_fence() */
 	return likely(tcp_skb_can_collapse_to(to) &&
 		      mptcp_skb_can_collapse(to, from) &&
+		      !skb_cmp_decrypted(to, from) &&
 		      skb_pure_zcopy_same(to, from) &&
 		      skb_frags_readable(to) == skb_frags_readable(from));
 }
@@ -2327,7 +2327,7 @@ static inline void tcp_rtx_queue_unlink_
 
 static inline void tcp_write_collapse_fence(struct sock *sk)
 {
-	struct sk_buff *skb = tcp_write_queue_tail(sk);
+	struct sk_buff *skb = tcp_write_queue_tail(sk) ?: tcp_rtx_queue_tail(sk);
 
 	if (skb)
 		TCP_SKB_CB(skb)->eor = 1;
author maintainer
#246 lore raw

PATCH 246/457 sctp: discard the rest of the packet on a stale-cookie error

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aohan Mei <[email protected]>

commit 4498467a8af06cfa3d71cb04bd7c4170dec8f449 upstream.

When an association is in COOKIE-ECHOED state and the peer sends a bundled [ERROR(Stale Cookie)][DATA] packet from one of its non-primary addresses, processing the ERROR chunk takes the non-fatal stale-cookie retry path sctp_sf_do_5_2_6_stale(), which queues SCTP_CMD_DEL_NON_PRIMARY while keeping the association alive. sctp_cmd_del_non_primary() removes every non-primary transport - including the very transport this packet arrived on, which is still referenced by the receive lookup and shared by all chunks of the packet via chunk->transport.

sctp_assoc_rm_peer() does redirect asoc->peer.last_data_from away from the removed transport, but right afterwards the bundled DATA chunk makes sctp_assoc_bh_rcv() re-register asoc->peer.last_data_from = chunk->transport unconditionally, undoing the redirection with the just-removed transport.

Once the packet is done, the receive reference is dropped and the transport is RCU-freed, while the surviving association keeps the dangling last_data_from. A later FWD-TSN (or the delayed SACK timer) makes sctp_gen_sack() dereference it (->param_flags and friends), and sctp_make_sack()/sctp_outq_select_transport() may write to the freed object and link it into the live transport list. This is a use-after-free triggerable by any malicious SCTP peer (or a local unprivileged user acting as one) with no capabilities required:

  BUG: KASAN: slab-use-after-free in sctp_do_sm+0x498a/0x5660
  Read of size 4 at addr ffff88800e1e356c by task poc/115
  Call Trace: sctp_do_sm <- sctp_assoc_bh_rcv <- sctp_inq_push <-
              sctp_rcv <- ip_protocol_deliver_rcu <- ip_rcv
  Allocated: sctp_transport_new <- sctp_assoc_add_peer <-
             sctp_process_init (INIT-ACK processing)
  Freed: kfree <- sctp_transport_destroy_rcu <- rcu_core
         (call_rcu queued by sctp_transport_put at end of sctp_rcv)
  The buggy address is located 364 bytes inside of freed 1024-byte
  region [ffff88800e1e3400, ffff88800e1e3800), cache kmalloc-1k

Note that commit 03a9d10ecf71 ("sctp: drop a chunk if its transport was removed") only covers the window between the receive lookup and the chunk processing (e.g. an ASCONF DEL-IP racing the socket backlog); here the transport is removed *while* the packet is being processed, by an earlier chunk of the same packet, so the drop in sctp_inq_push() does not reach this path. Verified with the bundled [ERROR(Stale Cookie)][DATA] + FWD-TSN reproducer: the KASAN report above still fires with that commit applied, and is gone with this patch on top.

Fix it by discarding the rest of the packet on this path, as suggested by Xin. After the stale-cookie ERROR has sent the association back to COOKIE-WAIT and removed the non-primary transports, the remaining chunks of the packet can only run against the restarted handshake while referencing the removed arrival transport through chunk->transport: besides the last_data_from registration above, sctp_cmd_setup_t2() and the sctp_make_*() reply builders would also copy that pointer into association-lifetime state that sctp_assoc_rm_peer() has already sanitized. Let the peer retransmit them, in line with what sctp_inq_push() does for chunks whose transport was removed before processing.

---
 net/sctp/sm_statefuns.c |    2 ++
 1 file changed, 2 insertions(+)
net/sctp/sm_statefuns.c +2 -0
@@ -2654,6 +2654,8 @@ static enum sctp_disposition sctp_sf_do_
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
 
+	sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+
 	return SCTP_DISPOSITION_CONSUME;
 
 nomem:
author maintainer
#247 lore raw

PATCH 247/457 af_packet: fix integer overflow in prb_calc_retire_blk_tmo()

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dairui Zhang <[email protected]>

commit 56d82862a0a243ac14ba11b6d7b57ddc2d064b95 upstream.

prb_calc_retire_blk_tmo() computes in 32-bit int arithmetic:

        mbits = (blk_size_in_bytes * 8) / (1024 * 1024);

If I'm reading the validation right, tp_block_size is user controlled and packet_set_ring() only rejects values that are <= 0 as int or not page aligned, so a 256MiB block goes right through (and alloc_one_pg_vec_page() even has a vzalloc fallback for it). 0x10000000 * 8 wraps to INT_MIN, and on a NIC reporting 1 Gbps (div == 1) the function ends up returning -2047.

The condition is actually (8 * size) mod 2^32 >= 2^31 && div == 1, so the trigger set is [256,512), [768,1024), [1280,1536) and [1792,2048) MiB. Other sizes wrap to non-negative values and faster links divide the unsigned value back below 2^31, which is why this doesn't blow up for everyone.

What makes it fatal is what happens next in init_prb_bdqc():

        p1->interval_ktime = ms_to_ktime(prb_calc_retire_blk_tmo(...));
        hrtimer_start(&p1->retire_blk_timer, p1->interval_ktime,
                      HRTIMER_MODE_REL_SOFT);

A negative relative timeout expires immediately. The callback unconditionally returns HRTIMER_RESTART, and hrtimer_forward() turns the negative interval into hrtimer_resolution:

if (interval < hrtimer_resolution)
interval = hrtimer_resolution;

So the SOFT timer re-fires at the maximum rate forever, holding sk_receive_queue.lock each pass. One CPU spins in softirq until the socket is closed. Repeat with more rings and the machine is gone.

The overflow itself is ancient - it was introduced together with TPACKET_V3 in f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation."). Its effect prior to f7460d2989fa ("net:
af_packet: Use hrtimer to do the retire operation", v6.18) was not as clear-cut, though: the return value was stored into an unsigned short retire_blk_tov, so a negative result was truncated, and a 0-jiffy delay loop could be programmed as well. Neither is nearly as detrimental as the immediate maximum-rate spin the hrtimer conversion turned it into.

(Unrelated to CVE-2019-20812 - that one was the ethtool failure path returning 0, which now returns DEFAULT_PRB_RETIRE_TOV.)

Reproducer, needs CAP_NET_RAW (a --network host container has it by default) and a 1 Gbps NIC (QEMU e1000 works):

        int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        bind(fd, ...);
        int v = TPACKET_V3;
        setsockopt(fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
        struct tpacket_req3 req = {
                .tp_block_size = 0x10000000,
                .tp_block_nr = 1,
                .tp_frame_size = 2048,
                .tp_frame_nr = 0x10000000 / 2048,
                .tp_retire_blk_tov = 0,
        };
        setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));

Compute in 64 bits instead. The operands are already bounded by the existing validation, so nothing else changes. If you'd prefer a different fix, just say so and I'll respin.

---
 net/packet/af_packet.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/packet/af_packet.c +1 -1
@@ -617,7 +617,7 @@ static int prb_calc_retire_blk_tmo(struc
 		return DEFAULT_PRB_RETIRE_TOV;
 
 	div = ecmd.base.speed / 1000;
-	mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
+	mbits = (u64)blk_size_in_bytes * 8 / (1024 * 1024);
 
 	if (div)
 		mbits /= div;
author maintainer
#248 lore raw

PATCH 248/457 arm64/boot: Disable trapping of PMZR_EL0 writes to EL2

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

commit 2bc6b218717b9d08f466f88209251d54bc09b207 upstream.

__init_el2_fgt2() writes one mask to both HDFGRTR2_EL2 and HDFGWTR2_EL2. PMZR_EL0 is write-only, so its trap bit, nPMZR_EL0, exists only in HDFGWTR2_EL2 and is therefore never set: a PMZR_EL0 write from the host traps to EL2, where the nVHE hypervisor has no handler and BUG()s. The kernel never writes PMZR_EL0, but kernel.perf_user_access=1 has the PMU driver set PMUSERENR_EL0.UEN for a task with a user-read event, so a write from EL0 reaches the trap and takes the host down without a panic message.

Accumulate the HDFGWTR2_EL2 bits separately, as __init_el2_fgt() already does for HDFGWTR_EL2, and set nPMZR_EL0 with the other FEAT_PMUv3p9 bits.

Fixes 858c7bfcb35e1 ("arm64/boot: Enable EL2 requirements for FEAT_PMUv3p9")
---
 Documentation/arch/arm64/booting.rst |    1 +
 arch/arm64/include/asm/el2_setup.h   |    9 ++++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)
Documentation/arch/arm64/booting.rst +1 -0
@@ -465,6 +465,7 @@ Before jumping into the kernel, the foll
     - HDFGWTR2_EL2.nPMICNTR_EL0 (bit 2) must be initialised to 0b1.
     - HDFGWTR2_EL2.nPMICFILTR_EL0 (bit 3) must be initialised to 0b1.
     - HDFGWTR2_EL2.nPMUACR_EL1 (bit 4) must be initialised to 0b1.
+    - HDFGWTR2_EL2.nPMZR_EL0 (bit 21) must be initialised to 0b1.
 
   For CPUs with SPE data source filtering (FEAT_SPE_FDS):
 
arch/arm64/include/asm/el2_setup.h +8 -1
@@ -418,6 +418,7 @@
 	b.lt	.Lskip_fgt2_\@
 
 	mov	x0, xzr
+	mov	x2, xzr
 	mrs	x1, id_aa64dfr0_el1
 	ubfx	x1, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
 	cmp	x1, #ID_AA64DFR0_EL1_PMUVer_V3P9
@@ -426,6 +427,11 @@
 	orr	x0, x0, #HDFGRTR2_EL2_nPMICNTR_EL0
 	orr	x0, x0, #HDFGRTR2_EL2_nPMICFILTR_EL0
 	orr	x0, x0, #HDFGRTR2_EL2_nPMUACR_EL1
+	orr	x2, x2, #HDFGWTR2_EL2_nPMICNTR_EL0
+	orr	x2, x2, #HDFGWTR2_EL2_nPMICFILTR_EL0
+	orr	x2, x2, #HDFGWTR2_EL2_nPMUACR_EL1
+	/* PMZR_EL0 is write-only, so it has no read trap to disable */
+	orr	x2, x2, #HDFGWTR2_EL2_nPMZR_EL0
 .Lskip_pmuv3p9_\@:
 	/* If SPE is implemented, */
 	__spe_vers_imp .Lskip_spefds_\@, ID_AA64DFR0_EL1_PMSVer_IMP, x1
@@ -436,10 +442,11 @@
 	cbz	x1, .Lskip_spefds_\@
 	/* disable traps of PMSDSFR to EL2. */
 	orr	x0, x0, #HDFGRTR2_EL2_nPMSDSFR_EL1
+	orr	x2, x2, #HDFGWTR2_EL2_nPMSDSFR_EL1
 
 .Lskip_spefds_\@:
 	msr_s   SYS_HDFGRTR2_EL2, x0
-	msr_s   SYS_HDFGWTR2_EL2, x0
+	msr_s   SYS_HDFGWTR2_EL2, x2
 	msr_s   SYS_HFGRTR2_EL2, xzr
 	msr_s   SYS_HFGWTR2_EL2, xzr
 	msr_s   SYS_HFGITR2_EL2, xzr
author maintainer
#249 lore raw

PATCH 249/457 arm64: errata: match the target implementation CPUs own MIDR

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: David Carlier <[email protected]>

commit b7403afb7a5f85073243df10238b3483958ad69e upstream.

__is_affected_midr_range() is handed the MIDR and REVIDR of one target implementation CPU, but tests the erratum's range with is_midr_in_range(), which re-scans all of target_impl_cpus[] and ignores the @midr argument. The range test is thus constant across the per-CPU loop in is_affected_midr_range() and only answers "is any target CPU in range".

Since just the fixed_revs REVIDR check uses the iteration's own registers, an out-of-range target CPU can decide whether a MIDR_FIXED() exemption applies. A VM then enables a workaround whose only in-range CPU is fixed silicon, e.g. erratum 2658417 on a Cortex-A510 r1p1 with REVIDR_EL1[25] set.

Factor the range test into __is_midr_in_range(), which takes an explicit MIDR, and use it in __is_affected_midr_range().

Fixes 86edf6bdcf05 ("smccc/kvm_guest: Enable errata based on implementation CPUs")
Assisted-by Claude:claude-opus-5
---
 arch/arm64/kernel/cpu_errata.c |   15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
arch/arm64/kernel/cpu_errata.c +9 -6
@@ -28,18 +28,21 @@ bool cpu_errata_set_target_impl(u64 num,
 	return true;
 }
 
+static inline bool __is_midr_in_range(u32 midr, struct midr_range const *range)
+{
+	return midr_is_cpu_model_range(midr, range->model,
+				       range->rv_min, range->rv_max);
+}
+
 static inline bool is_midr_in_range(struct midr_range const *range)
 {
 	int i;
 
 	if (!target_impl_cpu_num)
-		return midr_is_cpu_model_range(read_cpuid_id(), range->model,
-					       range->rv_min, range->rv_max);
+		return __is_midr_in_range(read_cpuid_id(), range);
 
 	for (i = 0; i < target_impl_cpu_num; i++) {
-		if (midr_is_cpu_model_range(target_impl_cpus[i].midr,
-					    range->model,
-					    range->rv_min, range->rv_max))
+		if (__is_midr_in_range(target_impl_cpus[i].midr, range))
 			return true;
 	}
 	return false;
@@ -59,7 +62,7 @@ __is_affected_midr_range(const struct ar
 			 u32 midr, u32 revidr)
 {
 	const struct arm64_midr_revidr *fix;
-	if (!is_midr_in_range(&entry->midr_range))
+	if (!__is_midr_in_range(midr, &entry->midr_range))
 		return false;
 
 	midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
author maintainer
#250 lore raw

PATCH 250/457 ata: libata-scsi: bound the ATA passthru sense descriptor writes

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Matthias Goergens <[email protected]>

commit 80320b278fea07ffcda3f57b67b61658e0a4e1ca upstream.

When an ATA PASS-THROUGH command to an ATAPI device fails, the sense buffer holds the device's REQUEST SENSE reply, and ata_scsi_set_passthru_sense_fields() trusts its additional length byte, sb[7], when adding the ATA Status Return descriptor. A faulty or malicious device can use that to make the kernel read and write past the 96-byte buffer in three ways:

- scsi_sense_desc_find() is passed sb[7] + 8 as the buffer length, so its clamp against sb[7] does nothing and the walk runs off the end.
- A type-9 descriptor found near the end is filled in unchecked.
- A new descriptor at sb[8 + len] needs len + 22 bytes, not len + 14, so len 75..82 writes up to 8 bytes past the end.

Reproduced with KASAN under qemu, with the emulated ATAPI REQUEST SENSE reply patched:

  BUG: KASAN: slab-out-of-bounds in scsi_sense_desc_find+0x1a5/0x210
  BUG: KASAN: slab-out-of-bounds in ata_scsi_qc_complete+0x1a15/0x1a50

Both are gone with this patch, and a valid descriptor is still filled in.

Fixes 97981926224a ("ata: libata-scsi: Do not overwrite valid sense data when CK_COND=1")
---
 drivers/ata/libata-scsi.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/ata/libata-scsi.c +8 -2
@@ -261,12 +261,18 @@ static void ata_scsi_set_passthru_sense_
 
 		/* descriptor format */
 		len = sb[7];
-		desc = (char *)scsi_sense_desc_find(sb, len + 8, 9);
+		desc = (char *)scsi_sense_desc_find(sb, SCSI_SENSE_BUFFERSIZE, 9);
 		if (!desc) {
-			if (SCSI_SENSE_BUFFERSIZE < len + 14)
+			/*
+			 * The descriptor is written at sb[8 + len] and is 14
+			 * bytes long, so it needs len + 22 bytes of buffer.
+			 */
+			if (len + 22 > SCSI_SENSE_BUFFERSIZE)
 				return;
 			sb[7] = len + 14;
 			desc = sb + 8 + len;
+		} else if (desc - sb > SCSI_SENSE_BUFFERSIZE - 14) {
+			return;
 		}
 		desc[0] = 9;
 		desc[1] = 12;
author maintainer
#251 lore raw

PATCH 251/457 bna: prevent IOC timer rearm during teardown

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Myeonghun Pak <[email protected]>

commit 77b1718e39e5c9f6956fb60807326af20baf889d upstream.

bna: prevent IOC timer rearm during teardown

bnad_pci_remove() and the probe disable_ioceth path call timer_delete_sync() for ioc_timer, sem_timer and hb_timer, but not for iocpf_timer. bnad_iocpf_timeout() then takes bnad->bna_lock after free_netdev() has freed the struct bnad.

Deleting iocpf_timer last does not fix this. sem_timer and iocpf_timer rearm each other: bnad_iocpf_sem_timeout() can arm iocpf_timer, and bnad_iocpf_timeout() arms sem_timer from bfa_ioc_hw_sem_get() when the semaphore is busy. timer_delete_sync() only waits out its own callback. bnad_ioceth_disable() can time out and leave that callback live.

Shut all four IOC timers down with timer_shutdown_sync() on both paths, so a later mod_timer() is ignored.

This issue was identified during our ongoing static-analysis research while reviewing kernel code.

---
 drivers/net/ethernet/brocade/bna/bnad.c |   24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/net/ethernet/brocade/bna/bnad.c +18 -6
@@ -2571,6 +2571,22 @@ bnad_ioceth_disable(struct bnad *bnad)
 	return err;
 }
 
+/*
+ * The IOC timers rearm one another, so deleting one cannot stop a
+ * sibling callback from arming it again.  Shut them down so a later
+ * mod_timer() is ignored.
+ */
+static void
+bnad_ioc_timers_shutdown(struct bnad *bnad)
+{
+	struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
+
+	timer_shutdown_sync(&ioc->ioc_timer);
+	timer_shutdown_sync(&ioc->sem_timer);
+	timer_shutdown_sync(&ioc->hb_timer);
+	timer_shutdown_sync(&ioc->iocpf_timer);
+}
+
 static int
 bnad_ioceth_enable(struct bnad *bnad)
 {
@@ -3727,9 +3743,7 @@ probe_uninit:
 	bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX);
 disable_ioceth:
 	bnad_ioceth_disable(bnad);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.ioc_timer);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.sem_timer);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.hb_timer);
+	bnad_ioc_timers_shutdown(bnad);
 	spin_lock_irqsave(&bnad->bna_lock, flags);
 	bna_uninit(bna);
 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -3770,9 +3784,7 @@ bnad_pci_remove(struct pci_dev *pdev)
 
 	mutex_lock(&bnad->conf_mutex);
 	bnad_ioceth_disable(bnad);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.ioc_timer);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.sem_timer);
-	timer_delete_sync(&bnad->bna.ioceth.ioc.hb_timer);
+	bnad_ioc_timers_shutdown(bnad);
 	spin_lock_irqsave(&bnad->bna_lock, flags);
 	bna_uninit(bna);
 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
author maintainer
#252 lore raw

PATCH 252/457 bpf: fs/xattr: dont assume the inode is locked in path_unlink/path_rmdir

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Andrea Parri <[email protected]>

commit 35d442ed1f86465e49df3119fb898f985186db13 upstream.

bpf_lsm_has_d_inode_locked() makes the verifier rewrite bpf_[set|remove]_dentry_xattr() to the _locked variants, which assume that the caller already holds the inode's i_rwsem. The path_unlink and path_rmdir hooks are listed, but security_path_unlink() and security_path_rmdir() run before vfs_unlink()/vfs_rmdir() take the victim inode's i_rwsem, so a sleepable BPF LSM program attached to either hook mutates the victim's xattrs without the lock held.

Drop the two path hooks from d_inode_locked_hooks so that the verifier keeps the locking bpf_[set|remove]_dentry_xattr() variants, which take the lock themselves.

Fixes 56467292794b8 ("bpf: fs/xattr: Add BPF kfuncs to set and remove xattrs")
---
 fs/bpf_fs_kfuncs.c |    4 ----
 1 file changed, 4 deletions(-)
fs/bpf_fs_kfuncs.c +0 -4
@@ -419,10 +419,6 @@ BTF_ID(func, bpf_lsm_inode_rmdir)
 BTF_ID(func, bpf_lsm_inode_setattr)
 BTF_ID(func, bpf_lsm_inode_setxattr)
 BTF_ID(func, bpf_lsm_inode_unlink)
-#ifdef CONFIG_SECURITY_PATH
-BTF_ID(func, bpf_lsm_path_unlink)
-BTF_ID(func, bpf_lsm_path_rmdir)
-#endif /* CONFIG_SECURITY_PATH */
 BTF_SET_END(d_inode_locked_hooks)
 
 bool bpf_lsm_has_d_inode_locked(const struct bpf_prog *prog)
author maintainer
#253 lore raw

PATCH 253/457 crypto: s390/hmac - Generate intermediate CV for API partial block handling

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Holger Dengler <[email protected]>

commit 10396a2d6d41d594975b6ece712278570c3c970c upstream.

The API partial block handling requires a intermediate chaining value (CV). The internal function hash_data() sets the function code correctly, so also call cpacf_kimd() instruction for intermediate CV generation, as cpacf_klmd() always generate the final hash value.

Fixes 08811169ac01 ("crypto: s390/hmac - Use API partial block handling")
---
 arch/s390/crypto/hmac_s390.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/s390/crypto/hmac_s390.c +4 -1
@@ -150,7 +150,10 @@ static int hash_data(const u8 *in, unsig
 
 #undef PARAM_INIT
 
-	cpacf_klmd(func, &param, in, inlen);
+	if (final)
+		cpacf_klmd(func, &param, in, inlen);
+	else
+		cpacf_kimd(func, &param, in, inlen);
 
 	memcpy(digest, &param, digestsize);
 
author maintainer
#254 lore raw

PATCH 254/457 cgroup/cpuset: Return PERR_NOCPUS in remote_partition_enable() on subpartitions_cpus conflict

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

commit 31c88350b7dd1522792f726f79607f31bb55c50f upstream.

When a remote partition is created underneath an existing local partition via a non-partition (PRS_MEMBER) intermediate cgroup, update_prstate() sees parent->partition_root_state == PRS_MEMBER and calls remote_partition_enable().

Commit 86888c7bd117 ("cgroup/cpuset: Add warnings to catch inconsistency in exclusive CPUs") replaced the cpumask_intersects(tmp->new_cpus, subpartitions_cpus) error check in remote_partition_enable() with WARN_ON_ONCE(). As a result, remote_partition_enable() emits a warning and proceeds to enable the remote partition on CPUs that are already owned by the ancestor local partition in subpartitions_cpus.

This can be reproduced on Linux 7.3.0-rc3 with:

mkdir -p /tmp/cg1
mount -t cgroup2 none /tmp/cg1
echo "+cpuset" > /tmp/cg1/cgroup.subtree_control

mkdir /tmp/cg1/A
echo 1 > /tmp/cg1/A/cpuset.cpus
echo 1 > /tmp/cg1/A/cpuset.cpus.exclusive echo root > /tmp/cg1/A/cpuset.cpus.partition echo "+cpuset" > /tmp/cg1/A/cgroup.subtree_control

mkdir /tmp/cg1/A/B
echo 1 > /tmp/cg1/A/B/cpuset.cpus
echo 1 > /tmp/cg1/A/B/cpuset.cpus.exclusive echo "+cpuset" > /tmp/cg1/A/B/cgroup.subtree_control

mkdir /tmp/cg1/A/B/D
echo 1 > /tmp/cg1/A/B/D/cpuset.cpus
echo 1 > /tmp/cg1/A/B/D/cpuset.cpus.exclusive echo root > /tmp/cg1/A/B/D/cpuset.cpus.partition

which triggers:

  WARNING: kernel/cgroup/cpuset.c:1594 at remote_partition_enable+0x1c1/0x300

and leaves both /tmp/cg1/A and /tmp/cg1/A/B/D as active root partitions claiming exclusive CPU 1.

Fix this by returning PERR_NOCPUS when tmp->new_cpus intersects subpartitions_cpus in remote_partition_enable(), matching the error code used by remote_cpus_update() for the same subpartitions_cpus conflict, and add a regression test case to tools/testing/selftests/cgroup/test_cpuset_prs.sh.

Tested in QEMU on Linux 7.3.0-rc3 using the reproducer above and tools/testing/selftests/cgroup/test_cpuset_prs.sh.

Fixes 86888c7bd117 ("cgroup/cpuset: Add warnings to catch inconsistency in exclusive CPUs")
Assisted-by LLM
---
 kernel/cgroup/cpuset.c                            |    3 ++-
 tools/testing/selftests/cgroup/test_cpuset_prs.sh |    2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)
kernel/cgroup/cpuset.c +2 -1
@@ -1552,10 +1552,11 @@ static int remote_partition_enable(struc
 	 * above it or remote partition root underneath it is not allowed.
 	 */
 	compute_excpus(cs, tmp->new_cpus);
-	WARN_ON_ONCE(cpumask_intersects(tmp->new_cpus, subpartitions_cpus));
 	if (!cpumask_intersects(tmp->new_cpus, cpu_active_mask) ||
 	    cpumask_subset(top_cpuset.effective_cpus, tmp->new_cpus))
 		return PERR_INVCPUS;
+	if (cpumask_intersects(tmp->new_cpus, subpartitions_cpus))
+		return PERR_NOCPUS;
 	if (((new_prs == PRS_ISOLATED) &&
 	     !isolated_cpus_can_update(tmp->new_cpus, NULL)) ||
 	    prstate_housekeeping_conflict(new_prs, tmp->new_cpus))
tools/testing/selftests/cgroup/test_cpuset_prs.sh +2 -0
@@ -298,6 +298,8 @@ TEST_MATRIX=(
 	" C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
 				   .      .      .      X1      .    0 A1:0-1|A2:2-4|A3:2-4 \
 								       A1:P0|A2:P2|A3:P-1 2-4"
+	" CX1-3:P1 CX1-3  CX1-3    .      .      .      P1      .    0 A1:1-3|A2:1-3|A3:1-3 \
+								       A1:P1|A2:P0|A3:P-1"
 
 	# Remote partition offline tests
 	"   C0-3    C1-3  C2-3     .    X2-3   X2-3 X2-3:P2:O2=0 .   0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
author maintainer
#255 lore raw

PATCH 255/457 cgroup/pids: Restore pids.events notifications in local mode

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guopeng Zhang <[email protected]>

commit 1765a153d985c231357145e26798f9408db10e42 upstream.

A fork rejected by the pids controller increments the counter reported by pids.events. When local event accounting is selected, however, pids_event() returns after notifying only events_local_file, leaving pids.events pollers asleep.

On legacy hierarchies, pids.events.local does not exist. With pids_localevents, pids.events reports the same local counter. In both cases, pids.events changes without generating a notification.

This can be reproduced with a pids_localevents mount:

mkdir /tmp/test
mount -t cgroup2 -o pids_localevents none /tmp/test mkdir /tmp/test/t
echo 1 > /tmp/test/t/pids.max
cat /tmp/test/t/pids.events # max 0
timeout 3 inotifywait -e modify /tmp/test/t/pids.events & sh -c 'echo $$ > /tmp/test/t/cgroup.procs; (true &)' 2>/dev/null wait
cat /tmp/test/t/pids.events # max 1

Without this patch, inotifywait times out without reporting an event. Notify pids.events before returning from the local event path.

Fixes 3f26a885a068 ("cgroup/pids: Add pids.events.local")
Cc [email protected] # v6.11+
---
 kernel/cgroup/pids.c |    5 +++++
 1 file changed, 5 insertions(+)
kernel/cgroup/pids.c +5 -0
@@ -253,6 +253,11 @@ static void pids_event(struct pids_cgrou
 	}
 	if (!cgroup_subsys_on_dfl(pids_cgrp_subsys) ||
 	    cgrp_dfl_root.flags & CGRP_ROOT_PIDS_LOCAL_EVENTS) {
+		/*
+		 * pids.events reports the local counter on legacy hierarchies
+		 * and when pids_localevents is enabled.
+		 */
+		cgroup_file_notify(&p->events_file);
 		cgroup_file_notify(&p->events_local_file);
 		return;
 	}
author maintainer
#256 lore raw

PATCH 256/457 fou: reject omitted FOU_ATTR_IPPROTO on FOU_ENCAP_DIRECT

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hui Peng <[email protected]>

commit d22609f3d13fc5baacd92c222731b03c593401db upstream.

Commit 7a9bc9e3f423 ("fou: Don't allow 0 for FOU_ATTR_IPPROTO.") added NLA_POLICY_MIN(NLA_U8, 1) to fou_nl_policy[FOU_ATTR_IPPROTO], which rejects an explicitly supplied FOU_ATTR_IPPROTO == 0 attribute with -ERANGE.

However, FOU_ATTR_IPPROTO is an optional netlink attribute. When a user sends FOU_CMD_ADD with FOU_ATTR_TYPE set to FOU_ENCAP_DIRECT and omits FOU_ATTR_IPPROTO entirely, nla_policy validation succeeds and parse_nl_config() leaves cfg->protocol as 0 (from memset(cfg, 0, sizeof(*cfg))). fou_create() then creates a FOU_ENCAP_DIRECT socket with fou->protocol == 0.

In fou_udp_recv(), returning -fou->protocol to udp_queue_rcv_one_skb() triggers IP protocol resubmission when fou->protocol > 0, whereas returning 0 tells the UDP tunnel layer that the skb was consumed without freeing it. When fou->protocol == 0, every packet received on the socket returns 0 from fou_udp_recv() and leaks the sk_buff.

Reject FOU_ENCAP_DIRECT when !cfg->protocol in fou_create() so that creating a direct encapsulation port without FOU_ATTR_IPPROTO fails with -EINVAL while leaving FOU_CMD_DEL and FOU_CMD_GET (which share parse_nl_config()) unaffected.

Tested in QEMU against Linux 7.3.0-rc3 by sending a FOU_CMD_ADD Generic Netlink request with FOU_ATTR_PORT = 5555 and FOU_ATTR_TYPE = FOU_ENCAP_DIRECT while omitting FOU_ATTR_IPPROTO. On the unfixed kernel, FOU_CMD_ADD succeeds (err = 0), FOU_CMD_GET reports fou->type = 1 and fou->protocol = 0, and sending 4000 UDP packets to 127.0.0.1:5555 leaks all 4000 sk_buffs (SUnreclaim in /proc/meminfo grows from 41456 kB to 59008 kB, +17552 kB); with this patch applied, FOU_CMD_ADD is rejected with -EINVAL (-22).

Fixes 23461551c006 ("fou: Support for foo-over-udp RX path")
Fixes 7a9bc9e3f423 ("fou: Don't allow 0 for FOU_ATTR_IPPROTO.")
---
 net/ipv4/fou_core.c |    4 ++++
 1 file changed, 4 insertions(+)
net/ipv4/fou_core.c +4 -0
@@ -600,6 +600,10 @@ static int fou_create(struct net *net, s
 	/* Initial for fou type */
 	switch (cfg->type) {
 	case FOU_ENCAP_DIRECT:
+		if (!cfg->protocol) {
+			err = -EINVAL;
+			goto error;
+		}
 		tunnel_cfg.encap_rcv = fou_udp_recv;
 		tunnel_cfg.gro_receive = fou_gro_receive;
 		tunnel_cfg.gro_complete = fou_gro_complete;
author maintainer
#257 lore raw

PATCH 257/457 fprobe: Terminate the fgraph_data list when the reservation is not filled

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: David Carlier <[email protected]>

commit 1d653a183973f5283a3db5a38cd5e195eb152244 upstream.

fprobe_fgraph_entry() reserves shadow stack space for every fprobe with an exit handler, but only fills it for those whose entry handler returns
0. fgraph_reserve_data() does not clear the area, so fprobe_return() parses the unused tail as headers left over from an earlier call, and an exit handler can run twice or despite its entry handler asking to skip it.

Write a zero word after the last entry to terminate the walk. A zeroed slot does not decode to a NULL fprobe on the arches that encode the header into one unsigned long, since arch_decode_fprobe_header_fp() ORs in FPROBE_HEADER_MSB_PATTERN, so make read_fprobe_header() return NULL for a zeroed slot.

Fixes e0a384434ae1 ("tracing: fprobe: do not zero out unused fgraph_data")
---
 kernel/trace/fprobe.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
kernel/trace/fprobe.c +15 -0
@@ -171,6 +171,11 @@ static inline bool write_fprobe_header(u
 static inline void read_fprobe_header(unsigned long *stack,
 					struct fprobe **fp, unsigned int *size_words)
 {
+	if (!*stack) {
+		*fp = NULL;
+		*size_words = 0;
+		return;
+	}
 	*fp = arch_decode_fprobe_header_fp(*stack);
 	*size_words = arch_decode_fprobe_header_size(*stack);
 }
@@ -203,6 +208,12 @@ static inline void read_fprobe_header(un
 {
 	struct __fprobe_header *fph = (struct __fprobe_header *)stack;
 
+	if (!*stack) {
+		*fp = NULL;
+		*size_words = 0;
+		return;
+	}
+
 	*fp = fph->fp;
 	*size_words = fph->size_words;
 }
@@ -642,6 +653,10 @@ static int fprobe_fgraph_entry(struct ft
 		}
 	}
 
+	/* Terminate the list, fgraph_reserve_data() does not clear it. */
+	if (used && used < reserved_words)
+		fgraph_data[used] = 0;
+
 	/* If any exit_handler is set, data must be used. */
 	return used != 0;
 }
author maintainer
#258 lore raw

PATCH 258/457 fs/ntfs3: use d_instantiate_new() in ntfs_create_inode() and murder syzbots "WARNING in do_new_mount" saga

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Brauner <[email protected]>

commit 1abd643f3783ea8f8e273c18697ff0413aa92dc7 upstream.

ntfs_create_inode() creates a new inode via ntfs_new_inode(). It hashes it with insert_inode_locked() and so it's marked as I_NEW until unlock_new_inode().

ntfs 3 calls d_instantiate() in between though... Since the dentry was already hashed by the lookup before the create any path walk finds it without touching the parent's i_rwsem and so can lock the inode.

If the inode is a directory unlock_new_inode() calls lockdep_annotate_inode_mutex_key() and marks i_rwsem with the i_mutex_dir_key class.

That resets the count and the owner of a lock somebody else may already hold by now...

syzbot has been spamming us with the same godforsaken bug

"WARNING in do_new_mount"

since 2023. I can't take it anymore so I went looking. Afaict, syzbot's executor chdirs into a freshly mounted ntfs3 image, creates a directory and then mounts some pseudofs on it. Everytime the mkdir() takes longer than syzbot waits mount() runs concurrently:

mkdir("./sys") mount(NULL, "./sys", "sysfs")
ntfs_create_inode()

    d_instantiate()
                                        user_path_at() finds the dentry
                                        do_lock_mount()
                                          inode_lock(inode)
                                          namespace_lock()
    unlock_new_inode()
      lockdep_annotate_inode_mutex_key()
        init_rwsem(&inode->i_rwsem)
                                        unlock_mount()
                                          inode_unlock(inode)

The mount side then releases a lock that according to the rwsem nobody holds:

DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) && ...):
count = 0x0, magic = 0xffff888043a854e8, owner = 0x0, curr 0xffff888000244880, list empty

  WARNING: CPU: 0 PID: 5346 at kernel/locking/rwsem.c:1368 __up_write
  Call Trace:
   inode_unlock include/linux/fs.h:877 [inline]
   unlock_mount fs/namespace.c:2892 [inline]
   do_new_mount_fc fs/namespace.c:3828 [inline]
   do_new_mount+0x777/0xa40 fs/namespace.c:3887

On PREEMPT_RT the same thing shows up as

DEBUG_LOCKS_WARN_ON(rt_mutex_owner(lock) != current)

  WARNING: kernel/locking/rtmutex_common.h:193 at rt_mutex_slowunlock

The up_write() underflows the reset count. A following inode_lock() on that directory then never returns. A path walk into the new directory racing with the mkdir() corrupts the lock the same way via inode_lock_shared() in lookup_slow().

Switch to d_instantiate_new() and drop the trailing unlock_new_inode(). All error paths bail out before that point with I_NEW still set and keep using discard_new_inode().

May we never see this fscking bug report again.

---
 fs/ntfs3/inode.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
fs/ntfs3/inode.c +2 -5
@@ -1648,10 +1648,10 @@ int ntfs_create_inode(struct mnt_idmap *
 		goto out6;
 
 	/*
-	 * Call 'd_instantiate' after inode->i_op is set
+	 * Call 'd_instantiate_new' after inode->i_op is set
 	 * but before finish_open.
 	 */
-	d_instantiate(dentry, inode);
+	d_instantiate_new(dentry, inode);
 
 	/* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
 	inode_set_atime_to_ts(inode, ni->i_crtime);
@@ -1699,9 +1699,6 @@ out1:
 	if (!fnd)
 		ni_unlock(dir_ni);
 
-	if (!err)
-		unlock_new_inode(inode);
-
 	return err;
 }
 
author maintainer
#259 lore raw

PATCH 259/457 netfs: Fix missing alloc tagging of direct mempool allocations

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hao Ge <[email protected]>

commit b78b728e21c32ec4c330b299f657fb1eb02dffc2 upstream.

Commit 1d78d56c43ef ("netfs: Fix folio_queue ENOMEM in writeback by adding a mempool") added a mempool for the folio_queues and made the request, subrequest and folio_queue allocations distinguish between writeback and everything else. Writeback is part of memory reclaim and must not fail due to ENOMEM, so it allocates under GFP_NOFS through mempool_alloc(), which may dip into the pool's reserve and, if that runs empty, wait for elements to be returned. The GFP_KERNEL paths, which can return -ENOMEM to their callers, invoke the pool's ->alloc() callback directly instead.

The direct call, however, skips the alloc_hooks() wrapper that the mempool_alloc() macro provides. The pool callbacks, mempool_alloc_slab() and mempool_kmalloc(), call kmem_cache_alloc_noprof() and kmalloc_noprof() and rely on current->alloc_tag having been set by the caller. With CONFIG_MEM_ALLOC_PROFILING_DEBUG=y this leads to

current->alloc_tag not set
WARNING: ./include/linux/alloc_tag.h:161 at __alloc_tagging_slab_alloc_hook alloc_tag was not set
WARNING: ./include/linux/alloc_tag.h:166 at __alloc_tagging_slab_free_hook

at allocation and free time respectively, as reported when reading files on a CIFS mount. The allocations are also missing from /proc/allocinfo.

Wrap the direct ->alloc() invocations in alloc_hooks() with a new mempool_alloc_noreserve() helper in include/linux/mempool.h, next to the other alloc_hooks()-wrapped macros such as mempool_alloc(). The GFP_KERNEL paths keep their failable allocation semantics, they just get tagged now.

---
 fs/netfs/objects.c        |    4 ++--
 fs/netfs/rolling_buffer.c |    2 +-
 include/linux/mempool.h   |    7 +++++++
 3 files changed, 10 insertions(+), 3 deletions(-)
fs/netfs/objects.c +2 -2
@@ -34,7 +34,7 @@ struct netfs_io_request *netfs_alloc_req
 
 		rreq = mempool_alloc(mempool, gfp);
 	} else {
-		rreq = mempool->alloc(gfp, mempool->pool_data);
+		rreq = mempool_alloc_noreserve(mempool, gfp);
 		if (!rreq)
 			return ERR_PTR(-ENOMEM);
 	}
@@ -214,7 +214,7 @@ struct netfs_io_subrequest *netfs_alloc_
 	struct kmem_cache *cache = mempool->pool_data;
 
 	if (rreq->gfp == GFP_KERNEL)
-		subreq = mempool->alloc(rreq->gfp, mempool->pool_data);
+		subreq = mempool_alloc_noreserve(mempool, rreq->gfp);
 	else
 		subreq = mempool_alloc(mempool, rreq->gfp);
 	if (!subreq)
fs/netfs/rolling_buffer.c +1 -1
@@ -29,7 +29,7 @@ struct folio_queue *netfs_folioq_alloc(u
 	struct folio_queue *fq;
 
 	if (gfp == GFP_KERNEL)
-		fq = netfs_folioq_pool.alloc(gfp, netfs_folioq_pool.pool_data);
+		fq = mempool_alloc_noreserve(&netfs_folioq_pool, gfp);
 	else
 		fq = mempool_alloc(&netfs_folioq_pool, gfp);
 	if (fq) {
include/linux/mempool.h +7 -0
@@ -70,6 +70,13 @@ int mempool_alloc_bulk_noprof(struct mem
 #define mempool_alloc_bulk(...)						\
 	alloc_hooks(mempool_alloc_bulk_noprof(__VA_ARGS__))
 
+/*
+ * Allocate a new element without dipping into the pool's reserves or
+ * waiting.  Returns NULL on failure.
+ */
+#define mempool_alloc_noreserve(_pool, _gfp)				\
+	alloc_hooks((_pool)->alloc(_gfp, (_pool)->pool_data))
+
 void *mempool_alloc_preallocated(struct mempool *pool) __malloc;
 void mempool_free(void *element, struct mempool *pool);
 unsigned int mempool_free_bulk(struct mempool *pool, void **elem,
author maintainer
#260 lore raw

PATCH 260/457 writeback: bound cleanup_offline_cgwb() rescans by rotating scanned inodes

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Patrick Lu (Anthropic) <[email protected]>

commit f6988c90671e83db79df1b7b9d6fdb0e5947fd84 upstream.

cleanup_offline_cgwb() prepares at most WB_MAX_INODES_PER_ISW inodes per call and is called again until the dying wb is drained, but every call walks wb->b_attached and then wb->b_dirty_time from the same end. Inodes already prepared (they stay on the list with I_WB_SWITCH set until the switch worker runs) and inodes that cannot be switched (I_FREEING, I_WILL_FREE, !SB_ACTIVE, DAX, already on the target wb) stay where they are, so each pass rescans a growing run of them under wb->list_lock and a full drain is quadratic in the number of inodes on the list. With ~17M inodes attached to one dying cgwb we saw this end in soft lockups, with CPUs reported stuck for 21-48s.

Walk both lists from the oldest end and move every scanned inode to the newest end, so the next pass starts where the previous one stopped and the drain becomes linear. b_attached is unordered, so nobody sees the reorder there. b_dirty_time is ordered by dirtied_when, but the oldest unscanned inode stays at the end move_expired_inodes() picks from, sync takes the whole list regardless of order, and prepared inodes leave the list as soon as the switch work runs and get a new dirtied_time_when on the new wb anyway, so the only inodes left out of order are the ones that can never switch (DAX), and only on the dying wb.

---
 fs/fs-writeback.c |   25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)
fs/fs-writeback.c +20 -5
@@ -726,19 +726,34 @@ static bool isw_prepare_wbs_switch(struc
 				   struct inode_switch_wbs_context *isw,
 				   struct list_head *list, int *nr)
 {
-	struct inode *inode;
+	struct inode *inode, *tmp;
+	LIST_HEAD(scanned);
+	bool full = false;
+
+	/*
+	 * Walk from the oldest end and move scanned inodes to the newest
+	 * end, so the next scan resumes at unscanned inodes instead of
+	 * re-walking an ever-growing run of prepared and skipped ones.
+	 * For b_dirty_time this keeps the oldest unscanned inode at the
+	 * end move_expired_inodes() picks from; b_attached is unordered.
+	 */
+	list_for_each_entry_safe_reverse(inode, tmp, list, i_io_list) {
+		list_move(&inode->i_io_list, &scanned);
 
-	list_for_each_entry(inode, list, i_io_list) {
 		if (!inode_prepare_wbs_switch(inode, new_wb))
 			continue;
 
 		isw->inodes[*nr] = inode;
 		(*nr)++;
 
-		if (*nr >= WB_MAX_INODES_PER_ISW - 1)
-			return true;
+		if (*nr >= WB_MAX_INODES_PER_ISW - 1) {
+			full = true;
+			break;
+		}
 	}
-	return false;
+	list_splice(&scanned, list);
+
+	return full;
 }
 
 /**
author maintainer
#261 lore raw

PATCH 261/457 workqueue: Fix NULL current_pwq deref in flush dependency check

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pavankumar Kondeti <[email protected]>

commit db6365ced4d5855e321f772b240c0e473bcfcdd5 upstream.

check_flush_dependency() uses current_wq_worker() to determine whether the caller is a workqueue worker and then dereferences worker->current_pwq to test whether the current workqueue is WQ_MEM_RECLAIM.

current_wq_worker() only means that %current has PF_WQ_WORKER set. A kworker can reach check_flush_dependency() while it is not executing a work item. One such path is worker_thread() acting as the pool manager, where create_worker() does GFP_KERNEL allocation and the allocation path invokes the OOM notifier. In that state worker->current_pwq is NULL because current_pwq is set only by process_one_work() and cleared again after the work function returns.

[  416.760634][  T375] Call trace:
[  416.760638][  T375]  check_flush_dependency+0x80/0x120 (P)
[  416.760648][  T375]  __flush_work+0x98/0x224
[  416.760657][  T375]  flush_work+0x30/0x44
[  416.760665][  T375]  ...
[  416.760710][  T375]  blocking_notifier_call_chain+0x58/0xa0
[  416.760719][  T375]  out_of_memory+0xb4/0x458
[  416.760730][  T375]  __alloc_pages_may_oom+0x11c/0x1a8
[  416.760739][  T375]  __alloc_pages_slowpath+0x314/0x46c
[  416.760746][  T375]  __alloc_frozen_pages_noprof+0x110/0x1a4
[  416.760753][  T375]  new_slab+0x12c/0x484
[  416.760759][  T375]  ___slab_alloc+0x7a8/0xc7c
[  416.760765][  T375]  __slab_alloc+0x74/0xd8
[  416.760772][  T375]  __kmalloc_cache_node_noprof+0x2ac/0x304
[  416.760779][  T375]  alloc_worker+0x28/0x60
[  416.760785][  T375]  create_worker+0x4c/0x20c
[  416.760790][  T375]  worker_thread+0xe8/0x2b8
[  416.760796][  T375]  kthread+0x1a8/0x200
[  416.760805][  T375]  ret_from_fork+0x10/0x20

Guard the WQ_MEM_RECLAIM-worker warning with worker->current_pwq. If the kworker is not currently executing a work item, there is no current workqueue to diagnose with that warning. The PF_MEMALLOC warning is left unchanged so explicit reclaim context flushing a !WQ_MEM_RECLAIM target is still reported.

Fixes fca839c00a12 ("workqueue: warn if memory reclaim tries to flush !WQ_MEM_RECLAIM workqueue")
Assisted-by LLM
---
 kernel/workqueue.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/workqueue.c +1 -1
@@ -3844,7 +3844,7 @@ static void check_flush_dependency(struc
 	WARN_ONCE(current->flags & PF_MEMALLOC,
 		  "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%ps",
 		  current->pid, current->comm, target_wq->name, target_func);
-	WARN_ONCE(worker && ((worker->current_pwq->wq->flags &
+	WARN_ONCE(worker && worker->current_pwq && ((worker->current_pwq->wq->flags &
 			      (WQ_MEM_RECLAIM | __WQ_LEGACY)) == WQ_MEM_RECLAIM),
 		  "workqueue: WQ_MEM_RECLAIM %s:%ps is flushing !WQ_MEM_RECLAIM %s:%ps",
 		  worker->current_pwq->wq->name, worker->current_func,
author maintainer
#262 lore raw

PATCH 262/457 writeback: report a Tasks-RCU quiescent state per cgwb drain pass

In reply to Greg Kroah-Hartman

7.2-stable review patch. If anyone has any objections, please let me know.

------------------

From: Josef Bacik <[email protected]>

commit 407a5d205179a4ab186571b0e16ec42725dc77bc upstream.

cleanup_offline_cgwbs_workfn() drains a dying cgwb by calling cleanup_offline_cgwb() until it returns false, with a cond_resched() between passes. On a CONFIG_PREEMPTION kernel that cond_resched() does
nothing: _cond_resched() is a plain "return 0", and under PREEMPT_DYNAMIC the full and lazy modes disable it. Since commit 7dadeaa6e851 ("sched:
Further restrict the preemption modes") those are the only two models on the architectures with PREEMPT_LAZY support, arm64 and x86 among them, so the drain loop never reports a Tasks-RCU quiescent state.

A worker draining a cgwb with millions of attached inodes runs for minutes. On a 6.18 arm64 host in lazy mode the cgwb worker drained one dying cgroup's writeback domain for over 11 minutes. A BPF program unlink (bpf_trampoline_unlink_prog -> bpf_trampoline_update -> unregister_ftrace_direct -> ftrace_shutdown -> synchronize_rcu_tasks()) waited on that grace period while holding the trampoline mutex, 42 tasks queued behind it in D state, and the hung task detector fired at 614 s and panicked the host. Any BPF or ftrace detach during a long drain inherits the drain's length.

Fix this by calling cond_resched_tasks_rcu_qs() so we do not stall out anybody who calls sycnrhonize_rcu_tasks(). We put this in a do { } while loop because if we have many small cgroups cleanup_offline_cgwb() will return false and we will never call cond_resched_tasks_rcu_qs(), creating the same problem.

Fixes c22d70a162d3 ("writeback, cgroup: release dying cgwbs by switching attached inodes")
Assisted-by LLM
Cc David Hildenbrand <[email protected]>
Cc Dennis Zhou <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc "Paul E . McKenney" <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 mm/backing-dev.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
mm/backing-dev.c +3 -2
@@ -910,8 +910,9 @@ static void cleanup_offline_cgwbs_workfn
 			continue;
 
 		spin_unlock_irq(&cgwb_lock);
-		while (cleanup_offline_cgwb(wb))
-			cond_resched();
+		do {
+			cond_resched_tasks_rcu_qs();
+		} while (cleanup_offline_cgwb(wb));
 		spin_lock_irq(&cgwb_lock);
 
 		wb_put(wb);