6.18.55-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 130/395 net/mlx5: Bridge, dont fail switchdev events of sibling eswitch ports
In reply to Greg Kroah-Hartman6.18-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.
--- .../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
@@ -89,9 +89,16 @@ mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct mstruct 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;
@@ -108,6 +115,28 @@ mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct mreturn 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) {
@@ -222,8 +251,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;
@@ -255,8 +283,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;
@@ -287,8 +314,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
@@ -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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 131/395 net/mlx5: Bridge, dont fail unlink of untracked/unsupported peer ports
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 132/395 sctp: hold asoc or transport before mod_timer() in timer handlers
In reply to Greg Kroah-Hartman6.18-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
@@ -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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 133/395 net: stmmac: selftests: Support running selftests on DSA conduits
In reply to Greg Kroah-Hartman6.18-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
@@ -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; }
@@ -775,7 +823,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 = priv->plat->rx_fifo_size;
@@ -833,7 +881,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; }
@@ -938,18 +986,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) {
@@ -976,9 +1026,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; }
@@ -1032,18 +1082,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) {
@@ -1070,9 +1122,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; }
@@ -1303,7 +1355,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)
@@ -1311,6 +1362,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 ;
@@ -1328,9 +1381,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
Greg Kroah-Hartman
maintainerPATCH 134/395 net: stmmac: selftests: Check the dev->features for S-TAG offload testing
In reply to Greg Kroah-Hartman6.18-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
@@ -1395,7 +1395,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
Greg Kroah-Hartman
maintainerPATCH 135/395 net: stmmac: selftests: Capture all packets for vlan checks
In reply to Greg Kroah-Hartman6.18-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
@@ -242,6 +242,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;
@@ -344,13 +345,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;
@@ -923,6 +926,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;
@@ -934,10 +942,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 );
@@ -979,6 +983,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
@@ -1075,6 +1080,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
@@ -1355,6 +1361,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
Greg Kroah-Hartman
maintainerPATCH 136/395 net: stmmac: dwmac4: Use the correct bufzise when the len is exactly 8K
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -496,11 +496,11 @@ static void dwmac4_set_sarc(struct dma_desc *p, u32 sarc_type) p->des3 |=cpu_to_le32 (sarc_type &TDES3_SA_INSERT_CTRL_MASK ); } -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
@@ -536,7 +536,7 @@ struct stmmac_mode_ops {unsigned int (*is_jumbo_frm) (int len,int ehn_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
@@ -128,10 +128,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
Greg Kroah-Hartman
maintainerPATCH 137/395 net: stmmac: selftests: Account for alignment shift on dwmac1000 for Jumbo test
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +3 -0
@@ -1769,6 +1769,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
Greg Kroah-Hartman
maintainerPATCH 138/395 eth: fbnic: Avoid rounding zero ring sizes
In reply to Greg Kroah-Hartman6.18-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
@@ -299,6 +299,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)
@@ -320,10 +325,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
Greg Kroah-Hartman
maintainerPATCH 139/395 net/sched: fix potential stack infoleak in em_text_dump()
In reply to Greg Kroah-Hartman6.18-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 uninitializedI 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.
--- net/sched/em_text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/em_text.c +1 -1
@@ -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
Greg Kroah-Hartman
maintainerPATCH 140/395 bpf: Reject dev-bound-only programs on other devices
In reply to Greg Kroah-Hartman6.18-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
@@ -708,6 +708,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
Greg Kroah-Hartman
maintainerPATCH 141/395 nfc: nfcmrvl: validate helper command length before pull
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/nfc/nfcmrvl/fw_dnld.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/nfc/nfcmrvl/fw_dnld.c +8 -3
@@ -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
Greg Kroah-Hartman
maintainerPATCH 142/395 nfc: st21nfca: validate received frame size
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/nfc/st21nfca/i2c.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/nfc/st21nfca/i2c.c +19 -10
@@ -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
Greg Kroah-Hartman
maintainerPATCH 143/395 nfc: llcp: Fix list corruption / refcount desync in nfc_llcp_recv_dm()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 144/395 selftests: nci: Correct pthread_create return value check
In reply to Greg Kroah-Hartman6.18-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.
--- tools/testing/selftests/nci/nci_dev.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
tools/testing/selftests/nci/nci_dev.c +7 -5
@@ -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
Greg Kroah-Hartman
maintainerPATCH 145/395 nfc: llcp: Fix race condition in accept_queue lifecycle
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 146/395 selftests: nci: Fix uninitialized family ID on missing attribute
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 147/395 selftests/nci: Fix out-of-bounds store on thread join
In reply to Greg Kroah-Hartman6.18-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
@@ -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 pvoid *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 pif (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
Greg Kroah-Hartman
maintainerPATCH 148/395 nfc: virtual_ncidev: Add missing ioctl compat handler
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 149/395 nfc: llcp: fix sdreq TLV list leak on parse/alloc/send failure
In reply to Greg Kroah-Hartman6.18-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.
--- net/nfc/netlink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/nfc/netlink.c +5 -2
@@ -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
Greg Kroah-Hartman
maintainerPATCH 150/395 nfc: st21nfca: validate ISO15693 inventory length
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/nfc/st21nfca/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/nfc/st21nfca/core.c +1 -3
@@ -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
Greg Kroah-Hartman
maintainerPATCH 151/395 nfc: llcp: fix -ENOMEM on connect with zero-length service name
In reply to Greg Kroah-Hartman6.18-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
@@ -759,12 +759,16 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_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
Greg Kroah-Hartman
maintainerPATCH 152/395 nfc: llcp: fix WKS SAP hijacking via prefix match in nfc_llcp_wks_sap()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 153/395 nfc: llcp: fix slab-out-of-bounds reads when logging service names
In reply to Greg Kroah-Hartman6.18-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
@@ -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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 154/395 nfc: pn533: fix OOB read in pn533_acr122_is_rx_frame_valid()
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/nfc/pn533/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/nfc/pn533/usb.c +3 -1
@@ -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
Greg Kroah-Hartman
maintainerPATCH 155/395 net/sched: act_gate: budget the per-entry list in get_fill_size
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 156/395 net: bcmgenet: stop Tx NAPI before disabling the queues
In reply to Greg Kroah-Hartman6.18-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
--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +4 -2
@@ -3439,6 +3439,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 */
@@ -3453,7 +3455,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);
@@ -4325,6 +4326,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 */
@@ -4353,7 +4356,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
Greg Kroah-Hartman
maintainerPATCH 157/395 veth: manage XDP program pointers during channel resize
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 158/395 net: skbuff: fix pull-bound underflow in skb_checksum_setup_ipv6()
In reply to Greg Kroah-Hartman6.18-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.
--- net/core/skbuff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/core/skbuff.c +6 -3
@@ -5911,7 +5911,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;
@@ -5926,7 +5927,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;
@@ -5941,7 +5943,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
Greg Kroah-Hartman
maintainerPATCH 159/395 vrf: Stop corrupting skb->csum when capturing CHECKSUM_COMPLETE packets
In reply to Greg Kroah-Hartman6.18-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
@@ -1225,8 +1225,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
Greg Kroah-Hartman
maintainerPATCH 160/395 bpf: Fix immediate JMP JEQ/JNE on MIPS32
In reply to Greg Kroah-Hartman6.18-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.
--- arch/mips/net/bpf_jit_comp32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/net/bpf_jit_comp32.c +1 -1
@@ -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
Greg Kroah-Hartman
maintainerPATCH 161/395 bpf: Fix BSWAP 32 and 16 on MIPS64
In reply to Greg Kroah-Hartman6.18-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.
--- arch/mips/net/bpf_jit_comp64.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/mips/net/bpf_jit_comp64.c +1 -2
@@ -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
Greg Kroah-Hartman
maintainerPATCH 162/395 tg3: use random MAC address when tg3_get_device_address fails
In reply to Greg Kroah-Hartman6.18-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
@@ -17928,11 +17928,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
Greg Kroah-Hartman
maintainerPATCH 163/395 net: stmmac: clear stale buf->page after recycling on skb build failure
In reply to Greg Kroah-Hartman6.18-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
@@ -5672,6 +5672,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
Greg Kroah-Hartman
maintainerPATCH 164/395 net: bcmgenet: fix 64-bit RTNL stats reading in ethtool on 32-bit systems
In reply to Greg Kroah-Hartman6.18-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
@@ -1347,9 +1347,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
Greg Kroah-Hartman
maintainerPATCH 165/395 net: bcmgenet: initialize u64 stats seq counter for all queues
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +2 -2
@@ -4140,10 +4140,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
Greg Kroah-Hartman
maintainerPATCH 166/395 net: bcmgenet: do not skip WoL power up on GENET V1
In reply to Greg Kroah-Hartman6.18-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
@@ -1758,13 +1758,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)) {
@@ -1788,8 +1787,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
Greg Kroah-Hartman
maintainerPATCH 167/395 net: bcmgenet: validate Ethernet address in bcmgenet_set_mac_addr
In reply to Greg Kroah-Hartman6.18-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
@@ -3633,6 +3633,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
Greg Kroah-Hartman
maintainerPATCH 168/395 net: bcmgenet: mask DMA_TIMEOUT_MASK when reading DMA_RING0_TIMEOUT
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +2 -1
@@ -853,7 +853,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
Greg Kroah-Hartman
maintainerPATCH 169/395 ip_gre: Reject enabling collect metadata through changelink
In reply to Greg Kroah-Hartman6.18-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
@@ -1459,6 +1459,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;
@@ -1491,6 +1497,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
Greg Kroah-Hartman
maintainerPATCH 170/395 vxlan: use one headroom snapshot for neighbour replies
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/vxlan/vxlan_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +4 -2
@@ -1956,13 +1956,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 )
@@ -1970,7 +1972,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
Greg Kroah-Hartman
maintainerPATCH 171/395 net: xps: reject an out of range traffic class
In reply to Greg Kroah-Hartman6.18-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.
--- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/dev.c +1 -1
@@ -2863,7 +2863,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
Greg Kroah-Hartman
maintainerPATCH 172/395 drm/imagination: clamp freelist reconstruction requests
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 173/395 bonding: crypto offload enabled, non-offload slave failover, rekey failed
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/bonding/bond_main.c +1 -1
@@ -492,7 +492,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
Greg Kroah-Hartman
maintainerPATCH 174/395 macsec: initialize SecY before registering the netdevice
In reply to Greg Kroah-Hartman6.18-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
@@ -3533,6 +3533,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 ;
@@ -3545,8 +3561,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);
@@ -3554,6 +3568,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)
@@ -4108,26 +4130,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 );
@@ -4141,15 +4148,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;
@@ -4212,6 +4216,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;
@@ -4224,31 +4246,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
Greg Kroah-Hartman
maintainerPATCH 175/395 net: dsa: mt7530: fix NULL dereference on unbind of MT7531 and MT7621
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/dsa/mt7530-mdio.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/net/dsa/mt7530-mdio.c +11 -9
@@ -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
Greg Kroah-Hartman
maintainerPATCH 176/395 net: dsa: mt7530: leave the MDIO IRQ mappings to regmap-irq
In reply to Greg Kroah-Hartman6.18-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.
--- drivers/net/dsa/mt7530.c | 3 --- 1 file changed, 3 deletions(-)
drivers/net/dsa/mt7530.c +0 -3
@@ -3446,9 +3446,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
Greg Kroah-Hartman
maintainerPATCH 177/395 tcp: fix use-after-free of retransmit_skb_hint in tcp_send_synack()
In reply to Greg Kroah-Hartman6.18-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
@@ -3821,6 +3821,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);
@@ -3838,6 +3839,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
Greg Kroah-Hartman
maintainerPATCH 178/395 net: phylink: record the PHY only once bringup cannot fail
In reply to Greg Kroah-Hartman6.18-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
@@ -2115,7 +2115,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 ;
@@ -2182,10 +2181,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
Greg Kroah-Hartman
maintainerPATCH 179/395 nfp: hold IPsec RX state under the XArray lock
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 180/395 net/smc: fix UAF on lgr list traversal in smcr_port_err()
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -1835,6 +1835,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 ))
@@ -1849,6 +1850,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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 181/395 tipc: Fix a data race on mon->peer_cnt in mon_timeout()
In reply to Greg Kroah-Hartman6.18-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.
--- net/tipc/monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/tipc/monitor.c +2 -1
@@ -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
Greg Kroah-Hartman
maintainerPATCH 182/395 net: ethernet: stmmac: dwmac-rk: fix bulk clock leak when the PHY clock fails
In reply to Greg Kroah-Hartman6.18-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
@@ -1434,8 +1434,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; + }if (bsp_priv->ops && bsp_priv->ops->set_clock_selection) bsp_priv->ops->set_clock_selection(bsp_priv,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 183/395 gve: Consolidate and persist ethtool ring changes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit c30fd916c4d7760ccf654e52370b0a31be885789 ]
Refactor the ethtool ring parameter configuration logic to address two
issues: unnecessary queue resets and lost configuration changes when the interface is down.
Previously, gve_set_ringparam could trigger multiple queue destructions and recreations for a single command, as different settings (e.g., header split, ring sizes) were applied one by one. Furthermore, if the interface was down, any changes made via ethtool were discarded instead of being saved for the next time the interface was brought up.
This patch centralizes the configuration logic. Individual functions like gve_set_hsplit_config are modified to only validate and stage changes in a temporary config struct.
The main gve_set_ringparam function now gathers all staged changes and applies them as a single, combined configuration:
1. If the interface is up, it calls gve_adjust_config once.
2. If the interface is down, it saves the settings directly to the driver's private struct, ensuring they persist and are used when the interface is brought back up.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve.h | 3 +- drivers/net/ethernet/google/gve/gve_ethtool.c | 86 +++++++++---------- drivers/net/ethernet/google/gve/gve_main.c | 17 ++-- 3 files changed, 51 insertions(+), 55 deletions(-)
drivers/net/ethernet/google/gve/gve.h +2 -1
@@ -1254,7 +1254,8 @@ void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);void gve_rx_stop_ring_gqi (struct gve_priv *priv,int idx);u16 gve_get_pkt_buf_size (const struct gve_priv *priv,bool enable_hplit);bool gve_header_split_supported (const struct gve_priv *priv); -int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split); +int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split, +struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);/* rx buffer handling */ int gve_buf_ref_cnt (struct gve_rx_buf_state_dqo *bs); void gve_free_page_dqo(struct gve_priv *priv, struct gve_rx_buf_state_dqo *bs,
drivers/net/ethernet/google/gve/gve_ethtool.c +43 -43
111 lines not on this page · raw message
drivers/net/ethernet/google/gve/gve_main.c +6 -11
@@ -2058,12 +2058,10 @@ bool gve_header_split_supported(const struct gve_priv *priv) priv->queue_format ==GVE_DQO_RDA_FORMAT && !priv->xdp_prog; } -int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split) +int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split, +struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) { -struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0 }; -struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0 };bool enable_hdr_split; -int err =0 ;if (tcp_data_split ==ETHTOOL_TCP_DATA_SPLIT_UNKNOWN )return 0 ;
@@ -2081,14 +2079,11 @@ int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split)if (enable_hdr_split == priv->header_split_enabled)return 0 ; -gve_get_curr_alloc_cfgs (priv, &tx_alloc_cfg, &rx_alloc_cfg); - - rx_alloc_cfg.enable_header_split = enable_hdr_split; - rx_alloc_cfg.packet_buffer_size =gve_get_pkt_buf_size (priv, enable_hdr_split); + rx_alloc_cfg->enable_header_split = enable_hdr_split; + rx_alloc_cfg->packet_buffer_size = +gve_get_pkt_buf_size (priv, enable_hdr_split); -if (netif_running (priv->dev)) - err =gve_adjust_config (priv, &tx_alloc_cfg, &rx_alloc_cfg); -return err; +return 0 ; } static int gve_set_features(struct net_device *netdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 184/395 gve: Use extack to log xdp config verification errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit 091a3b6ff2b98354270cb9278faad6d17d5aa27d ]
Plumb extack as it allows us to send more detailed error messages back and append 'gve' suffix to method name per convention.
NL_SET_ERR_MSG_FMT_MOD doesn't support format string longer than 80 chars so keeping netdev warning with actual queue count details.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve_main.c | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-)
drivers/net/ethernet/google/gve/gve_main.c +15 -9
@@ -1707,18 +1707,21 @@ static int gve_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)return 0 ; } -static int verify_xdp_configuration (struct net_device *dev) +static int gve_verify_xdp_configuration (struct net_device *dev, +struct netlink_ext_ack *extack) {struct gve_priv *priv =netdev_priv (dev);u16 max_xdp_mtu;if (dev->features &NETIF_F_LRO ) { -netdev_warn (dev,"XDP is not supported when LRO is on.\n" ); +NL_SET_ERR_MSG_MOD (extack, +"XDP is not supported when LRO is on." );return -EOPNOTSUPP ; }if (priv->header_split_enabled) { -netdev_warn (dev,"XDP is not supported when header-data split is enabled.\n" ); +NL_SET_ERR_MSG_MOD (extack, +"XDP is not supported when header-data split is enabled." );return -EOPNOTSUPP ; }
@@ -1727,17 +1730,20 @@ static int verify_xdp_configuration(struct net_device *dev) max_xdp_mtu -=GVE_RX_PAD ;if (dev->mtu > max_xdp_mtu) { -netdev_warn (dev,"XDP is not supported for mtu %d.\n" , - dev->mtu); +NL_SET_ERR_MSG_FMT_MOD (extack, +"XDP is not supported for mtu %d." , + dev->mtu);return -EOPNOTSUPP ; }if (priv->rx_cfg.num_queues != priv->tx_cfg.num_queues || (2 * priv->tx_cfg.num_queues > priv->tx_cfg.max_queues)) { -netdev_warn (dev,"XDP load failed: The number of configured RX queues %d should be equal to the number of configured TX queues %d and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues %d" , - priv->rx_cfg.num_queues, - priv->tx_cfg.num_queues, +netdev_warn (dev, +"XDP load failed: The number of configured RX queues %d should be equal to the number of configured TX queues %d and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues %d." , + priv->rx_cfg.num_queues, priv->tx_cfg.num_queues, priv->tx_cfg.max_queues); +NL_SET_ERR_MSG_MOD (extack, +"XDP load failed: The number of configured RX queues should be equal to the number of configured TX queues and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues" );return -EINVAL ; }return 0 ;
@@ -1748,7 +1754,7 @@ static int gve_xdp(struct net_device *dev, struct netdev_bpf *xdp)struct gve_priv *priv =netdev_priv (dev);int err; - err =verify_xdp_configuration (dev); + err =gve_verify_xdp_configuration (dev, xdp->extack);if (err)return err;switch (xdp->command) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 185/395 gve: Allow ethtool to configure rx_buf_len
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit d235bb213f411ace8317bcca3740a1008628ea9c ]
Add support for getting and setting the RX buffer length via the ethtool ring parameters (ethtool -g/-G). The driver restricts the allowed buffer length to 2048 (SZ_2K) by default and allows 4096 (SZ_4K) based on device options.
As XDP is only supported when the rx_buf_len is 2048, the driver now enforces this in two places:
1. In gve_xdp_set, rejecting XDP programs if the current buffer
length is not 2048.
2. In gve_set_rx_buf_len_config, rejecting buffer length changes if XDP is loaded and the new length is not 2048.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve.h | 9 +++++ drivers/net/ethernet/google/gve/gve_ethtool.c | 13 ++++++- drivers/net/ethernet/google/gve/gve_main.c | 39 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-)
drivers/net/ethernet/google/gve/gve.h +9 -0
@@ -1172,6 +1172,12 @@ static inline bool gve_is_gqi(struct gve_priv *priv) priv->queue_format ==GVE_GQI_QPL_FORMAT ; } +static inline bool gve_is_dqo (struct gve_priv *priv) +{ +return priv->queue_format ==GVE_DQO_RDA_FORMAT || + priv->queue_format ==GVE_DQO_QPL_FORMAT ; +} +static inline u32 gve_num_tx_queues (struct gve_priv *priv) {return priv->tx_cfg.num_queues + priv->tx_cfg.num_xdp_queues;
@@ -1254,6 +1260,9 @@ void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);void gve_rx_stop_ring_gqi (struct gve_priv *priv,int idx);u16 gve_get_pkt_buf_size (const struct gve_priv *priv,bool enable_hplit);bool gve_header_split_supported (const struct gve_priv *priv); +int gve_set_rx_buf_len_config (struct gve_priv *priv,u32 rx_buf_len, +struct netlink_ext_ack *extack, +struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split,struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);/* rx buffer handling */
drivers/net/ethernet/google/gve/gve_ethtool.c +12 -1
@@ -554,6 +554,8 @@ static void gve_get_ringparam(struct net_device *netdev, cmd->rx_pending = priv->rx_desc_cnt; cmd->tx_pending = priv->tx_desc_cnt; + kernel_cmd->rx_buf_len = priv->rx_cfg.packet_buffer_size; +if (!gve_header_split_supported (priv)) kernel_cmd->tcp_data_split =ETHTOOL_TCP_DATA_SPLIT_UNKNOWN ;else if (priv->header_split_enabled)
@@ -614,6 +616,12 @@ static int gve_set_ringparam(struct net_device *netdev,int err;gve_get_curr_alloc_cfgs (priv, &tx_alloc_cfg, &rx_alloc_cfg); + + err =gve_set_rx_buf_len_config (priv, kernel_cmd->rx_buf_len, extack, + &rx_alloc_cfg); +if (err) +return err; + err =gve_set_hsplit_config (priv, kernel_cmd->tcp_data_split, &rx_alloc_cfg);if (err)
@@ -630,6 +638,8 @@ static int gve_set_ringparam(struct net_device *netdev,return err; }else {/* Set ring params for the next up */ + priv->rx_cfg.packet_buffer_size = + rx_alloc_cfg.packet_buffer_size; priv->header_split_enabled = rx_alloc_cfg.enable_header_split; priv->rx_cfg.packet_buffer_size = rx_alloc_cfg.packet_buffer_size;
@@ -971,7 +981,8 @@ static int gve_get_ts_info(struct net_device *netdev,const struct ethtool_ops gve_ethtool_ops = { .supported_coalesce_params =ETHTOOL_COALESCE_USECS , - .supported_ring_params =ETHTOOL_RING_USE_TCP_DATA_SPLIT , + .supported_ring_params =ETHTOOL_RING_USE_TCP_DATA_SPLIT | +ETHTOOL_RING_USE_RX_BUF_LEN , .get_drvinfo = gve_get_drvinfo, .get_strings = gve_get_strings, .get_sset_count = gve_get_sset_count,
drivers/net/ethernet/google/gve/gve_main.c +39 -0
@@ -1725,6 +1725,13 @@ static int gve_verify_xdp_configuration(struct net_device *dev,return -EOPNOTSUPP ; } +if (priv->rx_cfg.packet_buffer_size !=SZ_2K ) { +NL_SET_ERR_MSG_FMT_MOD (extack, +"XDP is not supported for Rx buf len %d, only %d supported." , + priv->rx_cfg.packet_buffer_size,SZ_2K ); +return -EOPNOTSUPP ; + } + max_xdp_mtu = priv->rx_cfg.packet_buffer_size -sizeof (struct ethhdr );if (priv->queue_format ==GVE_GQI_QPL_FORMAT ) max_xdp_mtu -=GVE_RX_PAD ;
@@ -2064,6 +2071,38 @@ bool gve_header_split_supported(const struct gve_priv *priv) priv->queue_format ==GVE_DQO_RDA_FORMAT && !priv->xdp_prog; } +int gve_set_rx_buf_len_config (struct gve_priv *priv,u32 rx_buf_len, +struct netlink_ext_ack *extack, +struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ +u32 old_rx_buf_len = rx_alloc_cfg->packet_buffer_size; + +if (rx_buf_len == old_rx_buf_len) +return 0 ; + +/* device options may not always contain support for 4K buffers */ +if (!gve_is_dqo (priv) || priv->max_rx_buffer_size <SZ_4K ) { +NL_SET_ERR_MSG_MOD (extack, +"Modifying Rx buf len is not supported" ); +return -EOPNOTSUPP ; + } + +if (priv->xdp_prog && rx_buf_len !=SZ_2K ) { +NL_SET_ERR_MSG_MOD (extack, +"Rx buf len can only be 2048 when XDP is on" ); +return -EINVAL ; + } + +if (rx_buf_len !=SZ_2K && rx_buf_len !=SZ_4K ) { +NL_SET_ERR_MSG_MOD (extack, +"Rx buf len can only be 2048 or 4096" ); +return -EINVAL ; + } + rx_alloc_cfg->packet_buffer_size = rx_buf_len; + +return 0 ; +} +int gve_set_hsplit_config (struct gve_priv *priv,u8 tcp_data_split,struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 186/395 gve: Advertise NETIF_F_GRO_HW instead of NETIF_F_LRO
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit e637c244b954426b84340cbc551ca0e2a32058ce ]
The device behind DQO format has always coalesced packets per stricter hardware GRO spec even though it was being advertised as LRO.
Update advertised capability to match device behavior.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve_adminq.c | 6 +++--- drivers/net/ethernet/google/gve/gve_main.c | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-)
drivers/net/ethernet/google/gve/gve_adminq.c +3 -3
@@ -791,7 +791,7 @@ static void gve_adminq_get_create_rx_queue_cmd(struct gve_priv *priv, cmd->create_rx_queue.rx_buff_ring_size =cpu_to_be16 (priv->rx_desc_cnt); cmd->create_rx_queue.enable_rsc = - !!(priv->dev->features &NETIF_F_LRO ); + !!(priv->dev->features &NETIF_F_GRO_HW );if (priv->header_split_enabled) cmd->create_rx_queue.header_buffer_size =cpu_to_be16 (priv->header_buf_size);
@@ -1123,9 +1123,9 @@ int gve_adminq_describe_device(struct gve_priv *priv)gve_set_default_rss_sizes (priv); -/* DQO supports LRO. */ +/* DQO supports HW-GRO. */ if (!gve_is_gqi (priv)) - priv->dev->hw_features |=NETIF_F_LRO ; + priv->dev->hw_features |=NETIF_F_GRO_HW ; priv->max_registered_pages =be64_to_cpu (descriptor->max_registered_pages);
drivers/net/ethernet/google/gve/gve_main.c +8 -7
@@ -1713,9 +1713,9 @@ static int gve_verify_xdp_configuration(struct net_device *dev,struct gve_priv *priv =netdev_priv (dev);u16 max_xdp_mtu; -if (dev->features &NETIF_F_LRO ) { +if (dev->features &NETIF_F_GRO_HW ) {NL_SET_ERR_MSG_MOD (extack, -"XDP is not supported when LRO is on." ); +"XDP is not supported when HW-GRO is on." );return -EOPNOTSUPP ; }
@@ -2142,12 +2142,13 @@ static int gve_set_features(struct net_device *netdev,gve_get_curr_alloc_cfgs (priv, &tx_alloc_cfg, &rx_alloc_cfg); -if ((netdev->features &NETIF_F_LRO ) != (features &NETIF_F_LRO )) { - netdev->features ^=NETIF_F_LRO ; -if (priv->xdp_prog && (netdev->features &NETIF_F_LRO )) { +if ((netdev->features &NETIF_F_GRO_HW ) != + (features &NETIF_F_GRO_HW )) { + netdev->features ^=NETIF_F_GRO_HW ; +if (priv->xdp_prog && (netdev->features &NETIF_F_GRO_HW )) {netdev_warn (netdev, -"XDP is not supported when LRO is on.\n" ); - err = -EOPNOTSUPP ; +"HW-GRO is not supported when XDP is on." ); + err = -EOPNOTSUPP ; goto revert_features; }if (netif_running (netdev)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 187/395 gve: Enable hw-gro by default if device supported
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit 3c398063ef01b02d7efd31662154fe70fd28ace6 ]
Change the driver's default behavior to enable hw-gro whenever supported for device.
Performance observations:
- We observed ~10% improvement in RX single stream throughput across various MTU sizes.
- No change in TCP_RR/TCP_CRR latencies
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve_adminq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/google/gve/gve_adminq.c +3 -1
@@ -1124,8 +1124,10 @@ int gve_adminq_describe_device(struct gve_priv *priv)gve_set_default_rss_sizes (priv);/* DQO supports HW-GRO. */ -if (!gve_is_gqi (priv)) +if (gve_is_dqo (priv)) { priv->dev->hw_features |=NETIF_F_GRO_HW ; + priv->dev->features |=NETIF_F_GRO_HW ; + } priv->max_registered_pages =be64_to_cpu (descriptor->max_registered_pages);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 188/395 gve: add support for UDP GSO for DQO format
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ankit Garg <[email protected]>
[ Upstream commit 014c607f86abc903d7bf46e13373d89392e371fe ]
Enable support for UDP GSO when using DQO format. Advertise the feature flag during device initialization and enable offload by default.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- drivers/net/ethernet/google/gve/gve_adminq.c | 8 +++-- drivers/net/ethernet/google/gve/gve_tx_dqo.c | 33 ++++++++++++++------ 2 files changed, 29 insertions(+), 12 deletions(-)
drivers/net/ethernet/google/gve/gve_adminq.c +5 -3
@@ -1123,10 +1123,12 @@ int gve_adminq_describe_device(struct gve_priv *priv)gve_set_default_rss_sizes (priv); -/* DQO supports HW-GRO. */ +/* DQO supports HW-GRO and UDP_GSO */ if (gve_is_dqo (priv)) { - priv->dev->hw_features |=NETIF_F_GRO_HW ; - priv->dev->features |=NETIF_F_GRO_HW ; +u64 additional_features =NETIF_F_GRO_HW |NETIF_F_GSO_UDP_L4 ; + + priv->dev->hw_features |= additional_features; + priv->dev->features |= additional_features; } priv->max_registered_pages =
drivers/net/ethernet/google/gve/gve_tx_dqo.c +24 -9
@@ -575,9 +575,11 @@ static void gve_tx_fill_pkt_desc_dqo(struct gve_tx_ring *tx, u32 *desc_idx,*/ static int gve_prep_tso (struct sk_buff *skb) { +struct skb_shared_info *shinfo =skb_shinfo (skb); +u32 paylen, l4_start;struct tcphdr *tcp; +struct udphdr *udp;int header_len; -u32 paylen;int err;/* Note: HW requires MSS (gso_size) to be <= 9728 and the total length
@@ -588,21 +590,34 @@ static int gve_prep_tso(struct sk_buff *skb)* - Kernel will not produce a TSO larger than 64k */ -if (unlikely (skb_shinfo (skb)->gso_size <GVE_TX_MIN_TSO_MSS_DQO )) +if (unlikely (shinfo->gso_size <GVE_TX_MIN_TSO_MSS_DQO ))return -1 ; -if (!(skb_shinfo (skb)->gso_type & (SKB_GSO_TCPV4 |SKB_GSO_TCPV6 ))) -return -EINVAL ; -/* Needed because we will modify header. */ err =skb_cow_head (skb,0 );if (err <0 )return err; - tcp =tcp_hdr (skb); - paylen = skb->len -skb_transport_offset (skb); -csum_replace_by_diff (&tcp->check, (__force __wsum )htonl (paylen)); - header_len =skb_tcp_all_headers (skb); + l4_start =skb_transport_offset (skb); + paylen = skb->len - l4_start; + +switch (shinfo->gso_type) { +case SKB_GSO_TCPV4 : +case SKB_GSO_TCPV6 : + tcp =tcp_hdr (skb); +csum_replace_by_diff (&tcp->check, + (__force __wsum )htonl (paylen)); + header_len =skb_tcp_all_headers (skb); +break ; +case SKB_GSO_UDP_L4 : + udp =udp_hdr (skb); +csum_replace_by_diff (&udp->check, + (__force __wsum )htonl (paylen)); + header_len =sizeof (struct udphdr ) + l4_start; +break ; +default : +return -EINVAL ; + }if (unlikely (header_len >GVE_TX_MAX_HDR_SIZE_DQO ))return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 189/395 gve: DQO: fix header length used by gve_can_send_tso() for UDP GSO
In reply to Greg Kroah-Hartman6.18-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.
Stable-dep-of: 3b430ea62340 ("gve: fix TX drop when GSO MSS is too small for hw")
--- 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
@@ -923,13 +923,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
Greg Kroah-Hartman
maintainerPATCH 190/395 gve: fix TX drop when GSO MSS is too small for hw
In reply to Greg Kroah-Hartman6.18-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
@@ -582,17 +582,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 )
@@ -930,6 +919,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
Greg Kroah-Hartman
maintainerPATCH 191/395 gve: DQO: reject TSO packets with an out of range MSS
In reply to Greg Kroah-Hartman6.18-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
@@ -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
@@ -582,6 +582,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 )
@@ -969,7 +983,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
Greg Kroah-Hartman
maintainerPATCH 192/395 llc: fix skb UAF and leaks on llc_mac_hdr_init() failure
In reply to Greg Kroah-Hartman6.18-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
@@ -443,7 +443,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
@@ -127,6 +127,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; }
@@ -176,6 +178,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
Greg Kroah-Hartman
maintainerPATCH 193/395 bridge: check llc_mac_hdr_init() return value in br_send_bpdu()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 194/395 net/sched: sch_teql: fix shadowed err in __teql_resolve()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 195/395 vlan: ensure sufficient headroom in vlan_dev_hard_header()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 196/395 autofs: fix sbi->pipe file reference leak in autofs_kill_sb()
In reply to Greg Kroah-Hartman6.18-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
@@ -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
Greg Kroah-Hartman
maintainerPATCH 197/395 perf/x86/intel: Ensure KVM guest PEBS path doesnt set unwanted PERF_GLOBAL_CTRL bits
In reply to Greg Kroah-Hartman6.18-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.
--- arch/x86/events/intel/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/events/intel/core.c +1 -1
@@ -4694,7 +4694,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
Greg Kroah-Hartman
maintainerPATCH 198/395 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-Hartman6.18-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).
--- arch/x86/events/intel/core.c | 55 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 18 deletions(-)
arch/x86/events/intel/core.c +37 -18
@@ -4627,12 +4627,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)++;
@@ -4679,24 +4682,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
Greg Kroah-Hartman
maintainerPATCH 199/395 perf/x86/intel: Dont pointlessly context switch DS_AREA (and PEBS config) if PEBS is unused
In reply to Greg Kroah-Hartman6.18-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.
--- arch/x86/events/intel/core.c | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-)
arch/x86/events/intel/core.c +25 -14
@@ -4665,23 +4665,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
@@ -4708,6 +4699,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
Greg Kroah-Hartman
maintainerPATCH 200/395 perf/x86/intel: Make @data a mandatory param for intel_guest_get_msrs()
In reply to Greg Kroah-Hartman6.18-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
@@ -4666,11 +4666,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
Greg Kroah-Hartman
maintainerPATCH 201/395 perf/core: Fix a refcount leak in attach_perf_ctx_data()
In reply to Greg Kroah-Hartman6.18-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().
--- kernel/events/core.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/events/core.c +2 -0
@@ -5311,6 +5311,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
Greg Kroah-Hartman
maintainerPATCH 202/395 sched/core: Account PSI IRQ time to the execution context, not the scheduling context
In reply to Greg Kroah-Hartman6.18-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.
--- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/core.c +1 -1
@@ -5613,7 +5613,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
Greg Kroah-Hartman
maintainerPATCH 203/395 mptcp: return sk_wait_data() errors from recvmsg()
In reply to Greg Kroah-Hartman6.18-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
@@ -2302,7 +2302,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
Greg Kroah-Hartman
maintainerPATCH 204/395 rculist: add list_splice_rcu() for private lists
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ]
This patch adds a helper function, list_splice_rcu(), to safely splice a private (non-RCU-protected) list into an RCU-protected list.
The function ensures that only the pointer visible to RCU readers (prev->next) is updated using rcu_assign_pointer(), while the rest of the list manipulations are performed with regular assignments, as the source list is private and not visible to concurrent RCU readers.
This is useful for moving elements from a private list into a global RCU-protected list, ensuring safe publication for RCU readers. Subsystems with some sort of batching mechanism from userspace can benefit from this new function.
The function __list_splice_rcu() has been added for clarity and to follow the same pattern as in the existing list_splice*() interfaces, where there is a check to ensure that the list to splice is not empty. Note that __list_splice_rcu() has no documentation for this reason.
--- include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
include/linux/rculist.h +29 -0
@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old, old->prev =LIST_POISON2 ; } +static inline void __list_splice_rcu (struct list_head *list, +struct list_head *prev, +struct list_head *next) +{ +struct list_head *first = list->next; +struct list_head *last = list->prev; + + last->next = next; + first->prev = prev; + next->prev = last; +rcu_assign_pointer (list_next_rcu (prev), first); +} + +/** +* list_splice_rcu - splice a non-RCU list into an RCU-protected list, +* designed for stacks. +* @list: the non RCU-protected list to splice +* @head: the place in the existing RCU-protected list to splice +* +* The list pointed to by @head can be RCU-read traversed concurrently with +* this function. +*/ +static inline void list_splice_rcu (struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) +__list_splice_rcu (list, head, head->next); +} +/** * __list_splice_init_rcu - join an RCU-protected list into an existing list. * @list: the RCU-protected list to splice
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 205/395 netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit a6134e62dba2ea4f760b29d5226907f447c92400 ]
Publish new hooks in the list into the basechain/flowtable using splice_list_rcu() to ensure netlink dump list traversal via rcu is safe while concurrent ruleset update is going on.
--- net/netfilter/nf_tables_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_tables_api.c +4 -4
@@ -10867,8 +10867,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)nft_chain_commit_update (nft_trans_container_chain (trans));nf_tables_chain_notify (&ctx,NFT_MSG_NEWCHAIN , &nft_trans_chain_hooks (trans)); -list_splice (&nft_trans_chain_hooks (trans), - &nft_trans_basechain (trans)->hook_list); +list_splice_rcu (&nft_trans_chain_hooks (trans), + &nft_trans_basechain (trans)->hook_list);/* trans destroyed after rcu grace period */ }else {nft_chain_commit_drop_policy (nft_trans_container_chain (trans));
@@ -10997,8 +10997,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)nft_trans_flowtable (trans), &nft_trans_flowtable_hooks (trans), NFT_MSG_NEWFLOWTABLE); -list_splice (&nft_trans_flowtable_hooks (trans), - &nft_trans_flowtable (trans)->hook_list); +list_splice_rcu (&nft_trans_flowtable_hooks (trans), + &nft_trans_flowtable (trans)->hook_list); }else {nft_clear (net,nft_trans_flowtable (trans)); nf_tables_flowtable_notify(&ctx,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 206/395 x86/mce: Fix hardware debug register corruption on task migration
In reply to Greg Kroah-Hartman6.18-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
@@ -2078,6 +2078,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));
@@ -2086,20 +2089,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); }
@@ -2108,21 +2117,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
@@ -2139,28 +2140,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
Greg Kroah-Hartman
maintainerPATCH 207/395 x86/PCI: Disable enhanced atomics on AMD NBIO 7.7 and 7.11
In reply to Greg Kroah-Hartman6.18-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 /*
Greg Kroah-Hartman
maintainerPATCH 208/395 virtio_net: copy zerocopy frags in start_xmit without NAPI
In reply to Greg Kroah-Hartman6.18-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
@@ -3397,6 +3397,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);
@@ -3429,6 +3437,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);
Greg Kroah-Hartman
maintainerPATCH 209/395 tipc: reject invalid and unexpected GRP_ACK_MSG to prevent bc_ackers underflow
In reply to Greg Kroah-Hartman6.18-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.
--- 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_grtipc_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)
Greg Kroah-Hartman
maintainerPATCH 210/395 tcp: prevent collapsing skbs across boundary in rtx queue
In reply to Greg Kroah-Hartman6.18-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
@@ -1151,9 +1151,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)); }
@@ -2275,7 +2275,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 ;
Greg Kroah-Hartman
maintainerPATCH 211/395 sctp: discard the rest of the packet on a stale-cookie error
In reply to Greg Kroah-Hartman6.18-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-1kNote 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:
Greg Kroah-Hartman
maintainerPATCH 212/395 af_packet: fix integer overflow in prb_calc_retire_blk_tmo()
In reply to Greg Kroah-Hartman6.18-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
@@ -615,7 +615,7 @@ static int prb_calc_retire_blk_tmo(strucreturn 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;
Greg Kroah-Hartman
maintainerPATCH 213/395 arm64/boot: Disable trapping of PMZR_EL0 writes to EL2
In reply to Greg Kroah-Hartman6.18-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.
--- 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
@@ -409,6 +409,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
@@ -417,6 +418,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
@@ -427,10 +433,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
Greg Kroah-Hartman
maintainerPATCH 214/395 arm64: errata: match the target implementation CPUs own MIDR
In reply to Greg Kroah-Hartman6.18-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().
--- 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, void *impl_cpus)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 arm64_cpu_capabilities *entry, 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 ;
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 215/395 ata: libata-scsi: bound the ATA passthru sense descriptor writes
In reply to Greg Kroah-Hartman6.18-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.
--- 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 ;
Greg Kroah-Hartman
maintainerPATCH 216/395 bna: prevent IOC timer rearm during teardown
In reply to Greg Kroah-Hartman6.18-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
@@ -2574,6 +2574,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) {
@@ -3730,9 +3746,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);
@@ -3773,9 +3787,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);
Greg Kroah-Hartman
maintainerPATCH 217/395 bpf: fs/xattr: dont assume the inode is locked in path_unlink/path_rmdir
In reply to Greg Kroah-Hartman6.18-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.
--- fs/bpf_fs_kfuncs.c | 4 ---- 1 file changed, 4 deletions(-)
fs/bpf_fs_kfuncs.c +0 -4
@@ -403,10 +403,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)
Greg Kroah-Hartman
maintainerPATCH 218/395 crypto: s390/hmac - Generate intermediate CV for API partial block handling
In reply to Greg Kroah-Hartman6.18-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.
--- arch/s390/crypto/hmac_s390.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/s390/crypto/hmac_s390.c +4 -1
@@ -151,7 +151,10 @@ static int hash_data(const u8 *in, unsig#undef PARAM_INIT -cpacf_klmd (func, ¶m, in, inlen); +if (final) +cpacf_klmd (func, ¶m, in, inlen); +else +cpacf_kimd (func, ¶m, in, inlen);memcpy (digest, ¶m, digestsize);
Greg Kroah-Hartman
maintainerPATCH 219/395 cgroup/pids: Restore pids.events notifications in local mode
In reply to Greg Kroah-Hartman6.18-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.
--- 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 ; }
Greg Kroah-Hartman
maintainerPATCH 220/395 fou: reject omitted FOU_ATTR_IPPROTO on FOU_ENCAP_DIRECT
In reply to Greg Kroah-Hartman6.18-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).
--- net/ipv4/fou_core.c | 4 ++++ 1 file changed, 4 insertions(+)
net/ipv4/fou_core.c +4 -0
@@ -603,6 +603,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;
Greg Kroah-Hartman
maintainerPATCH 221/395 fs/ntfs3: use d_instantiate_new() in ntfs_create_inode() and murder syzbots "WARNING in do_new_mount" saga
In reply to Greg Kroah-Hartman6.18-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
@@ -1668,10 +1668,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);
@@ -1719,9 +1719,6 @@ out1:if (!fnd)ni_unlock (dir_ni); -if (!err) -unlock_new_inode (inode); -return err; }
Greg Kroah-Hartman
maintainerPATCH 222/395 writeback: bound cleanup_offline_cgwb() rescans by rotating scanned inodes
In reply to Greg Kroah-Hartman6.18-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
@@ -693,19 +693,34 @@ static bool isw_prepare_wbs_switch(strucstruct 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; }/**
Greg Kroah-Hartman
maintainerPATCH 223/395 workqueue: Fix NULL current_pwq deref in flush dependency check
In reply to Greg Kroah-Hartman6.18-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.
--- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/workqueue.c +1 -1
@@ -3796,7 +3796,7 @@ static void check_flush_dependency(strucWARN_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,
Greg Kroah-Hartman
maintainerPATCH 224/395 writeback: report a Tasks-RCU quiescent state per cgwb drain pass
In reply to Greg Kroah-Hartman6.18-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.
--- 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_workfncontinue ;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);
Greg Kroah-Hartman
maintainerPATCH 225/395 fsl/fman: Fix clk reference leak in read_dts_node()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit a644f09b2090ad22a13fbcf9d141084f573108ef upstream.
of_clk_get() returns a clock with its reference count incremented, but read_dts_node() only uses it to read the rate and never calls clk_put(). The clock is not stored anywhere, so the reference cannot be released later either.
Release the clock once its rate has been read, which also covers the error path taken when the rate is zero.
--- drivers/net/ethernet/freescale/fman/fman.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/freescale/fman/fman.c +1 -0
@@ -2734,6 +2734,7 @@ static struct fman *read_dts_node(struct } clk_rate =clk_get_rate (clk); +clk_put (clk);if (!clk_rate) { err = -EINVAL ; dev_err(&of_dev->dev, "%s: Failed to determine FM%d clock rate\n",
Greg Kroah-Hartman
maintainerPATCH 226/395 ipe: fix use-after-free when auditing a newly loaded policy
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 9814077275eca36ebf8d510d2f076d235ff9f51a upstream.
new_policy() audits the policy after ipe_new_policyfs_node() publishes it and drops the new directory's inode lock. A concurrent delete can free the policy while ipe_audit_policy_load() is still using it.
Audit the successful load under that lock.
--- security/ipe/fs.c | 8 +++----- security/ipe/policy_fs.c | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-)
security/ipe/fs.c +3 -5
@@ -159,18 +159,16 @@ static ssize_t new_policy(struct file *f } rc =ipe_new_policyfs_node (p); -if (rc) - goto out; out:kfree (copy);if (rc <0 ) {ipe_free_policy (p);ipe_audit_policy_load (ERR_PTR (rc)); - }else { -ipe_audit_policy_load (p); +return rc; } -return (rc <0 ) ? rc : len; + +return len; }static const struct file_operations np_fops = {
security/ipe/policy_fs.c +3 -0
@@ -481,6 +481,9 @@ int ipe_new_policyfs_node(struct ipe_polinode_lock (root); p->policyfs = policyfs; root->i_private = p; +/* Only audit signed policies from userspace */ +if (p->pkcs7) +ipe_audit_policy_load (p);inode_unlock (root);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 227/395 ipe: protect the dm-verity root hash with RCU
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 2776e9c28513a1c855a94792b292cbcc533418c8 upstream.
ipe_bdev_setintegrity() frees the old root hash when dm-verity publishes a new one on ->preresume, while policy evaluation can still be dereferencing it.
Protect the root hash with RCU. The evaluation path already runs under rcu_read_lock().
--- security/ipe/eval.c | 12 ++++++++---- security/ipe/eval.h | 2 +- security/ipe/hooks.c | 22 +++++++++++++++++----- 3 files changed, 26 insertions(+), 10 deletions(-)
security/ipe/eval.c +8 -4
@@ -134,10 +134,14 @@ static bool evaluate_boot_verified(conststatic bool evaluate_dmv_roothash (const struct ipe_eval_ctx *const ctx,struct ipe_prop *p) { -return !!ctx->ipe_bdev && - !!ctx->ipe_bdev->root_hash && -ipe_digest_eval (p->value, - ctx->ipe_bdev->root_hash); +const struct digest_info *root_hash; + +if (!ctx->ipe_bdev) +return false; + + root_hash =rcu_dereference (ctx->ipe_bdev->root_hash); + +return root_hash &&ipe_digest_eval (p->value, root_hash); }#else static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
security/ipe/eval.h +1 -1
@@ -27,7 +27,7 @@ struct ipe_bdev {#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE bool dm_verity_signed;#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ - struct digest_info *root_hash; + struct digest_info __rcu *root_hash; };#endif /* CONFIG_IPE_PROP_DM_VERITY */
security/ipe/hooks.c +17 -5
@@ -9,6 +9,7 @@#include <linux/binfmts.h> #include <linux/mman.h> #include <linux/blk_types.h> +#include <linux/rcupdate.h> #include "ipe.h" #include "hooks.h"
@@ -204,7 +205,20 @@ void ipe_bdev_free_security(struct block {struct ipe_bdev *blob =ipe_bdev (bdev); -ipe_digest_free (blob->root_hash); +ipe_digest_free (rcu_access_pointer (blob->root_hash)); +} + +static void ipe_set_dmverity_roothash (struct ipe_bdev *blob, +struct digest_info *info) +{ +struct digest_info *old; + +/* Protected by device-mapper's md->suspend_lock */ + old =rcu_replace_pointer (blob->root_hash, info, true); +if (old) { +synchronize_rcu (); +ipe_digest_free (old); + } }#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
@@ -252,8 +266,7 @@ int ipe_bdev_setintegrity(struct block_dreturn -EINVAL ;if (!value) { -ipe_digest_free (blob->root_hash); - blob->root_hash =NULL ; +ipe_set_dmverity_roothash (blob,NULL );return 0 ; }
@@ -273,8 +286,7 @@ int ipe_bdev_setintegrity(struct block_d info->digest_len = digest->digest_len; -ipe_digest_free (blob->root_hash); - blob->root_hash = info; +ipe_set_dmverity_roothash (blob, info);return 0 ; err:
Greg Kroah-Hartman
maintainerPATCH 228/395 ipv6: do not let ipv6_find_hdr() return an offset past the packet end
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit ee319bd3a0e976af5087cbe59ebc50a66f31d202 upstream.
ipv6_find_hdr() walks the extension header chain, skipping each header by the length that header itself declares. ipv6_optlen() returns up to 2048, and the skip is never checked against skb->len, so the offset stored in *offset can point past the end of the packet.
openvswitch installs that offset as the transport header, and update_ipv6_checksum() then reads and writes the transport checksum field out of bounds:
BUG: KASAN: slab-use-after-free in inet_proto_csum_replace16+0x445/0x470 Read of size 2 at addr ffff88810b754b06 by task ovs_ipv6_oob/629 CPU: 4 UID: 1000 PID: 629 Comm: ovs_ipv6_oob Tainted: G N 7.3.0-rc3+ #348 Call Trace: inet_proto_csum_replace16+0x445/0x470 set_ipv6_addr+0x3dd/0x460 do_execute_actions+0x6a3d/0x7c40 ovs_execute_actions+0xfd/0x480 ovs_packet_cmd_execute+0xc38/0xf20 genl_rcv_msg+0x59e/0x870 netlink_rcv_skb+0x18b/0x450 genl_rcv+0x2d/0x40 netlink_unicast+0x6bc/0xa20 The buggy address belongs to the object at ffff88810b754980 which belongs to the cache skbuff_small_head of size 704 The buggy address is located 390 bytes inside of freed 704-byte region [ffff88810b754980, ffff88810b754c40)
Other callers use that offset too, so bound it here rather than in one caller.
Reject a header whose declared length does not fit in the packet. ipv6_find_hdr() already fails with -EBADMSG on a malformed chain, so this adds no new failure mode.
--- net/ipv6/exthdrs_core.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/exthdrs_core.c +3 -0
@@ -271,6 +271,9 @@ int ipv6_find_hdr(const struct sk_buff * hdrlen =ipv6_optlen (hp);if (!found) { +if (skb->len - start < hdrlen) +return -EBADMSG ; + nexthdr = hp->nexthdr; start += hdrlen; }
Greg Kroah-Hartman
maintainerPATCH 229/395 ipv6: sr: enforce exact attribute length for SEG6_ATTR_DST
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Peng <[email protected]>
commit 2d959c75c27f90e9ec489d18ce5ee6b852ad4741 upstream.
In seg6_genl_policy, SEG6_ATTR_DST is defined with .type = NLA_BINARY and .len = sizeof(struct in6_addr). For NLA_BINARY, .len only enforces the maximum payload length and permits shorter payloads (e.g., 0 bytes). When seg6_genl_set_tunsrc() copies sizeof(struct in6_addr) bytes via kmemdup(val, sizeof(*val), GFP_KERNEL), a short SEG6_ATTR_DST attribute triggers a 16-byte out-of-bounds read past skb->tail into uninitialized skb->head memory, which is stored in sdata->tun_src and leaked back to userspace via SEG6_CMD_GET_TUNSRC.
Switch SEG6_ATTR_DST in seg6_genl_policy to NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)) so that generic netlink validation rejects any attribute whose length is not exactly sizeof(struct in6_addr) with -ERANGE.
Tested in QEMU against Linux 7.3.0-rc3 by sending a SEG6_CMD_SET_TUNSRC Generic Netlink message with a 0-byte SEG6_ATTR_DST attribute followed by SEG6_CMD_GET_TUNSRC. On the unfixed kernel, SEG6_CMD_SET_TUNSRC succeeds (err = 0) and SEG6_CMD_GET_TUNSRC leaks 16 bytes of uninitialized kernel heap memory (tun_src = 836a61ecc4d25a1042a8d60411cfb378); with this patch applied, SEG6_CMD_SET_TUNSRC is rejected by netlink policy validation with -ERANGE (-34) and tun_src remains zeroed.
--- net/ipv6/seg6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/seg6.c +2 -2
@@ -138,8 +138,8 @@ out:static struct genl_family seg6_genl_family;static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX +1 ] = { - [SEG6_ATTR_DST ] = { .type =NLA_BINARY , - .len =sizeof (struct in6_addr ) }, + [SEG6_ATTR_DST ] = +NLA_POLICY_EXACT_LEN (sizeof (struct in6_addr )), [SEG6_ATTR_DSTLEN ] = { .type =NLA_S32 , }, [SEG6_ATTR_HMACKEYID ] = { .type =NLA_U32 , }, [SEG6_ATTR_SECRET ] = { .type =NLA_BINARY , },
Greg Kroah-Hartman
maintainerPATCH 230/395 gpio: arizona: Fix runtime PM leak in arizona_gpio_direction_out()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit e9d810279f84b30738f7790c0ed15f8dd5b9024a upstream.
Switching a persistent GPIO line from input to output acquires a runtime PM reference on the parent device, but if the subsequent regmap_update_bits() fails the reference is never dropped and no later direction_in() can balance it since the direction was never changed. Drop the reference on the update failure path.
--- drivers/gpio/gpio-arizona.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpio/gpio-arizona.c +6 -2
@@ -115,8 +115,12 @@ static int arizona_gpio_direction_out(stif (value) value =ARIZONA_GPN_LVL ; -return regmap_update_bits (arizona->regmap,ARIZONA_GPIO1_CTRL + offset, -ARIZONA_GPN_DIR |ARIZONA_GPN_LVL , value); + ret =regmap_update_bits (arizona->regmap,ARIZONA_GPIO1_CTRL + offset, +ARIZONA_GPN_DIR |ARIZONA_GPN_LVL , value); +if (ret <0 && (val &ARIZONA_GPN_DIR ) && persistent) +pm_runtime_put_autosuspend (chip->parent); + +return ret; } static int arizona_gpio_set(struct gpio_chip *chip, unsigned int offset,
Greg Kroah-Hartman
maintainerPATCH 231/395 gpio: cdev: fix kernel stack leak to user-space in error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit 1feb5d39b05afd902ed9fc902ec5b15be03a4bdb upstream.
If we fail to acquire the GPIO chip guard in gpio_desc_to_lineinfo(), we return immediately before zeroing the info struct we'll end up passing to the user-space later in lineinfo_get_v1(). This may leak the kernel stack contents. Make gpio_desc_to_lineinfo() return int so that the -ENODEV returned on failure to acquire the guard can be propagated to the callers.
While not strictly necessary: move the memset() before trying to acquire the SRCU read lock too for good measure.
--- drivers/gpio/gpiolib-cdev.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
drivers/gpio/gpiolib-cdev.c +25 -7
@@ -2245,18 +2245,19 @@ static void gpio_v2_line_info_changed_to#endif /* CONFIG_GPIO_CDEV_V1 */ -static void gpio_desc_to_lineinfo (struct gpio_desc *desc, -struct gpio_v2_line_info *info,bool atomic) +static int gpio_desc_to_lineinfo (struct gpio_desc *desc, +struct gpio_v2_line_info *info,bool atomic) {u32 debounce_period_us;unsigned long dflags;const char *label; +memset (info,0 ,sizeof (*info)); +CLASS (gpio_chip_guard, guard)(desc);if (!guard.gc) -return ; +return -ENODEV ; -memset (info,0 ,sizeof (*info)); info->offset =gpiod_hwgpio (desc);if (desc->name)
@@ -2331,6 +2332,8 @@ static void gpio_desc_to_lineinfo(struct debounce_period_us; info->num_attrs++; } + +return 0 ; }struct gpio_chardev_data {
@@ -2382,6 +2385,7 @@ static int lineinfo_get_v1(struct gpio_cstruct gpio_desc *desc;struct gpioline_info lineinfo;struct gpio_v2_line_info lineinfo_v2; +int ret;if (copy_from_user (&lineinfo, ip,sizeof (lineinfo)))return -EFAULT ;
@@ -2399,7 +2403,10 @@ static int lineinfo_get_v1(struct gpio_creturn -EBUSY ; } -gpio_desc_to_lineinfo (desc, &lineinfo_v2, false); + ret =gpio_desc_to_lineinfo (desc, &lineinfo_v2, false); +if (ret) +return ret; +gpio_v2_line_info_to_v1 (&lineinfo_v2, &lineinfo);if (copy_to_user (ip, &lineinfo,sizeof (lineinfo))) {
@@ -2417,6 +2424,7 @@ static int lineinfo_get(struct gpio_char {struct gpio_desc *desc;struct gpio_v2_line_info lineinfo; +int ret;if (copy_from_user (&lineinfo, ip,sizeof (lineinfo)))return -EFAULT ;
@@ -2436,7 +2444,10 @@ static int lineinfo_get(struct gpio_charif (test_and_set_bit (lineinfo.offset, cdev->watched_lines))return -EBUSY ; } -gpio_desc_to_lineinfo (desc, &lineinfo, false); + + ret =gpio_desc_to_lineinfo (desc, &lineinfo, false); +if (ret) +return ret;if (copy_to_user (ip, &lineinfo,sizeof (lineinfo))) {if (watch)
@@ -2562,6 +2573,7 @@ static int lineinfo_changed_notify(strucstruct lineinfo_changed_ctx *ctx;struct gpio_desc *desc = data;struct file *fp; +int ret;if (!test_bit (gpiod_hwgpio (desc), cdev->watched_lines))return NOTIFY_DONE ;
@@ -2592,7 +2604,13 @@ static int lineinfo_changed_notify(struc ctx->chg.event_type = action; ctx->chg.timestamp_ns =ktime_get_ns (); -gpio_desc_to_lineinfo (desc, &ctx->chg.info, true); + + ret =gpio_desc_to_lineinfo (desc, &ctx->chg.info, true); +if (ret) { +fput (fp); +return NOTIFY_DONE ; + } +/* Keep the GPIO device alive until we emit the event. */ ctx->gdev =gpio_device_get (desc->gdev); ctx->cdev = cdev;
Greg Kroah-Hartman
maintainerPATCH 232/395 gpio: zynq: fix runtime PM leak on request error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ridham Khurana <[email protected]>
commit e9438ab5328a177c9c0e5df87eb92a7162841e98 upstream.
pm_runtime_get_sync() leaves the usage counter incremented even when it fails, and zynq_gpio_request() returns the error without dropping it.
gpiolib does not call ->free() when ->request() fails, so zynq_gpio_free(), which holds the only matching pm_runtime_put(), never runs. The reference is leaked and the controller can no longer runtime-suspend, so its clock stays enabled.
Switch to pm_runtime_resume_and_get(), which only increments the usage counter on success.
--- drivers/gpio/gpio-zynq.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
drivers/gpio/gpio-zynq.c +1 -9
@@ -797,15 +797,7 @@ static int __maybe_unused zynq_gpio_runtstatic int zynq_gpio_request (struct gpio_chip *chip,unsigned int offset) { -int ret; - - ret =pm_runtime_get_sync (chip->parent); - -/* -* If the device is already active pm_runtime_get() will return 1 on -* success, but gpio_request still needs to return 0. -*/ -return ret <0 ? ret :0 ; +return pm_runtime_resume_and_get (chip->parent); }static void zynq_gpio_free (struct gpio_chip *chip,unsigned int offset)
Greg Kroah-Hartman
maintainerPATCH 233/395 llc: reserve device headroom for allocated frames
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zixuan Chai <[email protected]>
commit 72b5b9a28b996e09b8b5b944370c79851bb68f52 upstream.
llc_alloc_frame() reserves link-layer headroom using the device type. This is insufficient for stacked Ethernet devices such as VLAN devices, where vlan_dev_hard_header() pushes a VLAN header before the lower device's Ethernet header. An LLC response on such a device can therefore underflow skb headroom in eth_header().
Use LL_RESERVED_SPACE() to account for the device's actual required headroom while preserving the existing LLC device-type check.
--- net/llc/llc_sap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/llc/llc_sap.c +4 -4
@@ -25,12 +25,12 @@#include <linux/llc.h> #include <linux/slab.h> -static int llc_mac_header_len (unsigned short devtype) +static int llc_mac_header_len (struct net_device *dev) { -switch (devtype) { +switch (dev->type) {case ARPHRD_ETHER :case ARPHRD_LOOPBACK : -return sizeof (struct ethhdr ); +return LL_RESERVED_SPACE (dev); }return 0 ; }
@@ -51,7 +51,7 @@ struct sk_buff *llc_alloc_frame(struct sint hlen = type ==LLC_PDU_TYPE_U ?3 :4 ;struct sk_buff *skb; - hlen +=llc_mac_header_len (dev->type); + hlen +=llc_mac_header_len (dev); skb =alloc_skb (hlen + data_size,GFP_ATOMIC );if (skb) {
Greg Kroah-Hartman
maintainerPATCH 234/395 mctp: route: iterate socket tag list in mctp_lookup_prealloc_tag()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Peng <[email protected]>
commit 26cc0e69cce062cd3aa6fae33074684669c35a71 upstream.
When a socket transmits a packet with MCTP_TAG_PREALLOC set, mctp_lookup_prealloc_tag() iterates over the per-netns &mns->keys list and matches netid, req_tag, peer_addr, and manual_alloc, without checking whether tmp->sk == &msk->sk. This allows any MCTP socket in the same network namespace to use and consume another socket's preallocated tag.
Iterate the socket's own tag list (&msk->keys via sklist) instead of the namespace-wide &mns->keys list in mctp_lookup_prealloc_tag(), ensuring that only tags allocated by msk are matched.
Tested in QEMU against Linux 7.3.0-rc3 by allocating a manual tag (0x18) on socket A via SIOCMCTPALLOCTAG for peer EID 9 and sending a 4-byte message with MCTP_TAG_PREALLOC from socket B in the same network namespace. On the unfixed kernel, sendto(sock_b) using socket A's preallocated tag succeeds (ret = 4); with this patch applied, sendto(sock_b) fails with -ENOENT (errno = 2) while sendto(sock_a) succeeds (ret = 4).
--- net/mctp/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mctp/route.c +1 -1
@@ -825,7 +825,7 @@ static struct mctp_sk_key *mctp_lookup_pspin_lock_irqsave (&mns->keys_lock, flags); -hlist_for_each_entry (tmp, &mns->keys, hlist) { +hlist_for_each_entry (tmp, &msk->keys, sklist) {if (tmp->net != netid)continue ;
Greg Kroah-Hartman
maintainerPATCH 235/395 rds: ib: Clear the sg list when mapping an MR fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongliang Qin <[email protected]>
commit 58eb1b3325edac42dc6df72c80962bd53a3c8ca7 upstream.
rds_ib_map_frmr() stores the caller's scatterlist in the MR before DMA mapping and registration can fail. On failure, __rds_rdma_map() unpins the pages and frees the scatterlist, but rds_ib_free_frmr() can still return the MR to the pool with the stale pointer set.
This leaves the pool with a dangling scatterlist and can lead to local privilege escalation. KASAN detects the resulting use-after-free when the MR is later torn down:
BUG: KASAN: slab-use-after-free in __rds_ib_teardown_mr Read of size 8 Call Trace: __rds_ib_teardown_mr rds_ib_unreg_frmr rds_ib_flush_mr_pool rds_ib_flush_mrs rds_free_mr rds_setsockopt
Store the scatterlist in the MR only after DMA mapping succeeds. If DMA mapping fails, return directly while the MR fields remain clear; the caller keeps ownership of the scatterlist and its pinned pages. If a later registration step fails, unmap the scatterlist and clear the MR fields before returning.
--- net/rds/ib_frmr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/rds/ib_frmr.c +5 -6
@@ -204,19 +204,16 @@ static int rds_ib_map_frmr(struct rds_ib*/ rds_ib_teardown_mr (ibmr); - ibmr->sg = sg; - ibmr->sg_len = sg_len; - ibmr->sg_dma_len =0 ; frmr->sg_byte_len =0 ; -WARN_ON (ibmr->sg_dma_len); - ibmr->sg_dma_len =ib_dma_map_sg (dev, ibmr->sg, ibmr->sg_len, + ibmr->sg_dma_len =ib_dma_map_sg (dev, sg, sg_len,DMA_BIDIRECTIONAL );if (unlikely (!ibmr->sg_dma_len)) {pr_warn ("RDS/IB: %s failed!\n" , __func__);return -EBUSY ; } - frmr->sg_byte_len =0 ; + ibmr->sg = sg; + ibmr->sg_len = sg_len; frmr->dma_npages =0 ; len =0 ;
@@ -264,6 +261,8 @@ out_unmap:ib_dma_unmap_sg (rds_ibdev->dev, ibmr->sg, ibmr->sg_len,DMA_BIDIRECTIONAL ); ibmr->sg_dma_len =0 ; + ibmr->sg =NULL ; + ibmr->sg_len =0 ;return ret; }
Greg Kroah-Hartman
maintainerPATCH 236/395 drm/imagination: Propagate map failures correctly from pvr_mmu_map_sgl()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brajesh Gupta <[email protected]>
commit 7b824c293a6b56de8285a97984c507cba56bc4c4 upstream.
Map failure from pvr_mmu_map_sgl() interface was not returned correctly to pvr_mmu_map() interface. This resulted in pvr_mmu_map() interface to continue instead of returning an error to caller.
Fix it by returning a proper error code from pvr_mmu_map_sgl() interface.
Call stack for crash:
[ 1179.286237] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 [ 1179.295067] Mem abort info: [ 1179.297877] ESR = 0x0000000096000004 [ 1179.301656] EC = 0x25: DABT (current EL), IL = 32 bits [ 1179.306987] SET = 0, FnV = 0 [ 1179.310048] EA = 0, S1PTW = 0 [ 1179.313198] FSC = 0x04: level 0 translation fault [ 1179.318096] Data abort info: [ 1179.320993] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 1179.326483] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 1179.331546] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 1179.336895] user pgtable: 4k pages, 48-bit VAs, pgdp=000000009822a000 [ 1179.343402] [0000000000000008] pgd=0000000000000000, p4d=0000000000000000 [ 1179.350243] Internal error: Oops: 0000000096000004 [#2] SMP [ 1179.355908] Modules linked in: powervr gpu_sched drm_shmem_helper drm_gpuvm drm_exec xhci_plat_hcd xhci_hcd dwc3 usbcore usb_common snd_soc_simple_card snd_soc_simple_card_utils dwc3_am62 at24 sa2ul sha512 libsha512 sha256 authenc sch_fq_codel fuse dm_mod ipv6 [ 1179.378992] CPU: 1 UID: 1000 PID: 680 Comm: deqp-vk Tainted: G D 6.17.0 #1 PREEMPT [ 1179.388120] Tainted: [D]=DIE [ 1179.390994] Hardware name: Texas Instruments AM625 SK (DT) [ 1179.396467] pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 1179.403415] pc : pvr_mmu_op_context_unmap_curr_page+0x6c/0x134 [powervr] [ 1179.410140] lr : pvr_mmu_op_context_unmap_curr_page+0x58/0x134 [powervr] [ 1179.416848] sp : ffff8000839ab8c0 [ 1179.420153] x29: ffff8000839ab8c0 x28: 0000000000000001 x27: 000000008f386000 [ 1179.427283] x26: ffff000016d1df98 x25: 0000000000247000 x24: 00000000000001e6 [ 1179.434413] x23: 0000000000000002 x22: 000000000000ffff x21: 0000000000000247 [ 1179.441540] x20: 0000000000000245 x19: ffff000016d1df60 x18: 0000000000000002 [ 1179.448668] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000001 [ 1179.455793] x14: 0000000000060810 x13: ffff80007fffffff x12: ffff000004190480 [ 1179.462921] x11: ffff8000853f7000 x10: ffff8000811ae000 x9 : ffff0000041900b8 [ 1179.470051] x8 : 0000000000000000 x7 : 00000000990c4001 x6 : 0000000000000007 [ 1179.477177] x5 : ffff000016d1df60 x4 : 0000000000000000 x3 : ffff00000a7d8000 [ 1179.484306] x2 : 00000000000001ff x1 : 0000000000000000 x0 : 0000000000000000 [ 1179.491433] Call trace: [ 1179.493872] pvr_mmu_op_context_unmap_curr_page+0x6c/0x134 [powervr] (P) [ 1179.500582] pvr_mmu_map+0x31c/0x388 [powervr] [ 1179.505027] pvr_vm_gpuva_map+0x40/0x88 [powervr] [ 1179.509732] __drm_gpuvm_sm_map+0x250/0x44c [drm_gpuvm] [ 1179.514952] drm_gpuvm_sm_map+0x48/0x5c [drm_gpuvm] [ 1179.519822] pvr_vm_bind_op_exec+0x64/0x70 [powervr] [ 1179.524785] pvr_vm_map+0x1f8/0x2a8 [powervr] [ 1179.529142] pvr_ioctl_vm_map+0x12c/0x188 [powervr] [ 1179.534018] drm_ioctl_kernel+0xb8/0x128 [ 1179.537941] drm_ioctl+0x21c/0x4ec [ 1179.541337] __arm64_sys_ioctl+0xac/0x108 [ 1179.545344] invoke_syscall+0x44/0x100 [ 1179.549091] el0_svc_common.constprop.0+0x40/0xe0 [ 1179.553790] do_el0_svc+0x1c/0x28 [ 1179.557106] el0_svc+0x34/0xf0 [ 1179.560159] el0t_64_sync_handler+0xd0/0xe4 [ 1179.564334] el0t_64_sync+0x198/0x19c [ 1179.567996] Code: 54000300 35000360 f9402261 79409a62 (f9400421) [ 1179.574081] ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/imagination/pvr_mmu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/imagination/pvr_mmu.c +4 -1
@@ -12,6 +12,7 @@#include "pvr_rogue_mmu_defs.h" #include <drm/drm_drv.h> +#include <drm/drm_print.h> #include <linux/atomic.h> #include <linux/bitops.h> #include <linux/dma-mapping.h>
@@ -2556,7 +2557,9 @@ pvr_mmu_map_sgl(struct pvr_mmu_op_contex err_destroy_pages:memcpy (&op_ctx->curr_page, &ptr_copy,sizeof (op_ctx->curr_page)); - err =pvr_mmu_op_context_unmap_curr_page (op_ctx, page); +if (pvr_mmu_op_context_unmap_curr_page (op_ctx, page)) +drm_err (from_pvr_device (op_ctx->mmu_ctx->pvr_dev), +"%s : Failure in unmapping pages\n" , __func__);return err; }
Greg Kroah-Hartman
maintainerPATCH 237/395 drm/imagination: Fix page count for page table for map() interface
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brajesh Gupta <[email protected]>
commit 0a8224058a5835297dcf4a46bbcd16f77a9fe424 upstream.
The GPU virtual start address wasn't included in the calculation for the amount of page tables required for mapping a BO object in map() interface. It resulted in map failure later due to not enough pages at L0/L1 level. Update pvr_mmu_op_context_create() interface to pass device address as well to allow correct calculation for page table memory.
If L0 tables cover 2MB (0x200000), the range defined by device address 0x80001ff000 (general heap at 2MB - 4KB) and size 0x2000 (two 4KB pages) requires two L0 pages to be mapped, but without the base address a range of 0x2000 computes to a single L0 page which is not enough.
--- drivers/gpu/drm/imagination/pvr_mmu.c | 14 ++++++++------ drivers/gpu/drm/imagination/pvr_mmu.h | 2 +- drivers/gpu/drm/imagination/pvr_vm.c | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-)
drivers/gpu/drm/imagination/pvr_mmu.c +8 -6
@@ -2338,6 +2338,7 @@ void pvr_mmu_op_context_destroy(struct p* pvr_mmu_op_context_create() - Create an MMU op context. * @ctx: MMU context associated with owning VM context. * @sgt: Scatter gather table containing pages pinned for use by this context. +* @device_addr: Virtual device address at the start of the requested mapping. * @sgt_offset: Start offset of the requested device-virtual memory mapping. * @size: Size in bytes of the requested device-virtual memory mapping. For an * unmapping, this should be zero so that no page tables are allocated.
@@ -2349,8 +2350,9 @@ void pvr_mmu_op_context_destroy(struct p*/ struct pvr_mmu_op_context *pvr_mmu_op_context_create (struct pvr_mmu_context *ctx,struct sg_table *sgt, -u64 sgt_offset,u64 size) +u64 device_addr,u64 sgt_offset,u64 size) { +u64 start_addr = device_addr + sgt_offset;int err; struct pvr_mmu_op_context *op_ctx =
@@ -2367,16 +2369,16 @@ pvr_mmu_op_context_create(struct pvr_mmuif (size) {/* * The number of page table objects we need to prealloc is -* indicated by the mapping size, start offset and the sizes +* indicated by the mapping size, start address and the sizes * of the areas mapped per PT or PD. The range calculation is * identical to that for the index into a table for a device * address, so we reuse those functions here. */ -const u32 l1_start_idx =pvr_page_table_l2_idx (sgt_offset); -const u32 l1_end_idx =pvr_page_table_l2_idx (sgt_offset + size); +const u32 l1_start_idx =pvr_page_table_l2_idx (start_addr); +const u32 l1_end_idx =pvr_page_table_l2_idx (start_addr + size);const u32 l1_count = l1_end_idx - l1_start_idx +1 ; -const u32 l0_start_idx =pvr_page_table_l1_idx (sgt_offset); -const u32 l0_end_idx =pvr_page_table_l1_idx (sgt_offset + size); +const u32 l0_start_idx =pvr_page_table_l1_idx (start_addr); +const u32 l0_end_idx =pvr_page_table_l1_idx (start_addr + size);const u32 l0_count = l0_end_idx - l0_start_idx +1 ;/*
drivers/gpu/drm/imagination/pvr_mmu.h +1 -1
@@ -99,7 +99,7 @@ dma_addr_t pvr_mmu_get_root_table_dma_advoid pvr_mmu_op_context_destroy (struct pvr_mmu_op_context *op_ctx);struct pvr_mmu_op_context *pvr_mmu_op_context_create (struct pvr_mmu_context *ctx, -struct sg_table *sgt,u64 sgt_offset,u64 size); +struct sg_table *sgt,u64 device_addr,u64 sgt_offset,u64 size);int pvr_mmu_map (struct pvr_mmu_op_context *op_ctx,u64 size,u64 flags,u64 device_addr);
drivers/gpu/drm/imagination/pvr_vm.c +2 -2
@@ -275,7 +275,7 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bi goto err_bind_op_fini; bind_op->mmu_op_ctx = -pvr_mmu_op_context_create (vm_ctx->mmu_ctx, sgt, offset, size); +pvr_mmu_op_context_create (vm_ctx->mmu_ctx, sgt, device_addr, offset, size); err =PTR_ERR_OR_ZERO (bind_op->mmu_op_ctx);if (err) { bind_op->mmu_op_ctx =NULL ;
@@ -317,7 +317,7 @@ pvr_vm_bind_op_unmap_init(struct pvr_vm_ } bind_op->mmu_op_ctx = -pvr_mmu_op_context_create (vm_ctx->mmu_ctx,NULL ,0 ,0 ); +pvr_mmu_op_context_create (vm_ctx->mmu_ctx,NULL , device_addr,0 ,0 ); err =PTR_ERR_OR_ZERO (bind_op->mmu_op_ctx);if (err) { bind_op->mmu_op_ctx =NULL ;
Greg Kroah-Hartman
maintainerPATCH 238/395 drm/i915: fix incorrect RCU teardown order
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
commit d2da6696e0c4e60414706e607029d0bb0330c67e upstream.
i915_gem_busy_ioctl uses dma_resv_for_each_fence_unlocked() to iterate over the fences in an GEM object without holding a reference but only the RCU read side lock.
What can happen here is that the GEM object is destroyed concurrently while i915_gem_busy_ioctl is still running. This won't free the GEM objects memory, but still drops all the dma_fence references.
Now when dma_resv_for_each_fence_unlocked() sees a destroyed dma_fence it assumes that a new fence list was installed and re-starts the loop.
But in the case of a destroyed GEM object a new fence list is never installed, only the old one freed and therefore the iteration never finishes resulting in an endless loop.
The solution is to drop the fence references only after the RCU grace period.
The fixes tag is not necessary the patch introducing the problem, but the one making it so worse that we need to address it.
This problem was pointed out by Sashiko-bot.
--- drivers/gpu/drm/i915/gem/i915_gem_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gem/i915_gem_object.c +1 -1
@@ -88,6 +88,7 @@ struct drm_i915_gem_object *i915_gem_objvoid i915_gem_object_free (struct drm_i915_gem_object *obj) { +dma_resv_fini (&obj->base._resv);return kmem_cache_free (slab_objects, obj); }
@@ -143,7 +144,6 @@ void __i915_gem_object_fini(struct drm_i {mutex_destroy (&obj->mm.get_page.lock);mutex_destroy (&obj->mm.get_dma_page.lock); -dma_resv_fini (&obj->base._resv); }/**
Greg Kroah-Hartman
maintainerPATCH 239/395 drm/i915/dp_mst: Fix configuring FEC for a disconnected stream
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imre Deak <[email protected]>
commit acbe9a3b60b9a6ace8ef11fe898f586251c84592 upstream.
During an atomic commit after all the MST stream CRTC state is computed the driver ensures that the FEC is configured the same way (enabled or disabled) for all the streams on a given MST topology's link. drm_dp_mst_port_downstream_of_parent() used to determine if a stream is downstream of an MST port will return false if the whole topology is disconnected, since in that case it can't verify that the port/ parent_port passed to it is in the given MST topology. This is a problem during the above FEC configuration check, since intel_dp_mst_check_dsc_change()->get_pipes_downstream_of_mst_ports() will not return all the stream CRTCs/pipes for the topology as expected. Since passing parent_port==NULL to get_pipes_downstream_of_mst_port() is meant to return all the streams for the given topology (i.e. mst_mgr) skip checking if an MST port is downstream of a parent port in this case.
This fixes a problem where the FEC configuration check explained above failed to ensure that all streams' FEC is configured the same way if the topology was disconnected, leading to a FEC state mismatch error.
--- drivers/gpu/drm/i915/display/intel_dp_mst.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp_mst.c +2 -1
@@ -799,7 +799,8 @@ static u8 get_pipes_downstream_of_mst_poif (&connector->mst.dp->mst.mgr != mst_mgr)continue ; -if (connector->mst.port != parent_port && +if (parent_port && + connector->mst.port != parent_port && !drm_dp_mst_port_downstream_of_parent (mst_mgr, connector->mst.port, parent_port))
Greg Kroah-Hartman
maintainerPATCH 240/395 drm/i915/dp_mst: Fix configuring TUs for a disconnected stream
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imre Deak <[email protected]>
commit a443e0b8d647c1401b110d9f919d8c6cb8607260 upstream.
During an atomic commit after all the MST stream CRTC state is computed the driver ensures that the sum of TUs of all the streams on a given MST topology link is within limits (63 for 8b10 and 64 for 128b132b). For a disconnected stream the DRM MST core's BW verification doesn't ensure this, because the topology state it uses for this is destroyed as soon as the stream (i.e. MST connector/port) is disconnected. The driver should keep the link state valid even for such disconnected streams, as userspace may disable them one-by-one only in a deferred way. Ensure the link's sum of TUs stays within limits in this case by simply reusing the maximum link BPP limit from the stream's (i.e. CRTC's) old state.
The disconnection can happen either via the whole topology getting disconnected or via only the given stream's port getting disconnected. Check for both of these conditions separately, as a connector gets unregistered after a link disconnect event only in a deferred way.
--- drivers/gpu/drm/i915/display/intel_dp_mst.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.h | 2 ++ drivers/gpu/drm/i915/display/intel_link_bw.c | 3 ++- 3 files changed, 25 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp_mst.c +21 -0
@@ -2070,6 +2070,27 @@ bool intel_dp_mst_crtc_needs_modeset(strreturn false; } +bool intel_dp_mst_stream_disconnected (struct intel_atomic_state *state, +const struct intel_crtc *crtc) +{ +struct intel_connector *connector; + + connector =get_connector_in_state_for_crtc (state, crtc); +if (!connector) +return false; + +if (!connector->mst.dp) +return false; + +if (!connector->mst.dp->mst.mgr.mst_state) +return true; + +if (drm_connector_is_unregistered (&connector->base)) +return true; + +return false; +} +/** * intel_dp_mst_prepare_probe - Prepare an MST link for topology probing * @intel_dp: DP port object
drivers/gpu/drm/i915/display/intel_dp_mst.h +2 -0
@@ -28,6 +28,8 @@ int intel_dp_mst_atomic_check_link(struc struct intel_link_bw_limits *limits);bool intel_dp_mst_crtc_needs_modeset (struct intel_atomic_state *state,struct intel_crtc *crtc); +bool intel_dp_mst_stream_disconnected (struct intel_atomic_state *state, +const struct intel_crtc *crtc);void intel_dp_mst_prepare_probe (struct intel_dp *intel_dp);bool intel_dp_mst_verify_dpcd_state (struct intel_dp *intel_dp);
drivers/gpu/drm/i915/display/intel_link_bw.c +2 -1
@@ -63,7 +63,8 @@ void intel_link_bw_init_limits(struct inintel_atomic_get_new_crtc_state (state, crtc);int forced_bpp_x16 =get_forced_link_bpp_x16 (state, crtc); -if (state->base.duplicated && crtc_state) { +if ((state->base.duplicated && crtc_state) || +intel_dp_mst_stream_disconnected (state, crtc)) { limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;if (crtc_state->fec_enable) limits->force_fec_pipes |=BIT (pipe);
Greg Kroah-Hartman
maintainerPATCH 241/395 drm/amd/display: Fix dc stream excess put in dm_update_crtc_state()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit c5fd4eaad50d620c7e09ac2082b2fb55ee54170e upstream.
In dm_update_crtc_state(), when a modeset is required the newly created stream is stored in dm_new_crtc_state->stream and an extra reference is taken with dc_stream_retain(). The reference returned by create_validate_stream_for_sink() is released as an extra reference at the skip_modeset label, leaving the stream owned by the new CRTC state.
If amdgpu_dm_check_crtc_color_mgmt() fails afterwards, the code jumps to the fail label which releases new_stream again. Since the extra reference was already released at skip_modeset, this drops the reference owned by dm_new_crtc_state->stream and the stream is released while the atomic state still points to it, leading to a premature free of the dc stream.
Set new_stream to NULL after releasing the extra reference at the skip_modeset label so that a later goto fail cannot release the reference owned by the new CRTC state.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +3 -1
@@ -11639,8 +11639,10 @@ static int dm_update_crtc_state(struct a skip_modeset:/* Release extra reference */ -if (new_stream) +if (new_stream) {dc_stream_release (new_stream); + new_stream =NULL ; + } new_stream =NULL ;/*
Greg Kroah-Hartman
maintainerPATCH 242/395 drm/amd/display: Bump frame warning limit for clang builds of dml
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Lipski <[email protected]>
commit 18779dd84515db093fedb4ebaf0998c9b165a5fb upstream.
[Why&How]
When building the DML files with clang without any sanitizer or LTO, the following -Wframe-larger-than errors break the build under CONFIG_WERROR:
display_mode_vba_30.c: error: stack frame size (2512) exceeds limit
(2048) in 'dml30_ModeSupportAndSystemConfigurationFull'
display_mode_vba_31.c: error: stack frame size (2416) exceeds limit
(2048) in 'dml31_ModeSupportAndSystemConfigurationFull'
display_mode_vba_314.c: error: stack frame size (2392) exceeds limit
(2048) in 'dml314_ModeSupportAndSystemConfigurationFull'
Clang consistently spills more than gcc, pushing the frame past the 2048 byte limit.
Apply an existing approach of increasing the warn stack size to the non-sanitizer path so plain clang builds use a 3072 byte limit.
--- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dml/Makefile +5 -1
@@ -36,7 +36,11 @@ ifneq ($(CONFIG_FRAME_WARN),0) frame_warn_limit := 3072 endif else - frame_warn_limit := 2048 + ifeq ($(CONFIG_CC_IS_CLANG),y) + frame_warn_limit := 3072 + else + frame_warn_limit := 2048 + endif endif ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)
Greg Kroah-Hartman
maintainerPATCH 243/395 drm/amdgpu: Fix last_update fence leak in amdgpu_vm_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit b4f7b4459b1b155e4c4977a6482b5df2cf08758c upstream.
amdgpu_vm_init() initializes vm->last_update, vm->last_unlocked and vm->last_tlb_flush with references to the stub fence taken via dma_fence_get_stub(). The error label at the end of the function releases the last_unlocked and last_tlb_flush references with dma_fence_put(), but the reference stored in vm->last_update is never dropped, so whenever the page table root creation, the reservation of the root BO or the PASID registration fails, the stub fence reference leaks.
Drop the vm->last_update reference together with the other stub fence references on the error path.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +1 -0
@@ -2673,6 +2673,7 @@ error_free_root:amdgpu_bo_unref (&root_bo); error_free_delayed: +dma_fence_put (vm->last_update);dma_fence_put (vm->last_tlb_flush);dma_fence_put (vm->last_unlocked);ttm_lru_bulk_move_fini (&adev->mman.bdev, &vm->lru_bulk_move);
Greg Kroah-Hartman
maintainerPATCH 244/395 drm/amdgpu: Fix runtime PM leak in amdgpu_debugfs_test_ib_show()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 2b86ab1bd6673c525adda88819d7658ba9e784ec upstream.
amdgpu_debugfs_test_ib_show() resumes the device with pm_runtime_get_sync() before taking the reset domain semaphore with down_write_killable(). If the write lock acquisition is interrupted, the function returns without calling pm_runtime_put_autosuspend(), leaking the runtime PM reference acquired for the device and keeping the GPU awake.
Drop the runtime PM reference on the interrupted down_write_killable() error path before returning.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +3 -1
@@ -1671,8 +1671,10 @@ static int amdgpu_debugfs_test_ib_show(s/* Avoid accidently unparking the sched thread during GPU reset */ r =down_write_killable (&adev->reset_domain->sem); -if (r) +if (r) { +pm_runtime_put_autosuspend (dev->dev);return r; + }/* hold on the scheduler */ for (i =0 ; i <AMDGPU_MAX_RINGS ; i++) {
Greg Kroah-Hartman
maintainerPATCH 245/395 drm/amdgpu: Fix vmid_wait fence leak in amdgpu_ring_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit aea841bc62a76242396610d22d8ff40c13065f64 upstream.
amdgpu_ring_init() initializes ring->vmid_wait with a reference to the stub fence taken via dma_fence_get_stub(). When a later step of the initialization fails, e.g. amdgpu_fence_driver_init_ring(), a writeback slot allocation or the ring buffer allocation, the function returns an error without releasing the stub fence reference and the reference is leaked if the ring is torn down without amdgpu_ring_fini().
Move the stub fence assignment to the end of the initialization, right before the ring is registered with the GPU scheduler, where no further failure is possible. The stub fence is only consumed by command submission handling in amdgpu_ids.c once the ring is up and running, so nothing reads it during the error-prone part of the initialization.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +1 -1
@@ -260,7 +260,6 @@ int amdgpu_ring_init(struct amdgpu_devic ring->adev = adev; ring->num_hw_submission = sched_hw_submission; ring->sched_score = sched_score; - ring->vmid_wait =dma_fence_get_stub (); ring->idx = adev->num_rings++; adev->rings[ring->idx] = ring;
@@ -380,6 +379,7 @@ int amdgpu_ring_init(struct amdgpu_devic ring->max_dw = max_dw; ring->hw_prio = hw_prio; + ring->vmid_wait =dma_fence_get_stub ();if (!ring->no_scheduler && ring->funcs->type <AMDGPU_HW_IP_NUM ) { hw_ip = ring->funcs->type;
Greg Kroah-Hartman
maintainerPATCH 246/395 drm/nouveau/uvmm: fix UAF in nouveau_uvmm_sm when BO is in TTM_PL_SYSTEM
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 3359a372efb6d585c97019ee1b7f1874442bcebe upstream.
nouveau_uvmm_sm() calls op_map(), which passes bo->resource through nouveau_mem() to nouveau_uvma_map(). nouveau_uvmm_vmm_map() then reads mem->mem.type.
But this is only valid when bo->resource is backed by struct nouveau_mem, as is the case for VRAM and TT resources. If the BO is left in TTM_PL_SYSTEM, bo->resource is only a struct ttm_resource. Treating it as struct nouveau_mem makes the mem->mem.type read past the end of the resource, causing a KASAN: slab-use-after-free Read in nouveau_uvmm_sm report:
BUG: KASAN: slab-use-after-free in nouveau_uvmm_vmm_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:152 [inline] BUG: KASAN: slab-use-after-free in nouveau_uvma_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:199 [inline] BUG: KASAN: slab-use-after-free in op_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:849 [inline] BUG: KASAN: slab-use-after-free in nouveau_uvmm_sm.constprop.0+0x6ab/0x900 drivers/gpu/drm/nouveau/nouveau_uvmm.c:903 Read of size 1 at addr ffff888127d3e3a0 by task kworker/0:1/11 CPU: 0 UID: 0 PID: 11 Comm: kworker/0:1 Not tainted 7.2.0 #5 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: nouveau_sched_wq_2224 drm_sched_run_job_work Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x95/0xe0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xcb/0x5a0 mm/kasan/report.c:482 kasan_report+0xca/0x100 mm/kasan/report.c:595 nouveau_uvmm_vmm_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:152 [inline] nouveau_uvma_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:199 [inline] op_map drivers/gpu/drm/nouveau/nouveau_uvmm.c:849 [inline] nouveau_uvmm_sm.constprop.0+0x6ab/0x900 drivers/gpu/drm/nouveau/nouveau_uvmm.c:903 nouveau_uvmm_sm_unmap drivers/gpu/drm/nouveau/nouveau_uvmm.c:932 [inline] nouveau_uvmm_bind_job_run+0xd6/0x250 drivers/gpu/drm/nouveau/nouveau_uvmm.c:1532 nouveau_job_run drivers/gpu/drm/nouveau/nouveau_sched.c:350 [inline] nouveau_sched_run_job+0x62/0xd0 drivers/gpu/drm/nouveau/nouveau_sched.c:364 drm_sched_run_job_work+0x356/0xa10 drivers/gpu/drm/scheduler/sched_main.c:1061 process_one_work+0x8a5/0x1900 kernel/workqueue.c:3322 process_scheduled_works kernel/workqueue.c:3405 [inline] worker_thread+0x5dd/0xd80 kernel/workqueue.c:3486 kthread+0x31d/0x420 kernel/kthread.c:436 ret_from_fork+0x662/0x940 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK> Allocated by task 2224 on cpu 0 at 66.550027s: kasan_save_stack+0x24/0x50 mm/kasan/common.c:57 kasan_save_track+0x17/0x60 mm/kasan/common.c:78 poison_kmalloc_redzone mm/kasan/common.c:398 [inline] __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:415 kasan_kmalloc include/linux/kasan.h:263 [inline] __do_kmalloc_node mm/slub.c:5334 [inline] __kmalloc_noprof+0x304/0x7c0 mm/slub.c:5359 _kmalloc_noprof include/linux/slab.h:992 [inline] dma_resv_list_alloc+0x27/0x90 drivers/dma-buf/dma-resv.c:106 dma_resv_reserve_fences+0x60e/0xa30 drivers/dma-buf/dma-resv.c:205 ttm_bo_alloc_resource+0x12c/0xbd0 drivers/gpu/drm/ttm/ttm_bo.c:721 ttm_bo_validate+0x1bc/0x4a0 drivers/gpu/drm/ttm/ttm_bo.c:856 ttm_bo_init_reserved+0x2c3/0x570 drivers/gpu/drm/ttm/ttm_bo.c:970 nouveau_bo_init+0x159/0x2c0 drivers/gpu/drm/nouveau/nouveau_bo.c:359 nouveau_gem_new+0x234/0x5f0 drivers/gpu/drm/nouveau/nouveau_gem.c:272 nouveau_gem_ioctl_new+0x1eb/0x420 drivers/gpu/drm/nouveau/nouveau_gem.c:352 drm_ioctl_kernel+0x192/0x350 drivers/gpu/drm/drm_ioctl.c:817 drm_ioctl+0x4f8/0xb40 drivers/gpu/drm/drm_ioctl.c:914 nouveau_drm_ioctl+0xea/0x2c0 drivers/gpu/drm/nouveau/nouveau_drm.c:1338 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x180/0x1d0 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x115/0x690 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 2223 on cpu 0 at 66.554063s: kasan_save_stack+0x24/0x50 mm/kasan/common.c:57 kasan_save_track+0x17/0x60 mm/kasan/common.c:78 kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:253 [inline] __kasan_slab_free+0x61/0x80 mm/kasan/common.c:285 kasan_slab_free include/linux/kasan.h:235 [inline] slab_free_hook mm/slub.c:2677 [inline] __rcu_free_sheaf_prepare+0xb6/0x2e0 mm/slub.c:2928 rcu_free_sheaf+0x1b/0x120 mm/slub.c:5978 rcu_do_batch kernel/rcu/tree.c:2645 [inline] rcu_core+0x521/0x1490 kernel/rcu/tree.c:2897 handle_softirqs+0x1b1/0x8a0 kernel/softirq.c:622 __do_softirq kernel/softirq.c:656 [inline] invoke_softirq kernel/softirq.c:496 [inline] __irq_exit_rcu+0x137/0x1c0 kernel/softirq.c:735 irq_exit_rcu+0x9/0x20 kernel/softirq.c:752 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1062 [inline] sysvec_apic_timer_interrupt+0x70/0x80 arch/x86/kernel/apic/apic.c:1062 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:674 The buggy address belongs to the object at ffff888127d3e380 which belongs to the cache kmalloc-96 of size 96
The buggy address is located 32 bytes inside of
freed 96-byte region [ffff888127d3e380, ffff888127d3e3e0)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x127d3e
flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff888100041280 dead000000000122 0000000000000000
raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888127d3e280: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc
ffff888127d3e300: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc
>ffff888127d3e380: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
^
ffff888127d3e400: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
ffff888127d3e480: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fcFix by resetting the placement to the BO's valid domains before calling nouveau_bo_validate(), matching the handling in nouveau_uvmm_bo_validate(), so map jobs do not run for SYSTEM resources; Reject BO that cannot reside in VRAM or GART;
Also skip op_map() when the GPUVA has been invalidated, matching the handling in the unmap and remap paths.
Found when fuzzing the nouveau driver with a modified Syzkaller.
--- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nouveau_uvmm.c +11 -2
@@ -780,6 +780,9 @@ op_map(struct nouveau_uvma *uvma) {struct nouveau_bo *nvbo =nouveau_gem_object (uvma->va.gem.obj); +if (drm_gpuva_invalidated (&uvma->va)) +return ; +nouveau_uvma_map (uvma,nouveau_mem (nvbo->bo.resource)); }
@@ -1164,6 +1167,7 @@ bind_lock_validate(struct nouveau_job *jdrm_gpuva_for_each_op (va_op, op->ops) {struct drm_gem_object *obj =op_gem_obj (va_op); +struct nouveau_bo *nvbo;if (unlikely (!obj))continue ;
@@ -1178,8 +1182,13 @@ bind_lock_validate(struct nouveau_job *jif (va_op->op ==DRM_GPUVA_OP_UNMAP )continue ; - ret =nouveau_bo_validate (nouveau_gem_object (obj), - true, false); + nvbo =nouveau_gem_object (obj); +if (!(nvbo->valid_domains & + (NOUVEAU_GEM_DOMAIN_VRAM |NOUVEAU_GEM_DOMAIN_GART ))) +return -EINVAL ; + +nouveau_bo_placement_set (nvbo, nvbo->valid_domains,0 ); + ret =nouveau_bo_validate (nvbo, true, false);if (ret)return ret; }
Greg Kroah-Hartman
maintainerPATCH 247/395 drm/nouveau: fix autosuspend cleanup during teardown
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit fefd9480ec361969f1a836df46326a1801062c26 upstream.
nouveau_drm_device_init() calls pm_runtime_use_autosuspend(), but nouveau_drm_device_fini() does not call the matching pm_runtime_dont_use_autosuspend().
If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped and usage_count remains unbalanced.
The documentation for pm_runtime_use_autosuspend() also notes that it is important to undo it with pm_runtime_dont_use_autosuspend() at driver exit time, unless runtime PM was initially enabled with devm_pm_runtime_enable().
Add the missing pm_runtime_dont_use_autosuspend() call to the common device teardown path.
This issue was found by manual code inspection.
--- drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/nouveau/nouveau_drm.c +1 -0
@@ -584,6 +584,7 @@ nouveau_drm_device_fini(struct nouveau_dif (nouveau_pmops_runtime ()) {pm_runtime_get_sync (dev->dev);pm_runtime_forbid (dev->dev); +pm_runtime_dont_use_autosuspend (dev->dev); }nouveau_led_fini (dev);
Greg Kroah-Hartman
maintainerPATCH 248/395 drm/nouveau: Fix bridge reference leak in nv1a_ram_new()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 67b4411538c8341692548429d43256f25be99f7a upstream.
pci_get_domain_bus_and_slot() takes a reference to the PCI device, which is never released once the memory size has been read from its config space. Drop the reference before returning.
--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +2 -0
@@ -51,6 +51,8 @@ nv1a_ram_new(struct nvkm_fb *fb, struct mib = ((mem >>4 ) &127 ) +1 ; } +pci_dev_put (bridge); +return nvkm_ram_new_ (&nv04_ram_func, fb,NVKM_RAM_TYPE_STOLEN , mib *1024 *1024 , pram); }
Greg Kroah-Hartman
maintainerPATCH 249/395 drm/nouveau: fix double-free in nvif_vmm_dtor
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 97077ac87afe9e91ec074ef0be64454e7ccbf344 upstream.
On failure, nouveau_cli_init() calls nouveau_cli_fini() to tear the client down. Then, nouveau_drm_open() also enters into its cleanup path and calls nouveau_cli_fini() AGAIN. nouveau_cli_fini() calls nouveau_vmm_fini():
void
nouveau_vmm_fini(struct nouveau_vmm *vmm)
{
nouveau_svmm_fini(&vmm->svmm);
nvif_vmm_dtor(&vmm->vmm);
vmm->cli = NULL;
}Inside nvif_vmm_dtor(), vmm->page is freed unconditionally:
void
nvif_vmm_dtor(struct nvif_vmm *vmm)
{
kfree(vmm->page);
nvif_object_dtor(&vmm->object);
}vmm->page is never cleared after being freed, so the second call of nvif_vmm_dtor() will cause a double-free.
Found by fuzzing the nouveau driver with a modified Syzkaller:
BUG: KASAN: double-free in nvif_vmm_dtor+0x31/0x50 drivers/gpu/drm/nouveau/nvif/vmm.c:194 Free of addr ffff888010fcdc30 by task syz.0.173/2567 CPU: 1 UID: 0 PID: 2567 Comm: syz.0.173 Not tainted 7.2.0 #24 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x95/0xe0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xcb/0x5a0 mm/kasan/report.c:482 kasan_report_invalid_free+0xaa/0xd0 mm/kasan/report.c:557 check_slab_allocation+0xe4/0x110 mm/kasan/common.c:235 kasan_slab_pre_free include/linux/kasan.h:199 [inline] slab_free_hook mm/slub.c:2622 [inline] slab_free mm/slub.c:6377 [inline] kfree+0x192/0x590 mm/slub.c:6692 nvif_vmm_dtor+0x31/0x50 drivers/gpu/drm/nouveau/nvif/vmm.c:194 nouveau_vmm_fini+0x16/0x50 drivers/gpu/drm/nouveau/nouveau_vmm.c:127 nouveau_cli_fini+0x10e/0x210 drivers/gpu/drm/nouveau/nouveau_drm.c:225 nouveau_drm_open+0x24e/0x740 drivers/gpu/drm/nouveau/nouveau_drm.c:1255 drm_file_alloc+0x5f2/0xad0 drivers/gpu/drm/drm_file.c:176 drm_open_helper+0x1d7/0x4a0 drivers/gpu/drm/drm_file.c:335 drm_open+0x190/0x3d0 drivers/gpu/drm/drm_file.c:388 drm_stub_open+0x1f2/0x460 drivers/gpu/drm/drm_drv.c:1211 chrdev_open+0x21c/0x660 fs/char_dev.c:411 do_dentry_open+0x59d/0x12b0 fs/open.c:947 vfs_open+0x82/0x390 fs/open.c:1052 do_open fs/namei.c:4700 [inline] path_openat+0x2345/0x3420 fs/namei.c:4863 do_file_open+0x207/0x460 fs/namei.c:4892 do_sys_openat2+0xd1/0x1d0 fs/open.c:1368 do_sys_open fs/open.c:1374 [inline] __do_sys_openat fs/open.c:1390 [inline] __se_sys_openat fs/open.c:1385 [inline] __x64_sys_openat+0x144/0x200 fs/open.c:1385 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x115/0x690 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fc6d687594d Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007fc6d5295008 EFLAGS: 00000246 ORIG_RAX: 0000000000000101 RAX: ffffffffffffffda RBX: 00007fc6d6b06180 RCX: 00007fc6d687594d RDX: 0000000000022501 RSI: 0000200000000000 RDI: ffffffffffffff9c RBP: 00007fc6d691c303 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fc6d6b06218 R14: 00007fc6d6b06180 R15: 00007ffd9451d760 </TASK> Allocated by task 2567 on cpu 1 at 163.593900s: kasan_save_stack+0x24/0x50 mm/kasan/common.c:57 kasan_save_track+0x17/0x60 mm/kasan/common.c:78 poison_kmalloc_redzone mm/kasan/common.c:398 [inline] __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:415 kasan_kmalloc include/linux/kasan.h:263 [inline] __do_kmalloc_node mm/slub.c:5334 [inline] __kmalloc_noprof+0x304/0x7c0 mm/slub.c:5359 _kmalloc_noprof include/linux/slab.h:992 [inline] nvif_vmm_ctor+0x3c0/0x7e0 drivers/gpu/drm/nouveau/nvif/vmm.c:237 nouveau_vmm_init+0x40/0x90 drivers/gpu/drm/nouveau/nouveau_vmm.c:134 nouveau_cli_init+0x7b9/0xe10 drivers/gpu/drm/nouveau/nouveau_drm.c:293 nouveau_drm_open+0x236/0x740 drivers/gpu/drm/nouveau/nouveau_drm.c:1243 drm_file_alloc+0x5f2/0xad0 drivers/gpu/drm/drm_file.c:176 drm_open_helper+0x1d7/0x4a0 drivers/gpu/drm/drm_file.c:335 drm_open+0x190/0x3d0 drivers/gpu/drm/drm_file.c:388 drm_stub_open+0x1f2/0x460 drivers/gpu/drm/drm_drv.c:1211 chrdev_open+0x21c/0x660 fs/char_dev.c:411 do_dentry_open+0x59d/0x12b0 fs/open.c:947 vfs_open+0x82/0x390 fs/open.c:1052 do_open fs/namei.c:4700 [inline] path_openat+0x2345/0x3420 fs/namei.c:4863 do_file_open+0x207/0x460 fs/namei.c:4892 do_sys_openat2+0xd1/0x1d0 fs/open.c:1368 do_sys_open fs/open.c:1374 [inline] __do_sys_openat fs/open.c:1390 [inline] __se_sys_openat fs/open.c:1385 [inline] __x64_sys_openat+0x144/0x200 fs/open.c:1385 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x115/0x690 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 2567 on cpu 1 at 163.601355s: kasan_save_stack+0x24/0x50 mm/kasan/common.c:57 kasan_save_track+0x17/0x60 mm/kasan/common.c:78 kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:253 [inline] __kasan_slab_free+0x61/0x80 mm/kasan/common.c:285 kasan_slab_free include/linux/kasan.h:235 [inline] slab_free_hook mm/slub.c:2677 [inline] slab_free mm/slub.c:6377 [inline] kfree+0x383/0x590 mm/slub.c:6692 nvif_vmm_dtor+0x31/0x50 drivers/gpu/drm/nouveau/nvif/vmm.c:194 nouveau_vmm_fini+0x16/0x50 drivers/gpu/drm/nouveau/nouveau_vmm.c:127 nouveau_cli_fini+0x10e/0x210 drivers/gpu/drm/nouveau/nouveau_drm.c:225 nouveau_cli_init+0x593/0xe10 drivers/gpu/drm/nouveau/nouveau_drm.c:324 nouveau_drm_open+0x236/0x740 drivers/gpu/drm/nouveau/nouveau_drm.c:1243 drm_file_alloc+0x5f2/0xad0 drivers/gpu/drm/drm_file.c:176 drm_open_helper+0x1d7/0x4a0 drivers/gpu/drm/drm_file.c:335 drm_open+0x190/0x3d0 drivers/gpu/drm/drm_file.c:388 drm_stub_open+0x1f2/0x460 drivers/gpu/drm/drm_drv.c:1211 chrdev_open+0x21c/0x660 fs/char_dev.c:411 do_dentry_open+0x59d/0x12b0 fs/open.c:947 vfs_open+0x82/0x390 fs/open.c:1052 do_open fs/namei.c:4700 [inline] path_openat+0x2345/0x3420 fs/namei.c:4863 do_file_open+0x207/0x460 fs/namei.c:4892 do_sys_openat2+0xd1/0x1d0 fs/open.c:1368 do_sys_open fs/open.c:1374 [inline] __do_sys_openat fs/open.c:1390 [inline] __se_sys_openat fs/open.c:1385 [inline] __x64_sys_openat+0x144/0x200 fs/open.c:1385 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x115/0x690 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The buggy address belongs to the object at ffff888010fcdc30 which belongs to the cache kmalloc-16 of size 16 The buggy address is located 0 bytes inside of 16-byte region [ffff888010fcdc30, ffff888010fcdc40) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10fcd flags: 0x100000000000000(node=0|zone=1) page_type: f5(slab) raw: 0100000000000000 ffff88800d441640 dead000000000100 dead000000000122 raw: 0000000000000000 0000000000550055 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888010fcdb00: fc fc 00 04 fc fc fc fc fa fb fc fc fc fc fa fb ffff888010fcdb80: fc fc fc fc fa fb fc fc fc fc 00 07 fc fc fc fc >ffff888010fcdc00: fa fb fc fc fc fc fa fb fc fc fc fc fa fb fc fc ^ ffff888010fcdc80: fc fc fa fb fc fc fc fc 00 04 fc fc fc fc fa fb ffff888010fcdd00: fc fc fc fc 00 00 fc fc fc fc fa fb fc fc fc fc
Fix by removing the redundant teardown in nouveau_drm_open(), since nouveau_cli_init() already does the cleanup work. Also clear vmm->page after its freeing.
--- drivers/gpu/drm/nouveau/nouveau_drm.c | 4 +--- drivers/gpu/drm/nouveau/nvif/vmm.c | 1 + 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/gpu/drm/nouveau/nouveau_drm.c +1 -3
@@ -1220,10 +1220,8 @@ nouveau_drm_open(struct drm_device *dev,mutex_unlock (&drm->clients_lock); done: -if (ret && cli) { -nouveau_cli_fini (cli); +if (ret && cli)kfree (cli); - }pm_runtime_mark_last_busy (dev->dev);pm_runtime_put_autosuspend (dev->dev);
drivers/gpu/drm/nouveau/nvif/vmm.c +1 -0
@@ -192,6 +192,7 @@ void nvif_vmm_dtor(struct nvif_vmm *vmm) {kfree (vmm->page); + vmm->page =NULL ;nvif_object_dtor (&vmm->object); }
Greg Kroah-Hartman
maintainerPATCH 250/395 drm/nouveau: Fix gem reference leak in validate_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 5ea72f7b7139b123713a7983448f910bc4514d9e upstream.
On the ttm_bo_reserve() failure and "vma not found" error paths, the loop breaks without adding the looked-up object to any validate list, so the reference taken by drm_gem_object_lookup() is never released; validate_fini() only walks the spliced lists. Drop the reference before breaking out on both paths.
--- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/nouveau/nouveau_gem.c +2 -0
@@ -522,6 +522,7 @@ retry:if (unlikely (ret)) {if (ret != -ERESTARTSYS )NV_PRINTK (err, cli,"fail reserve\n" ); +drm_gem_object_put (gem);break ; } }
@@ -531,6 +532,7 @@ retry:struct nouveau_vma *vma =nouveau_vma_find (nvbo, vmm);if (!vma) {NV_PRINTK (err, cli,"vma not found!\n" ); +drm_gem_object_put (gem); ret = -EINVAL ;break ; }
Greg Kroah-Hartman
maintainerPATCH 251/395 drm/nouveau: Fix runtime PM leak in nouveau_connector_detect()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 1e04611d3735543bd80a67d9d13dc13f503746fb upstream.
If nvif_outp_edid_get() fails, nouveau_connector_detect() returns early without dropping the runtime PM reference taken at the start of the function, keeping the device powered on until the next successful detect.
Balance the reference on the error path like the other exit paths do.
--- drivers/gpu/drm/nouveau/nouveau_connector.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_connector.c +4 -1
@@ -600,8 +600,11 @@ nouveau_connector_detect(struct drm_conn new_edid =drm_get_edid (connector, nv_encoder->i2c); }else { ret =nvif_outp_edid_get (&nv_encoder->outp, (u8 **)&new_edid); -if (ret <0 ) +if (ret <0 ) { +pm_runtime_mark_last_busy (dev->dev); +pm_runtime_put_autosuspend (dev->dev);return connector_status_disconnected; + } }nouveau_connector_set_edid (nv_connector, new_edid);
Greg Kroah-Hartman
maintainerPATCH 252/395 drm/nouveau: RCU-free the scheduler-containing nouveau_sched
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonghyuk Kim(MalHyuk) <[email protected]>
commit f7eae6d8d768fabd6b59779ca7da79e02c74e113 upstream.
struct nouveau_sched embeds a struct drm_gpu_scheduler (base). nouveau_sched_destroy() calls nouveau_sched_fini() (which does drm_sched_fini(&sched->base)) and then frees the object with plain kfree(sched).
drm_sched_fence_get_timeline_name() returns fence->sched->name, and the scheduler fence keeps a .release callback so it is not ops-detached on signalling. A finished fence exported to userspace via drm_syncobj / sync_file therefore keeps pointing at &sched->base after nouveau_sched_destroy(), and a later get_timeline_name() -- reachable unprivileged through SYNC_IOC_FILE_INFO -- dereferences freed memory (KASAN slab-use-after-free read).
Per the dma-fence lifetime contract the exporter must keep the data backing a signalled fence alive for an RCU grace period. Free the scheduler-containing object with kfree_rcu() instead of kfree().
--- drivers/gpu/drm/nouveau/nouveau_sched.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sched.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_sched.c +1 -1
@@ -518,7 +518,7 @@ nouveau_sched_destroy(struct nouveau_schstruct nouveau_sched *sched = *psched;nouveau_sched_fini (sched); -kfree (sched); +kfree_rcu (sched, rcu); *psched =NULL ; }
drivers/gpu/drm/nouveau/nouveau_sched.h +1 -0
@@ -98,6 +98,7 @@ void nouveau_job_free(struct nouveau_jobstruct nouveau_sched {struct drm_gpu_scheduler base; +struct rcu_head rcu;struct drm_sched_entity entity;struct workqueue_struct *wq;struct mutex mutex;
Greg Kroah-Hartman
maintainerPATCH 253/395 drm/nouveau: dont bump pin count on failed re-pin in nouveau_bo_pin_locked()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 6a6870d3077faa501ca97760057ddca22b68418d upstream.
nouveau_bo_pin_locked() checks whether an already pinned BO is in a memory domain compatible with a new pin request. When the domains are incompatible, it sets -EBUSY but still calls ttm_bo_pin() before returning.
Callers treat a failed nouveau_bo_pin() as not having acquired a new pin, so the extra pin count is never decreased by a matching unpin. This triggers the warning in ttm_bo_release():
WARN_ON_ONCE(bo->pin_count);
Found when fuzzing the nouveau driver with a modified Syzkaller:
WARNING: drivers/gpu/drm/ttm/ttm_bo.c:256 at ttm_bo_release+0x827/0x9e0 drivers/gpu/drm/ttm/ttm_bo.c:256, CPU#1: syz.3.24/2212 Modules linked in: CPU: 1 UID: 0 PID: 2212 Comm: syz.3.24 Not tainted 7.2.0 #24 PREEMPT(lazy) nouveau 0000:01:00.0: gsp:msg fn:103 len:0x40/0x20 res:0x19 resp:0x19 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:ttm_bo_release+0x827/0x9e0 drivers/gpu/drm/ttm/ttm_bo.c:256 Code: 02 00 0f 85 51 01 00 00 48 8b 7b 08 e8 d2 20 01 00 e9 80 fd ff ff e8 d8 15 c0 fe 90 0f 0b 90 e9 e1 f8 ff ff e8 ca 15 c0 fe 90 <0f> 0b 90 e9 a4 f8 ff ff e8 bc 15 c0 fe be 03 00 00 00 4c 89 e7 e8 msg: 00000000: 05 00 d0 c1 04 00 f0 f1 01 30 00 00 2d 90 00 00 .........0..-... RSP: 0018:ffffc9000f5cf710 EFLAGS: 00010293 RAX: 0000000000000000 RBX: ffff888018e5d2a8 RCX: ffffffff82bb1b36 RDX: ffff888017b68000 RSI: 0000000000000004 RDI: ffff888018e5d2a8 msg: 00000010: 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ RBP: ffff88801261c720 R08: 0000000000000001 R09: ffffed10031cba55 R10: ffff888018e5d2ab R11: 00000000000000f3 R12: ffff888018e5d290 R13: ffff888018e5d2d4 R14: ffff88801b219c18 R15: dffffc0000000000 FS: 0000000000000000(0000) GS:ffff8880e0f6f000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b31223ffc CR3: 0000000028e00005 CR4: 0000000000770ef0 PKRU: 80000000 Call Trace: <TASK> kref_put include/linux/kref.h:65 [inline] ttm_bo_put drivers/gpu/drm/ttm/ttm_bo.c:325 [inline] ttm_bo_fini+0x55/0x80 drivers/gpu/drm/ttm/ttm_bo.c:330 nouveau_gem_object_del+0xb2/0x1b0 drivers/gpu/drm/nouveau/nouveau_gem.c:90 drm_gem_object_free+0x5f/0x90 drivers/gpu/drm/drm_gem.c:1165 kref_put include/linux/kref.h:65 [inline] __drm_gem_object_put include/drm/drm_gem.h:562 [inline] drm_gem_object_put include/drm/drm_gem.h:575 [inline] nouveau_abi16_chan_fini.constprop.0+0x44f/0x5a0 drivers/gpu/drm/nouveau/nouveau_abi16.c:195 nouveau 0000:01:00.0: syz.2.23[2209]: Unknown handle 0x00000000 nouveau_abi16_fini+0x1d0/0x340 drivers/gpu/drm/nouveau/nouveau_abi16.c:225 nouveau_drm_postclose+0x18b/0x3e0 drivers/gpu/drm/nouveau/nouveau_drm.c:1284 nouveau 0000:01:00.0: syz.2.23[2209]: validate_init drm_file_free.part.0+0x6d6/0xb60 drivers/gpu/drm/drm_file.c:267 drm_file_free drivers/gpu/drm/drm_file.c:237 [inline] drm_close_helper.isra.0+0x11a/0x160 drivers/gpu/drm/drm_file.c:290 drm_release+0x1ab/0x330 drivers/gpu/drm/drm_file.c:438 __fput+0x39c/0xa60 fs/file_table.c:512 nouveau 0000:01:00.0: syz.2.23[2209]: validate: -2 task_work_run+0x15a/0x230 kernel/task_work.c:233 exit_task_work include/linux/task_work.h:40 [inline] do_exit+0x82b/0x25a0 kernel/exit.c:1009 do_group_exit+0xc2/0x280 kernel/exit.c:1152 get_signal+0x1d6e/0x1f30 kernel/signal.c:3046 arch_do_signal_or_restart+0x7d/0x6e0 arch/x86/kernel/signal.c:337 __exit_to_user_mode_loop kernel/entry/common.c:66 [inline] exit_to_user_mode_loop+0xdf/0x440 kernel/entry/common.c:101 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline] syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline] do_syscall_64+0x4f8/0x690 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f12bac8594d Code: Unable to access opcode bytes at 0x7f12bac85923. RSP: 002b:00007f12b96e70d8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca RAX: 0000000000000001 RBX: 00007f12baf15fa8 RCX: 00007f12bac8594d RDX: 00000000000f4240 RSI: 0000000000000081 RDI: 00007f12baf15fac RBP: 00007f12baf15fa0 R08: 00007f12baee8000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f12baf16038 R14: 0000000000000006 R15: 00007ffe2ed394b0 </TASK> irq event stamp: 47867 hardirqs last enabled at (47883): [<ffffffff815cafc6>] __up_console_sem+0x66/0x70 kernel/printk/printk.c:347 hardirqs last disabled at (47892): [<ffffffff815cafab>] __up_console_sem+0x4b/0x70 kernel/printk/printk.c:345 softirqs last enabled at (47880): [<ffffffff81434277>] __do_softirq kernel/softirq.c:656 [inline] softirqs last enabled at (47880): [<ffffffff81434277>] invoke_softirq kernel/softirq.c:496 [inline] softirqs last enabled at (47880): [<ffffffff81434277>] __irq_exit_rcu+0x137/0x1c0 kernel/softirq.c:735 softirqs last disabled at (47875): [<ffffffff81434277>] __do_softirq kernel/softirq.c:656 [inline] softirqs last disabled at (47875): [<ffffffff81434277>] invoke_softirq kernel/softirq.c:496 [inline] softirqs last disabled at (47875): [<ffffffff81434277>] __irq_exit_rcu+0x137/0x1c0 kernel/softirq.c:735
Fix by calling ttm_bo_pin() only when the existing placement is compatible with the new pin request. This matches the correct behavior in other DRM drivers such as amdgpu_bo_pin() in amdgpu.
--- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_bo.c +2 -1
@@ -578,8 +578,9 @@ int nouveau_bo_pin_locked(struct nouveau"0x%08x vs 0x%08x\n" , bo, bo->resource->mem_type, domain); ret = -EBUSY ; + }else { +ttm_bo_pin (&nvbo->bo); } -ttm_bo_pin (&nvbo->bo); goto out; }
Greg Kroah-Hartman
maintainerPATCH 254/395 drm/xe/vm: nuke PTs only after unlinking contested VMAs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Auld <[email protected]>
commit 24a22fb3c731474b68e986af6804db450fb88617 upstream.
In xe_vm_close_and_put(), external-BO VMAs are queued on the contested list for deferred destruction via xe_vma_destroy_unlocked(). However, xe_vm_pt_destroy() was previously invoked before processing contested VMAs, destroying vm->pt_root while those VMAs were still linked to their respective buffer objects (vm_bo->list.gpuva).
If a concurrent thread evicts one of those shared buffer objects, xe_bo_trigger_rebind() holding only bo->resv walks the BO's VMAs and, in fault mode, calls xe_vm_invalidate_vma() -> xe_pt_zap_ptes(). Because vm->pt_root[tile->id] is already NULL, dereferencing pt->level causes a NULL ptr deref.
Fix this by deferring xe_vm_free_scratch() and xe_vm_pt_destroy() until after all contested VMAs have been unlinked and destroyed.
User is reporting hitting a NULL ptr deref in xe_pt_zap_ptes(), which could be explained by this race.
--- drivers/gpu/drm/xe/xe_vm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-)
drivers/gpu/drm/xe/xe_vm.c +9 -12
@@ -1744,21 +1744,13 @@ void xe_vm_close_and_put(struct xe_vm *v vma->gpuva.flags |=XE_VMA_DESTROYED ; } -/* -* All vm operations will add shared fences to resv. -* The only exception is eviction for a shared object, -* but even so, the unbind when evicted would still -* install a fence to resv. Hence it's safe to -* destroy the pagetables immediately. -*/ -xe_vm_free_scratch (vm); -xe_vm_pt_destroy (vm);xe_vm_unlock (vm);/* -* VM is now dead, cannot re-add nodes to vm->vmas if it's NULL -* Since we hold a refcount to the bo, we can remove and free -* the members safely without locking. +* Unlink and destroy all contested external-BO VMAs before destroying +* the page tables. Otherwise, concurrent eviction holding only bo->resv +* can walk the BO's VMAs and attempt to invalidate/zap page tables that +* have already been freed. */ list_for_each_entry_safe (vma, next_vma, &contested, combined_links.destroy) {
@@ -1766,6 +1758,11 @@ void xe_vm_close_and_put(struct xe_vm *vxe_vma_destroy_unlocked (vma); } +xe_vm_lock (vm, false); +xe_vm_free_scratch (vm); +xe_vm_pt_destroy (vm); +xe_vm_unlock (vm); +xe_svm_fini (vm);up_write (&vm->lock);
Greg Kroah-Hartman
maintainerPATCH 255/395 drm/xe: harden adjust_idledly() against divide-by-zero and overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tangudu Tilak Tirumalesh <[email protected]>
commit 90f467577ebc28c5bc4ba2f0f1b83a4419fb0740 upstream.
adjust_idledly() has several corner-case issues flagged during review:
1. If xe_gt_clock_init() failed to recognise the crystal clock, gt->info.timestamp_base is 0, which makes idledly_units_ps also 0. The subsequent DIV_ROUND_CLOSEST(..., idledly_units_ps) is then a divide-by-zero and panics the kernel.
2. The tick-to-ns conversions are done in u32:
idledly * idledly_units_ps, (maxcnt - 1) * 1000
Both overflow u32 before DIV_ROUND_CLOSEST() sees them.
3. If IDLE_WAIT_TIME reads back as 0, maxcnt evaluates to 0 and
the maxcnt - 1 clamp wraps to 0xFFFFFFFF in u32.
4. The register only stores whole ticks, so the clamped ns value has to be converted to ticks and back. DIV_ROUND_CLOSEST() can round that conversion up past maxcnt:
maxcnt = 640 ns, one tick = 666664 ps
clamp: maxcnt - 1 = 639 ns
ns -> ticks: 639000 / 666664 = 0.958 -> rounds to 1 tick
tick -> ns: 1 * 666664 / 1000 = 667 ns
667 ns is programmed into RING_IDLEDLY, but 667 >= maxcnt (640), so xe_gt_WARN_ON() fires again on every subsequent init.
Return early if timestamp_base is 0 (the unknown-crystal path). Do the conversions in u64 via the *_ULL() helpers so they cannot wrap. Clamp with a floor (DIV_ROUND_DOWN_ULL) so the programmed delay stays strictly below maxcnt, and guard the maxcnt == 0 case with a zero delay while still writing RING_IDLEDLY so INHIBIT_SWITCH_UNTIL_PREEMPTED is cleared.
v2: Drop the redundant warn on the timestamp_base == 0 path;
xe_gt_clock_init() already warns on an unrecognised crystal clock. Keep the early return to avoid the divide-by-zero. - Vinay
v3: Field-mask the RING_IDLEDLY write with REG_FIELD_PREP(IDLE_DELAY, ...)
instead of writing the raw tick count, which could clobber INHIBIT_SWITCH_UNTIL_PREEMPTED and reserved bits. Split the inhibit-switch clear from the maxcnt clamp so a set inhibit bit no longer forces a needless delay overwrite when the delay itself is already valid. Use gt_to_xe(gt) instead of gt_to_xe(hwe->gt).
--- drivers/gpu/drm/xe/xe_hw_engine.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-)
drivers/gpu/drm/xe/xe_hw_engine.c +21 -6
@@ -577,22 +577,37 @@ static void adjust_idledly(struct xe_hw_u32 idledly_units_ps =8 * gt->info.timestamp_base;u32 maxcnt_units_ns =640 ;bool inhibit_switch =0 ; +bool wa_applied = false; + +if (!IS_SRIOV_VF (gt_to_xe (gt)) &&XE_GT_WA (gt,16023105232 )) { +/* xe_gt_clock_init() warns and zeroes timestamp_base on unknown crystal clock. */ +if (!idledly_units_ps) +return ; -if (!IS_SRIOV_VF (gt_to_xe (hwe->gt)) &&XE_GT_WA (gt,16023105232 )) { idledly =xe_mmio_read32 (>->mmio,RING_IDLEDLY (hwe->mmio_base)); maxcnt =xe_mmio_read32 (>->mmio,RING_PWRCTX_MAXCNT (hwe->mmio_base)); inhibit_switch = idledly &INHIBIT_SWITCH_UNTIL_PREEMPTED ; idledly =REG_FIELD_GET (IDLE_DELAY , idledly); - idledly =DIV_ROUND_CLOSEST (idledly * idledly_units_ps,1000 ); + idledly =DIV_ROUND_CLOSEST_ULL ((u64 )idledly * idledly_units_ps,1000 ); maxcnt =REG_FIELD_GET (IDLE_WAIT_TIME , maxcnt); maxcnt *= maxcnt_units_ns; -if (xe_gt_WARN_ON (gt, idledly >= maxcnt || inhibit_switch)) { - idledly =DIV_ROUND_CLOSEST (((maxcnt -1 ) *1000 ), - idledly_units_ps); -xe_mmio_write32 (>->mmio,RING_IDLEDLY (hwe->mmio_base), idledly); +/* Clear the inhibit switch without disturbing a valid delay. */ +if (inhibit_switch) + wa_applied = true; + +if (xe_gt_WARN_ON (gt, idledly >= maxcnt)) { +/* Floor below maxcnt; write 0 to still clear the inhibit bit. */ + idledly = maxcnt ? +DIV_ROUND_DOWN_ULL ((u64)(maxcnt -1 ) *1000 , + idledly_units_ps) :0 ; + wa_applied = true; } + +if (wa_applied) +xe_mmio_write32 (>->mmio,RING_IDLEDLY (hwe->mmio_base), +REG_FIELD_PREP (IDLE_DELAY , idledly)); } }
Greg Kroah-Hartman
maintainerPATCH 256/395 drm/xe: Limit sg segment size to PAGE_SIZE on Xen PV
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Szymon Acedański <[email protected]>
commit 141008dec73521ccf64878517460cec8b3297251 upstream.
Fix display corruption on Xen PV dom0, where DMA buffers are not guaranteed machine-contiguous, in which case bounce buffering kicks in, breaking xe's memory coherency assumptions.
Apply the same workaround i915 carries in i915_sg_segment_size() since commit 78a07fe777c4 ("drm/i915: stop abusing swiotlb_max_segment").
--- drivers/gpu/drm/xe/xe_bo.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
drivers/gpu/drm/xe/xe_bo.h +19 -0
@@ -9,6 +9,8 @@#include <drm/drm_prime.h> #include <drm/ttm/ttm_tt.h> +#include <xen/xen.h> +#include "xe_bo_types.h" #include "xe_macros.h" #include "xe_validation.h"
@@ -481,6 +483,23 @@ static inline unsigned int xe_sg_segmentstruct scatterlist __maybe_unused sg;size_t max =BIT_ULL (sizeof (sg.length) *8 ) -1 ; +/* +* For Xen PV guests pages aren't contiguous in DMA (machine) address +* space. The DMA API takes care of that both in dma_alloc_* (by +* calling into the hypervisor to make the pages contiguous) and in +* dma_map_* (by bounce buffering). But xe (like i915, see commit +* 78a07fe777c4) ignores the coherency aspects of the DMA API and thus +* can't cope with bounce buffering actually happening, so add a hack +* here to force small allocations and mappings when running in PV +* mode on Xen. +* +* Note this will still break if bounce buffering is required for other +* reasons, like confidential computing hypervisors or PCIe root ports +* with addressing limitations. +*/ +if (xen_pv_domain ()) +return PAGE_SIZE ; + max =min_t (size_t, max,dma_max_mapping_size (dev));/*
Greg Kroah-Hartman
maintainerPATCH 257/395 drm/xe: Keep walking on SVM eviction failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit be1df8badae513e01d9575398438716cfae18655 upstream.
The desired behavior for SVM eviction failures, which can occur due to various uncontrollable races, is for TTM to continue walking the LRU list and look for another eviction candidate. This is expressed by returning -ENOSPC from the ->move() callback.
Adjust the SVM eviction failure path because of races in ->move() to return -ENOSPC so that TTM continues searching for another buffer to evict.
--- drivers/gpu/drm/xe/xe_bo.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/xe/xe_bo.c +7 -0
@@ -853,6 +853,13 @@ static int xe_bo_move(struct ttm_buffer_ }else {drm_dbg (&xe->drm,"Evict system allocator BO failed=%pe\n" ,ERR_PTR (ret)); +/* +* The semantic we want upon SVM eviction failure +* because of racing access is keep walking for +* eviction, which is -ENOSPC. +*/ +if (ret == -EBUSY ) + ret = -ENOSPC ; } goto out;
Greg Kroah-Hartman
maintainerPATCH 258/395 drm/virtio: fix memory leak of fence event on execbuffer failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit b74aad23d99b279bb34d135795f39a6d8ecdc075 upstream.
virtio_gpu_execbuffer_ioctl() reserves a DRM event with drm_event_reserve_init() when VIRTGPU_EXECBUF_RING_IDX selects a ring that userspace has enabled polling for. virtio_gpu_init_submit() does this before the BO handles, the command buffer, the syncobj arrays and the in-fence are processed, so every later error path runs with the event already pending, including plain argument validation failures such as an invalid bo_handle or an in-syncobj that carries no fence.
On those paths, virtio_gpu_cleanup_submit() drops the out-fence without cancelling the event. The fence is freed without ever having been emitted, taking the only driver-side pointer to the event with it. Closing the DRM file does not help. drm_events_release() unlinks pending events but deliberately leaves the freeing to the driver's later drm_send_event(), which never runs for an orphaned event, so the allocation is leaked permanently.
Found when fuzzing the virtio driver with Syzkaller:
BUG: memory leak unreferenced object 0xffff88802c176e80 (size 96): comm "syz.1.367", pid 10561, jiffies 4294960122 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ c8 6e 17 2c 80 88 ff ff 00 00 00 00 00 00 00 00 .n.,............ backtrace (crc e1973c6b): kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline] slab_post_alloc_hook mm/slub.c:4597 [inline] slab_alloc_node mm/slub.c:4917 [inline] __kmalloc_cache_noprof+0x49d/0x6f0 mm/slub.c:5485 _kmalloc_noprof include/linux/slab.h:988 [inline] _kzalloc_noprof include/linux/slab.h:1309 [inline] virtio_gpu_fence_event_create drivers/gpu/drm/virtio/virtgpu_submit.c:282 [inline] virtio_gpu_init_submit drivers/gpu/drm/virtio/virtgpu_submit.c:398 [inline] virtio_gpu_execbuffer_ioctl+0xbbf/0x1aa0 drivers/gpu/drm/virtio/virtgpu_submit.c:505 drm_ioctl_kernel+0x1f4/0x3e0 drivers/gpu/drm/drm_ioctl.c:817 drm_ioctl+0x5f4/0xc70 drivers/gpu/drm/drm_ioctl.c:914 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x116/0x800 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fix by cancelling and freeing the DRM event on the execbuffer error path before dropping the fence. Clear the fence's event pointer after cancellation so it does not retain a dangling pointer.
--- drivers/gpu/drm/virtio/virtgpu_submit.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/virtio/virtgpu_submit.c +4 -0
@@ -538,6 +538,10 @@ int virtio_gpu_execbuffer_ioctl(struct dvirtio_gpu_process_post_deps (&submit);virtio_gpu_complete_submit (&submit); cleanup: +if (ret && submit.out_fence && submit.out_fence->e) { +drm_event_cancel_free (dev, &submit.out_fence->e->base); + submit.out_fence->e =NULL ; + }virtio_gpu_cleanup_submit (&submit);return ret;
Greg Kroah-Hartman
maintainerPATCH 259/395 drm/virtio: fix NULL pointer dereference on fence allocation failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 846b3c64fe3e77d9db20a7e3e62dbbb637c773e1 upstream.
virtio_gpu_fence_alloc() can fail due to memory pressure and return NULL, but its caller like virtio_gpu_init_submit() never checks it. Later, virtio_gpu_init_submit() passes the NULL fence to virtio_gpu_fence_event_create(), which unconditionally dereferences it.
Found when fuzzing the virtio driver with Syzkaller:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000012: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000090-0x0000000000000097] CPU: 1 UID: 0 PID: 9991 Comm: syz.0.121 Not tainted 7.2.0 #4 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 RIP: 0010:virtio_gpu_fence_event_create drivers/gpu/drm/virtio/virtgpu_submit.c:295 [inline] RIP: 0010:virtio_gpu_init_submit drivers/gpu/drm/virtio/virtgpu_submit.c:398 [inline] RIP: 0010:virtio_gpu_execbuffer_ioctl+0xc78/0x1aa0 drivers/gpu/drm/virtio/virtgpu_submit.c:505 Code: 85 ed 0f 85 21 09 00 00 e8 05 5a c9 fb 48 8b 44 24 10 48 8d b8 90 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9a 0d 00 00 48 8b 44 24 10 4c 89 b0 90 00 00 00 RSP: 0018:ffffc900039dfad0 EFLAGS: 00010216 RAX: dffffc0000000000 RBX: ffffc900039dfdd8 RCX: ffffffff85f6fd3d RDX: 0000000000000012 RSI: ffffffff85f6fd4b RDI: 0000000000000090 RBP: 0000000000000000 R0virtio_gpu_virgl_process_cmd: ctrl 0x102, error 0x1203 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8880132c4000 R13: 0000000000000000 R14: ffff888073b6c700 R15: 000000000000003b FS: 00007fab480b96c0(0000) GS:ffff8880eb6e9000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007effbf5e55a8 CR3: 0000000048d19000 CR4: 0000000000350ef0 Call Trace: <TASK> drm_ioctl_kernel+0x1f4/0x3e0 drivers/gpu/drm/drm_ioctl.c:817 drm_ioctl+0x5f4/0xc70 drivers/gpu/drm/drm_ioctl.c:914 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl fs/ioctl.c:583 [inline] __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x116/0x800 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fab471a82bd Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007fab480b9018 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007fab47435fa0 RCX: 00007fab471a82bd RDX: 00002000000000c0 RSI: 00000000c0406442 RDI: 0000000000000003 RBP: 00007fab480b9080 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 R13: 00007fab47436038 R14: 00007fab47435fa0 R15: 00007ffe85ab0740 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:virtio_gpu_fence_event_create drivers/gpu/drm/virtio/virtgpu_submit.c:295 [inline] RIP: 0010:virtio_gpu_init_submit drivers/gpu/drm/virtio/virtgpu_submit.c:398 [inline] RIP: 0010:virtio_gpu_execbuffer_ioctl+0xc78/0x1aa0 drivers/gpu/drm/virtio/virtgpu_submit.c:505 Code: 85 ed 0f 85 21 09 00 00 e8 05 5a c9 fb 48 8b 44 24 10 48 8d b8 90 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9a 0d 00 00 48 8b 44 24 10 4c 89 b0 90 00 00 00 RSP: 0018:ffffc900039dfad0 EFLAGS: 00010216 RAX: dffffc0000000000 RBX: ffffc900039dfdd8 RCX: ffffffff85f6fd3d RDX: 0000000000000012 RSI: ffffffff85f6fd4b RDI: 0000000000000090 RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8880132c4000 R13: 0000000000000000 R14: ffff888073b6c700 R15: 000000000000003b FS: 00007fab480b96c0(0000) GS:ffff888098ae9000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f24c3759000 CR3: 0000000048d19000 CR4: 0000000000350ef0 ---------------- Code disassembly (best guess): 0: 85 ed test %ebp,%ebp 2: 0f 85 21 09 00 00 jne 0x929 8: e8 05 5a c9 fb call 0xfbc95a12 d: 48 8b 44 24 10 mov 0x10(%rsp),%rax 12: 48 8d b8 90 00 00 00 lea 0x90(%rax),%rdi 19: 48 b8 00 00 00 00 00 movabs $0xdffffc0000000000,%rax 20: fc ff df 23: 48 89 fa mov %rdi,%rdx 26: 48 c1 ea 03 shr $0x3,%rdx * 2a: 80 3c 02 00 cmpb $0x0,(%rdx,%rax,1) <-- trapping instruction 2e: 0f 85 9a 0d 00 00 jne 0xdce 34: 48 8b 44 24 10 mov 0x10(%rsp),%rax 39: 4c 89 b0 90 00 00 00 mov %r14,0x90(%rax)
Fix by checking virtio_gpu_fence_alloc() in virtio_gpu_init_submit() and returning -ENOMEM before any later code can dereference the NULL fence.
--- drivers/gpu/drm/virtio/virtgpu_submit.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/virtio/virtgpu_submit.c +5 -2
@@ -389,10 +389,13 @@ static int virtio_gpu_init_submit(structif ((exbuf->flags &VIRTGPU_EXECBUF_FENCE_FD_OUT ) || exbuf->num_out_syncobjs || exbuf->num_bo_handles || - drm_fence_event) + drm_fence_event) { out_fence =virtio_gpu_fence_alloc (vgdev, fence_ctx, ring_idx); -else +if (!out_fence) +return -ENOMEM ; + }else { out_fence =NULL ; + }if (drm_fence_event) { err =virtio_gpu_fence_event_create (dev, file, out_fence, ring_idx);
Greg Kroah-Hartman
maintainerPATCH 260/395 gpio: tps65219: Fix GPIO input value reads
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 4cbe530c0233c7413aaaeb029a4f32dd6aadacbb upstream.
TPS65219_MFP_GPIO_STATUS_MASK is already BIT(4). Passing it to BIT() again tests bit 16, which cannot be set in the 8-bit MFP_CTRL register, so GPIO0 is always reported low when configured as an input.
Test the register value with the mask directly.
--- drivers/gpio/gpio-tps65219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-tps65219.c +1 -1
@@ -79,7 +79,7 @@ static int tps65219_gpio_get(struct gpioif (ret)return ret; - ret = !!(val &BIT (TPS65219_MFP_GPIO_STATUS_MASK )); + ret = !!(val &TPS65219_MFP_GPIO_STATUS_MASK );dev_warn (dev,"GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n" , offset, ret);/*
Greg Kroah-Hartman
maintainerPATCH 261/395 gpio: tps65219: Use the variant-specific direction callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 93cf8cedeaaa05714f709b539cfb976e0b80c830 upstream.
The TPS65214 template installs its own get_direction callback because its direction bit is in GENERAL_CONFIG. The shared get and direction callbacks nevertheless call tps65219_gpio_get_direction() directly and interpret the unrelated TPS65219 MFP bit.
On TPS65214 this can reject reads from an input and skip the change from input to output. Call the callback selected by the gpio_chip template instead.
--- drivers/gpio/gpio-tps65219.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpio-tps65219.c +3 -3
@@ -87,7 +87,7 @@ static int tps65219_gpio_get(struct gpio* status bit. */ -if (tps65219_gpio_get_direction (gc, offset) ==GPIO_LINE_DIRECTION_OUT ) +if (gc->get_direction (gc, offset) ==GPIO_LINE_DIRECTION_OUT )return -ENOTSUPP ;return ret;
@@ -176,7 +176,7 @@ static int tps65219_gpio_direction_inputreturn -ENOTSUPP ; } -if (tps65219_gpio_get_direction (gc, offset) ==GPIO_LINE_DIRECTION_IN ) +if (gc->get_direction (gc, offset) ==GPIO_LINE_DIRECTION_IN )return 0 ;return gpio->change_dir (gc, offset,GPIO_LINE_DIRECTION_IN );
@@ -190,7 +190,7 @@ static int tps65219_gpio_direction_outpuif (offset !=TPS6521X_GPIO0_IDX )return 0 ; -if (tps65219_gpio_get_direction (gc, offset) ==GPIO_LINE_DIRECTION_OUT ) +if (gc->get_direction (gc, offset) ==GPIO_LINE_DIRECTION_OUT )return 0 ;return gpio->change_dir (gc, offset,GPIO_LINE_DIRECTION_OUT );
Greg Kroah-Hartman
maintainerPATCH 262/395 gpio: tps65219: Fix TPS65214 GPIO direction programming
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 270437f3fe62516f16482742a7762a075e7a9457 upstream.
GPIO_LINE_DIRECTION_OUT and GPIO_LINE_DIRECTION_IN have the values 0 and 1, respectively, while the TPS65214 GPIO_CONFIG field is BIT(1). regmap_update_bits() masks the supplied value, so passing either direction value clears the field and selects input mode.
Translate the GPIO direction to the register encoding used by tps65214_gpio_get_direction(), setting GPIO_CONFIG for output and clearing it for input.
--- drivers/gpio/gpio-tps65219.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpio/gpio-tps65219.c +3 -1
@@ -158,8 +158,10 @@ static int tps65214_gpio_change_directioif (ret)dev_err (dev,"GPIO%d configured as VSEL, not GPIO\n" , offset); + val = direction ==GPIO_LINE_DIRECTION_OUT ? +TPS65214_GPIO0_DIR_MASK :0 ; ret =regmap_update_bits (gpio->tps->regmap,TPS65219_REG_GENERAL_CONFIG , -TPS65214_GPIO0_DIR_MASK , direction); +TPS65214_GPIO0_DIR_MASK , val);if (ret)dev_err (dev,"Fail to change direction to %u for GPIO%d.\n" , direction, offset);
Greg Kroah-Hartman
maintainerPATCH 263/395 mm/hugetlb: preserve mremap address delta when skipping page tables
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jaewook You <[email protected]>
commit 9bdad082d44bdcf93716973dcba6be77e8a06e7b upstream.
move_hugetlb_page_tables() optimizes mremap() by advancing to the last entry in the page table when the source page table does not exist, either initially or after unsharing a PMD table. The common loop increment then steps to the first entry in the next page table.
However, the code advances both the source and destination addresses to the last entries in their respective page tables, which is wrong. The destination address must be advanced only by the same amount as the source address.
If the source and destination offsets within their page tables differ, the destination address can be advanced too far, causing follow-up issues. Fix this by advancing the destination address by the source advance distance.
With a reproducer, we were able to trigger a kernel panic on x86-64. With this fix in place, we can no longer reproduce the issue.
--- mm/hugetlb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
mm/hugetlb.c +7 -4
@@ -5828,18 +5828,21 @@ int move_hugetlb_page_tables(struct vm_ahugetlb_vma_lock_write (vma);i_mmap_lock_write (mapping);for (; old_addr < old_end; old_addr += sz, new_addr += sz) { +const unsigned long offset_to_last_entry = + (old_addr | last_addr_mask) - old_addr; + src_pte =hugetlb_walk (vma, old_addr, sz);if (!src_pte) { - old_addr |= last_addr_mask; - new_addr |= last_addr_mask; + old_addr += offset_to_last_entry; + new_addr += offset_to_last_entry;continue ; }if (huge_pte_none (huge_ptep_get (mm, old_addr, src_pte)))continue ;if (huge_pmd_unshare (&tlb, vma, old_addr, src_pte)) { - old_addr |= last_addr_mask; - new_addr |= last_addr_mask; + old_addr += offset_to_last_entry; + new_addr += offset_to_last_entry;continue ; }
Greg Kroah-Hartman
maintainerPATCH 264/395 mm/damon/vaddr: avoid hw-driven pte updates during damon_hugetlb_mkold()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 39c0ceedd54557bdc1542de08d22b2ed33e534e4 upstream.
damon_hugetlb_mkold() reads the page table entry into a local variable, unsets the accessed bit in the variable, and updates the page table entry with the updated variable value. If hardware updates the same page table entry in parallel, the hw updates could be lost. For example, hardware-updated dirty bits might be lost.
Avoid the parallel updates by clearing the page table entry when reading it together, using huge_ptep_get_and_clear(). If a parallel write to the memory is made after the clearing, the hw will see the page table entry is cleared, trigger page fault and wait until it is handled. The page fault handling will wait for damon_hugetlb_mkold() due to the page table lock.
Because hugetlbfs is an in-memory file system and hugetlb pages cannot be reclaimed, no critical issue is expected to my best knowledge. But definitely this is a nasty bug that should be fixed sooner rather than later.
The issue was discovered [1] by Sashiko.
--- mm/damon/vaddr.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
mm/damon/vaddr.c +14 -7
@@ -339,22 +339,29 @@ out: }#ifdef CONFIG_HUGETLB_PAGE +static bool damon_hugetlb_ptep_mkold (pte_t *pte,struct mm_struct *mm, +struct vm_area_struct *vma,unsigned long addr,pte_t *entry) +{ +unsigned long psize =huge_page_size (hstate_vma (vma)); + +if (!pte_young (*entry)) +return false; + *entry =huge_ptep_get_and_clear (mm, addr, pte, psize); + *entry =pte_mkold (*entry); +set_huge_pte_at (mm, addr, pte, *entry, psize); +return true; +} +static void damon_hugetlb_mkold (pte_t *pte,struct mm_struct *mm,struct vm_area_struct *vma,unsigned long addr) {bool referenced = false;pte_t entry =huge_ptep_get (mm, addr, pte);struct folio *folio =pfn_folio (pte_pfn (entry)); -unsigned long psize =huge_page_size (hstate_vma (vma));folio_get (folio); -if (pte_young (entry)) { - referenced = true; - entry =pte_mkold (entry); -set_huge_pte_at (mm, addr, pte, entry, psize); - } - + referenced =damon_hugetlb_ptep_mkold (pte, mm, vma, addr, &entry);if (mmu_notifier_clear_young (mm, addr, addr +huge_page_size (hstate_vma (vma)))) referenced = true;
Greg Kroah-Hartman
maintainerPATCH 265/395 PCI: of_property: Omit bus properties without a subordinate bus
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Angel J <[email protected]>
commit 8805840aad73df7146778be243a196d48b4f6430 upstream.
A bridge (a device with a Type 1 header) may not have a secondary bus allocated (pdev->subordinate), e.g., if there are no available bus numbers or the bridge secondary/subordinate bus numbers are not writable.
The dynamic OF helpers of_pci_prop_bus_range() and of_pci_prop_intr_map() dereference pdev->subordinate without checking it. When CONFIG_PCI_DYNAMIC_OF_NODES is enabled, this can cause a NULL pointer dereference and early boot hang.
Generate 'bus-range' and 'interrupt-map' properties only when a subordinate bus exists. Keep the node and its remaining properties for bridges without one.
The problem was latent since 407d1a51921e ("PCI: Create device tree node for bridge"), but wasn't reachable until 1f340724419e ("PCI: of: Create device tree PCI host bridge node"), which appeared in v6.15. Before 1f340724419e, of_pci_make_dev_node() returned early because the parent OF node was missing.
--- drivers/pci/of_property.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/pci/of_property.c +9 -2
@@ -95,9 +95,13 @@ static int of_pci_prop_bus_range(structstruct of_changeset *ocs, struct device_node *np) { - u32 bus_range[] = { pdev->subordinate->busn_res.start, - pdev->subordinate->busn_res.end }; + u32 bus_range[2]; +if (!pdev->subordinate) +return 0 ; + + bus_range[0 ] = pdev->subordinate->busn_res.start; + bus_range[1 ] = pdev->subordinate->busn_res.end;return of_changeset_add_prop_u32_array (ocs, np,"bus-range" , bus_range,ARRAY_SIZE (bus_range)); }
@@ -220,6 +224,9 @@ static int of_pci_prop_intr_map(struct pint ret;u8 pin; +if (!pdev->subordinate) +return 0 ; + pnode =pci_device_to_OF_node (pdev->bus->self);if (!pnode) pnode =pci_bus_to_OF_node (pdev->bus);
Greg Kroah-Hartman
maintainerPATCH 266/395 packet: use ubuf_info completion for TX_RING packets
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Willem de Bruijn <[email protected]>
commit 9518405613863d0bf0700927a21367f5942cf058 upstream.
tpacket_snd sends skbs with frags pointing into its ring slots. Slots are released when skb->destructor is called.
A call to skb_orphan calls skb->destructor before the skb is freed. This can cause the slot to be reused while still linked into the skb.
Switch to standard zerocopy completion (ubuf_info) so the slot is only released once all references to the payload are freed or copied. Restore skb->destructor to standard sock_wfree.
The ubuf_info completion callback can be called with a NULL skb, but only from net_zcopy_put and related API, used by zerocopy implementations that hold their own reference on the uarg, such as MSG_ZEROCOPY. This uarg is only ever completed from skb_zcopy_clear, so skb is always set.
To prevent userspace from aliasing in-flight state on shared ring slots, allocate tpacket_uarg per packet, rather than per slot. This adds a small allocation to the transmit path. Use standard kmalloc to allow backporting to stable kernels.
The uarg holds an sk_wmem_alloc reference, rather than an sk_refcnt reference. packet_free_tx_ring waits on sk_wmem_alloc before freeing the ring pages. Always allocate vec->deferred for tx_ring so page-backed rings also wait on sk_wmem_alloc when skb_copy_ubufs drops page refs before calling tpacket_ubuf_complete.
Drop the tx_ring.pg_vec test that tpacket_destruct_skb performed before accessing the slot. The sk_wmem_alloc reference now guarantees that the slot is valid. The test is also not sufficient by itself, as it reads pg_vec without pg_vec_lock, so it can race with packet_set_ring.
As a result a slot is released when its payload is copied, which can be before transmission (e.g., in skb_orphan_frags_rx). If copied before skb_tx_timestamp() is called, no slot timestamp is recorded, similar to when skb_orphan() was called early in the datapath before this patch.
Revert the now unused previous skb_zcopy_.._nouarg infra.
Depends on commit 992cc9f94ca9 ("net/packet: defer vmalloc TX_RING free until skbs finish").
--- include/linux/skbuff.h | 19 --------- net/packet/af_packet.c | 102 ++++++++++++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 56 deletions(-)
include/linux/skbuff.h +1 -18
@@ -1833,22 +1833,6 @@ static inline void skb_zcopy_set(struct } } -static inline void skb_zcopy_set_nouarg (struct sk_buff *skb,void *val) -{ -skb_shinfo (skb)->destructor_arg = (void *)((uintptr_t ) val |0x1UL ); -skb_shinfo (skb)->flags |=SKBFL_ZEROCOPY_FRAG ; -} - -static inline bool skb_zcopy_is_nouarg (struct sk_buff *skb) -{ -return (uintptr_t )skb_shinfo (skb)->destructor_arg &0x1UL ; -} - -static inline void *skb_zcopy_get_nouarg (struct sk_buff *skb) -{ -return (void *)((uintptr_t )skb_shinfo (skb)->destructor_arg & ~0x1UL ); -} -static inline void net_zcopy_put (struct ubuf_info *uarg) {if (uarg)
@@ -1871,8 +1855,7 @@ static inline void skb_zcopy_clear(strucstruct ubuf_info *uarg =skb_zcopy (skb);if (uarg) { -if (!skb_zcopy_is_nouarg (skb)) - uarg->ops->complete (skb, uarg, zerocopy_success); + uarg->ops->complete (skb, uarg, zerocopy_success);skb_shinfo (skb)->flags &= ~SKBFL_ALL_ZEROCOPY ; }
net/packet/af_packet.c +64 -38
158 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 267/395 HID: alps: fix use-after-free on input2 registration failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Changcheng <[email protected]>
commit d3aba3442798ce4a4c8ce3104d7b286d61e605f9 upstream.
alps_input_configured() stores data->input2 before calling input_register_device(). If registration fails, input_free_device() frees the input device but data->input2 still points to the freed memory. alps_input_configured() calls hid_hw_open() before allocating input2, so URBs are already active and raw_event can fire during the failure window. A U1_SP_ABSOLUTE_REPORT_ID report arriving then causes u1_raw_event() to dereference the freed data->input2 -> use-after-free.
Fix by only storing input2 into drvdata after successful registration and adding a NULL guard in the raw_event path.
--- drivers/hid/hid-alps.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/hid/hid-alps.c +4 -2
@@ -407,6 +407,8 @@ static int u1_raw_event(struct alps_devreturn 1 ;case U1_SP_ABSOLUTE_REPORT_ID : +if (!hdata->input2) +return 0 ; sp_x =get_unaligned_le16 (data+2 ); sp_y =get_unaligned_le16 (data+4 );
@@ -738,7 +740,6 @@ static int alps_input_configured(struct goto exit; } - data->input2 = input2; input2->phys = input->phys; input2->name ="DualPoint Stick" ; input2->id.bustype =BUS_I2C ;
@@ -762,11 +763,12 @@ static int alps_input_configured(struct__set_bit (INPUT_PROP_POINTER , input2->propbit);__set_bit (INPUT_PROP_POINTING_STICK , input2->propbit); -if (input_register_device (data->input2)) { +if (input_register_device (input2)) {input_free_device (input2); ret = -ENOENT ; goto exit; } + data->input2 = input2; } exit:
Greg Kroah-Hartman
maintainerPATCH 268/395 HID: quirks: add ALWAYS_POLL quirk for SDINNOVATION gaming keyboard
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junjie Cao <[email protected]>
commit cdb669a3b8f844aca71fc3224990157d61562165 upstream.
The SDINNOVATION gaming keyboard (USB ID 36ae:feab) stops reporting input events after its RGB lighting mode is switched about twice. Disabling USB autosuspend and unbinding the other HID interfaces make no difference; the issue does not occur on Windows.
HID_QUIRK_ALWAYS_POLL alone resolves it, verified on 7.1.8 via usbhid.quirks=0x36ae:0xfeab:0x400.
--- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+)
drivers/hid/hid-ids.h +3 -0
@@ -1232,6 +1232,9 @@#define USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD 0xa006#define USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD 0xa064 +#define USB_VENDOR_ID_SDINNOVATION 0x36ae +#define USB_DEVICE_ID_SDINNOVATION_GAMING_KBD 0xfeab +#define USB_VENDOR_ID_SEMICO 0x1a2c#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD2 0x0027
drivers/hid/hid-quirks.c +1 -0
@@ -182,6 +182,7 @@ static const struct hid_device_id hid_qu { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SDINNOVATION, USB_DEVICE_ID_SDINNOVATION_GAMING_KBD), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
Greg Kroah-Hartman
maintainerPATCH 269/395 HID: wacom: fix OOB read in wacom_wac_pen_serial_enforce()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Jie LAW <[email protected]>
commit 9aa237cf66495b2426ddde8532e9b08a0ed83aaa upstream.
The 'wacom_wac_pen_serial_enforce()' function may calculate and pass an invalid offset to hid_field_extract(), resulting in memory reads at incorrect addresses -- possibly beyond the end of the report. If a field in the HID descriptor lists more usages than its Report Count actually reserves space for, the function's inner 'j' will walk past the end of the field:
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->maxusage; j++) {
...
value = hid_field_extract(hdev, raw_data + 1,
offset + j * size, size);A descriptor listing 12288 usages against Report Count 1 has the loop extract the usage at index 12287 from bit offset 98296 -- about 12 KB past a 2-byte received report. The value is stored in wacom_wac->serial[0] and can reach userspace as an MSC_SERIAL event, making this an information disclosure.
Clamp the loop to field->report_count, the number of value slots the report holds. Value slots past the last declared usage are still scanned; they reuse that usage (HID 1.11, 6.2.2.8).
Verified on v6.12.105 with a UHID reproducer: a 2-byte report from such a descriptor trips KASAN before the patch and not after it.
--- drivers/hid/wacom_sys.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hid/wacom_sys.c +3 -2
@@ -117,8 +117,9 @@ static int wacom_wac_pen_serial_enforce(/* Queue events which have invalid tool type or serial number */ for (i =0 ; i < report->maxfield; i++) { -for (j =0 ; j < report->field[i]->maxusage; j++) { -struct hid_field *field = report->field[i]; +struct hid_field *field = report->field[i]; + +for (j =0 ; j < field->report_count; j++) {struct hid_usage *usage = &field->usage[j];unsigned int equivalent_usage =wacom_equivalent_usage (usage->hid);unsigned int offset;
Greg Kroah-Hartman
maintainerPATCH 270/395 net/mlx5: Fix rev_entry reference leak in mlx5_tc_ct_shared_counter_get()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 0bf6bb567f0edaa771e7dd208ef98da50e6a4485 upstream.
When the reverse entry is found but its counter is already being released, refcount_inc_not_zero() fails and the reference taken by mlx5_tc_ct_entry_get() is never dropped before falling through to create_counter. Drop it so the reverse entry is not kept alive forever by a shared counter lookup that did not use it.
--- drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c +3 -0
@@ -1082,6 +1082,9 @@ mlx5_tc_ct_shared_counter_get(struct mlxspin_unlock_bh (&ct_priv->ht_lock); +if (rev_entry) +mlx5_tc_ct_entry_put (rev_entry); + create_counter: shared_counter =mlx5_tc_ct_counter_create (ct_priv);
Greg Kroah-Hartman
maintainerPATCH 271/395 net/mlx5e: advertise MACsec offload only when supported
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ralf Lici <[email protected]>
commit 4581c3d2adc3c73a019bc38db64ca11f28bbd7fd upstream.
Commit 339ccec8d43d ("net/mlx5: Enable MACsec offload feature for VLAN interface") added NETIF_F_HW_MACSEC unconditionally to vlan_features so that VLAN devices could inherit MACsec offload support.
mlx5e_build_nic_netdev subsequently copies vlan_features into hw_features and features. As a result, all mlx5e NIC netdevices advertise MACsec hardware offload, even when the firmware does not support it and the driver does not install macsec_ops.
Set the MACsec feature bits in mlx5e_macsec_build_netdev, after device capabilities have been validated. This preserves MACsec-over-VLAN support and the ethtool feature control on capable devices, without advertising either on unsupported hardware.
--- drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +2 -0
@@ -1727,6 +1727,8 @@ void mlx5e_macsec_build_netdev(struct mlmlx5_core_dbg (priv->mdev,"mlx5e: MACsec acceleration enabled\n" ); netdev->macsec_ops = &macsec_offload_ops; netdev->features |=NETIF_F_HW_MACSEC ; + netdev->hw_features |=NETIF_F_HW_MACSEC ; + netdev->vlan_features |=NETIF_F_HW_MACSEC ;netif_keep_dst (netdev); }
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +0 -1
@@ -5685,7 +5685,6 @@ static void mlx5e_build_nic_netdev(struc netdev->vlan_features |=NETIF_F_SG ; netdev->vlan_features |=NETIF_F_HW_CSUM ; - netdev->vlan_features |=NETIF_F_HW_MACSEC ; netdev->vlan_features |=NETIF_F_GRO ; netdev->vlan_features |=NETIF_F_TSO ; netdev->vlan_features |=NETIF_F_TSO6 ;
Greg Kroah-Hartman
maintainerPATCH 272/395 net/mlx5e: fix swapped IPv6 IPsec policy masks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrea Parri <[email protected]>
commit 10de7ed8ef4840da9ca21de4c29578657ac367db upstream.
IPv6 XFRM policies may use different source and destination prefix lengths. mlx5e_ipsec_policy_mask() builds the corresponding masks independently, but setup_fte_addr6() installs each mask in the opposite address field.
When the prefix lengths differ, this makes the source match use the destination prefix and the destination match use the source prefix. The resulting hardware rule can both miss traffic covered by the policy and match traffic outside it.
Install each mask in its corresponding match field.
--- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +2 -2
@@ -1564,14 +1564,14 @@ static void setup_fte_addr6(struct mlx5_memcpy (MLX5_ADDR_OF (fte_match_param, spec->match_value, outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), saddr,16 );memcpy (MLX5_ADDR_OF (fte_match_param, spec->match_criteria, - outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), dmask,16 ); + outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), smask,16 ); }if (!addr6_all_zero (daddr)) {memcpy (MLX5_ADDR_OF (fte_match_param, spec->match_value, outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), daddr,16 );memcpy (MLX5_ADDR_OF (fte_match_param, spec->match_criteria, - outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), smask,16 ); + outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), dmask,16 ); } }
Greg Kroah-Hartman
maintainerPATCH 273/395 net/sched: reject IDR error pointers when deleting actions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit c82b797abe668d0b668601a93ba2c0b071a63574 upstream.
tcf_action_delete() drops the reference held by its lookup before calling tcf_idr_delete_index() with the saved action index. An unlocked classifier can remove that action and reserve the same IDR slot with ERR_PTR(-EBUSY) in between.
tcf_idr_delete_index() only checks the lookup result for NULL. It therefore treats the reservation as a tc_action and dereferences tcfa_bindcnt. A hardware execution breakpoint was used to schedule the interleaving without changing the kernel source. KASAN reported this decoded trace:
BUG: KASAN: null-ptr-deref in tca_action_gd+0x5b9/0x1010
Read of size 4 at addr 0000000000000010 by task poc/150
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000002
RIP: tca_action_gd+0x5c0/0x1010:
arch_atomic_read at arch/x86/include/asm/atomic.h:23
raw_atomic_read at include/linux/atomic/atomic-arch-fallback.h:457
atomic_read at include/linux/atomic/atomic-instrumented.h:33
tcf_idr_delete_index at net/sched/act_api.c:766
tcf_action_delete at net/sched/act_api.c:1859
tcf_del_notify at net/sched/act_api.c:2014
tca_action_gd at net/sched/act_api.c:2064
R13: 0000000000000010 R15: fffffffffffffff0
Kernel panic - not syncing: Fatal exceptionR15 contains ERR_PTR(-EBUSY), and adding the tcfa_bindcnt offset produces the address in R13. With the guard applied, the same reproducer returned -ENOENT without a KASAN report or panic. Treat error pointers as absent and return -ENOENT.
--- net/sched/act_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/act_api.c +1 -1
@@ -758,7 +758,7 @@ static int tcf_idr_delete_index(struct tmutex_lock (&idrinfo->lock); p =idr_find (&idrinfo->action_idr, index); -if (!p) { +if (IS_ERR_OR_NULL (p)) {mutex_unlock (&idrinfo->lock);return -ENOENT ; }
Greg Kroah-Hartman
maintainerPATCH 274/395 net: airoha: npu: cancel wdt_work after releasing the WDT IRQ
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 4bdee8060d1e4581624e68fbd369b1afb14df4bc upstream.
airoha_npu_remove() calls cancel_work_sync() on each core's wdt_work, but the watchdog IRQ that queues it is requested with devm_request_irq() and is freed only after .remove() returns. airoha_npu_wdt_handler() can therefore schedule_work() again once the cancel has returned. struct airoha_npu, which contains the work, is devm_kzalloc()'d and is freed in that same unwind, so the late work dereferences freed memory.
Register the work with devm_work_autocancel() before devm_request_irq() and drop .remove(). Devres runs in reverse order, so the IRQ is freed before cancel_work_sync(), including when probe fails. A cancel left in .remove() cannot get that order. Initializing the work first also stops a pending watchdog interrupt from queuing an uninitialized work item. Probe currently calls INIT_WORK() only after devm_request_irq().
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/net/ethernet/airoha/airoha_npu.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-)
drivers/net/ethernet/airoha/airoha_npu.c +6 -12
@@ -5,6 +5,7 @@*/ #include <linux/devcoredump.h> +#include <linux/devm-helpers.h> #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/of_net.h>
@@ -669,12 +670,15 @@ static int airoha_npu_probe(struct platfif (irq <0 )return irq; + err =devm_work_autocancel (dev, &core->wdt_work, + airoha_npu_wdt_work); +if (err) +return err; + err =devm_request_irq (dev, irq, airoha_npu_wdt_handler,IRQF_SHARED ,"airoha-npu-wdt" , core);if (err)return err; - -INIT_WORK (&core->wdt_work, airoha_npu_wdt_work); }/* wlan IRQ lines */
@@ -716,18 +720,8 @@ static int airoha_npu_probe(struct platfreturn 0 ; } -static void airoha_npu_remove (struct platform_device *pdev) -{ -struct airoha_npu *npu =platform_get_drvdata (pdev); -int i; - -for (i =0 ; i <ARRAY_SIZE (npu->cores); i++) -cancel_work_sync (&npu->cores[i].wdt_work); -} -static struct platform_driver airoha_npu_driver = { .probe = airoha_npu_probe, - .remove = airoha_npu_remove, .driver = { .name ="airoha-npu" , .of_match_table = of_airoha_npu_match,
Greg Kroah-Hartman
maintainerPATCH 275/395 net: arp: terminate device name before lookup
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijie Huang <[email protected]>
commit d8b6529e80bcb4fb8177121404cbb3377acaebd2 upstream.
The ARP ioctl copies a user-provided struct arpreq into a stack object. Its arp_dev field may contain IFNAMSIZ bytes without a NUL terminator.
Such input is passed to dev_get_by_name_rcu() or __dev_get_by_name(), where strcmp() can read past the end of the stack object when a matching alternative interface name exists.
Terminate the field before the lookup to prevent the out-of-bounds read.
--- net/ipv4/arp.c | 1 + 1 file changed, 1 insertion(+)
net/ipv4/arp.c +1 -0
@@ -1278,6 +1278,7 @@ int arp_ioctl(struct net *net, unsigned err =copy_from_user (&r, arg,sizeof (struct arpreq ));if (err)return -EFAULT ; + r.arp_dev[IFNAMSIZ -1 ] ='\0' ;break ;default :return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 276/395 net: atl1: fix soft lockup on out-of-range cmb_tpd_next_to_clean read
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gajdos Tamás <[email protected]>
commit 43e746821f5f5afbbf68e388bf9fbe221e03bfca upstream.
Same issue as atl1c (see the first commit in this series, "net:
atl1c: fix soft lockup on out-of-range tpd_cons read"): the hardware can report an out-of-range cmb_tpd_next_to_clean (seen as 0xffff) while the PCIe link/MAC is resetting. An out-of-range value can never be reached and the loop below would spin forever. Treat it as "nothing new to clean" instead.
--- drivers/net/ethernet/atheros/atlx/atl1.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/atheros/atlx/atl1.c +3 -0
@@ -2066,6 +2066,9 @@ static int atl1_intr_tx(struct atl1_adap sw_tpd_next_to_clean =atomic_read (&tpd_ring->next_to_clean); cmb_tpd_next_to_clean =le16_to_cpu (adapter->cmb.cmb->tpd_cons_idx); +if (unlikely (cmb_tpd_next_to_clean >= tpd_ring->count)) + cmb_tpd_next_to_clean = sw_tpd_next_to_clean; +while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];if (buffer_info->dma) {
Greg Kroah-Hartman
maintainerPATCH 277/395 net: hisilicon: hns_dsaf_mac: fix mdio device leak in hns_mac_register_phy()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 999e8295bc41d6ce45b8e54f88150efa96f3f01e upstream.
hns_dsaf_find_platform_device() returns the mdio platform device with its reference count incremented. hns_mac_register_phy() never drops that reference, so the mdio device can not be released.
Release the reference on both the deferred probe and the normal path.
--- drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +3 -0
@@ -793,6 +793,7 @@ static int hns_mac_register_phy(struct hdev_err (mac_cb->dev,"mac%d mdio is NULL, dsaf will probe again later\n" , mac_cb->mac_id); +put_device (&pdev->dev);return -EPROBE_DEFER ; }
@@ -801,6 +802,8 @@ static int hns_mac_register_phy(struct hdev_dbg (mac_cb->dev,"mac%d register phy addr:%d\n" , mac_cb->mac_id, addr); +put_device (&pdev->dev); +return rc; }
Greg Kroah-Hartman
maintainerPATCH 278/395 net: openvswitch: conntrack: avoid modifying shared unconfirmed ct entry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
commit 26b2bd70d22457556e2fa01cbf1192cb1a94d619 upstream.
In a case where skb with an unconfirmed ct entry gets cloned, we may end up committing both but with different sets of extensions.
The series of events:
1. The first clone wants to commit and runs the helpers wiring up the extension pointer into the expectation list.
2. Then it looses the confirmation keeping the entry unconfirmed.
3. Second clone now wants to commit labels and adds the new extension for that breaking the pointer in the expectation list causing UAF on the destruction path later.
While this is possible to trigger, there should be no practical network pipeline where committing both clones without modifications into the same zone is needed. So, let's just reset the entry in case for some reason we got an skb with a shared one during commit. This doesn't affect any known use cases, but avoids any potential problems with sharing and modification of the unconfirmed ct entry.
The fixes tag points to the introduction of helpers, since that's the main UAF trigger for the sharing.
--- include/net/netfilter/nf_conntrack.h | 5 +++++ net/openvswitch/conntrack.c | 12 ++++++++++++ 2 files changed, 17 insertions(+)
include/net/netfilter/nf_conntrack.h +5 -0
@@ -184,6 +184,11 @@ static inline void nf_ct_put(struct nf_cnf_ct_destroy (&ct->ct_general); } +static inline bool nf_ct_shared (const struct nf_conn *ct) +{ +return refcount_read (&ct->ct_general.use) >1 ; +} +/* load module; enable/disable conntrack in this namespace */ int nf_ct_netns_get (struct net *net,u8 nfproto);void nf_ct_netns_put (struct net *net,u8 nfproto);
net/openvswitch/conntrack.c +12 -0
@@ -734,6 +734,18 @@ static int __ovs_ct_lookup(struct net *nenum ip_conntrack_info ctinfo;struct nf_conn *ct; +/* If the ct entry is not confirmed and shared with some other skb, +* e.g., a cloned one, we can't just modify it with the commit as we +* must not modify the extension set. Reset. +*/ +if (cached && info->commit) { + ct =nf_ct_get (skb, &ctinfo); +if (ct && !nf_ct_is_confirmed (ct) &&nf_ct_shared (ct)) { +nf_reset_ct (skb); + cached = false; + } + } +if (!cached) {struct nf_hook_state state = { .hook =NF_INET_PRE_ROUTING ,