6.6.157-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 256/1424 net: usb: qmi_wwan: add Telit Cinterion FE990D50 composition
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Porcedda <[email protected]>
commit 1056e79fffd0841f43c6a1b25664b196b3caf1c6 upstream.
Add the followin Telit Cinterion FE990D50 composition:
0x0991: rmnet + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0991 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=2aa802d2 C: #Ifs= 9 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 6 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/usb/qmi_wwan.c +1 -0
@@ -1368,6 +1368,7 @@ static const struct usb_device_id produc {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x0991, 0)}, /* Telit FE990D50 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1034, 2)}, /* Telit LE910C4-WWX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1037, 4)}, /* Telit LE910C4-WWX */
Greg Kroah-Hartman
maintainerPATCH 257/1424 net: tun: bound receive headroom
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit 447c9303942c439a117d9b76ce6d6e2116b38ee7 upstream.
tun_get_user() uses tun->align both as skb headroom and when choosing how much packet data to keep linear. OVS can propagate an oversized headroom request from another port to TUN or TAP.
When align is larger than the usable space in a one-page skb head, SKB_MAX_HEAD(align) underflows and the result becomes negative when stored in good_linear. That value later wraps when assigned to the size_t linear variable, and tun_alloc_skb() can place skb->data outside the allocated head.
Bound the headroom stored by TUN to the one-page skb-head budget and the largest non-sentinel 16-bit skb header offset. Leave one linear byte for raw TUN and a complete Ethernet header for TAP, including NET_IP_ALIGN.
Also pull the raw-TUN protocol byte and the TAP Ethernet header before accessing them, so these checks remain safe for nonlinear skbs supplied by other allocation paths.
--- drivers/net/tun.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/net/tun.c +16 -5
@@ -1175,11 +1175,16 @@ static netdev_features_t tun_net_fix_feastatic void tun_set_headroom (struct net_device *dev,int new_hr) {struct tun_struct *tun =netdev_priv (dev); +size_t max_headroom; -if (new_hr <NET_SKB_PAD ) - new_hr =NET_SKB_PAD ; + max_headroom =min_t (size_t,SKB_MAX_HEAD (0 ),U16_MAX -1 ); - tun->align = new_hr; +if ((tun->flags &TUN_TYPE_MASK ) ==IFF_TAP ) + max_headroom -=ETH_HLEN +NET_IP_ALIGN ; +else + max_headroom -=1 ; + + tun->align =clamp_t (int, new_hr,NET_SKB_PAD , max_headroom); } static void
@@ -1879,7 +1884,13 @@ static ssize_t tun_get_user(struct tun_sswitch (tun->flags &TUN_TYPE_MASK ) {case IFF_TUN :if (tun->flags &IFF_NO_PI ) { -u8 ip_version = skb->len ? (skb->data[0 ] >>4 ) :0 ; +u8 ip_version; + +if (!pskb_may_pull (skb,1 )) { + err = -EINVAL ; + goto drop; + } + ip_version = skb->data[0 ] >>4 ;switch (ip_version) {case 4 :
@@ -1899,7 +1910,7 @@ static ssize_t tun_get_user(struct tun_s skb->dev = tun->dev;break ;case IFF_TAP : -if (frags && !pskb_may_pull (skb,ETH_HLEN )) { +if (!pskb_may_pull (skb,ETH_HLEN )) { err = -ENOMEM ; drop_reason =SKB_DROP_REASON_HDR_TRUNC ; goto drop;
Greg Kroah-Hartman
maintainerPATCH 258/1424 net: openvswitch: fix flow mask use-after-free on flow deletion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
commit 4e30317ff67a2eb12b4d890d39f72fd7e7117d48 upstream.
The commit in the Fixes tag below made so flow->mask free is scheduled via RCU right after it is removed from the flow table. The pointer stays in the flow structure and it can be accessible while in the same RCU critical section. This is done to avoid requiring ovs_mutex for the ovs_flow_free().
However, while removing the flow during processing of CMD_DEL, we do not take RCU read lock before the removal, and ovs_flow_cmd_fill_info() uses the flow->mask pointer afterwards. The RCU read lock is taken, but it's already late at that point. The comment on that line acknowledges that the lock is cosmetic and doesn't serve a real purpose.
This leads to use-after-free if the RCU grace period passes between removal and the filling. It is a short race window, but it is there and can lead to a real crash in case memory allocation for the info takes a bit longer:
BUG: KASAN: slab-use-after-free in __ovs_nla_put_key
net/openvswitch/flow_netlink.c:1996
BUG: KASAN: slab-use-after-free in ovs_nla_put_key+0x2463/0x2e30
net/openvswitch/flow_netlink.c:2250
Read of size 4 at addr ffff88801ee89970 by task ovs_flow_del_ec/9487
Call Trace:
<TASK>
__ovs_nla_put_key net/openvswitch/flow_netlink.c:1996
ovs_nla_put_key+0x2463/0x2e30 net/openvswitch/flow_netlink.c:2250
ovs_flow_cmd_fill_info+0x420/0x9c0 net/openvswitch/datapath.c:930
ovs_flow_cmd_del+0x53a/0x970 net/openvswitch/datapath.c:1467
...
netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556
</TASK>
Allocated by task 9487:
mask_alloc net/openvswitch/flow_table.c:967
flow_mask_insert net/openvswitch/flow_table.c:1012
ovs_flow_tbl_insert+0xea2/0x1a90 net/openvswitch/flow_table.c:1084
ovs_flow_cmd_new+0x7e3/0xd90 net/openvswitch/datapath.c:1086
...
netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556
Freed by task 9485:
rcu_free_sheaf+0x1e/0x100 mm/slub.c:5978
rcu_do_batch kernel/rcu/tree.c:2645
rcu_core+0x59c/0x10c0 kernel/rcu/tree.c:2897
handle_softirqs+0x1e4/0x9a0 kernel/softirq.c:622
...
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1062ovs_flow_tbl_remove() must be called after the ovs_flow_cmd_fill_info() to avoid this race. This also helps with cleaning up the forced cast and the cosmetic RCU read lock. Before the commit in the Fixes tag the order did not matter as long as the flow object itself was not freed.
A wider RCU critical section could be another option, but we have a GFP_KERNEL allocation in the way.
Reported by Trend Micro's Zero Day Initiative as ZDI-CAN-32042.
--- net/openvswitch/datapath.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-)
net/openvswitch/datapath.c +23 -22
@@ -1443,33 +1443,34 @@ static int ovs_flow_cmd_del(struct sk_bu goto unlock; } -ovs_flow_tbl_remove (&dp->table, flow); -ovs_unlock (); - - reply =ovs_flow_cmd_alloc_info ((const struct sw_flow_actions __force *) flow->sf_acts, + reply =ovs_flow_cmd_alloc_info (ovsl_dereference (flow->sf_acts), &flow->id, info, false, ufid_flags); -if (likely (reply)) { -if (!IS_ERR (reply)) { -rcu_read_lock ();/*To keep RCU checker happy. */ - err =ovs_flow_cmd_fill_info (flow, ovs_header->dp_ifindex, - reply, info->snd_portid, - info->snd_seq,0 , -OVS_FLOW_CMD_DEL , - ufid_flags); -rcu_read_unlock (); -if (WARN_ON_ONCE (err <0 )) { -kfree_skb (reply); - goto out_free; - } +if (IS_ERR (reply)) { +netlink_set_err (sock_net (skb->sk)->genl_sock,0 ,0 , +PTR_ERR (reply)); + reply =NULL ; + } -ovs_notify (&dp_flow_genl_family, reply, info); - }else { -netlink_set_err (sock_net (skb->sk)->genl_sock,0 ,0 , -PTR_ERR (reply)); +if (likely (reply)) { + err =ovs_flow_cmd_fill_info (flow, ovs_header->dp_ifindex, + reply, info->snd_portid, + info->snd_seq,0 , +OVS_FLOW_CMD_DEL , ufid_flags); +if (WARN_ON_ONCE (err <0 )) { +kfree_skb (reply); + reply =NULL ; } } +/* Removal has to happen after ovs_flow_cmd_fill_info(), as it uses +* the flow->mask that can be scheduled to be freed by the +* ovs_flow_tbl_remove() and we're not holding the RCU read lock. +*/ +ovs_flow_tbl_remove (&dp->table, flow); +ovs_unlock (); + +if (likely (reply)) +ovs_notify (&dp_flow_genl_family, reply, info); -out_free:ovs_flow_free (flow, true);return 0 ; unlock:
Greg Kroah-Hartman
maintainerPATCH 259/1424 net: openvswitch: fix nf_connlabels leak in ovs_ct_init
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit f9de5db270a4c2641de87ee558c16a9bc6eb4cd8 upstream.
ovs_ct_init() acquires a connlabels reference before initializing the conntrack limit state. If ovs_ct_limit_init() fails, its error is returned directly. The pernet core does not invoke the exit callback for the operation whose initialization failed, so ovs_ct_exit() cannot drop the reference.
This leaves labels_used elevated when Open vSwitch pernet registration fails for an existing network namespace. Subsequent conntrack entries in that namespace may allocate label extensions even though Open vSwitch failed to register.
Drop the connlabels reference before returning a conntrack limit initialization error. ovs_ct_limit_init() already releases its partial state, and the original error remains unchanged.
This issue was found by a static analysis checker and confirmed by manual source review.
--- net/openvswitch/conntrack.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/openvswitch/conntrack.c +5 -3
@@ -1977,6 +1977,7 @@ int ovs_ct_init(struct net *net) {unsigned int n_bits =sizeof (struct ovs_key_ct_labels ) *BITS_PER_BYTE ;struct ovs_net *ovs_net =net_generic (net, ovs_net_id); +int err =0 ;if (nf_connlabels_get (net, n_bits -1 )) { ovs_net->xt_label = false;
@@ -1986,10 +1987,11 @@ int ovs_ct_init(struct net *net) }#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -return ovs_ct_limit_init (net, ovs_net); -#else -return 0 ; + err =ovs_ct_limit_init (net, ovs_net); +if (err && ovs_net->xt_label) +nf_connlabels_put (net);#endif +return err; }void ovs_ct_exit (struct net *net)
Greg Kroah-Hartman
maintainerPATCH 260/1424 net: ravb: avoid dereferencing an invalid PTP clock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit 1f77af0aaf277413ff32f6ff8c2c4282bd64c897 upstream.
The PTP clock is unavailable before the first open, so querying its index can dereference a NULL pointer. Registration failures can also leave an error pointer in priv->ptp.clock.
Cache the PHC index separately and report -1 while no clock is registered. Normalize registration errors to NULL and preserve the static timestamping capabilities.
--- drivers/net/ethernet/renesas/ravb.h | 1 + drivers/net/ethernet/renesas/ravb_main.c | 3 ++- drivers/net/ethernet/renesas/ravb_ptp.c | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-)
drivers/net/ethernet/renesas/ravb.h +1 -0
@@ -1005,6 +1005,7 @@ struct ravb_ptp_perout {struct ravb_ptp {struct ptp_clock *clock;struct ptp_clock_info info; +int phc_index;u32 default_addend;u32 current_addend;int extts[N_EXT_TS ];
drivers/net/ethernet/renesas/ravb_main.c +2 -1
@@ -1684,7 +1684,7 @@ static int ravb_get_ts_info(struct net_d (1 <<HWTSTAMP_FILTER_NONE ) | (1 <<HWTSTAMP_FILTER_PTP_V2_L2_EVENT ) | (1 <<HWTSTAMP_FILTER_ALL ); - info->phc_index =ptp_clock_index (priv->ptp.clock); + info->phc_index =READ_ONCE (priv->ptp.phc_index); }return 0 ;
@@ -2713,6 +2713,7 @@ static int ravb_probe(struct platform_de priv->rstc = rstc; priv->ndev = ndev; priv->pdev = pdev; + priv->ptp.phc_index =-1 ; priv->num_tx_ring[RAVB_BE ] =BE_TX_RING_SIZE ; priv->num_rx_ring[RAVB_BE ] =BE_RX_RING_SIZE ;if (info->nc_queues) {
drivers/net/ethernet/renesas/ravb_ptp.c +13 -2
@@ -325,6 +325,7 @@ void ravb_ptp_interrupt(struct net_devicvoid ravb_ptp_init (struct net_device *ndev,struct platform_device *pdev) {struct ravb_private *priv =netdev_priv (ndev); +struct ptp_clock *clock;unsigned long flags; priv->ptp.info = ravb_ptp_info;
@@ -337,7 +338,15 @@ void ravb_ptp_init(struct net_device *ndravb_modify (ndev,GCCR ,GCCR_TCSS ,GCCR_TCSS_ADJGPTP );spin_unlock_irqrestore (&priv->lock, flags); - priv->ptp.clock =ptp_clock_register (&priv->ptp.info, &pdev->dev); + clock =ptp_clock_register (&priv->ptp.info, &pdev->dev); +if (IS_ERR (clock)) { +netdev_err (ndev,"failed to register PTP clock: %pe\n" , clock); + clock =NULL ; + } + + priv->ptp.clock = clock; +if (clock) +WRITE_ONCE (priv->ptp.phc_index,ptp_clock_index (clock)); }void ravb_ptp_stop (struct net_device *ndev)
@@ -347,5 +356,7 @@ void ravb_ptp_stop(struct net_device *ndravb_write (ndev,0 ,GIC );ravb_write (ndev,0 ,GIS ); -ptp_clock_unregister (priv->ptp.clock); +WRITE_ONCE (priv->ptp.phc_index,-1 ); +if (priv->ptp.clock) +ptp_clock_unregister (priv->ptp.clock); }
Greg Kroah-Hartman
maintainerPATCH 261/1424 net: thunderbolt: Release the Rx HopID that was handed out on mismatch
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
commit 2f1463554d0561a2fead81e3888604e5c1125e29 upstream.
tb_xdomain_alloc_in_hopid() passes the wanted HopID to ida_alloc_range() as the lower bound, so a taken id is not an error there: the allocator returns the next free one above it. tbnet_connected_work() asks for the peer's transmit path, treats any other id as a failure and returns without releasing what it got, so that allocation stays live for the rest of the XDomain connection with nothing left holding a reference to it.
Release the id when it is not the one we asked for, the same way the error unwind at the end of the function releases the expected one.
--- drivers/net/thunderbolt/main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/thunderbolt/main.c +2 -0
@@ -650,6 +650,8 @@ static void tbnet_connected_work(struct ret =tb_xdomain_alloc_in_hopid (net->xd, net->remote_transmit_path);if (ret != net->remote_transmit_path) {netdev_err (net->dev,"failed to allocate Rx HopID\n" ); +if (ret >=0 ) +tb_xdomain_release_in_hopid (net->xd, ret);return ; }
Greg Kroah-Hartman
maintainerPATCH 262/1424 net: thunderbolt: Mark the connection down when bringing it up fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
commit 3c8b26ebf525ba5960510f48c6e9936a79ebe76f upstream.
Every failure path in tbnet_connected_work() undoes its own work and returns without clearing login_sent, so the connection still looks established. The next tbnet_tear_down() therefore takes its main branch and repeats a teardown that already happened: it stops rings that are already stopped, which is a dev_WARN() and fatal under panic_on_warn, and it releases net->remote_transmit_path even on the HopID mismatch path, where this connection never owned that id, silently freeing one that someone else is still using.
Clear login_sent on those paths. That is enough for tbnet_tear_down() to leave the unwound state alone, and login_received has to stay set: it records that the peer has logged in and carries the transmit path it gave us, which nothing on this side can make the peer send again. Two things change beyond keeping the teardown out of the way: the logout request in that block is no longer sent, and the peer's next login request now re-queues our login work rather than connected_work, giving the connection a fresh login instead of a retry on stale state.
--- drivers/net/thunderbolt/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/thunderbolt/main.c +10 -0
@@ -629,6 +629,14 @@ static int tbnet_alloc_tx_buffers(structreturn 0 ; } +static void tbnet_connect_failed (struct tbnet *net) +{ +/* Leave login_received set: only the peer can make it true again. */ +mutex_lock (&net->connection_lock); + net->login_sent = false; +mutex_unlock (&net->connection_lock); +} +static void tbnet_connected_work (struct work_struct *work) {struct tbnet *net =container_of (work,typeof (*net), connected_work);
@@ -652,6 +660,7 @@ static void tbnet_connected_work(structnetdev_err (net->dev,"failed to allocate Rx HopID\n" );if (ret >=0 )tb_xdomain_release_in_hopid (net->xd, ret); +tbnet_connect_failed (net);return ; }
@@ -696,6 +705,7 @@ err_stop_rings:tb_ring_stop (net->rx_ring.ring);tb_ring_stop (net->tx_ring.ring);tb_xdomain_release_in_hopid (net->xd, net->remote_transmit_path); +tbnet_connect_failed (net); }static void tbnet_login_work (struct work_struct *work)
Greg Kroah-Hartman
maintainerPATCH 263/1424 NTB: ntb_transport: Recycle TX entries before client callbacks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 256496397287334a19ed80ec7be92bffcae76b9d upstream.
ntb_tx_copy_callback() invokes the client callback before returning the entry to tx_free_q. The callback may wake a stopped client queue, only for the next enqueue to find no local entry and return -EBUSY. The window is narrow, but the retry is unnecessary.
Save the callback data and length, then return the entry to tx_free_q before invoking the client. A completion callback then means both the client buffer and transport entry are ready for reuse.
--- drivers/ntb/ntb_transport.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/ntb/ntb_transport.c +14 -9
@@ -1745,9 +1745,16 @@ static void ntb_transport_rxc_db(unsignestatic void ntb_tx_copy_callback (void *data,const struct dmaengine_result *res) { +struct ntb_payload_header __iomem *hdr;struct ntb_queue_entry *entry = data; -struct ntb_transport_qp *qp = entry->qp; -struct ntb_payload_header __iomem *hdr = entry->tx_hdr; +struct ntb_transport_qp *qp; +unsigned int len; +void *cb_data; + + qp = entry->qp; + hdr = entry->tx_hdr; + cb_data = entry->cb_data; + len = entry->len;/* we need to check DMA results if we are using DMA */ if (res) {
@@ -1787,15 +1794,13 @@ static void ntb_tx_copy_callback(void *d* "link down" or similar. Since no payload is being sent in these * cases, there is nothing to add to the completion queue. */ -if (entry->len >0 ) { - qp->tx_bytes += entry->len; - -if (qp->tx_handler) - qp->tx_handler (qp, qp->cb_data, entry->cb_data, - entry->len); - } +if (len >0 ) + qp->tx_bytes += len;ntb_list_add (&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q); + +if (len >0 && qp->tx_handler) + qp->tx_handler (qp, qp->cb_data, cb_data, len); }static void ntb_memcpy_tx (struct ntb_queue_entry *entry,void __iomem *offset)
Greg Kroah-Hartman
maintainerPATCH 264/1424 NTB: ntb_transport: Fail TX enqueue when the QP link is down
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 873ce713fef5dde0939220f04f3484ec86a16fba upstream.
Commit f195a1a6fe41 ("ntb: Drop packets when qp link is down") meant to make ntb_transport_tx_enqueue() drop packets submitted while the QP link is down, but it only returns 0 without consuming the packet. Zero means success by this function's contract, so ntb_netdev reports NETDEV_TX_OK and forgets the skb: nothing queued it, nothing frees it, and it leaks, one skb for every transmit racing a link-down.
Return -ENOLINK instead, restoring the contract that a non-zero return leaves the buffer owned by the caller. With the preceding patch, ntb_netdev frees the skb on non-retryable enqueue failures and returns NETDEV_TX_OK, so a packet racing with link-down is dropped without leaking or entering a busy retry loop.
--- drivers/ntb/ntb_transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/ntb/ntb_transport.c +1 -2
@@ -2304,9 +2304,8 @@ int ntb_transport_tx_enqueue(struct ntb_if (!qp || !len)return -EINVAL ; -/* If the qp link is down already, just ignore. */ if (!qp->link_is_up) -return 0 ; +return -ENOLINK ; entry =ntb_list_rm (&qp->ntb_tx_free_q_lock, &qp->tx_free_q);if (!entry) {
Greg Kroah-Hartman
maintainerPATCH 265/1424 NTB: ntb_transport: Reject oversized TX buffers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit a4f2387db6f1cc2f03abba7f3a6807ad61e26ff7 upstream.
ntb_process_tx() handles an oversized buffer by calling tx_handler() with a NULL data pointer and returning success. ntb_netdev therefore neither frees the skb in its completion callback nor takes its enqueue error path, leaking it.
Reject oversized buffers in ntb_transport_tx_enqueue() before acquiring a queue entry and return -EMSGSIZE. The caller retains ownership of the buffer, and the preceding netdev patch frees the skb when enqueue returns this permanent error.
--- drivers/ntb/ntb_transport.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
drivers/ntb/ntb_transport.c +3 -9
@@ -1924,15 +1924,6 @@ static int ntb_process_tx(struct ntb_trareturn -EAGAIN ; } -if (entry->len > qp->tx_max_frame -sizeof (struct ntb_payload_header )) { -if (qp->tx_handler) - qp->tx_handler (qp, qp->cb_data,NULL , -EIO ); - -ntb_list_add (&qp->ntb_tx_free_q_lock, &entry->entry, - &qp->tx_free_q); -return 0 ; - } -ntb_async_tx (qp, entry); qp->tx_index++;
@@ -2307,6 +2298,9 @@ int ntb_transport_tx_enqueue(struct ntb_if (!qp->link_is_up)return -ENOLINK ; +if (len > qp->tx_max_frame -sizeof (struct ntb_payload_header )) +return -EMSGSIZE ; + entry =ntb_list_rm (&qp->ntb_tx_free_q_lock, &qp->tx_free_q);if (!entry) { qp->tx_err_no_buf++;
Greg Kroah-Hartman
maintainerPATCH 266/1424 net: ntb_netdev: Avoid double-accounting netif_rx() drops
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 82e15be2d8b9efa6fb1750528d9b6f40e6a8eea7 upstream.
netif_rx() already accounts packets it drops in the core rx_dropped counter. ntb_netdev counts them again as both errors and drops.
Leave netif_rx() drops to the core. Count the packet and bytes unconditionally since it was received successfully by the driver.
--- drivers/net/ntb_netdev.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/net/ntb_netdev.c +3 -7
@@ -125,13 +125,9 @@ static void ntb_netdev_rx_handler(struct skb->protocol =eth_type_trans (skb, ndev); skb->ip_summed =CHECKSUM_NONE ; -if (netif_rx (skb) ==NET_RX_DROP ) { - ndev->stats.rx_errors++; - ndev->stats.rx_dropped++; - }else { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += len; - } +netif_rx (skb); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; skb = new_skb;
Greg Kroah-Hartman
maintainerPATCH 267/1424 net: ntb_netdev: Count packets dropped on RX refill failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 31ded341c375bb2faac1d77ab0012a732ba3e2a6 upstream.
When replacement skb allocation fails, ntb_netdev drops a packet that was received successfully and requeues the original buffer. The drop is counted, but rx_packets and rx_bytes are not.
Count every good packet before allocating its replacement.
--- drivers/net/ntb_netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ntb_netdev.c +3 -2
@@ -115,6 +115,9 @@ static void ntb_netdev_rx_handler(struct goto enqueue_again; } + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + new_skb =netdev_alloc_skb (ndev, ndev->mtu +ETH_HLEN );if (!new_skb) { ndev->stats.rx_dropped++;
@@ -126,8 +129,6 @@ static void ntb_netdev_rx_handler(struct skb->ip_summed =CHECKSUM_NONE ;netif_rx (skb); - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += len; skb = new_skb;
Greg Kroah-Hartman
maintainerPATCH 268/1424 net/smc: do not dereference an unset send buffer on the SMC-D teardown path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit b395dd319cea422239cb45b998fb38d7e373af87 upstream.
smc_close_stream_wait() calls smc_tx_prepared_sends() from inside its sk_wait_event() condition, and sk_wait_event() evaluates that condition once with the socket lock released. smcd_buf_detach() clears conn->sndbuf_desc from smc_conn_kill() under lock_sock(), so a link group terminating while a socket waits there leaves the helper dereferencing NULL, faulting out of close(). SIOCOUTQ reads the field by hand, and smc_close_cancel_work() drops the lock across two cancel_*_sync() calls.
Sample the pointer once in the helper, report nothing prepared while it is unset, and bound the ioctl the same way. The receive tasklet dereferences the field directly in smc_cdc_msg_recv_action(), not through this helper; 1/2 is what keeps it from running that late.
--- net/smc/af_smc.c | 3 ++- net/smc/smc_tx.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-)
net/smc/af_smc.c +2 -1
@@ -3224,7 +3224,8 @@ static int smc_ioctl(struct socket *sockreturn -EINVAL ; }if (smc->sk.sk_state ==SMC_INIT || - smc->sk.sk_state ==SMC_CLOSED ) + smc->sk.sk_state ==SMC_CLOSED || + !READ_ONCE (smc->conn.sndbuf_desc)) answ =0 ;else answ = smc->conn.sndbuf_desc->len -
net/smc/smc_tx.h +5 -1
@@ -20,11 +20,15 @@static inline int smc_tx_prepared_sends (struct smc_connection *conn) { +struct smc_buf_desc *sndbuf_desc =READ_ONCE (conn->sndbuf_desc);union smc_host_cursor sent, prep; +if (!sndbuf_desc) +return 0 ; +smc_curs_copy (&sent, &conn->tx_curs_sent, conn);smc_curs_copy (&prep, &conn->tx_curs_prep, conn); -return smc_curs_diff (conn->sndbuf_desc->len, &sent, &prep); +return smc_curs_diff (sndbuf_desc->len, &sent, &prep); }void smc_tx_pending (struct smc_connection *conn);
Greg Kroah-Hartman
maintainerPATCH 269/1424 net/smc: fix socket refcount leak in smc_switch_conns()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit 719296c4aa8213d4ac8002e77d5956d436bc98d0 upstream.
smc_switch_conns() takes a reference on the SMC socket before dropping lgr->conns_lock, so the connection stays alive while the CDC slot is fetched:
sock_hold(&smc->sk);
read_unlock_bh(&lgr->conns_lock);
/* pre-fetch buffer outside of send_lock, might sleep */
rc = smc_cdc_get_free_slot(conn, to_lnk, &wr_buf, NULL, &pend);
if (rc)
goto err_out;The err_out label only drops the wr_tx link reference, so this early exit returns without the matching sock_put(). The second error exit is not affected, because sock_put() has already run by then.
A leaked sk_refcnt means the smc_sock is never destroyed. Its send and receive buffers stay allocated, and for a user socket the reference held on the network namespace is never released, so the netns can no longer be torn down.
smc_cdc_get_free_slot() fails when the target link goes down or when the connection has been killed while the switch is in progress. Both are reachable during the link failover this function implements, so the leak is triggered by the same hardware events that make smc_switch_conns() run in the first place.
Restructure so there is a single sock_put() covering both outcomes, instead of adding a second one to the error path.
--- net/smc/smc_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
net/smc/smc_core.c +7 -7
@@ -1086,13 +1086,13 @@ again:read_unlock_bh (&lgr->conns_lock);/* pre-fetch buffer outside of send_lock, might sleep */ rc =smc_cdc_get_free_slot (conn, to_lnk, &wr_buf,NULL , &pend); -if (rc) - goto err_out; -/* avoid race with smcr_tx_sndbuf_nonempty() */ -spin_lock_bh (&conn->send_lock); -smc_switch_link_and_count (conn, to_lnk); - rc =smc_switch_cursor (smc, pend, wr_buf); -spin_unlock_bh (&conn->send_lock); +if (!rc) { +/* avoid race with smcr_tx_sndbuf_nonempty() */ +spin_lock_bh (&conn->send_lock); +smc_switch_link_and_count (conn, to_lnk); + rc =smc_switch_cursor (smc, pend, wr_buf); +spin_unlock_bh (&conn->send_lock); + }sock_put (&smc->sk);if (rc) goto err_out;
Greg Kroah-Hartman
maintainerPATCH 270/1424 net/smc: fix use-after-free in smc_rx_pipe_buf_release()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit c924884743e948e25625b7fbf3ee2a9325a204a7 upstream.
smc_rx_splice() hands RMB pages to a pipe and takes a socket reference per entry so the smc_sock stays alive until the reader finishes. The connection does not: a concurrent close runs smc_conn_free(), which releases the receive buffer back to the link group pool.
smc_rx_pipe_buf_release() tests sk_state before taking the socket lock. The state can change between the test and the lock, and smc_rx_update_cons() then dereferences conn->rmb_desc and walks conn->lgr, which smc_conn_free() has already released. On the is_reg_err path smcr_buf_unuse() frees the descriptor outright, so this is a use-after-free.
Take the socket lock first and test conn->freed instead. smc_conn_free() sets that flag before releasing anything, and every caller holds the socket lock. The two paths exclude each other: either the pipe release runs first with everything valid, or it sees the flag and skips the update.
--- net/smc/smc_rx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/smc/smc_rx.c +5 -6
@@ -115,16 +115,15 @@ static void smc_rx_pipe_buf_release(stru struct pipe_buffer *buf) {struct smc_spd_priv *priv = (struct smc_spd_priv *)buf->private; +struct smc_connection *conn = &priv->smc->conn;struct smc_sock *smc = priv->smc; -struct smc_connection *conn;struct sock *sk = &smc->sk; -if (sk->sk_state ==SMC_CLOSED || - sk->sk_state ==SMC_PEERFINCLOSEWAIT || - sk->sk_state ==SMC_APPFINCLOSEWAIT ) - goto out; - conn = &smc->conn;lock_sock (sk); +if (conn->freed) { +release_sock (sk); + goto out; + }smc_rx_update_cons (smc, priv->len);release_sock (sk);if (atomic_sub_and_test (priv->len, &conn->splice_pending))
Greg Kroah-Hartman
maintainerPATCH 271/1424 net/smc: unregister the connection before draining the rx tasklet
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 36cdf5d48ca191dcd71c28cadbe0981b1d25318d upstream.
smc_conn_free() calls smc_ism_unset_conn() only while the link group is still on its device list, and never sets conn->killed. smc_lgr_terminate_sched() unlinks the group immediately and defers killing its connections to a work item, so a connection freed in that window keeps its smcd->conn[] slot with both gates in smcd_handle_irq() open, and the device can re-arm the receive tasklet after tasklet_kill() has returned. On the DMB-nocopy path the ghost send buffer is freed right after that drain, so the re-armed tasklet dereferences it.
Unregister unconditionally and drain before the detach at both teardown sites, mirroring rmb_desc, which smc_buf_unuse() releases after the drain. Clear conn->sndbuf_desc before freeing it as well, so a reader that samples the pointer cannot get one that is already freed.
--- net/smc/smc_core.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
net/smc/smc_core.c +7 -6
@@ -1147,14 +1147,16 @@ static void smcd_buf_detach(struct smc_c {struct smcd_dev *smcd = conn->lgr->smcd;u64 peer_token = conn->peer_token; +struct smc_buf_desc *buf_desc;if (!conn->sndbuf_desc)return ;smc_ism_detach_dmb (smcd, peer_token); -kfree (conn->sndbuf_desc); + buf_desc = conn->sndbuf_desc; conn->sndbuf_desc =NULL ; +kfree (buf_desc); } static void smc_buf_unuse(struct smc_connection *conn,
@@ -1198,11 +1200,10 @@ void smc_conn_free(struct smc_connection goto lgr_put;if (lgr->is_smcd) { -if (!list_empty (&lgr->list)) -smc_ism_unset_conn (conn); +smc_ism_unset_conn (conn); +tasklet_kill (&conn->rx_tsklet);if (smc_ism_support_dmb_nocopy (lgr->smcd))smcd_buf_detach (conn); -tasklet_kill (&conn->rx_tsklet); }else {smc_cdc_wait_pend_tx_wr (conn);if (current_work () != &conn->abort_work)
@@ -1455,12 +1456,12 @@ static void smc_conn_kill(struct smc_consmc_sk_wake_ups (smc);if (conn->lgr->is_smcd) {smc_ism_unset_conn (conn); -if (smc_ism_support_dmb_nocopy (conn->lgr->smcd)) -smcd_buf_detach (conn);if (soft)tasklet_kill (&conn->rx_tsklet);else tasklet_unlock_wait (&conn->rx_tsklet); +if (smc_ism_support_dmb_nocopy (conn->lgr->smcd)) +smcd_buf_detach (conn); }else {smc_cdc_wait_pend_tx_wr (conn); }
Greg Kroah-Hartman
maintainerPATCH 272/1424 net: cap advertised IP tunnel headroom
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit 6b222adeb9340306e2ff97127c76117abb9b3df8 upstream.
IP tunnel devices derive their advertised needed_headroom from lower output devices. A stack of user-created devices can make the derived value larger than the 16-bit skb header offsets can represent. Once IP output reserves it, skb head expansion can wrap those offsets.
The runtime transmit path already caps a growing needed_headroom at 512. Apply the same cap when tunnel configuration publishes needed_headroom derived from a lower output device.
Capping the advertised value is safe: IP tunnel transmit still expands the skb when a packet needs more headroom. A nonsensical stacked configuration can therefore incur an extra reallocation, but it cannot publish an unbounded reservation to upper layers.
--- include/net/ip_tunnels.h | 11 +++++++++-- net/ipv4/ip_tunnel.c | 2 +- net/ipv6/ip6_gre.c | 7 +++++-- net/ipv6/ip6_tunnel.c | 7 +++++-- net/ipv6/sit.c | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-)
include/net/ip_tunnels.h +9 -2
@@ -492,8 +492,7 @@ struct metadata_dst *iptunnel_metadata_rint skb_tunnel_check_pmtu (struct sk_buff *skb,struct dst_entry *encap_dst,int headroom,bool reply); -static inline void ip_tunnel_adj_headroom (struct net_device *dev, -unsigned int headroom) +static inline unsigned int ip_tunnel_limit_headroom (unsigned int headroom) {/* we must cap headroom to some upperlimit, else pskb_expand_head * will overflow header offsets in skb_headers_offset_update().
@@ -503,6 +502,14 @@ static inline void ip_tunnel_adj_headrooif (headroom > max_allowed) headroom = max_allowed; +return headroom; +} + +static inline void ip_tunnel_adj_headroom (struct net_device *dev, +unsigned int headroom) +{ + headroom =ip_tunnel_limit_headroom (headroom); +if (headroom >READ_ONCE (dev->needed_headroom))WRITE_ONCE (dev->needed_headroom, headroom); }
net/ipv4/ip_tunnel.c +1 -1
@@ -316,7 +316,7 @@ static int ip_tunnel_bind_dev(struct net mtu =min (tdev->mtu,IP_MAX_MTU ); } - dev->needed_headroom = t_hlen + hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (t_hlen + hlen); mtu -= t_hlen + (dev->type ==ARPHRD_ETHER ? dev->hard_header_len :0 );if (mtu <IPV4_MIN_MTU )
net/ipv6/ip6_gre.c +5 -2
@@ -1150,8 +1150,11 @@ static void ip6gre_tnl_link_config_routereturn ;if (rt->dst.dev) { - dev->needed_headroom = rt->dst.dev->hard_header_len + - t_hlen; +unsigned int headroom; + + headroom = rt->dst.dev->hard_header_len + t_hlen; + headroom =ip_tunnel_limit_headroom (headroom); + dev->needed_headroom = headroom;if (set_mtu) {int mtu = rt->dst.dev->mtu - t_hlen;
net/ipv6/ip6_tunnel.c +5 -2
@@ -1504,8 +1504,11 @@ static void ip6_tnl_link_config(struct i tdev =__dev_get_by_index (t->net, p->link);if (tdev) { - dev->needed_headroom = tdev->hard_header_len + - tdev->needed_headroom + t_hlen; +unsigned int headroom; + + headroom = tdev->hard_header_len + tdev->needed_headroom; + headroom += t_hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (headroom); mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU); mtu = mtu - t_hlen;
net/ipv6/sit.c +1 -1
@@ -1133,7 +1133,7 @@ static void ipip6_tunnel_bind_dev(structWRITE_ONCE (dev->mtu, mtu); hlen = tdev->hard_header_len + tdev->needed_headroom; } - dev->needed_headroom = t_hlen + hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (t_hlen + hlen); } static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
Greg Kroah-Hartman
maintainerPATCH 273/1424 net: fix spurious TX timeout after dev_activate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 82aeed2400786bd3f79d88cb8b8f42e6127e5923 upstream.
While debugging another issue today, I found out that my TX queue is reported as stopped for 4294907392 ms (49.7 days), on a machine that had been up for four minutes.
bnxt_en 0002:01:00.0 eth0: NETDEV WATCHDOG: CPU: 28: transmit queue 23 timed out 4294907392 ms
4294907392 is not an elapsed time. It is the value of jiffies at that
moment: INITIAL_JIFFIES is 4294667296, which leaves jiffies 59 seconds short of wrapping.
dev_activate() runs transition_one_qdisc() over every TX queue, which resets trans_start to 0, and then stamps only queue 0 through netif_trans_update().
Stamp jiffies instead. A queue stopped across dev_activate() now gets a full watchdog_timeo of grace, and is still reported if it is stopped that long.
--- net/sched/sch_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_generic.c +1 -1
@@ -1237,7 +1237,7 @@ static void transition_one_qdisc(structrcu_assign_pointer (dev_queue->qdisc, new_qdisc);if (need_watchdog_p) { -WRITE_ONCE (dev_queue->trans_start,0 ); +WRITE_ONCE (dev_queue->trans_start, jiffies); *need_watchdog_p =1 ; } }
Greg Kroah-Hartman
maintainerPATCH 274/1424 net: skbuff: dont touch shared zerocopy state in skb_tx_error()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit f66bdb1cc0fcd227a062378f8be0b5873aa5600a upstream.
skb_tx_error() completes the zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, and skb_zcopy_downgrade_managed() clears SKBFL_MANAGED_FRAG_REFS. Both live in skb_shinfo(), which every clone shares, while the caller only owns the reference it is about to drop. Through a clone it tells the producer its pages are free and drops SKBFL_SHARED_FRAG for an skb that is still in flight.
Open vSwitch reaches this with a non-last OVS_ACTION_ATTR_RECIRC:clone_execute() sends a skb_clone() into ovs_dp_process_packet() while do_execute_actions() keeps forwarding the original, and skb_clone() does not privatise the frags here -- skb_orphan_frags() returns early on SKBFL_DONT_ORPHAN. A flow miss on the clone then strips the marker from the packet still being forwarded, and a later local ESP delivery decrypts in place over frags it does not own privately.
Skip it for a cloned skb. Nothing is lost: skb_release_data() clears the zerocopy state once the last reference to the shared data goes.
--- net/core/skbuff.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/core/skbuff.c +4 -1
@@ -1256,10 +1256,13 @@ EXPORT_SYMBOL(skb_dump);* * Report xmit error if a device callback is tracking this skb. * skb must be freed afterwards. +* +* Does nothing for a cloned skb: the zerocopy state lives in +* skb_shinfo(), which the clones share. */ void skb_tx_error (struct sk_buff *skb) { -if (skb) { +if (skb && !skb_cloned (skb)) {skb_zcopy_downgrade_managed (skb);skb_zcopy_clear (skb, true); }
Greg Kroah-Hartman
maintainerPATCH 275/1424 seg6: reset IP6CB after IPv6 decapsulation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit f967455fb2a5a2079b9eb5823e9ccf359174bf9f upstream.
decap_and_validate() pulls the outer SRv6 headers and makes the inner packet the skb network header. The IPv6 control block still contains values collected while parsing the outer packet, including nhoff and extension-header flags.
End.DX6 and End.DT6 route the inner IPv6 packet directly to the IPv6 input path. An unprivileged user can reach End.DT6 from a user and net namespace by installing a local SID and injecting an outer packet with Hop-by-Hop and Destination Options headers followed by an SRH and a minimal inner IPv6 packet.
The outer extension headers leave a large nhoff in IP6CB. After decapsulation, ip6_protocol_deliver_rcu() uses that stale offset on the inner packet and reads beyond the skb head. KASAN reports:
BUG: KASAN: slab-out-of-bounds in ip6_protocol_deliver_rcu ip6_protocol_deliver_rcu+0x1118/0x1450 ip6_input_finish+0x11b/0x240 seg6_local_input_core+0xed/0x2e0 lwtunnel_input+0x1e9/0x4e0 ipv6_rthdr_rcv+0x525f/0x6c50 ip6_protocol_deliver_rcu+0xcb7/0x1450
Before clearing IP6CB for an inner IPv6 packet, save its incoming interface index and L3 slave state. Restore both after the clear and set nhoff to the inner IPv6 base-header nexthdr field.
Use IP6CB(skb)->iif rather than skb->skb_iif because VRF processing can replace skb_iif with the L3 master while IP6CB keeps the receiving interface. Preserve IP6SKB_L3SLAVE for the same reason.
--- net/ipv6/seg6_local.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/ipv6/seg6_local.c +9 -0
@@ -261,6 +261,15 @@ static bool decap_and_validate(struct skmemset (IPCB (skb),0 ,sizeof (*IPCB (skb)));IPCB (skb)->iif = iif; + }else if (proto ==IPPROTO_IPV6 ) { +bool l3slave =ipv6_l3mdev_skb (IP6CB (skb)->flags); +int iif =IP6CB (skb)->iif; + +memset (IP6CB (skb),0 ,sizeof (*IP6CB (skb))); +IP6CB (skb)->iif = iif; +IP6CB (skb)->nhoff = offsetof(struct ipv6hdr , nexthdr); +if (l3slave) +IP6CB (skb)->flags |=IP6SKB_L3SLAVE ; }return true;
Greg Kroah-Hartman
maintainerPATCH 276/1424 ALSA: 6fire: bound the MIDI event length from the device
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit a478893b59e36cfe7d77a76b352f2db55502e879 upstream.
usb6fire_comm_receiver_handler() forwards a MIDI event using a length byte the device supplies, with no bound and no check that the transfer delivered that many bytes:
if (!urb->status) {
if (rt->receiver_buffer[0] == 0x10) /* midi in event */
if (midi_rt)
midi_rt->in_received(midi_rt,
rt->receiver_buffer + 2,
rt->receiver_buffer[1]);
}receiver_buffer is a 64-byte kzalloc() buffer (COMM_RECEIVER_BUFSIZE), so only 62 bytes follow the two-byte header. receiver_buffer[1] is a u8 the device chooses, so a device that answers with 0x10 and a length of 0xFF makes snd_rawmidi_receive() read 255 bytes starting two bytes into a 64-byte object. The bytes past the buffer are handed to userspace through the rawmidi read path.
urb->actual_length is not consulted either, so a short transfer leaves both the type byte and the length byte at their previous values and the handler acts on stale data.
The receiver URB is submitted from usb6fire_comm_init() at probe, so the read happens on plug with no user action; forwarding to userspace also needs a MIDI input substream open, since usb6fire_midi_in_received() only calls snd_rawmidi_receive() when rt->in is set.
KASAN on 7.2.0-rc5 (arm64), single packet from an emulated device:
BUG: KASAN: slab-out-of-bounds in snd_rawmidi_receive Read of size 255 at addr ffff000009f64682 by task bash/183 __asan_memcpy snd_rawmidi_receive usb6fire_midi_in_received [snd_usb_6fire] usb6fire_comm_receiver_handler [snd_usb_6fire] Allocated by task 11: usb6fire_comm_init [snd_usb_6fire] usb6fire_chip_probe [snd_usb_6fire] The buggy address is located 2 bytes inside of allocated 64-byte region [ffff000009f64680, ffff000009f646c0)
Reject the event when the length exceeds the bytes that follow the header, and require the transfer to have delivered the header plus that many bytes. The receiver URB is submitted with a 64-byte transfer_buffer_length, so a genuine device cannot deliver an event longer than those 62 bytes and nothing valid is dropped.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/6fire/comm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
sound/usb/6fire/comm.c +6 -3
@@ -36,11 +36,14 @@ static void usb6fire_comm_receiver_handlstruct midi_runtime *midi_rt = rt->chip->midi;if (!urb->status) { -if (rt->receiver_buffer[0 ] ==0x10 )/* midi in event */ +u8 len = rt->receiver_buffer[1 ]; + +if (rt->receiver_buffer[0 ] ==0x10 &&/* midi in event */ + len <=COMM_RECEIVER_BUFSIZE -2 && + urb->actual_length >= len +2 )if (midi_rt) midi_rt->in_received (midi_rt, - rt->receiver_buffer +2 , - rt->receiver_buffer[1 ]); + rt->receiver_buffer +2 , len); }if (!rt->chip->shutdown) {
Greg Kroah-Hartman
maintainerPATCH 277/1424 ALSA: aloop: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 819b106a9fd2ef3fd8abf898b9a8e4524eca8f48 upstream.
aloop driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/aloop.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/aloop.c +6 -0
@@ -1739,6 +1739,12 @@ static int loopback_probe(struct platforint dev = devptr->id;int err; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } + err =snd_devm_card_new (&devptr->dev, index[dev], id[dev],THIS_MODULE ,sizeof (struct loopback ), &card);if (err <0 )
Greg Kroah-Hartman
maintainerPATCH 278/1424 ALSA: bcd2000: clear the URB pointers on disconnect
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 459d3a64766f5ca2f1886daeaf24582831a5f5ab upstream.
bcd2000_free_usb_related_resources() frees both URBs and leaves the pointers behind:
usb_kill_urb(bcd2k->midi_out_urb); usb_kill_urb(bcd2k->midi_in_urb); usb_free_urb(bcd2k->midi_out_urb); usb_free_urb(bcd2k->midi_in_urb);
The rawmidi device outlives that call. A substream that is still open when the device is unplugged reaches bcd2000_midi_send() from the trigger path on close. That function writes to the freed URB and then hands it to the USB core:
bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE; ... ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC);
usb_kill_urb() does not stop a later submission either, so a submit that races the disconnect can requeue the URB after it has been reaped. midi_in_urb is exposed the same way: bcd2000_input_complete() resubmits it from the completion handler.
KASAN on 7.2.0-rc5 (arm64):
BUG: KASAN: slab-use-after-free in bcd2000_midi_send [snd_bcd2000] Write of size 4 at addr ffff00001827d388 by task bpoc/168 __asan_store4 bcd2000_midi_send [snd_bcd2000] bcd2000_midi_output_trigger [snd_bcd2000] snd_rawmidi_kernel_write1 close_substream.part.0 Freed by task 168: usb_free_urb bcd2000_disconnect [snd_bcd2000] BUG: KASAN: slab-use-after-free in usb_submit_urb Read of size 8 at addr ffff00001827d3b8 by task bpoc/168
Clear both pointers after freeing and test them on the paths that can still run. Poison the URBs before freeing them: usb_poison_urb() waits for a running completion handler and rejects any later submission, so after it returns the input path is quiesced and only the rawmidi trigger path can still reach bcd2000_midi_send(). No unpoison is needed; the URBs are freed on the next line.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/bcd2000/bcd2000.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
sound/usb/bcd2000/bcd2000.c +8 -3
@@ -134,6 +134,9 @@ static void bcd2000_midi_send(struct bcdif (!midi_out_substream)return ; +if (!bcd2k->midi_out_urb) +return ; +/* copy command prefix bytes */ memcpy (bcd2k->midi_out_buf, device_cmd_prefix,sizeof (device_cmd_prefix));
@@ -178,7 +181,7 @@ static int bcd2000_midi_output_close(str {struct bcd2000 *bcd2k = substream->rmidi->private_data; -if (bcd2k->midi_out_active) { +if (bcd2k->midi_out_active && bcd2k->midi_out_urb) {usb_kill_urb (bcd2k->midi_out_urb); bcd2k->midi_out_active =0 ; }
@@ -348,11 +351,13 @@ static int bcd2000_init_midi(struct bcd2static void bcd2000_free_usb_related_resources (struct bcd2000 *bcd2k,struct usb_interface *interface) { -usb_kill_urb (bcd2k->midi_out_urb); -usb_kill_urb (bcd2k->midi_in_urb); +usb_poison_urb (bcd2k->midi_out_urb); +usb_poison_urb (bcd2k->midi_in_urb);usb_free_urb (bcd2k->midi_out_urb);usb_free_urb (bcd2k->midi_in_urb); + bcd2k->midi_out_urb =NULL ; + bcd2k->midi_in_urb =NULL ;if (bcd2k->intf) {usb_set_intfdata (bcd2k->intf,NULL );
Greg Kroah-Hartman
maintainerPATCH 279/1424 ALSA: mpu401: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit f7dcecb92ed192ff5fcf842918fb1aaea84b5bdd upstream.
mpu401 driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/mpu401/mpu401.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/mpu401/mpu401.c +6 -0
@@ -89,6 +89,12 @@ static int snd_mpu401_probe(struct platfint err;struct snd_card *card; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (port[dev] ==SNDRV_AUTO_PORT ) {snd_printk (KERN_ERR "specify port\n" );return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 280/1424 ALSA: mts64: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit d18a260720f86a5f8b5fcfefc4ba2e9dd01c10f8 upstream.
Although mts64 driver has a check of the given devptr->id value, it doesn't check for a negative id, which is often given as "none" or such value when bound via sysfs. This may lead to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/mts64.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/mts64.c +6 -0
@@ -919,6 +919,12 @@ static int snd_mts64_probe(struct platfo p =platform_get_drvdata (pdev);platform_set_drvdata (pdev,NULL ); +if (dev <0 ) { +dev_warn (&pdev->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (dev >=SNDRV_CARDS )return -ENODEV ;if (!enable[dev])
Greg Kroah-Hartman
maintainerPATCH 281/1424 ALSA: pcxhr: initialize mutexes before requesting threaded IRQ
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 6c97817e20598e5473094e0e38d1f51f1cf4dfff upstream.
pcxhr_probe() requests pcxhr_threaded_irq() before initializing mgr->lock, even though the threaded handler takes that mutex.
Initialize the manager locks before request_threaded_irq() so an early interrupt cannot run against uninitialized mutex state during probe.
--- sound/pci/pcxhr/pcxhr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
sound/pci/pcxhr/pcxhr.c +7 -7
@@ -1551,6 +1551,13 @@ static int pcxhr_probe(struct pci_dev *p mgr->pci = pci; mgr->irq =-1 ; +/* ISR lock */ +mutex_init (&mgr->lock); +mutex_init (&mgr->msg_lock); + +/* init setup mutex*/ +mutex_init (&mgr->setup_mutex); +if (request_threaded_irq (pci->irq, pcxhr_interrupt, pcxhr_threaded_irq,IRQF_SHARED ,KBUILD_MODNAME , mgr)) {
@@ -1564,13 +1571,6 @@ static int pcxhr_probe(struct pci_dev *p"Digigram at 0x%lx & 0x%lx, 0x%lx irq %i" , mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); -/* ISR lock */ -mutex_init (&mgr->lock); -mutex_init (&mgr->msg_lock); - -/* init setup mutex*/ -mutex_init (&mgr->setup_mutex); - mgr->prmh = kmalloc(sizeof(*mgr->prmh) + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS),
Greg Kroah-Hartman
maintainerPATCH 282/1424 ALSA: portman2x4: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 3690ef20469d5959378260e2752f2314a2572913 upstream.
Although portman2x4 driver has a check of the given devptr->id value, it doesn't check for a negative id, which is often given as "none" or such value when bound via sysfs. This may lead to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/portman2x4.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/portman2x4.c +6 -0
@@ -705,6 +705,12 @@ static int snd_portman_probe(struct plat p =platform_get_drvdata (pdev);platform_set_drvdata (pdev,NULL ); +if (dev <0 ) { +dev_warn (&pdev->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (dev >=SNDRV_CARDS )return -ENODEV ;if (!enable[dev])
Greg Kroah-Hartman
maintainerPATCH 283/1424 ALSA: serial-u16550: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit e0fb960b227fcdebe22e4f26c9486d60943c0424 upstream.
serial-u16550 driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/serial-u16550.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/serial-u16550.c +6 -0
@@ -863,6 +863,12 @@ static int snd_serial_probe(struct platfint err;int dev = devptr->id; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +switch (adaptor[dev]) {case SNDRV_SERIAL_SOUNDCANVAS : ins[dev] =1 ;
Greg Kroah-Hartman
maintainerPATCH 284/1424 ALSA: virmidi: Check card index validity at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit b65d5182ecd6b7a24a83d980a0d06e809ef876c5 upstream.
virmidi driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/virmidi.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/virmidi.c +6 -0
@@ -75,6 +75,12 @@ static int snd_virmidi_probe(struct platint idx, err;int dev = devptr->id; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } + err =snd_devm_card_new (&devptr->dev, index[dev], id[dev],THIS_MODULE ,sizeof (struct snd_card_virmidi ), &card);if (err <0 )
Greg Kroah-Hartman
maintainerPATCH 285/1424 cgroup/cpuset: Fix misplaced DL migration reset
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
Mainline commit 4a39eda5fdd8 ("cgroup/cpuset: Reset DL migration state on can_attach() failure") puts the common error cleanup in cpuset_can_attach(). The 6.6.y backport instead placed that hunk at cpuset_can_fork()'s similarly named out_unlock label, while removing cpuset_can_attach()'s two existing targeted resets.
If cpuset_can_attach() fails after accounting a SCHED_DEADLINE task, cgroup_migrate_execute() does not call cpuset_cancel_attach() for the failing subsystem. The temporary migration fields remain set, and a later successful migration can consume the stale state and corrupt deadline-task and pending-bandwidth accounting.
Move the reset to cpuset_can_attach()'s common error exit. It is not needed in cpuset_can_fork(), which never accumulates migration DL state.
--- kernel/cgroup/cpuset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/cgroup/cpuset.c +2 -2
@@ -2630,6 +2630,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)*/ cs->attach_in_progress++; out_unlock: +if (ret) +reset_migrate_dl_data (cs);mutex_unlock (&cpuset_mutex);return ret; }
@@ -3462,8 +3464,6 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset) cs->attach_in_progress++; out_unlock: -if (ret) -reset_migrate_dl_data (cs);mutex_unlock (&cpuset_mutex);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 286/1424 PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naman Jain <[email protected]>
[ Upstream commit 86bdd16e8f390d51bae9e77a4bc4164ca2f580fe ]
The Hyper-V vPCI MSI irqchip never installs an irq_retrigger() callback.
On CPU hot-unplug fixup_irqs() migrates the interrupts which are affine to the outgoing CPU to a new target. If an interrupt still has its pending bit set in the outgoing CPU's IRR at that point, fixup_irqs() resends it on the new target through the irqchip's irq_retrigger() callback. As the Hyper-V PCI/MSI chip does not provide that callback, the pending interrupt is silently dropped, which can result in lost interrupts, stalls and "No irq handler for vector" messages during CPU hotplug.
Install irq_chip_retrigger_hierarchy() as the irq_retrigger() callback for the Hyper-V PCI/MSI irqchip, so that a pending interrupt is resent on its new target CPU via the parent x86 vector domain.
--- drivers/pci/controller/pci-hyperv.c | 1 + 1 file changed, 1 insertion(+)
drivers/pci/controller/pci-hyperv.c +1 -0
@@ -2058,6 +2058,7 @@ static struct irq_chip hv_msi_irq_chip = { .name = "Hyper-V PCIe MSI", .irq_compose_msi_msg = hv_compose_msi_msg, .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_retrigger = irq_chip_retrigger_hierarchy,#ifdef CONFIG_X86 .irq_ack = irq_chip_ack_parent,#elif defined(CONFIG_ARM64 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 287/1424 x86/tdx: Fix zero-extension for 32-bit port I/O
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
[ Upstream commit 941370fc93cc3474e26811f4d3b062903eefe2cf ]
According to x86 architecture rules, 32-bit operations zero-extend the result to 64 bits. The current implementation of handle_in() only masks the lower 32 bits, which preserves the upper 32 bits of RAX when a 32-bit port IN instruction is emulated.
Use insn_assign_reg() to write the result back into RAX with proper partial-register-write semantics: 1- and 2-byte forms leave the upper bits untouched, the 4-byte form zero-extends to the full register.
--- arch/x86/coco/tdx/tdx.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
arch/x86/coco/tdx/tdx.c +3 -5
@@ -580,8 +580,8 @@ static bool handle_in(struct pt_regs *regs, int size, int port) .r13 = PORT_READ, .r14 = port, }; -u64 mask =GENMASK (BITS_PER_BYTE * size -1 ,0 );bool success; +u64 val;/* * Emulate the I/O read via hypercall. More info about ABI can be found
@@ -589,11 +589,9 @@ static bool handle_in(struct pt_regs *regs, int size, int port)* "TDG.VP.VMCALL<Instruction.IO>". */ success = !__tdx_hypercall_ret (&args); + val = success ? args.r11 :0 ; -/* Update part of the register affected by the emulated instruction */ - regs->ax &= ~mask; -if (success) - regs->ax |= args.r11 & mask; +insn_assign_reg (®s->ax, val, size);return success; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 288/1424 arch_numa: avoid false positive fortify warning in setup_node_to_cpumask_map()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit f2b1cb39d5ccab090d8353788f186f7e7a1fffd4 upstream.
When building ARCH=riscv using clang with CONFIG_FORTIFY_SOURCE and CONFIG_UBSAN_BOUNDS enabled, CONFIG_NR_CPUS > 64, and the default value of 2 for CONFIG_NODES_SHIFT, there is a compiletime warning from the fortify routines.
In file included from mm/arch_numa.c:11:
In file included from include/linux/acpi.h:14:
In file included from include/linux/resource_ext.h:11:
In file included from include/linux/slab.h:17:
In file included from include/linux/gfp.h:7:
In file included from include/linux/mmzone.h:8:
In file included from include/linux/spinlock.h:60:
In file included from include/linux/interrupt_rc.h:17:
In file included from include/linux/smp.h:13:
In file included from include/linux/cpumask.h:11:
In file included from include/linux/bitmap.h:13:
In file included from include/linux/string.h:383:
include/linux/fortify-string.h:430:4: warning: call to '__write_overflow_field' declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribue-warning]
430 | __write_overflow_field(p_size_field, size);
| ^
include/linux/fortify-string.h:430:4: note: called by function 'fortify_memset_chk(unsigned long, unsigned long, unsigned long)'
include/linux/bitmap.h:248:3: note: inlined by function 'setup_node_to_cpumask_map'
248 | memset(dst, 0, len);
| ^
include/linux/fortify-string.h:462:25: note: expanded from macro 'memset'
462 | #define memset(p, c, s) __fortify_memset_chk(p, c, s, \
| ^
include/linux/fortify-string.h:453:2: note: expanded from macro '__fortify_memset_chk'
453 | fortify_memset_chk(__fortify_size, p_size, p_size_field), \
| ^
include/linux/fortify-string.h:430:4: note: use '-gline-directives-only' (implied by '-g1') or higher for more accurate inlining chain locations
430 | __write_overflow_field(p_size_field, size);
| ^1 warning generated.
In this configuration, MAX_NUMNODES is 4. clang unrolls the for loop in setup_node_to_cpumask_map() past this, which triggers the fortify check when accessing node_to_cpumask_map on the theoretical fifth loop iteration because it would be an out of bounds write.
Make it clear to clang that nr_node_ids is bounded by MAX_NUMNODES due to the logic in setup_nr_node_ids() by early returning in setup_node_to_cpumask_map() should that condition be violated.
--- drivers/base/arch_numa.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/base/arch_numa.c +12 -0
@@ -105,6 +105,18 @@ static void __init setup_node_to_cpumaskif (nr_node_ids ==MAX_NUMNODES )setup_nr_node_ids (); +/* +* This check should never be true but it makes it clear to compilers +* that node_to_cpumask_map is bound by nr_node_ids, avoiding false +* positive fortify warnings when accessing node_to_cpumask_map in the +* for loop below. +*/ +if (unlikely (nr_node_ids >MAX_NUMNODES )) { +pr_err ("nr_node_ids (%u) is larger than MAX_NUMNODES (%u)\n" , + nr_node_ids,MAX_NUMNODES ); +return ; + } +/* allocate and clear the mapping */ for (node =0 ; node < nr_node_ids; node++) {alloc_bootmem_cpumask_var (&node_to_cpumask_map[node]);
Greg Kroah-Hartman
maintainerPATCH 289/1424 dm-stats: fix a crash if allocation of per-cpu data fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit cc87e26d9cce22061dc21e51e11afef29dbbc36a upstream.
If "dm_kvzalloc(percpu_alloc_size, cpu_to_node(cpu))" fails, the code jumps to the "out" label and calls dm_stat_free. dm_stat_free does "for_each_possible_cpu(cpu) { dm_kvfree(s->stat_percpu[cpu][0].histogram, s->histogram_alloc_size);", which crashes with NULL pointer dereference if s->stat_percpu[cpu] is NULL.
This commit fixes the bug by testing s->stat_percpu[cpu] for NULL before using it.
--- drivers/md/dm-stats.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/md/dm-stats.c +4 -2
@@ -175,8 +175,10 @@ static void dm_stat_free(struct rcu_headkfree (s->program_id);kfree (s->aux_data);for_each_possible_cpu (cpu) { -dm_kvfree (s->stat_percpu[cpu][0 ].histogram, s->histogram_alloc_size); -dm_kvfree (s->stat_percpu[cpu], s->percpu_alloc_size); +if (s->stat_percpu[cpu]) { +dm_kvfree (s->stat_percpu[cpu][0 ].histogram, s->histogram_alloc_size); +dm_kvfree (s->stat_percpu[cpu], s->percpu_alloc_size); + } }dm_kvfree (s->stat_shared[0 ].tmp.histogram, s->histogram_alloc_size);dm_kvfree (s, s->shared_alloc_size);
Greg Kroah-Hartman
maintainerPATCH 290/1424 dm-switch: use WRITE_ONCE() in switch_region_table_write()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haotian Zhang <[email protected]>
commit c7391ebe33162c7962b313caea4d8e6b0bc2a671 upstream.
switch_region_table_read() accesses the region table with READ_ONCE() and is called from the lockless switch_map() IO path. However, switch_region_table_write() stores to the same array with a plain assignment. This results in an inconsistent access pattern for a lockless shared variable and may trigger data race reports.
Use WRITE_ONCE() to pair with the existing READ_ONCE() in switch_region_table_read().
--- drivers/md/dm-switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/dm-switch.c +1 -1
@@ -184,7 +184,7 @@ static void switch_region_table_write(st pte = sctx->region_table[region_index]; pte &= ~((((region_table_slot_t )1 << sctx->region_table_entry_bits) -1 ) << bit); pte |= (region_table_slot_t )value << bit; - sctx->region_table[region_index] = pte; +WRITE_ONCE (sctx->region_table[region_index], pte); }/*
Greg Kroah-Hartman
maintainerPATCH 291/1424 i3c: master: Fix info leak and UAF in device unregister path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
commit d2c743efd2d1ee64e94324664808f623dd865872 upstream.
i3c_master_unregister_i3c_devs() clears i3cdev->dev->desc before calling device_unregister(). During device_unregister(), device_del() emits a KOBJ_REMOVE uevent and unbinds the driver while the device descriptor is still expected to be valid. As a result, i3c_device_uevent() and a racing modalias_show() can observe a NULL desc and fall back to an uninitialized stack struct i3c_device_info, leaking kernel stack contents in the generated modalias. Driver .remove() callbacks may also encounter an unexpected NULL desc during unbind.
Keep desc valid until device_unregister() has completed. Since device_unregister() drops the device reference and may free the device, take an extra reference with get_device() before unregistering. Clear desc afterwards and release the extra reference with put_device(). This preserves the release-time invariant that desc must be NULL while avoiding both the information leak and a potential use-after-free from writing desc after the device has been released.
--- drivers/i3c/master.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/i3c/master.c +5 -4
@@ -2505,11 +2505,12 @@ static void i3c_master_unregister_i3c_deif (!i3cdev->dev)continue ; - i3cdev->dev->desc =NULL ; -if (device_is_registered (&i3cdev->dev->dev)) +if (device_is_registered (&i3cdev->dev->dev)) { +get_device (&i3cdev->dev->dev);device_unregister (&i3cdev->dev->dev); -else -put_device (&i3cdev->dev->dev); + } + i3cdev->dev->desc =NULL ; +put_device (&i3cdev->dev->dev); i3cdev->dev =NULL ; } }
Greg Kroah-Hartman
maintainerPATCH 292/1424 i3c: master: svc: bound IBI payload to the requested max_payload_len
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit e2bda39d7f9f285ec803e200b5c1f17143d0b483 upstream.
svc_i3c_master_handle_ibi() reads the IBI payload from the RX FIFO into the IBI slot. The loop is bounded by the hardware FIFO size (SVC_I3C_FIFO_SIZE), not by the slot size.
slot->data points into the IBI pool, which i3c_generic_ibi_alloc_pool() sizes at max_payload_len per slot. svc_i3c_master_request_ibi() only rejects a max_payload_len larger than SVC_I3C_FIFO_SIZE, so a driver can request a smaller one. mctp-i3c requests 1. Each readsb() then copies the controller RXCOUNT bytes (up to 31) with no check against the slot size. A device that sends more bytes than the slot holds writes past slot->data, an out-of-bounds write into the IBI pool.
Bound the loop by dev->ibi->max_payload_len and clamp each read to the space left in the slot, the same way dw-i3c does. A device can still send more than the requested payload. Flush the leftover bytes from the RX FIFO so they do not leak into the next transfer.
--- drivers/i3c/master/svc-i3c-master.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/i3c/master/svc-i3c-master.c +9 -1
@@ -380,14 +380,22 @@ static int svc_i3c_master_handle_ibi(str buf = slot->data;while (SVC_I3C_MSTATUS_RXPEND (readl (master->regs +SVC_I3C_MSTATUS )) && - slot->len <SVC_I3C_FIFO_SIZE ) { + slot->len < dev->ibi->max_payload_len) { mdatactrl =readl (master->regs +SVC_I3C_MDATACTRL ); count =SVC_I3C_MDATACTRL_RXCOUNT (mdatactrl); + count =min (count, dev->ibi->max_payload_len - slot->len);readsb (master->regs +SVC_I3C_MRDATAB , buf, count); slot->len += count; buf += count; } +/* +* The device may have sent more than the requested payload. Drop the +* extra bytes so they do not leak into the next transfer. +*/ +if (SVC_I3C_MSTATUS_RXPEND (readl (master->regs +SVC_I3C_MSTATUS ))) +writel (SVC_I3C_MDATACTRL_FLUSHRB , master->regs +SVC_I3C_MDATACTRL ); + master->ibi.tbq_slot = slot;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 293/1424 wifi: brcmfmac: Fix memory leak in brcmf_sdio_read_control()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 0d10db8e94fcb23a799789aaa696b4d8f937e207 upstream.
The memory allocated for buf is not freed in some of the error paths in brcmf_sdio_read_control(). Fix that by adding vfree() calls.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +2 -1
@@ -1826,17 +1826,18 @@ gotpkt:if (bus->rxctl) {brcmf_err ("last control frame is being processed.\n" );spin_unlock_bh (&bus->rxctl_lock); -vfree (buf); goto done; } bus->rxctl = buf + doff; bus->rxctl_orig = buf; bus->rxlen = len - doff;spin_unlock_bh (&bus->rxctl_lock); + buf =NULL ; done:/* Awake any waiters */ brcmf_sdio_dcmd_resp_wake (bus); +vfree (buf); }/* Pad read to blocksize for efficiency */
Greg Kroah-Hartman
maintainerPATCH 294/1424 wifi: mwifiex: Detach sync cmd buffer on interrupted wait
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Estevam <[email protected]>
commit ef06882c7d8a7400b67d0d003b1008093dd589ed upstream.
mwifiex synchronous commands keep the caller-provided data buffer in cmd_node->data_buf. Several callers pass stack-allocated objects there.
If wait_event_interruptible_timeout() is interrupted, the caller can return and release that stack object while the firmware command is still the current command. A late firmware response then reaches the normal response handler, which can copy data through cmd_node->data_buf into the stale stack address.
This fixes a stack corruption observed during repeated association and disassociation cycles. The panic trace showed the command wait being interrupted immediately before a bad pointer dereference:
cmd_wait_q terminated: -512
Unable to handle kernel paging request at virtual address 002c583837384662 Kernel panic - not syncing: stack-protector: Kernel stack is corrupted ... Tainted: [M]=MACHINE_CHECK
The fault address decodes as little-endian ASCII:
0x002c583837384662 -> "bF878X,\0"
which is a fragment of the VERSION_EXT firmware string exposed as debugfs "verext":
w8997o-V4, RF878X, FP92, 16.92.21.p153.7
The same runs also showed corrupted control data containing:
0x2400372e333531 -> "153.7\0$"
which is the tail of the same VERSION_EXT string. This points at a late VERSION_EXT response writing through a stale stack-backed data_buf after the interrupted wait returned.
After cancelling pending commands on an interrupted or timed-out wait, detach the caller-owned data buffer from the still-current command. This preserves the existing command cancellation behaviour while preventing a late response from writing through a pointer whose lifetime ended with the waiting caller.
Tested on an i.MX8MP board using an 88W8997.
--- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +12 -0
@@ -57,6 +57,18 @@ int mwifiex_wait_queue_complete(struct mmwifiex_dbg (adapter,ERROR ,"cmd_wait_q terminated: %d\n" , status);mwifiex_cancel_all_pending_cmd (adapter); + +/* The command response path writes through cmd_node->data_buf. +* On an interrupted wait, the caller can return and release a +* stack-allocated data_buf before a late firmware response is +* processed. Detach the caller-owned buffer from the current +* command so a late response cannot corrupt freed stack memory. +*/ +spin_lock_bh (&adapter->mwifiex_cmd_lock); +if (adapter->curr_cmd == cmd_queued) + adapter->curr_cmd->data_buf =NULL ; +spin_unlock_bh (&adapter->mwifiex_cmd_lock); +return status; }
Greg Kroah-Hartman
maintainerPATCH 295/1424 wifi: rtl818x: initialize eeprom_93cx6 struct to zero
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislaw Gruszka <[email protected]>
commit 799b5f45cb8194ebd06c9c89e0afdad5bedd2cc5 upstream.
Commit 7738a7ab9d12 ("misc: eeprom: eeprom_93cx6: Add quirk for extra read clock cycle") added extra 'quirk' field to struct eeprom_93cx6.
Many existing users of eeprom_93cx6, including rtl818x drivers, allocate the structure on the stack without initializing all fields. As a result, the added quirk field has an undefined value and can randomly cause reading wrong data from the EEPROM.
Fix by initializing the structures with {}.
--- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +1 -1
@@ -1648,7 +1648,7 @@ static void rtl8180_eeprom_register_writstatic void rtl8180_eeprom_read (struct rtl8180_priv *priv) { -struct eeprom_93cx6 eeprom; +struct eeprom_93cx6 eeprom = {};int eeprom_cck_table_adr;u16 eeprom_val;int i;
drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +1 -1
@@ -1441,7 +1441,7 @@ static int rtl8187_probe(struct usb_intestruct usb_device *udev =interface_to_usbdev (intf);struct ieee80211_hw *dev;struct rtl8187_priv *priv; -struct eeprom_93cx6 eeprom; +struct eeprom_93cx6 eeprom = {};struct ieee80211_channel *channel;const char *chip_name;u16 txpwr, reg;
Greg Kroah-Hartman
maintainerPATCH 296/1424 wifi: rtw88: Fix potential memory leak in rtw_txq_push_skb()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 9f2948010764d708bda27369d09ce6f194abe8e3 upstream.
The skb passed to the rtw_hci_tx_write() is expected to be freed when the function fails, but the error path in rtw_txq_push_skb() does not free the skb before returning. This can lead to a memory leak in rtw_txq_push() where a dequeued skb is passed to rtw_txq_push_skb().
--- drivers/net/wireless/realtek/rtw88/tx.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/realtek/rtw88/tx.c +1 -0
@@ -609,6 +609,7 @@ static int rtw_txq_push_skb(struct rtw_d ret =rtw_hci_tx_write (rtwdev, &pkt_info, skb);if (ret) {rtw_err (rtwdev,"failed to write TX skb to HCI\n" ); +ieee80211_free_txskb (rtwdev->hw, skb);return ret; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 297/1424 wifi: mt76: mt7615: avoid waiting for mac work under the mt76 mutex
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit bda8324270b1ac91bfba1df8928e0570e29759e8 upstream.
mt7615_suspend() acquired the mt76 mutex and then called cancel_delayed_work_sync() on mac_work. mt7615_mac_work() acquires the same mutex via mt7615_mutex_acquire() at the top of the worker, so if mac_work is already running and blocked on the mutex, the suspend path deadlocks waiting for the work it holds the mutex against.
Flush scan_work and mac_work before taking the mutex, matching the suspend paths in mt7921 and mt7925. scan_work only takes the mt76 spinlock, but moving it keeps the sequence consistent. This also keeps mac_work from running over an already suspended HIF, which the previous split (async cancel under the lock, sync cancel after release) would have allowed.
--- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/main.c +3 -2
@@ -1250,11 +1250,12 @@ static int mt7615_suspend(struct ieee802cancel_delayed_work_sync (&dev->pm.ps_work);mt76_connac_free_pending_tx_skbs (&dev->pm,NULL ); +cancel_delayed_work_sync (&phy->scan_work); +cancel_delayed_work_sync (&phy->mt76->mac_work); +mt7615_mutex_acquire (dev);clear_bit (MT76_STATE_RUNNING , &phy->mt76->state); -cancel_delayed_work_sync (&phy->scan_work); -cancel_delayed_work_sync (&phy->mt76->mac_work);set_bit (MT76_STATE_SUSPEND , &phy->mt76->state); ieee80211_iterate_active_interfaces(hw,
Greg Kroah-Hartman
maintainerPATCH 298/1424 vsock/virtio: flush works in dependency order
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 728836ebca239810f164262b10211ef59182f811 upstream.
virtio_vsock_remove() stops the virtqueues and then flushes each work item before freeing the enclosing virtio_vsock. The current order does not account for dependencies between those items: tx_work may queue send_pkt_work, and send_pkt_work may queue rx_work.
In particular, send_pkt_work can set restart_rx and release tx_lock. The remove path can then stop the queues and flush rx_work before send_pkt_work queues it. Although the later send_pkt_work flush waits for that producer to finish, nothing waits for the newly queued rx_work, so kfree(vsock) can race with it.
KASAN reported:
BUG: KASAN: slab-use-after-free in virtio_transport_rx_work+0x487/0x4b0 Read of size 8 at addr ffff888114c2b008 by task kworker/1:1/47 Workqueue: virtio_vsock virtio_transport_rx_work Call Trace: virtio_transport_rx_work+0x487/0x4b0 process_one_work+0x688/0x1120 worker_thread+0x45b/0xd10 Allocated by task 1: virtio_vsock_probe+0xef/0x6b0 Freed by task 84: kfree+0x131/0x3c0 virtio_vsock_remove+0xd1/0x100
Flush the works in producer-to-consumer order. virtio_vsock_vqs_del() has already disabled the queue callbacks and cleared the run flags, so after tx_work and send_pkt_work are drained, no source remains that can queue rx_work after its flush.
--- net/vmw_vsock/virtio_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/vmw_vsock/virtio_transport.c +1 -1
@@ -717,10 +717,10 @@ static void virtio_vsock_remove(struct v/* Other works can be queued before 'config->del_vqs()', so we flush * all works before to free the vsock object to avoid use after free. */ -flush_work (&vsock->rx_work);flush_work (&vsock->tx_work);flush_work (&vsock->event_work);flush_work (&vsock->send_pkt_work); +flush_work (&vsock->rx_work);mutex_unlock (&the_virtio_vsock_mutex);
Greg Kroah-Hartman
maintainerPATCH 299/1424 w1: ds28e17: reject an oversize length on an I2C block read
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit 169ae5e65e5aaf213b6a578f6478a9fd2e523606 upstream.
w1_f19_i2c_master_transfer() is the master_xfer for the DS28E17 1-Wire to I2C bridge. On an I2C_M_RECV_LEN read, it takes the length from the device. The downstream slave puts a length byte in buf[0]. The driver then reads that many bytes into buf[1] with w1_f19_i2c_read().
buf[0] is controlled by the device and can be 0 to 255. w1_f19_i2c_read() only rejects a zero count. The caller buffer is I2C_SMBUS_BLOCK_MAX + 2, so 34 bytes. A length above 32 makes the read run past it, up to about 222 bytes out of bounds.
The SMBus core does check buf[0] against I2C_SMBUS_BLOCK_MAX. That check runs after master_xfer returns. By then the write is already done. i2c-algo-bit rejects an oversize length before it copies, and returns -EPROTO.
Reject a length above I2C_SMBUS_BLOCK_MAX at both RECV_LEN sites, the same way i2c-algo-bit does.
--- drivers/w1/slaves/w1_ds28e17.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/w1/slaves/w1_ds28e17.c +8 -0
@@ -389,6 +389,10 @@ static int w1_f19_i2c_master_transfer(st* another simple read in that case. */ if (msgs[i+1 ].flags &I2C_M_RECV_LEN ) { +if (msgs[i+1 ].buf[0 ] >I2C_SMBUS_BLOCK_MAX ) { + i = -EPROTO ; + goto error; + } result =w1_f19_i2c_read (sl, msgs[i+1 ].addr, &(msgs[i+1 ].buf[1 ]), msgs[i+1 ].buf[0 ]);if (result <0 ) {
@@ -415,6 +419,10 @@ static int w1_f19_i2c_master_transfer(st* another simple read in that case. */ if (msgs[i].flags &I2C_M_RECV_LEN ) { +if (msgs[i].buf[0 ] >I2C_SMBUS_BLOCK_MAX ) { + i = -EPROTO ; + goto error; + } result = w1_f19_i2c_read(sl, msgs[i].addr, &(msgs[i].buf[1]),
Greg Kroah-Hartman
maintainerPATCH 300/1424 xarray: honor XA_FLAGS_ACCOUNT in xas_split_alloc()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zi Yan <[email protected]>
commit 789763523fb43cdc328de5cb5dcd19240ccf90d8 upstream.
XArray operations that allocate xa_nodes, such as xas_nomem() and xas_alloc(), add __GFP_ACCOUNT when the array has XA_FLAGS_ACCOUNT set. This charges the allocated memory and avoids the workingset convergence issue described by commit 7b785645e8f13 ("mm: fix page cache convergence regression").
xas_split_alloc() does not add _GFP_ACCOUNT when XA_FLAGS_ACCOUNT is present. Fix it.
--- lib/xarray.c | 3 +++ 1 file changed, 3 insertions(+)
lib/xarray.c +3 -0
@@ -1012,6 +1012,9 @@ void xas_split_alloc(struct xa_state *xaif (xas->xa_shift +XA_CHUNK_SHIFT > order)return ; +if (xas->xa->xa_flags &XA_FLAGS_ACCOUNT ) + gfp |= __GFP_ACCOUNT; + do { unsigned int i; void *sibling = NULL;
Greg Kroah-Hartman
maintainerPATCH 301/1424 tpm: tpm_i2c_nuvoton: disable IRQ on wait timeout
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 705c4ed0643366963547b2616d53165f2519c81f upstream.
i2c_nuvoton_wait_for_stat() enables the IRQ before waiting for the interrupt handler to report a status change. If the wait times out, or is interrupted before the handler runs, the function returns without balancing the enable_irq() call.
Disable the IRQ before leaving the failed wait path. Also preserve an interrupted wait's original error code instead of converting it to -ETIMEDOUT inside the helper.
--- drivers/char/tpm/tpm_i2c_nuvoton.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/char/tpm/tpm_i2c_nuvoton.c +4 -2
@@ -181,8 +181,10 @@ static int i2c_nuvoton_wait_for_stat(str timeout);if (rc >0 )return 0 ; -/* At this point we know that the SINT pin is asserted, so we -* do not need to do i2c_nuvoton_check_status */ + +disable_irq (priv->irq); +if (rc <0 ) +return rc; }else {unsigned long ten_msec, stop;bool status_valid;
Greg Kroah-Hartman
maintainerPATCH 302/1424 sticon/parisc: Detect default STI graphics card for console output
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit de508ece1d37cdbbbfa52f074954310f9b066b13 upstream.
If a machine has multiple graphic cards, detect the graphic card which is used to display firmware messages and use that one as the default graphic card for sticon and fbcon.
On parisc machines the default graphic card used for BCH (boot console handler, aka BIOS menu) is stored in the stable storage (equivalent to CMOS storage on x86) or in the console path in page zero. Extract that path and store it as default STI path for later comparism. Take care that the graphic card can be a GSC or a PCI card which use different path strings.
Increase max string size for default_sti_path to 32 chars as the print_pa_hwpath() function formats a hardware path using unbounded sprintf calls for up to 6 bus converter components and 1 module component (e.g., 255/255/...), which can produce a string up to 28 bytes long.
--- drivers/video/sticore.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
drivers/video/sticore.c +21 -1
@@ -325,7 +325,7 @@ static void sti_rom_copy(unsigned long b -static char default_sti_path[21 ]__read_mostly ; +static char default_sti_path[32 ]__read_mostly ;#ifndef MODULE static int __init sti_setup (char *str)
@@ -1143,6 +1143,26 @@ static void sti_init_roms(void)pr_info ("STI GSC/PCI core graphics driver " STI_DRIVERVERSION "\n" ); +/* +* Find default console by hardware path which is either stored in +* console entry in stable storage or alternatively from console path +* in PAGE0 used by BCH and PDC. +*/ +if (!default_sti_path[0 ]) { +struct pdc_module_path conspath; +struct device *dev =NULL ; + +if (pdc_stable_read (0x60 , &conspath,sizeof (conspath)) ==PDC_OK ) + dev =hwpath_to_device (&conspath.path); +if (!dev) + dev =hwpath_to_device (&PAGE0 ->mem_cons.dp.path); +if (dev &&dev_is_pci (dev)) +print_pci_hwpath (to_pci_dev (dev), default_sti_path); +else if (dev && !dev_is_pci (dev)) +print_pa_hwpath (to_parisc_device (dev), default_sti_path); +pr_debug ("default graphic card: %s\n" , default_sti_path); + } +/* Register drivers for native & PCI cards */ register_parisc_driver (&pa_sti_driver);WARN_ON (pci_register_driver (&pci_sti_driver));
Greg Kroah-Hartman
maintainerPATCH 303/1424 signal: avoid shared siginfo namespace rewrites
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
commit d19cdc167e696714509e87d3f7ae765b6e164589 upstream.
send_signal_locked() rewrites sender ids for the target namespace. Group sends reuse the same siginfo, so one recipient can affect the next.
Copy the siginfo before changing it.
--- kernel/signal.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/signal.c +4 -0
@@ -1226,6 +1226,7 @@ static inline bool has_si_pid_and_uid(stint send_signal_locked (int sig,struct kernel_siginfo *info,struct task_struct *t,enum pid_type type) { +struct kernel_siginfo rewritten;/* Should SIGKILL or SIGSTOP be received by a pid namespace init? */ bool force = false;
@@ -1239,6 +1240,9 @@ int send_signal_locked(int sig, struct k/* SIGKILL and SIGSTOP is special or has ids */ struct user_namespace *t_user_ns; + rewritten = *info; + info = &rewritten; +rcu_read_lock (); t_user_ns =task_cred_xxx (t, user_ns);if (current_user_ns () != t_user_ns) {
Greg Kroah-Hartman
maintainerPATCH 304/1424 smack: fix cred UAF in smack_file_send_sigiotask()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit fedc88e38ce979a720cd2de042578cb5df3dc8de upstream.
When inspecting the credentials of another task, objective credentials (->real_cred, accessed with __task_cred()) must always be used.
Accessing ->cred on a non-current task is forbidden unless that task is being created or destroyed; a task is allowed to change its own ->cred pointer with no synchronization, and changing ->cred should only affect the current syscall.
smack_file_send_sigiotask() was accessing both sets of credentials: First tsk->cred, then __task_cred(tsk).
Fix it, always access the objective credentials here.
I have tested that this bug can lead to a KASAN-reported UAF of struct cred in smack_file_send_sigiotask(), and that this fix prevents the race.
--- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/smack/smack_lsm.c +1 -1
@@ -1907,7 +1907,7 @@ static int smack_file_send_sigiotask(str {struct smack_known **blob;struct smack_known *skp; -struct smack_known *tkp =smk_of_task (smack_cred (tsk->cred)); +struct smack_known *tkp =smk_of_task_struct_obj (tsk);const struct cred *tcred;struct file *file;int rc;
Greg Kroah-Hartman
maintainerPATCH 305/1424 taskstats: fix cpumask parsing cutting off the last character
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
commit 1f58a5335cdd14b3fb5f2a5d3763dee1f5cba1d3 upstream.
parse() hands nla_strscpy() len as dstsize, and nla_strscpy() copies at most dstsize - 1 bytes. When the attr payload comes in without a trailing NUL, srclen == len >= dstsize and the last character of the cpumask string gets cut off. Register "0-15" and you are silently listening on "0-1", exit data for the rest never shows up.
The bug only bites when the sender doesn't NUL terminate the payload; senders that include the NUL were always fine (srclen gets decremented for the trailing NUL, so srclen < dstsize). Thats probably why this survived 20 years. And the policy is NLA_STRING, not NLA_NUL_STRING, so a payload without the trailing NUL is legit input here.
Skip the kmalloc/nla_strscpy dance entirely and use nla_strdup(), which already allocates srclen + 1 and terminates. The nla_len() bounds checks stay as they were.
--- kernel/taskstats.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/taskstats.c +1 -2
@@ -368,10 +368,9 @@ static int parse(struct nlattr *na, strureturn -E2BIG ;if (len <1 )return -EINVAL ; - data =kmalloc (len,GFP_KERNEL ); + data =nla_strdup (na,GFP_KERNEL );if (!data)return -ENOMEM ; -nla_strscpy (data, na, len); ret =cpulist_parse (data, mask);kfree (data);return ret;
Greg Kroah-Hartman
maintainerPATCH 306/1424 timer: Keep debugobjects state consistent in migrate_timer_list()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit c793bbfc4a0a9f5a66978fc91559e9681748dbeb upstream.
When timers are migrated away from an offline CPU the debugobjects state gets corrupted. The timer is accounted as inactive on deletion, but the enqueue on the alive CPU lacks the activation call.
That used to work, but got broken when the trace point and the debug objects call got separated. That change missed to fixup migrate_timer_list().
Add the missing debug_timer_activate() invocation to fix it.
--- kernel/time/timer.c | 1 + 1 file changed, 1 insertion(+)
kernel/time/timer.c +1 -0
@@ -2224,6 +2224,7 @@ static void migrate_timer_list(struct ti timer = hlist_entry(head->first, struct timer_list, entry);detach_timer (timer, false); timer->flags = (timer->flags & ~TIMER_BASEMASK ) | cpu; +debug_timer_activate (timer);internal_add_timer (new_base, timer); } }
Greg Kroah-Hartman
maintainerPATCH 307/1424 udf: Fix i_lenExtents truncation on 32-bit kernels
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit a5a5ed23b1340ff0f32a14a7ca8585f7c4e9b2e2 upstream.
In udf_do_extend_file() the total extent length is rounded up to a block boundary with:
iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
i_lenExtents is a __u64, but sb->s_blocksize is unsigned long. On 32-bit kernels unsigned long is 32-bit, so ~(sb->s_blocksize - 1) is a 32-bit value (e.g. 0xfffff800 for a 2 KiB block) that is zero-extended in the AND, clearing the upper 32 bits of i_lenExtents. For UDF files whose total extent length exceeds 4 GiB this truncates i_lenExtents when the file is extended, corrupting the tracked extent length.
Cast the block size to 64-bit before forming the mask. 64-bit kernels are unaffected.
--- fs/udf/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/udf/inode.c +1 -1
@@ -529,7 +529,7 @@ static int udf_do_extend_file(struct ino sb->s_blocksize - 1) & ~(sb->s_blocksize - 1)); iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize -1 ) & - ~(sb->s_blocksize -1 ); + ~((u64 )sb->s_blocksize -1 ); } add =0 ;
Greg Kroah-Hartman
maintainerPATCH 308/1424 platform/chrome: sensorhub: Fix dropped timestamp events and log spam
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
commit 9a3f43b30373c61477d0d3ab52946c05f9492bf9 upstream.
Commit 833740a2333c ("platform/chrome: sensorhub: Bound the EC-reported sensor number") evaluated the sensor_num against the bounds limit even for timestamp events. A timestamp event typically has a sensor_num of 0xff [1], causing the driver to flag it as invalid and skip to the next event.
As a result, we'd see a flooding of "Invalid sensor number 255 from EC" warning logs and these timestamp events were being dropped.
Move the bounds-check into cros_ec_sensor_ring_process_event() and evaluate it only after standalone timestamp events have already been processed and returned early.
[1] https://crrev.com/219ca6ef82ba266da788b673ee4ad50bd3ea1285/common/motion_sense_fifo.c#427
--- drivers/platform/chrome/cros_ec_sensorhub_ring.c | 27 ++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-)
drivers/platform/chrome/cros_ec_sensorhub_ring.c +15 -12
@@ -436,6 +436,21 @@ cros_ec_sensor_ring_process_event(struct fifo_timestamp, *current_timestamp, now); + +/* +* A standalone timestamp event typically has a sensor_num of +* 0xff. Return early here to prevent it from hitting the +* bounds check below and spamming the logs. +*/ +return false; + } + +/* Skip event if sensor_num from EC is out of bounds. */ +if (in->sensor_num >= sensorhub->sensor_num) { +dev_warn_ratelimited (sensorhub->dev, +"Invalid sensor number %u from EC\n" , + in->sensor_num); +return false; }if (in->flags &MOTIONSENSE_SENSOR_FLAG_ODR ) {
@@ -463,10 +478,6 @@ cros_ec_sensor_ring_process_event(structreturn true; } -if (in->flags &MOTIONSENSE_SENSOR_FLAG_TIMESTAMP ) -/* If we just have a timestamp, skip this entry. */ -return false; -/* Regular sample */ out->sensor_id = in->sensor_num; trace_cros_ec_sensorhub_data(in->sensor_num,
@@ -851,14 +862,6 @@ static void cros_ec_sensorhub_ring_handlfor (in = sensorhub->resp->fifo_read.data, j =0 ; j < number_data; j++, in++) { -/* Skip event if sensor_num from EC is out of bounds. */ -if (in->sensor_num >= sensorhub->sensor_num) { -dev_warn_ratelimited (sensorhub->dev, -"Invalid sensor number %u from EC\n" , - in->sensor_num); -continue ; - } - if (cros_ec_sensor_ring_process_event( sensorhub, fifo_info, fifo_timestamp,
Greg Kroah-Hartman
maintainerPATCH 309/1424 net: skbuff: dont skb_tx_error() the source skb in skb_zerocopy()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
[ Upstream commit 8ece906150128d5ec2462aabcc978c568433eca4 ]
skb_zerocopy() copies frags from @from into @to. On an skb_orphan_frags() failure it calls skb_tx_error(@from), a destructive operation on the source skb the copy helper does not own. That completes @from's zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, including the SKBFL_SHARED_FRAG page-ownership marker.
Both callers already report the failure on their own drop path. nfnetlink_queue does it at nla_put_failure, and Open vSwitch does it in the flow-miss drop arm of ovs_dp_process_packet(), so nothing is lost by dropping it here.
On Open vSwitch's OVS_ACTION_ATTR_USERSPACE path the skb is not freed on this error: do_execute_actions() ignores output_userspace()'s return value and, unless the upcall was the last action, keeps forwarding the same skb through the flow's remaining actions. The uarg is completed while that skb is still in flight, telling the producer its buffers are free, and SKBFL_SHARED_FRAG is cleared on an skb the rest of the stack still handles. That flag is what makes esp_input() call skb_cow_data() instead of decrypting in place, so a later local ESP delivery can decrypt over frags the skb does not own privately.
Leave error reporting to the callers.
--- net/core/skbuff.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/core/skbuff.c +2 -3
@@ -3629,10 +3629,9 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)skb_len_add (to, len + plen); -if (unlikely (skb_orphan_frags (from,GFP_ATOMIC ))) { -skb_tx_error (from); +if (unlikely (skb_orphan_frags (from,GFP_ATOMIC )))return -ENOMEM ; - } +skb_zerocopy_clone (to, from,GFP_ATOMIC );for (i =0 ; i <skb_shinfo (from)->nr_frags; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 310/1424 net: openvswitch: fix kernel-doc warnings in internal headers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
[ Upstream commit 6bb0dcb3d321c14be7ca33b71a149034d6a2cde8 ]
Some field descriptions were missing, some were not very accurate. Not touching the uAPI header or .c files for now.
Formatting of those comments isn't great in general, but at least they are not missing anything now.
Before:
$ ./scripts/kernel-doc -none -Wall net/openvswitch/*.h 2>&1 | wc -l 16
After:
$ ./scripts/kernel-doc -none -Wall net/openvswitch/*.h 2>&1 | wc -l 0
--- net/openvswitch/datapath.h | 20 ++++++++++++++------ net/openvswitch/vport.h | 9 +++++++++ 2 files changed, 23 insertions(+), 6 deletions(-)
net/openvswitch/datapath.h +14 -6
@@ -29,8 +29,8 @@* datapath. * @n_hit: Number of received packets for which a matching flow was found in * the flow table. -* @n_miss: Number of received packets that had no matching flow in the flow -* table. The sum of @n_hit and @n_miss is the number of packets that have +* @n_missed: Number of received packets that had no matching flow in the flow +* table. The sum of @n_hit and @n_missed is the number of packets that have * been received by the datapath. * @n_lost: Number of received packets that had no matching flow in the flow * table that could not be sent to userspace (normally due to an overflow in
@@ -40,6 +40,7 @@* up per packet. * @n_cache_hit: The number of received packets that had their mask found using * the mask cache. +* @syncp: Synchronization point for 64bit counters. */ struct dp_stats_percpu {u64 n_hit;
@@ -74,8 +75,10 @@ struct dp_nlsk_pids {* ovs_mutex and RCU. * @stats_percpu: Per-CPU datapath statistics. * @net: Reference to net namespace. -* @max_headroom: the maximum headroom of all vports in this datapath; it will +* @user_features: Bitmap of enabled %OVS_DP_F_* features. +* @max_headroom: The maximum headroom of all vports in this datapath; it will * be used by all the internal vports in this dp. +* @meter_tbl: Meter table. * @upcall_portids: RCU protected 'struct dp_nlsk_pids'. * * Context: See the comment on locking at the top of datapath.c for additional
@@ -125,10 +128,13 @@ struct ovs_skb_cb {#define OVS_CB (skb) ((struct ovs_skb_cb *)(skb)->cb)/** -* struct dp_upcall - metadata to include with a packet to send to userspace +* struct dp_upcall_info - metadata to include with a packet sent to userspace * @cmd: One of %OVS_PACKET_CMD_*. * @userdata: If nonnull, its variable-length value is passed to userspace as * %OVS_PACKET_ATTR_USERDATA. +* @actions: If nonnull, its variable-length value is passed to userspace as +* %OVS_PACKET_ATTR_ACTIONS. +* @actions_len: The length of the @actions. * @portid: Netlink portid to which packet should be sent. If @portid is 0 * then no packet is sent and the packet is accounted in the datapath's @n_lost * counter.
@@ -149,6 +155,10 @@ struct dp_upcall_info {* struct ovs_net - Per net-namespace data for ovs. * @dps: List of datapaths to enable dumping them all out. * Protected by genl_mutex. +* @dp_notify_work: A work notifier to handle port unregistering. +* @masks_rebalance: A work to periodically optimize flow table caches. +* @ct_limit_info: A hash table of conntrack zone connection limits. +* @xt_label: Whether connlables are configured for the network or not. */ struct ovs_net {struct list_head dps;
@@ -157,8 +167,6 @@ struct ovs_net {#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT )struct ovs_ct_limit_info *ct_limit_info;#endif - -/* Module reference for configuring conntrack. */ bool xt_label; };
net/openvswitch/vport.h +9 -0
@@ -97,6 +97,8 @@ struct vport {* @desired_ifindex: New vport's ifindex. * @dp: New vport's datapath. * @port_no: New vport's port number. +* @upcall_portids: %OVS_VPORT_ATTR_UPCALL_PID attribute from Netlink message, +* %NULL if none was supplied. */ struct vport_parms {const char *name;
@@ -125,6 +127,8 @@ struct vport_parms {* have any configuration. * @send: Send a packet on the device. * zero for dropped packets or negative for error. +* @owner: Module that implements this vport type. +* @list: List entry in the global list of vport types. */ struct vport_ops {enum ovs_vport_type type;
@@ -144,6 +148,7 @@ struct vport_ops {/** * struct vport_upcall_stats_percpu - per-cpu packet upcall statistics for * a given vport. +* @syncp: Synchronization point for 64bit counters. * @n_success: Number of packets that upcall to userspace succeed. * @n_fail: Number of packets that upcall to userspace failed. */
@@ -164,6 +169,8 @@ void ovs_vport_free(struct vport *);* * @vport: vport to access * +* Returns: A void pointer to a private data allocated in the @vport. +* * If a nonzero size was passed in priv_size of vport_alloc() a private data * area was allocated on creation. This allows that area to be accessed and * used for any purpose needed by the vport implementer.
@@ -178,6 +185,8 @@ static inline void *vport_priv(const struct vport *vport)* * @priv: Start of private data area. * +* Returns: A reference to a vport structure that contains @priv. +* * It is sometimes useful to translate from a pointer to the private data * area to the vport, such as in the case where the private data pointer is * the result of a hash table lookup. @priv must point to the start of the
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 311/1424 openvswitch: Fix CT limit teardown use-after-free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
[ Upstream commit 403f96c32c9e24600093d7d0c61c17daeedca957 ]
Packet processing uses CT limit state under RCU, while netns teardown frees that state under ovs_mutex. The CT limit pointer was neither removed from readers nor protected by a grace period, allowing packet processing to dereference the freed state.
An unprivileged user can trigger this bug from a user and network namespace, causing a slab-use-after-free in ovs_ct_execute() when the netns is torn down.
Publish the CT limit pointer through RCU, remove it before teardown, and wait for readers before freeing its contents. Keep ovs_mutex around individual CT limit updates, and use the RCU read-side lock while GET traverses the RCU-protected limit lists.
Netns teardown detaches the RCU-protected CT limit state in the pernet .pre_exit callback while holding ovs_mutex. The pernet core guarantees an RCU grace period between the .pre_exit and .exit callbacks, so the .exit callback completes the teardown without adding any extra synchronization.
The netlink command handlers do not need NULL checks because the userspace netlink socket holds an active reference to its network namespace while a request is processed. The per-netns exit path therefore cannot run concurrently with SET, DEL, or GET for that socket's namespace.
6.12+ doesn't have a 'family' argument in nf_conncount_init/destroy ]
--- net/openvswitch/conntrack.c | 122 +++++++++++++++++++++++------------- net/openvswitch/conntrack.h | 6 +- net/openvswitch/datapath.c | 10 ++- net/openvswitch/datapath.h | 8 ++- 4 files changed, 98 insertions(+), 48 deletions(-)
net/openvswitch/conntrack.c +79 -43
@@ -908,10 +908,14 @@ static int ovs_ct_check_limit(struct net *net, const struct ovs_conntrack_info *info) {struct ovs_net *ovs_net =net_generic (net, ovs_net_id); -const struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; +const struct ovs_ct_limit_info *ct_limit_info;u32 per_zone_limit, connections;u32 conncount_key; + ct_limit_info =rcu_dereference (ovs_net->ct_limit_info); +if (!ct_limit_info) +return 0 ; + conncount_key = info->zone.id; per_zone_limit =ct_limit_get (ct_limit_info, info->zone.id);
@@ -1557,43 +1561,56 @@ static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT )static int ovs_ct_limit_init (struct net *net,struct ovs_net *ovs_net) { +struct ovs_ct_limit_info *info;int i, err; - ovs_net->ct_limit_info =kmalloc (sizeof (*ovs_net->ct_limit_info), -GFP_KERNEL ); -if (!ovs_net->ct_limit_info) + info =kmalloc (sizeof (*info),GFP_KERNEL ); +if (!info)return -ENOMEM ; - ovs_net->ct_limit_info->default_limit =OVS_CT_LIMIT_DEFAULT ; - ovs_net->ct_limit_info->limits = + info->default_limit =OVS_CT_LIMIT_DEFAULT ; + info->limits =kmalloc_array (CT_LIMIT_HASH_BUCKETS ,sizeof (struct hlist_head ),GFP_KERNEL ); -if (!ovs_net->ct_limit_info->limits) { -kfree (ovs_net->ct_limit_info); +if (!info->limits) { +kfree (info);return -ENOMEM ; }for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; i++) -INIT_HLIST_HEAD (&ovs_net->ct_limit_info->limits[i]); +INIT_HLIST_HEAD (&info->limits[i]); - ovs_net->ct_limit_info->data = -nf_conncount_init (net,NFPROTO_INET ,sizeof (u32)); + info->data =nf_conncount_init (net,NFPROTO_INET ,sizeof (u32)); -if (IS_ERR (ovs_net->ct_limit_info->data)) { - err =PTR_ERR (ovs_net->ct_limit_info->data); -kfree (ovs_net->ct_limit_info->limits); -kfree (ovs_net->ct_limit_info); +if (IS_ERR (info->data)) { + err =PTR_ERR (info->data); +kfree (info->limits); +kfree (info);pr_err ("openvswitch: failed to init nf_conncount %d\n" , err);return err; } +rcu_assign_pointer (ovs_net->ct_limit_info, info);return 0 ; } -static void ovs_ct_limit_exit (struct net *net,struct ovs_net *ovs_net) +static void *ovs_ct_limit_exit_start (struct ovs_net *ovs_net) +{ +return rcu_replace_pointer (ovs_net->ct_limit_info,NULL , +lockdep_ovsl_is_held ()); +} + +/* The CT limit state must be detached by ovs_ct_limit_exit_start() and an +* RCU grace period must elapse before this function runs. The pernet core +* guarantees the grace period between the .pre_exit and .exit callbacks. +*/ +static void ovs_ct_limit_exit_finish (struct net *net,void *data) { -const struct ovs_ct_limit_info *info = ovs_net->ct_limit_info; +const struct ovs_ct_limit_info *info = data;int i; +if (!info) +return ; +nf_conncount_destroy (net,NFPROTO_INET , info->data);for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; ++i) {struct hlist_head *head = &info->limits[i];
@@ -1601,7 +1618,7 @@ static void ovs_ct_limit_exit(struct net *net, struct ovs_net *ovs_net)struct hlist_node *next;hlist_for_each_entry_safe (ct_limit, next, head, hlist_node) -kfree_rcu (ct_limit, rcu); +kfree (ct_limit); }kfree (info->limits);kfree (info);
@@ -1640,12 +1657,13 @@ static bool check_zone_id(int zone_id, u16 *pzone)return false; } -static int ovs_ct_limit_set_zone_limit (struct nlattr *nla_zone_limit, -struct ovs_ct_limit_info *info) +static int ovs_ct_limit_set_zone_limit (struct ovs_net *ovs_net, +struct nlattr *nla_zone_limit) {struct ovs_zone_limit *zone_limit; -int rem; +struct ovs_ct_limit_info *info;u16 zone; +int rem; rem =NLA_ALIGN (nla_len (nla_zone_limit)); zone_limit = (struct ovs_zone_limit *)nla_data (nla_zone_limit);
@@ -1654,6 +1672,7 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit,if (unlikely (zone_limit->zone_id ==OVS_ZONE_LIMIT_DEFAULT_ZONE )) {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info); info->default_limit = zone_limit->limit;ovs_unlock (); } else if (unlikely(!check_zone_id(
@@ -1671,6 +1690,7 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit, ct_limit->limit = zone_limit->limit;ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info);ct_limit_set (info, ct_limit);ovs_unlock (); }
@@ -1685,12 +1705,13 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit,return 0 ; } -static int ovs_ct_limit_del_zone_limit (struct nlattr *nla_zone_limit, -struct ovs_ct_limit_info *info) +static int ovs_ct_limit_del_zone_limit (struct ovs_net *ovs_net, +struct nlattr *nla_zone_limit) {struct ovs_zone_limit *zone_limit; -int rem; +struct ovs_ct_limit_info *info;u16 zone; +int rem; rem =NLA_ALIGN (nla_len (nla_zone_limit)); zone_limit = (struct ovs_zone_limit *)nla_data (nla_zone_limit);
@@ -1699,6 +1720,7 @@ static int ovs_ct_limit_del_zone_limit(struct nlattr *nla_zone_limit,if (unlikely (zone_limit->zone_id ==OVS_ZONE_LIMIT_DEFAULT_ZONE )) {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info); info->default_limit =OVS_CT_LIMIT_DEFAULT ;ovs_unlock (); } else if (unlikely(!check_zone_id(
@@ -1706,6 +1728,7 @@ static int ovs_ct_limit_del_zone_limit(struct nlattr *nla_zone_limit,OVS_NLERR (true,"zone id is out of range" ); }else {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info);ct_limit_del (info, zone);ovs_unlock (); }
@@ -1749,6 +1772,7 @@ static int __ovs_ct_limit_get_zone_limit(struct net *net,return nla_put_nohdr (reply,sizeof (zone_limit), &zone_limit); } +/* Called with RCU read lock held. */ static int ovs_ct_limit_get_zone_limit(struct net *net, struct nlattr *nla_zone_limit, struct ovs_ct_limit_info *info,
@@ -1772,12 +1796,10 @@ static int ovs_ct_limit_get_zone_limit(struct net *net, &zone))) { OVS_NLERR(true, "zone id is out of range"); } else { -rcu_read_lock (); limit =ct_limit_get (info, zone); err =__ovs_ct_limit_get_zone_limit ( net, info->data, zone, limit, reply); -rcu_read_unlock ();if (err)return err; }
@@ -1792,6 +1814,7 @@ static int ovs_ct_limit_get_zone_limit(struct net *net,return 0 ; } +/* Called with RCU read lock held. */ static int ovs_ct_limit_get_all_zone_limit (struct net *net,struct ovs_ct_limit_info *info,struct sk_buff *reply)
@@ -1804,19 +1827,16 @@ static int ovs_ct_limit_get_all_zone_limit(struct net *net,if (err)return err; -rcu_read_lock ();for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; ++i) { head = &info->limits[i];hlist_for_each_entry_rcu (ct_limit, head, hlist_node) { err =__ovs_ct_limit_get_zone_limit (net, info->data, ct_limit->zone, ct_limit->limit, reply);if (err) - goto exit_err; +return err; } } -exit_err: -rcu_read_unlock ();return err; }
@@ -1826,7 +1846,6 @@ static int ovs_ct_limit_cmd_set(struct sk_buff *skb, struct genl_info *info)struct sk_buff *reply;struct ovs_header *ovs_reply_header;struct ovs_net *ovs_net =net_generic (sock_net (skb->sk), ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_SET,
@@ -1839,8 +1858,8 @@ static int ovs_ct_limit_cmd_set(struct sk_buff *skb, struct genl_info *info) goto exit_err; } - err =ovs_ct_limit_set_zone_limit (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], - ct_limit_info); + err =ovs_ct_limit_set_zone_limit (ovs_net, + a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]);if (err) goto exit_err;
@@ -1860,7 +1879,6 @@ static int ovs_ct_limit_cmd_del(struct sk_buff *skb, struct genl_info *info)struct sk_buff *reply;struct ovs_header *ovs_reply_header;struct ovs_net *ovs_net =net_generic (sock_net (skb->sk), ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_DEL,
@@ -1873,8 +1891,8 @@ static int ovs_ct_limit_cmd_del(struct sk_buff *skb, struct genl_info *info) goto exit_err; } - err =ovs_ct_limit_del_zone_limit (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], - ct_limit_info); + err =ovs_ct_limit_del_zone_limit (ovs_net, + a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]);if (err) goto exit_err;
@@ -1894,7 +1912,7 @@ static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info)struct ovs_header *ovs_reply_header;struct net *net =sock_net (skb->sk);struct ovs_net *ovs_net =net_generic (net, ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; +struct ovs_ct_limit_info *ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_GET,
@@ -1908,18 +1926,19 @@ static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info) goto exit_err; } +rcu_read_lock (); + ct_limit_info =rcu_dereference (ovs_net->ct_limit_info);if (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]) { err =ovs_ct_limit_get_zone_limit ( net, a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], ct_limit_info, reply); -if (err) - goto exit_err; }else { err =ovs_ct_limit_get_all_zone_limit (net, ct_limit_info, reply); -if (err) - goto exit_err; } +rcu_read_unlock (); +if (err) + goto exit_err;nla_nest_end (reply, nla_reply);genlmsg_end (reply, ovs_reply_header);
@@ -1994,12 +2013,29 @@ int ovs_ct_init(struct net *net)return err; } -void ovs_ct_exit (struct net *net) +/* Must be called with ovs_mutex held. Detaches the RCU-protected +* ct_limit_info and stores it in ovs_net->ct_limit_exit_data for +* ovs_ct_exit_finish() to complete the teardown after an RCU grace period. +*/ +void ovs_ct_exit_start (struct net *net__maybe_unused ) +{ +#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) +struct ovs_net *ovs_net =net_generic (net, ovs_net_id); + + ovs_net->ct_limit_exit_data =ovs_ct_limit_exit_start (ovs_net); +#endif +} + +/* Completes the CT limit teardown. The pernet core guarantees an RCU +* grace period between detaching the state in ovs_ct_exit_start() and +* this call, so no RCU readers remain. +*/ +void ovs_ct_exit_finish (struct net *net) {struct ovs_net *ovs_net =net_generic (net, ovs_net_id);#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -ovs_ct_limit_exit (net, ovs_net); +ovs_ct_limit_exit_finish (net, ovs_net->ct_limit_exit_data);#endif if (ovs_net->xt_label)
net/openvswitch/conntrack.h +4 -2
@@ -14,7 +14,8 @@ enum ovs_key_attr;#if IS_ENABLED (CONFIG_NF_CONNTRACK )int ovs_ct_init (struct net *); -void ovs_ct_exit (struct net *); +void ovs_ct_exit_start (struct net *net); +void ovs_ct_exit_finish (struct net *net);bool ovs_ct_verify (struct net *,enum ovs_key_attr attr); int ovs_ct_copy_action(struct net *, const struct nlattr *, const struct sw_flow_key *, struct sw_flow_actions **,
@@ -40,7 +41,8 @@ void ovs_ct_free_action(const struct nlattr *a);static inline int ovs_ct_init (struct net *net) {return 0 ; } -static inline void ovs_ct_exit (struct net *net) { } +static inline void ovs_ct_exit_start (struct net *net) { } +static inline void ovs_ct_exit_finish (struct net *net) { }static inline bool ovs_ct_verify (struct net *net,int attr) {
net/openvswitch/datapath.c +9 -1
@@ -2731,6 +2731,13 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, } } +static void __net_exit ovs_pre_exit_net(struct net *dnet) +{ +ovs_lock (); +ovs_ct_exit_start (dnet); +ovs_unlock (); +} + static void __net_exit ovs_exit_net(struct net *dnet) {struct datapath *dp, *dp_next;
@@ -2741,7 +2748,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)ovs_lock (); -ovs_ct_exit (dnet); +ovs_ct_exit_finish (dnet);list_for_each_entry_safe (dp, dp_next, &ovs_net->dps, list_node)__dp_destroy (dp);
@@ -2765,6 +2772,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)static struct pernet_operations ovs_net_ops = { .init = ovs_init_net, + .pre_exit = ovs_pre_exit_net, .exit = ovs_exit_net, .id = &ovs_net_id, .size =sizeof (struct ovs_net ),
net/openvswitch/datapath.h +6 -2
@@ -157,7 +157,10 @@ struct dp_upcall_info {* Protected by genl_mutex. * @dp_notify_work: A work notifier to handle port unregistering. * @masks_rebalance: A work to periodically optimize flow table caches. -* @ct_limit_info: A hash table of conntrack zone connection limits. +* @ct_limit_info: Hash table of conntrack zone connection limits. Protected +* by RCU; updates and teardown are serialized by ovs_mutex. May be NULL during +* netns teardown. +* @ct_limit_exit_data: CT limit state detached at .pre_exit, freed at .exit. * @xt_label: Whether connlables are configured for the network or not. */ struct ovs_net {
@@ -165,7 +168,8 @@ struct ovs_net {struct work_struct dp_notify_work;struct delayed_work masks_rebalance;#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -struct ovs_ct_limit_info *ct_limit_info; +struct ovs_ct_limit_info __rcu *ct_limit_info; +struct ovs_ct_limit_info *ct_limit_exit_data;#endif bool xt_label; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 312/1424 landlock: Require LANDLOCK_ACCESS_FS_MAKE_REG for whiteout creation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Günther Noack <[email protected]>
[ Upstream commit 672fa082d48b21e1fb62cdb184fee41513e53421 ]
Whiteout objects are used in the upper layer of an OverlayFS to indicate that the file with this name does not exist in the unified view, even if it is present in one of the lower layer file systems.
For the userspace implementations of OverlayFS (fuse-overlayfs), whiteout objects can be created from userspace as well:
* mknod(2) with S_IFCHR and makedev(0, 0)
* renameat2(2) with RENAME_WHITEOUT,
creating the whiteout in the old place of the moved file.
This commit guards whiteout creation in both of these cases with LANDLOCK_ACCESS_FS_MAKE_REG. Whiteout objects are *not* considered character devices and are not bound to a driver.
LANDLOCK_ACCESS_FS_MAKE_REG describes the same permission class as a whiteout object: creating one is the only S_IFCHR creation that the VFS exempts from CAP_MKNOD, so it is as unprivileged as creating a regular file, while LANDLOCK_ACCESS_FS_MAKE_CHAR and LANDLOCK_ACCESS_FS_MAKE_BLOCK keep meaning the creation of devices that expose a kernel interface [1].
For the mknod(2) case, introduce a Landlock erratum. The creation of whiteout objects through mknod(2) was previously guarded using LANDLOCK_ACCESS_FS_MAKE_CHAR, and it is now guarded using LANDLOCK_ACCESS_FS_MAKE_REG.
For the renameat2(2) case, fix a bug: Before this commit, renameat2(2) with RENAME_WHITEOUT would create a directory entry even when all LANDLOCK_ACCESS_FS_MAKE_* rights were denied.
This does not affect normal renames within layered OverlayFS mounts:
When doing a regular rename() on a mounted fuse-overlayfs, it is the fuse-overlayfs daemon that exercises renameat2() with RENAME_WHITEOUT, and only the Landlock domain of that daemon is checked there.
Depends-on: 49c9e09d9610 ("landlock: Fix handling of disconnected directories")
Depends-on: fe72ce6710cb ("landlock: Add errata documentation section")
[mic: Record why LANDLOCK_ACCESS_FS_MAKE_REG is the matching right, and add link(2) to the user doc]
--- include/uapi/linux/landlock.h | 1 + security/landlock/errata/abi-1.h | 23 ++++++++++++++++++ security/landlock/fs.c | 40 +++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 9 deletions(-)
include/uapi/linux/landlock.h +1 -0
@@ -126,6 +126,7 @@ struct landlock_path_beneath_attr {* device. * - %LANDLOCK_ACCESS_FS_MAKE_DIR: Create (or rename) a directory. * - %LANDLOCK_ACCESS_FS_MAKE_REG: Create (or rename or link) a regular file. +* This also guards the creation of whiteout objects as used in OverlayFS. * - %LANDLOCK_ACCESS_FS_MAKE_SOCK: Create (or rename or link) a UNIX domain * socket. * - %LANDLOCK_ACCESS_FS_MAKE_FIFO: Create (or rename or link) a named pipe.
security/landlock/errata/abi-1.h +23 -0
@@ -14,3 +14,26 @@* actions. */ LANDLOCK_ERRATUM (3 ) + +/** +* DOC: erratum_4 +* +* Erratum 4: Creation of whiteout objects +* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* +* This fix changes the access rights required for the creation of whiteout +* objects through :manpage:`mknod(2)`, :manpage:`renameat2(2)`, or +* :manpage:`link(2)`. Creating whiteout objects is now guarded by +* ``LANDLOCK_ACCESS_FS_MAKE_REG`` instead of ``LANDLOCK_ACCESS_FS_MAKE_CHAR``. +* +* Whiteout objects are used in OverlayFS to mark the absence of a file in an +* upper file system. Despite being created with ``S_IFCHR``, whiteout objects +* do not count as character devices. +* +* Impact: +* +* Sandboxed programs that create OverlayFS whiteouts (such as fuse-overlayfs) +* now require ``LANDLOCK_ACCESS_FS_MAKE_REG`` instead of +* ``LANDLOCK_ACCESS_FS_MAKE_CHAR``. + */ +LANDLOCK_ERRATUM (4 )
security/landlock/fs.c +31 -9
@@ -15,6 +15,7 @@#include <linux/err.h> #include <linux/fs.h> #include <linux/init.h> +#include <linux/kdev_t.h> #include <linux/kernel.h> #include <linux/limits.h> #include <linux/list.h>
@@ -671,7 +672,7 @@ static inline int current_check_access_path(const struct path *const path,return check_access_path (dom, path, access_request); } -static inline access_mask_t get_mode_access (const umode_t mode) +static inline access_mask_t get_mode_access (const umode_t mode,const dev_t dev) {switch (mode &S_IFMT ) {case S_IFLNK :
@@ -679,6 +680,9 @@ static inline access_mask_t get_mode_access(const umode_t mode)case S_IFDIR :return LANDLOCK_ACCESS_FS_MAKE_DIR ;case S_IFCHR : +/* Whiteout objects are guarded with MAKE_REG. */ +if (dev ==WHITEOUT_DEV ) +return LANDLOCK_ACCESS_FS_MAKE_REG ;return LANDLOCK_ACCESS_FS_MAKE_CHAR ;case S_IFBLK :return LANDLOCK_ACCESS_FS_MAKE_BLOCK ;
@@ -695,6 +699,13 @@ static inline access_mask_t get_mode_access(const umode_t mode) } } +static inline access_mask_t get_dentry_access (const struct dentry *const dentry) +{ +const struct inode *const inode =d_backing_inode (dentry); + +return get_mode_access (inode->i_mode, inode->i_rdev); +} +static inline access_mask_t maybe_remove (const struct dentry *const dentry) {if (d_is_negative (dentry))
@@ -782,6 +793,7 @@ static bool collect_domain_accesses(* @new_dentry: Destination file or directory. * @removable: Sets to true if it is a rename operation. * @exchange: Sets to true if it is a rename operation with RENAME_EXCHANGE. +* @whiteout: Sets to true if it is a rename operation with RENAME_WHITEOUT. * * Because of its unprivileged constraints, Landlock relies on file hierarchies * (and not only inodes) to tie access rights to files. Being able to link or
@@ -830,7 +842,8 @@ static bool collect_domain_accesses(static int current_check_refer_path (struct dentry *const old_dentry,const struct path *const new_dir,struct dentry *const new_dentry, -const bool removable,const bool exchange) +const bool removable,const bool exchange, +const bool whiteout) {const struct landlock_ruleset *const dom =landlock_get_current_domain ();
@@ -850,18 +863,25 @@ static int current_check_refer_path(struct dentry *const old_dentry,if (exchange) {if (unlikely (d_is_negative (new_dentry)))return -ENOENT ; - access_request_parent1 = -get_mode_access (d_backing_inode (new_dentry)->i_mode); + access_request_parent1 =get_dentry_access (new_dentry); }else { access_request_parent1 =0 ; } - access_request_parent2 = -get_mode_access (d_backing_inode (old_dentry)->i_mode); + access_request_parent2 =get_dentry_access (old_dentry);if (removable) { access_request_parent1 |=maybe_remove (old_dentry); access_request_parent2 |=maybe_remove (new_dentry); } +/* +* In case of renameat2(2) with RENAME_WHITEOUT, a whiteout object is +* created in the source location, so we require an additional access +* right there. +*/ +if (whiteout) + access_request_parent1 |= +get_mode_access (S_IFCHR |WHITEOUT_MODE ,WHITEOUT_DEV ); +/* The mount points are the same for old and new paths, cf. EXDEV. */ if (old_dentry->d_parent == new_dir->dentry) {/*
@@ -1130,7 +1150,7 @@ static int hook_path_link(struct dentry *const old_dentry, struct dentry *const new_dentry) {return current_check_refer_path (old_dentry, new_dir, new_dentry, false, - false); + false, false); } static int hook_path_rename(const struct path *const old_dir,
@@ -1141,7 +1161,8 @@ static int hook_path_rename(const struct path *const old_dir, {/* old_dir refers to old_dentry->d_parent and new_dir->mnt */ return current_check_refer_path (old_dentry, new_dir, new_dentry, true, - !!(flags &RENAME_EXCHANGE )); + !!(flags &RENAME_EXCHANGE ), + !!(flags &RENAME_WHITEOUT )); } static int hook_path_mkdir(const struct path *const dir,
@@ -1159,7 +1180,8 @@ static int hook_path_mknod(const struct path *const dir,if (!dom)return 0 ; -return check_access_path (dom, dir,get_mode_access (mode)); +return check_access_path (dom, dir, +get_mode_access (mode,new_decode_dev (dev))); } static int hook_path_symlink(const struct path *const dir,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 313/1424 wifi: mt76: mt7996: validate default EEPROM firmware size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
[ Upstream commit 653c6e289b13cc6942f3e8f8e3c568e70fa42d1f ]
The default EEPROM firmware is parsed and copied as a full EEPROM without checking its length. A truncated file can make the driver read beyond the firmware buffer during variant validation or the fallback copy.
Reject files shorter than MT7996_EEPROM_SIZE before parsing or copying the firmware.
--- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +6 -0
@@ -43,6 +43,12 @@ mt7996_eeprom_load_default(struct mt7996_dev *dev) goto out; } +if (fw->size <MT7996_EEPROM_SIZE ) { +dev_err (dev->mt76.dev,"Invalid default bin size\n" ); + ret = -EINVAL ; + goto out; + } +memcpy (eeprom, fw->data,MT7996_EEPROM_SIZE ); dev->flash_mode = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 314/1424 fsnotify: Fix stale object mask after concurrent mark updates
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youngjae Kwon <[email protected]>
[ Upstream commit e422777fdd4746de1109575c51e65038d4c5c1be ]
When a mark gets a new event bit, fanotify and inotify may avoid recalculating the object mask if the cached aggregate already contains that bit. This is racy with a recalculation triggered by a concurrent update to another mark on the same connector.
The concurrent scan can read the mark before the new bit is added, while the updater reads the old aggregate before that scan publishes its result. The updater then skips recalculation and the scan publishes a mask without the bit, leaving the object mask stale after both updates complete.
This can be reproduced with two fanotify groups watching the same inode:
one thread removes FAN_MODIFY from one existing mark while another thread adds FAN_MODIFY to the other mark. After both fanotify_mark() calls return, writes can fail to produce FAN_MODIFY for the group whose mark now contains the bit. This was reproduced on an unmodified v6.12.95 kernel. The equivalent inotify interleaving loses IN_MODIFY events.
For normal fanotify additions, recalculate whenever the raw mark mask changes. The normal mask is not cleared asynchronously, so an unchanged addition cannot introduce missing interest. Always recalculate ignore-mask updates because FS_MODIFY handling may clear the ignore mask without taking mark->lock, making snapshot comparisons unreliable.
Always recalculate after updating an existing inotify watch. Its replace path temporarily sets mark->mask to zero, so a concurrent scan can observe zero even when the old and final masks are equal. Assigning the replacement mask directly would avoid the transient zero, but existing-watch updates are infrequent, so unconditional recalculation is simpler.
[yjkwon0026: Resolve the inotify conflict by retaining the branch-native inode->i_fsnotify_marks argument to fsnotify_recalc_mask(). This tree lacks 35ceae44742e ("fsnotify: Avoid data race between fsnotify_recalc_mask() and fsnotify_object_watched()") and 4520b96b8136 ("fsnotify: inotify: pass mark connector to fsnotify_recalc_mask()"). The differing READ_ONCE() line and connector call are in the conditional deleted by this patch, so neither commit is a prerequisite for this fix.]
--- fs/notify/fanotify/fanotify_user.c | 12 +++++++----- fs/notify/inotify/inotify_user.c | 15 +-------------- 2 files changed, 8 insertions(+), 19 deletions(-)
fs/notify/fanotify/fanotify_user.c +7 -5
@@ -1186,16 +1186,18 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,static bool fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark,__u32 mask,unsigned int fan_flags) { +__u32 old_mask;bool recalc;spin_lock (&fsn_mark->lock); -if (!(fan_flags &FANOTIFY_MARK_IGNORE_BITS )) +if (!(fan_flags &FANOTIFY_MARK_IGNORE_BITS )) { + old_mask = fsn_mark->mask; fsn_mark->mask |= mask; -else + recalc = old_mask != fsn_mark->mask; + }else { fsn_mark->ignore_mask |= mask; - - recalc =fsnotify_calc_mask (fsn_mark) & - ~fsnotify_conn_mask (fsn_mark->connector); + recalc = true; + } recalc |=fanotify_mark_update_flags (fsn_mark, fan_flags);spin_unlock (&fsn_mark->lock);
fs/notify/inotify/inotify_user.c +1 -14
@@ -540,7 +540,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, {struct fsnotify_mark *fsn_mark;struct inotify_inode_mark *i_mark; -__u32 old_mask, new_mask;int replace = !(arg &IN_MASK_ADD );int create = (arg &IN_MASK_CREATE );int ret;
@@ -556,27 +555,15 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);spin_lock (&fsn_mark->lock); - old_mask = fsn_mark->mask;if (replace) { fsn_mark->mask =0 ; fsn_mark->flags &= ~INOTIFY_MARK_FLAGS ; } fsn_mark->mask |=inotify_arg_to_mask (inode, arg); fsn_mark->flags |=inotify_arg_to_flags (arg); - new_mask = fsn_mark->mask;spin_unlock (&fsn_mark->lock); -if (old_mask != new_mask) { -/* more bits in old than in new? */ -int dropped = (old_mask & ~new_mask); -/* more bits in this fsn_mark than the inode's mask? */ -int do_inode = (new_mask & ~inode->i_fsnotify_mask); - -/* update the inode with this new fsn_mark */ -if (dropped || do_inode) -fsnotify_recalc_mask (inode->i_fsnotify_marks); - - } +fsnotify_recalc_mask (inode->i_fsnotify_marks);/* return the wd */ ret = i_mark->wd;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 315/1424 tcp: fix potential race in tcp_v6_syn_recv_sock()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 858d2a4f67ff69e645a43487ef7ea7f28f06deae ]
Code in tcp_v6_syn_recv_sock() after the call to tcp_v4_syn_recv_sock() is done too late.
After tcp_v4_syn_recv_sock(), the child socket is already visible from TCP ehash table and other cpus might use it.
Since newinet->pinet6 is still pointing to the listener ipv6_pinfo bad things can happen as syzbot found.
Move the problematic code in tcp_v6_mapped_child_init() and call this new helper from tcp_v4_syn_recv_sock() before the ehash insertion.
This allows the removal of one tcp_sync_mss(), since tcp_v4_syn_recv_sock() will call it with the correct context.
[florian:
- net/ipv6/tcp_ipv6.c:
- Set newnp->ipv6_fl_list = NULL instead of newinet->ipv6_fl_list = NULL, as ipv6_fl_list is in struct ipv6_pinfo.
- Guarded af_specific assignment with #ifdef CONFIG_TCP_MD5SIG instead of checking CONFIG_TCP_AO.
- Used if (tcp_inet6_sk(sk)->repflow) instead of inet6_test_bit(REPFLOW, sk).
- net/dccp/:
- Updated syn_recv_sock implementations and call sites for DCCP, which was removed in upstream kernels prior to this commit.]
--- include/net/inet_connection_sock.h | 4 +- include/net/tcp.h | 4 +- net/dccp/dccp.h | 4 +- net/dccp/ipv4.c | 4 +- net/dccp/ipv6.c | 7 ++- net/dccp/minisocks.c | 2 +- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp_fastopen.c | 2 +- net/ipv4/tcp_ipv4.c | 8 ++- net/ipv4/tcp_minisocks.c | 2 +- net/ipv6/tcp_ipv6.c | 97 +++++++++++++----------------- net/mptcp/subflow.c | 6 +- net/smc/af_smc.c | 6 +- 13 files changed, 78 insertions(+), 70 deletions(-)
include/net/inet_connection_sock.h +3 -1
@@ -42,7 +42,9 @@ struct inet_connection_sock_af_ops {struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));u16 net_header_len;u16 net_frag_header_len;u16 sockaddr_len;
include/net/tcp.h +3 -1
@@ -461,7 +461,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));int tcp_v4_do_rcv (struct sock *sk,struct sk_buff *skb);int tcp_v4_connect (struct sock *sk,struct sockaddr *uaddr,int addr_len);int tcp_connect (struct sock *sk);
net/dccp/dccp.h +3 -1
@@ -267,7 +267,9 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, struct sk_buff *skstruct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));struct sock *dccp_check_req (struct sock *sk,struct sk_buff *skb,struct request_sock *req);
net/dccp/ipv4.c +3 -1
@@ -409,7 +409,9 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq;struct inet_sock *newinet;
net/dccp/ipv6.c +5 -2
@@ -417,7 +417,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq = inet_rsk(req);struct ipv6_pinfo *newnp;
@@ -432,7 +434,8 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,* v6 mapped */ newsk =dccp_v4_request_recv_sock (sk, skb, req, dst, - req_unhash, own_req); + req_unhash, own_req, + opt_child_init);if (newsk ==NULL )return NULL ;
net/dccp/minisocks.c +1 -1
@@ -193,7 +193,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, goto drop; child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , - req, &own_req); + req, &own_req,NULL );if (child) { child =inet_csk_complete_hashdance (sk, child, req, own_req); goto out;
net/ipv4/syncookies.c +1 -1
@@ -199,7 +199,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,bool own_req; child = icsk->icsk_af_ops->syn_recv_sock (sk, skb, req, dst, -NULL , &own_req); +NULL , &own_req,NULL );if (child) {refcount_set (&req->rsk_refcnt,1 );tcp_sk (child)->tsoffset = tsoff;
net/ipv4/tcp_fastopen.c +1 -1
@@ -247,7 +247,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,bool own_req; child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , -NULL , &own_req); +NULL , &own_req,NULL );if (!child)return NULL ;
net/ipv4/tcp_ipv4.c +7 -1
@@ -1567,7 +1567,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq;bool found_dup_sk = false;
@@ -1623,6 +1625,10 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, }sk_setup_caps (newsk, dst); +#if IS_ENABLED (CONFIG_IPV6 ) +if (opt_child_init) +opt_child_init (newsk, sk); +#endif tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst_mtu (dst));
net/ipv4/tcp_minisocks.c +1 -1
@@ -817,7 +817,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,* socket is created, wait for troubles. */ child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , - req, &own_req); + req, &own_req,NULL );if (!child) goto listen_overflow;
net/ipv6/tcp_ipv6.c +42 -55
113 lines not on this page · raw message
net/mptcp/subflow.c +4 -2
@@ -788,7 +788,9 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);struct mptcp_subflow_request_sock *subflow_req;
@@ -834,7 +836,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, create_child: child = listener->icsk_af_ops->syn_recv_sock (sk, skb, req, dst, - req_unhash, own_req); + req_unhash, own_req, opt_child_init);if (child && *own_req) {struct mptcp_subflow_context *ctx =mptcp_subflow_ctx (child);
net/smc/af_smc.c +4 -2
@@ -119,7 +119,9 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct smc_sock *smc;struct sock *child;
@@ -144,7 +146,7 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,/* passthrough to original syn recv sock fct */ child = smc->ori_af_ops->syn_recv_sock (sk, skb, req, dst, req_unhash, - own_req); + own_req, opt_child_init);/* child must not inherit smc or its ops */ if (child) {rcu_assign_sk_user_data (child,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 316/1424 entry: Fix seccomp bypass after ptrace with TSYNC
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjie Ruan <[email protected]>
commit 4a3591287fb7f808e209b4974ed337f609a2006b upstream.
Sashiko review pointed out the following issue.
If a thread is stopped in syscall_trace_enter() for ptrace, another thread can install a seccomp filter with SECCOMP_FILTER_FLAG_TSYNC (e.g., via seccomp_attach_filter()). This will successfully set SYSCALL_WORK_SECCOMP on the stopped thread, but syscall_trace_enter() evaluates a cached 'work' variable sampled on entry. Consequently, the subsequent check for SYSCALL_WORK_SECCOMP misses the newly assigned flag, and the filter is silently bypassed.
This race condition could allow an unprivileged process to execute a prohibited system call (e.g., execve) that the newly installed filter was intended to block, especially since the tracer might have modified the system call number during the ptrace stop.
Fix this by re-reading the syscall_work flags after ptrace handling, so that any new SYSCALL_WORK_SECCOMP flag set by another thread via TSYNC during the ptrace stop is observed before the subsequent seccomp check.
--- kernel/entry/common.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/entry/common.c +3 -0
@@ -65,6 +65,9 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall, ret =ptrace_report_syscall_entry (regs);if (ret || (work &SYSCALL_WORK_SYSCALL_EMU ))return -1L ; + +/* ptrace might have changed work flags */ + work =READ_ONCE (current_thread_info ()->syscall_work); }/* Do seccomp after ptrace, to catch any tracer changes. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 317/1424 net: ntb_netdev: Fix TX busy and drop handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 8aaa47351db0f93a5c5297fbafdfa8bc75e8ae49 ]
Currently, ntb_netdev returns NETDEV_TX_BUSY for every enqueue error. It also increments the drop and error counters while leaving the skb owned by the qdisc, and may return BUSY with the subqueue still awake. Retrying a permanent error cannot succeed either.
The unconditional BUSY return and premature accounting date back to the initial driver. The error-path queue stop was later removed without changing that return value. The current flow-control code includes a resource check, but ntb_netdev does not honor its result before enqueue.
Honor the resource check before enqueue. For -EAGAIN and -EBUSY, stop the subqueue, arm the existing reaper timer, and return BUSY without touching the skb. For other errors, free the skb, increment tx_dropped, and return NETDEV_TX_OK.
[den: adapt to the single-queue implementation, as 6.6.y lacks commit:
ee970634c777 ("net: ntb_netdev: Introduce per-queue context")]
Stable-dep-of: 873ce713fef5 ("NTB: ntb_transport: Fail TX enqueue when the QP link is down")
Stable-dep-of: a4f2387db6f1 ("NTB: ntb_transport: Reject oversized TX buffers")
--- drivers/net/ntb_netdev.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
drivers/net/ntb_netdev.c +19 -8
@@ -164,8 +164,10 @@ static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,static int ntb_netdev_maybe_stop_tx (struct net_device *ndev,struct ntb_transport_qp *qp,int size) { -if (netif_queue_stopped (ndev) || - (ntb_transport_tx_free_entry (qp) >= size)) +if (netif_queue_stopped (ndev)) +return -EBUSY ; + +if (ntb_transport_tx_free_entry (qp) >= size)return 0 ;return __ntb_netdev_maybe_stop_tx (ndev, qp, size);
@@ -208,21 +210,30 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,struct ntb_netdev *dev =netdev_priv (ndev);int rc; -ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop); +if (unlikely (ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop))) +return NETDEV_TX_BUSY ; rc =ntb_transport_tx_enqueue (dev->qp, skb, skb->data, skb->len); -if (rc) - goto err; +if (rc) { +if (rc == -EAGAIN || rc == -EBUSY ) { +netif_stop_queue (ndev); +mod_timer (&dev->tx_timer, + jiffies +usecs_to_jiffies (tx_time)); +return NETDEV_TX_BUSY ; + } + + goto drop; + }/* check for next submit */ ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop);return NETDEV_TX_OK ; -err: +drop: +dev_kfree_skb_any (skb); ndev->stats.tx_dropped++; - ndev->stats.tx_errors++; -return NETDEV_TX_BUSY ; +return NETDEV_TX_OK ; }static void ntb_netdev_tx_timer (struct timer_list *t)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 318/1424 tracing/mmiotrace: Remove reference to unused per CPU data pointer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit 6936298393d8d8bc3cec6b704f6a774162cf9bd3 upstream.
The mmiotracer referenced the per CPU array_buffer->data descriptor but never actually used it. Remove the references to it.
--- kernel/trace/trace_mmiotrace.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-)
kernel/trace/trace_mmiotrace.c +2 -10
@@ -292,7 +292,6 @@ __init static int init_mmio_trace(void)device_initcall (init_mmio_trace);static void __trace_mmiotrace_rw (struct trace_array *tr, -struct trace_array_cpu *data,struct mmiotrace_rw *rw) {struct trace_event_call *call = &event_mmiotrace_rw;
@@ -318,12 +317,10 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,void mmio_trace_rw (struct mmiotrace_rw *rw) {struct trace_array *tr = mmio_trace_array; -struct trace_array_cpu *data =per_cpu_ptr (tr->array_buffer.data,smp_processor_id ()); -__trace_mmiotrace_rw (tr, data, rw); +__trace_mmiotrace_rw (tr, rw); }static void __trace_mmiotrace_map (struct trace_array *tr, -struct trace_array_cpu *data,struct mmiotrace_map *map) {struct trace_event_call *call = &event_mmiotrace_map;
@@ -349,12 +346,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,void mmio_trace_mapping (struct mmiotrace_map *map) {struct trace_array *tr = mmio_trace_array; -struct trace_array_cpu *data; - -preempt_disable (); - data =per_cpu_ptr (tr->array_buffer.data,smp_processor_id ()); -__trace_mmiotrace_map (tr, data, map); -preempt_enable (); +__trace_mmiotrace_map (tr, map); }int mmio_trace_printk (const char *fmt,va_list args)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 319/1424 tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 12b80cdbc54cf615b4717a4e8180063408091ea2 upstream.
mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.
Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().
--- kernel/trace/trace_mmiotrace.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +10 -2
@@ -295,11 +295,15 @@ static void __trace_mmiotrace_rw(struct trace_array *tr, struct mmiotrace_rw *rw) {struct trace_event_call *call = &event_mmiotrace_rw; -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_rw *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_RW ,sizeof (*entry), trace_ctx);
@@ -324,11 +328,15 @@ static void __trace_mmiotrace_map(struct trace_array *tr, struct mmiotrace_map *map) {struct trace_event_call *call = &event_mmiotrace_map; -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_map *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_MAP ,sizeof (*entry), trace_ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 320/1424 scsi: core: Fill in DMA padding bytes in scsi_alloc_sgtables()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Vaganov <[email protected]>
commit 626147717bea776b61ed3631d2c26283760c4cc4 upstream.
During fuzz testing, the following issue was discovered:
BUG: KMSAN: uninit-value in __dma_map_sg_attrs+0x217/0x310 __dma_map_sg_attrs+0x217/0x310 dma_map_sg_attrs+0x4a/0x70 ata_qc_issue+0x9f8/0x1420 __ata_scsi_queuecmd+0x1657/0x1740 ata_scsi_queuecmd+0x79a/0x920 scsi_queue_rq+0x4472/0x4f40 blk_mq_dispatch_rq_list+0x1cca/0x3ee0 __blk_mq_sched_dispatch_requests+0x458/0x630 blk_mq_sched_dispatch_requests+0x15b/0x340 __blk_mq_run_hw_queue+0xe5/0x250 __blk_mq_delay_run_hw_queue+0x138/0x780 blk_mq_run_hw_queue+0x4bb/0x7e0 blk_mq_sched_insert_request+0x2a7/0x4c0 blk_execute_rq+0x497/0x8a0 sg_io+0xbe0/0xe20 scsi_ioctl+0x2b36/0x3c60 sr_block_ioctl+0x319/0x440 blkdev_ioctl+0x80f/0xd70 __se_sys_ioctl+0x219/0x420 __x64_sys_ioctl+0x93/0xe0 x64_sys_call+0x1d6c/0x3ad0 do_syscall_64+0x4c/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
Uninit was created at:
__alloc_pages+0x5c0/0xc80 alloc_pages+0xe0e/0x1050 blk_rq_map_user_iov+0x2b77/0x6100 blk_rq_map_user_io+0x2fa/0x4d0 sg_io+0xad6/0xe20 scsi_ioctl+0x2b36/0x3c60 sr_block_ioctl+0x319/0x440 blkdev_ioctl+0x80f/0xd70 __se_sys_ioctl+0x219/0x420 __x64_sys_ioctl+0x93/0xe0 x64_sys_call+0x1d6c/0x3ad0 do_syscall_64+0x4c/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
Bytes 14-15 of 16 are uninitialized
Memory access of size 16 starts at ffff88800cbdb000
When processing the last unaligned element of the scatterlist, it is supplemented with missing bytes in the amount of pad_len. These bytes remain uninitialized, which leads to a problem.
Extend last_sg->length by pad_len first, then use sg_zero_buffer() to zero those pad_len bytes. sg_zero_buffer() uses sg_miter internally, which correctly handles sg entries spanning multiple pages and padding that crosses a page boundary.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- drivers/scsi/scsi_lib.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/scsi_lib.c +2 -0
@@ -1087,8 +1087,10 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd)if (blk_rq_bytes (rq) & rq->q->dma_pad_mask) {unsigned int pad_len = (rq->q->dma_pad_mask & ~blk_rq_bytes (rq)) +1 ; +unsigned int data_len = last_sg->length; last_sg->length += pad_len; +sg_zero_buffer (last_sg,1 , pad_len, data_len); cmd->extra_len += pad_len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 321/1424 drm/amd/display: fix division by zero in get_estimated_bw()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hari Mishal <[email protected]>
commit f63de9054da858d57054474c32464106f8375e0d upstream.
get_estimated_bw() divides by link->dpia_bw_alloc_config.bw_granularity, which is zeroed by reset_bw_alloc_struct() and only populated once DP_TUNNELING_BW_ALLOC_CAP_CHANGED has been handled.
link_dp_dpia_handle_bw_alloc_status(), the DPCD interrupt handler, calls get_estimated_bw() whenever DP_TUNNELING_ESTIMATED_BW_CHANGED is set, independently of whether DP_TUNNELING_BW_ALLOC_CAP_CHANGED has ever fired for that link. A connected USB4/DPIA tunneling device that reports an estimated-bandwidth change before ever reporting a capability change drives a division by zero in this IRQ path.
link_dpia_send_bw_alloc_request() already guards the same bw_granularity division; add the identical guard here rather than introducing a new pattern.
--- drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +5 -0
@@ -102,6 +102,11 @@ static int get_estimated_bw(struct dc_li {uint8_t bw_estimated_bw =0 ; +if (link->dpia_bw_alloc_config.bw_granularity ==0 ) { +DC_LOG_ERROR ("%s: BW granularity is zero!\n" , __func__); +return 0 ; + } + core_link_read_dpcd( link, ESTIMATED_BW,
Greg Kroah-Hartman
maintainerPATCH 322/1424 usb: image: mdc800: change kmalloc() to kzalloc()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit 2430eb81e44111b30eeb5273bbcf8b24ca517ef9 upstream.
Change the kmalloc() calls in usb_mdc800_init() for irq_urb_buffer and download_urb_buffer to kzalloc(), avoiding potential stack leaks if a shorter message is received in mdc800_usb_irq() and mdc800_usb_download_notify()
--- drivers/usb/image/mdc800.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/image/mdc800.c +2 -2
@@ -1001,13 +1001,13 @@ static int __init usb_mdc800_init (void) mdc800->downloaded =0 ; mdc800->written =0 ; - mdc800->irq_urb_buffer=kmalloc (8 ,GFP_KERNEL ); + mdc800->irq_urb_buffer=kzalloc (8 ,GFP_KERNEL );if (!mdc800->irq_urb_buffer) goto cleanup_on_fail; mdc800->write_urb_buffer=kmalloc (8 ,GFP_KERNEL );if (!mdc800->write_urb_buffer) goto cleanup_on_fail; - mdc800->download_urb_buffer=kmalloc (64 ,GFP_KERNEL ); + mdc800->download_urb_buffer=kzalloc (64 ,GFP_KERNEL );if (!mdc800->download_urb_buffer) goto cleanup_on_fail;
Greg Kroah-Hartman
maintainerPATCH 323/1424 ALSA: usb-audio: fix OOB write in snd_usbmidi_us122l_output()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit e4637ce34607f1733a34a57294966d26b263e626 upstream.
The snd_usbmidi_us122l_output() picks a count of 2 on anything slower than high speed and never relates it to ep->max_transfer. The URB buffer holds exactly max_transfer bytes, so a device declaring a one byte bulk endpoint takes two bytes from snd_rawmidi_transmit(), and the memset that pads the rest computes 1 - 2 in int and wraps to SIZE_MAX.
Only 0x800e and 0x800f are pinned to nine bytes. The US-122MKII at 0x0644:0x8021 falls to the default and takes usb_maxpacket(), which the USB core only clamps downward.
The akai and novation output ops in this file were given the same guard recently. Do the same here.
--- sound/usb/midi.c | 2 ++ 1 file changed, 2 insertions(+)
sound/usb/midi.c +2 -0
@@ -974,6 +974,8 @@ static void snd_usbmidi_us122l_output(stdefault : count =2 ; } +if (ep->max_transfer < count) +return ; count =snd_rawmidi_transmit (ep->ports[0 ].substream, urb->transfer_buffer, count);
Greg Kroah-Hartman
maintainerPATCH 324/1424 clk: qcom: gcc-mdm9607: Increase delay for USB PHY reset
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit c99bc8e83848358bd4a0436e4bdae5b7919babb2 upstream.
To conform to the specifications of the USB PHY, the reset signal should be asserted for at least 10us. Guarantee that by increasing the delay for the USB2_HS_PHY_ONLY_BCR reset control similar to commit dcc6c9fb7128 ("clk:
qcom: gcc-msm8909: Increase delay for USB PHY reset").
--- drivers/clk/qcom/gcc-mdm9607.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -1
@@ -1567,7 +1567,7 @@ static const struct qcom_reset_map gcc_m [USB_HS_HSIC_BCR] = { 0x3d05c }, [GCC_MSS_RESTART] = { 0x3e000 }, [USB_HS_BCR] = { 0x41000 }, - [USB2_HS_PHY_ONLY_BCR] = { 0x41034 }, + [USB2_HS_PHY_ONLY_BCR] = { .reg = 0x41034, .udelay = 15 }, [QUSB2_PHY_BCR] = { 0x4103c }, };
Greg Kroah-Hartman
maintainerPATCH 325/1424 media: usbtv: keep device alive while ALSA card exists
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit fc530fe168bb2b745a93f553ad21fc25fd9cba3d upstream.
The ALSA PCM callbacks store the driver state in pcm->private_data. An open PCM file can outlive USB disconnect because usbtv_audio_free() uses snd_card_free_when_closed(). The disconnect path can then drop the V4L2 device reference and free struct usbtv before ALSA releases the substream, so a later close dereferences freed memory in snd_usbtv_pcm_close().
Take a V4L2 device reference for the ALSA card and drop it from the card private_free callback. This keeps struct usbtv valid until ALSA has closed the remaining files and freed the card.
--- drivers/media/usb/usbtv/usbtv-audio.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/media/usb/usbtv/usbtv-audio.c +11 -0
@@ -317,6 +317,13 @@ static const struct snd_pcm_ops snd_usbt .pointer = snd_usbtv_pointer, }; +static void usbtv_audio_card_free (struct snd_card *card) +{ +struct usbtv *usbtv = card->private_data; + +v4l2_device_put (&usbtv->v4l2_dev); +} +int usbtv_audio_init (struct usbtv *usbtv) {int rv;
@@ -331,6 +338,10 @@ int usbtv_audio_init(struct usbtv *usbtvif (rv <0 )return rv; +v4l2_device_get (&usbtv->v4l2_dev); + card->private_data = usbtv; + card->private_free = usbtv_audio_card_free; +strscpy (card->driver, usbtv->dev->driver->name,sizeof (card->driver));strscpy (card->shortname,"usbtv" ,sizeof (card->shortname)); snprintf(card->longname, sizeof(card->longname),
Greg Kroah-Hartman
maintainerPATCH 326/1424 usb-storage: ene_ub6250: fix race between scan work and probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liu Qi <[email protected]>
commit 445fc368c6bc73eff0aeb3818cf5f355facfbb16 upstream.
ene_ub6250_probe() calls usb_stor_probe2(), which starts the usb-storage infrastructure and schedules the delayed scan work. The driver then calls ene_get_card_type(), which sends an ENE command through ene_send_scsi_cmd() and the usb-storage bulk transfer helpers.
Both the delayed scan work, through usb_stor_Bulk_max_lun(), and ene_get_card_type() use us->current_urb. The scan work serializes this access with us->dev_mutex, but the ENE card-type probe does not. If the scan work runs while ene_get_card_type() is still using us->current_urb, usb_submit_urb() warns that the URB is already active.
Serialize ene_get_card_type() with us->dev_mutex, matching the locking used by the scan path.
--- drivers/usb/storage/ene_ub6250.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/storage/ene_ub6250.c +2 -0
@@ -2358,7 +2358,9 @@ static int ene_ub6250_probe(struct usb_ireturn result;/* probe card type */ +mutex_lock (&us->dev_mutex); result =ene_get_card_type (us,REG_CARD_STATUS , info->bbuf); +mutex_unlock (&us->dev_mutex);if (result !=USB_STOR_XFER_GOOD ) {usb_stor_disconnect (intf);return USB_STOR_TRANSPORT_ERROR ;
Greg Kroah-Hartman
maintainerPATCH 327/1424 usb: f_mass_storage: Bump local buffer size in fsg_common_create_luns()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit 9f6f095beec82a80daa666a3b2186a5b95841e9a upstream.
GCC (Debian 14.2.0-19) is not happy about the buffer size:
drivers/usb/gadget/function/f_mass_storage.c:2970:48: error: ‘%d’ directive output may be truncated writing between 1 and 9 bytes into a region of size 5 [-Werror=format-truncation=]
Bump the size to get it enough for all possible values.
Note, although cfg->nluns is limited to FSG_MAX_LUNS (16), the compiler doesn't realize this and complains about the buffer size.
Also note, the existing comment is wrong as size 8 for the whole buffer doesn't cover 100 mil numbers, hence drop it altogether.
--- drivers/usb/gadget/function/f_mass_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_mass_storage.c +1 -1
@@ -2961,7 +2961,7 @@ EXPORT_SYMBOL_GPL(fsg_common_create_lun)int fsg_common_create_luns (struct fsg_common *common,struct fsg_config *cfg) { -char buf[8 ];/* enough for 100000000 different numbers, decimal */ +char buf[14 ];int i, rc;fsg_common_remove_luns (common);
Greg Kroah-Hartman
maintainerPATCH 328/1424 usb: typec: qcom-pmic: cancel reset_work on stop
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 7b0df6efd143f8085bdb68778a013a46f1349913 upstream.
pdphy_stop() disables IRQs but leaves reset_work pending. If the IRQ handler schedules it just before disable_irq(), the work runs after remove() frees the struct via devm.
Call cancel_work_sync() after disabling IRQs to close the window.
This issue was found by an in-house static analysis tool.
--- drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c +2 -0
@@ -464,6 +464,8 @@ void qcom_pmic_typec_pdphy_stop(struct pfor (i =0 ; i < pmic_typec_pdphy->nr_irqs; i++)disable_irq (pmic_typec_pdphy->irq_data[i].irq); +cancel_work_sync (&pmic_typec_pdphy->reset_work); +qcom_pmic_typec_pdphy_reset_on (pmic_typec_pdphy);regulator_disable (pmic_typec_pdphy->vdd_pdphy);
Greg Kroah-Hartman
maintainerPATCH 329/1424 usb: typec: ucsi: displayport: Fix OOB altmode array index
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jameson Thies <[email protected]>
commit 04cec690b1fd9d1c4c314b91a10d8c68a3acfe18 upstream.
The UCSI displayport driver indexes the connector's port altmode array with the GET_CURRENT_CAM response after checking it is not 0xff. The port altmode array is UCSI_MAX_ALTMODES elements long. If the PPM returns an invalid GET_CURRENT_CAM response above UCSI_MAX_ALTMODES and not equal to 0xff, the kernel may crash with an array index OOB error.
Update the UCSI displayport driver to verify the current cam is less than UCSI_MAX_ALTMODES before accessing the port altmode array.
--- drivers/usb/typec/ucsi/displayport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/ucsi/displayport.c +1 -1
@@ -74,7 +74,7 @@ static int ucsi_displayport_enter(struct cur =0xff ; } -if (cur !=0xff ) { +if (cur <UCSI_MAX_ALTMODES ) { ret = dp->con->port_altmode[cur] == alt ?0 : -EBUSY ; goto err_unlock; }
Greg Kroah-Hartman
maintainerPATCH 330/1424 usb: gadget: midi2: Fix null-pointer dereference in f_midi2_free_ep_reqs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
commit f0efaf1872949e96d213c8e910fd9517f7d7c406 upstream.
A null-pointer dereference occurs in f_midi2_free_ep_reqs() when attempting to clean up an endpoint that was never initialized.
When configuring the MIDI 2.0 gadget via configfs and setting the block direction to SNDRV_UMP_DIR_INPUT, the initialization of the midi1_ep_out endpoint is explicitly skipped during the gadget bind phase (f_midi2_bind()). As a result, the usb_ep->card field remains NULL.
Later, when the host sets the alternate setting, f_midi2_set_alt() unconditionally stops both the IN and OUT endpoints by calling f_midi2_stop_eps(), which in turn calls f_midi2_free_ep_reqs() for both endpoints. When f_midi2_free_ep_reqs() is called for the uninitialized midi1_ep_out, it attempts to dereference usb_ep->card to determine the number of requests to free, leading to a crash.
Fix this by using usb_ep->num_reqs instead of usb_ep->card->info.num_reqs in f_midi2_free_ep_reqs(). usb_ep->num_reqs is correctly set during f_midi2_init_ep() and remains 0 if the endpoint was never initialized, safely avoiding the loop. For consistency, apply the same change to f_midi2_alloc_ep_reqs().
Oops: general protection fault, probably for non-canonical address 0xdffffc00000000ee: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000770-0x0000000000000777] ... RIP: 0010:f_midi2_free_ep_reqs drivers/usb/gadget/function/f_midi2.c:1166 [inline] RIP: 0010:f_midi2_stop_eps+0x28e/0x4d0 drivers/usb/gadget/function/f_midi2.c:1246 ... Call Trace: <TASK> f_midi2_set_alt+0x11c/0xf00 drivers/usb/gadget/function/f_midi2.c:1296 composite_setup+0x1ffd/0x3480 drivers/usb/gadget/composite.c:1933 configfs_composite_setup+0xbd/0x100 drivers/usb/gadget/configfs.c:1877
--- drivers/usb/gadget/function/f_midi2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/usb/gadget/function/f_midi2.c +2 -3
@@ -1145,7 +1145,7 @@ static int f_midi2_alloc_ep_reqs(struct f_midi2_usb_ep *usb_ep)if (!usb_ep->reqs)return -EINVAL ; -for (i =0 ; i < midi2->info.num_reqs; i++) { +for (i =0 ; i < usb_ep->num_reqs; i++) {if (usb_ep->reqs[i].req)continue ; usb_ep->reqs[i].req = alloc_ep_req(usb_ep->usb_ep,
@@ -1160,10 +1160,9 @@ static int f_midi2_alloc_ep_reqs(struct f_midi2_usb_ep *usb_ep)/* Free allocated requests */ static void f_midi2_free_ep_reqs (struct f_midi2_usb_ep *usb_ep) { -struct f_midi2 *midi2 = usb_ep->card;int i; -for (i =0 ; i < midi2->info.num_reqs; i++) { +for (i =0 ; i < usb_ep->num_reqs; i++) {if (!usb_ep->reqs[i].req)continue ;free_ep_req (usb_ep->usb_ep, usb_ep->reqs[i].req);
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 331/1424 usb: gadget: f_midi2: fix use-after-free in string attribute show path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivy Lopez <[email protected]>
commit fed0aa7c6eaedc6c0d4e362fc91724aa47be4a7b upstream.
f_midi2_opts_str_show() takes the string lock internally, but its callers dereference the opts->info.<field> pointer before calling it, outside the lock. This races with f_midi2_opts_str_store(), which frees the old string under opts->lock when the attribute is written concurrently, the show path can read a pointer that gets freed before the lock inside str_show() is even taken.
Change f_midi2_opts_str_show() to take a pointer to the string field, matching the existing pattern in f_midi2_opts_str_store(), and dereference it only after the lock is held. Update all three callers (iface_name, block name, and the EP string option macro) accordingly.
--- drivers/usb/gadget/function/f_midi2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/usb/gadget/function/f_midi2.c +6 -6
@@ -2180,13 +2180,13 @@ end:/* generic show/store for string */ static ssize_t f_midi2_opts_str_show (struct f_midi2_opts *opts, -const char *str,char *page) +const char **strp,char *page) {int result =0 ;mutex_lock (&opts->lock); -if (str) - result =scnprintf (page,PAGE_SIZE ,"%s\n" , str); +if (*strp) + result =scnprintf (page,PAGE_SIZE ,"%s\n" , *strp);mutex_unlock (&opts->lock);return result; }
@@ -2280,7 +2280,7 @@ static ssize_t f_midi2_block_opts_name_s {struct f_midi2_block_opts *opts =to_f_midi2_block_opts (item); -return f_midi2_opts_str_show (opts->ep->opts, opts->info.name, page); +return f_midi2_opts_str_show (opts->ep->opts, &opts->info.name, page); } static ssize_t f_midi2_block_opts_name_store(struct config_item *item,
@@ -2437,7 +2437,7 @@ static ssize_t f_midi2_ep_opts_##name##_ char *page) \ { \struct f_midi2_ep_opts *opts =to_f_midi2_ep_opts (item); \ -return f_midi2_opts_str_show (opts->opts, opts->info.name, page);\ +return f_midi2_opts_str_show (opts->opts, &opts->info.name, page);\ } \ \ static ssize_t f_midi2_ep_opts_##name##_store(struct config_item *item, \
@@ -2592,7 +2592,7 @@ static ssize_t f_midi2_opts_iface_name_s {struct f_midi2_opts *opts =to_f_midi2_opts (item); -return f_midi2_opts_str_show (opts, opts->info.iface_name, page); +return f_midi2_opts_str_show (opts, &opts->info.iface_name, page); } static ssize_t f_midi2_opts_iface_name_store(struct config_item *item,
Greg Kroah-Hartman
maintainerPATCH 332/1424 USB: gadget: fix NULL pointer dereference in gadget_dev_ioctl()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lovekesh Solanki <[email protected]>
commit dd0eed9e165b1a6292f49e622e3dd0b7d99b106d upstream.
gadget_dev_ioctl() reads dev->gadget before acquiring dev->lock, but dev->state is checked after acquiring the lock. Therefore a concurrent bind can change the device state between these operations, which can leave ioctl with a stale NULL gadget pointer and causing a NULL pointer dereference at gadget->ops->ioctl.
Read dev->gadget while holding dev->lock so that the gadget pointer and device state are sampled consistently.
--- drivers/usb/gadget/legacy/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/gadget/legacy/inode.c +2 -1
@@ -1247,10 +1247,11 @@ out:static long gadget_dev_ioctl (struct file *fd,unsigned code,unsigned long value) {struct dev_data *dev = fd->private_data; -struct usb_gadget *gadget = dev->gadget; +struct usb_gadget *gadget;long ret = -ENOTTY ;spin_lock_irq (&dev->lock); + gadget = dev->gadget;if (dev->state ==STATE_DEV_OPENED || dev->state ==STATE_DEV_UNBOUND ) {/* Not bound to a UDC */
Greg Kroah-Hartman
maintainerPATCH 333/1424 usb: gadget: fix null pointer dereference in usb_put_function_instance()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeffin Philip <[email protected]>
commit 6e74ac5c596fd246e37eadfc354567179ccbe9aa upstream.
usb_put_function_instance() attempts to dereference fd inside fi struct to get mod in uvc_alloc_inst() error path. However, fd is not allocated until later in try_get_usb_function_instance() after allocating fi in uvc_alloc_inst() and thus guranteed to be null in error path. Fix this by adding a null check for fi->fd that returns if fd is null.
--- drivers/usb/gadget/functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/functions.c +1 -1
@@ -70,7 +70,7 @@ void usb_put_function_instance(struct us {struct module *mod; -if (!fi) +if (!fi || !fi->fd)return ; mod = fi->fd->mod;
Greg Kroah-Hartman
maintainerPATCH 334/1424 staging: rtl8723bs: fix OOB read / stack overflow in rtw_get_wps_attr()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit 99aa998dec83ba180822f70e6d48a514fc81c20d upstream.
rtw_get_wps_attr() walks WPS attributes inside a WPS IE taken from a wireless management frame. For each candidate attribute it only checks that the fixed 4-byte attribute header (2-byte ID + 2-byte length) fits inside the IE:
if (attr_ptr + 4 > wps_ie + wps_ielen) break; u16 attr_id = get_unaligned_be16(attr_ptr); u16 attr_data_len = get_unaligned_be16(attr_ptr + 2); u16 attr_len = attr_data_len + 4;
attr_data_len (and therefore attr_len) is read directly from the wire and is never checked against the remaining bytes in the IE before being used as the size of:
memcpy(buf_attr, attr_ptr, attr_len);
Since attr_len is fully attacker controlled (0 to 65535+4), this is both a heap OOB read of wps_ie, and, more seriously, a stack buffer overflow at several call sites where buf_attr is a single-byte stack variable, e.g. rtw_get_wps_attr_content()'s callers passing WPS_ATTR_SELECTED_REGISTRAR into a stack "u8 sr"/"u8 selected_registrar" (drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c, drivers/staging/rtl8723bs/core/rtw_mlme_ext.c). A crafted WPS IE in a beacon or probe response processed during scanning can therefore smash the stack of the parsing thread.
rtw_get_wps_attr_content() itself has no independent length check and simply trusts the attr_len it gets back from rtw_get_wps_attr(), so fixing the bound here also fixes that caller.
The "attr_ptr + 4 > wps_ie + wps_ielen" header check above was added by commit 1463ca3ec6601 ("staging: rtl8723bs: fix OOB reads in rtw_get_sec_ie(), rtw_get_wapi_ie(), and rtw_get_wps_attr()"), which bounded the fixed header but never extended the check to cover the variable-length attribute data that follows it. Add that missing check before attr_len is used as a memcpy() length or accepted as a match.
--- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +4 -0
@@ -745,6 +745,10 @@ u8 *rtw_get_wps_attr(u8 *wps_ie, uint wpu16 attr_data_len =get_unaligned_be16 (attr_ptr +2 );u16 attr_len = attr_data_len +4 ; +/* Reject attributes whose claimed length runs past the IE */ +if (attr_ptr + attr_len > wps_ie + wps_ielen) +break ; +if (attr_id == target_attr_id) { target_attr_ptr = attr_ptr;
Greg Kroah-Hartman
maintainerPATCH 335/1424 staging: rtl8723bs: fix OOB read in rtw_action_frame_parse()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit ff917923f4fb9c83717ba135ee47d7e4c1567bb7 upstream.
rtw_action_frame_parse() takes a frame_len parameter but never actually checks it before indexing into the frame body:
const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ... c = frame_body[0]; ... a = frame_body[1];
frame_body already points 24 bytes (sizeof(struct ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and frame_body[1] requires frame_len >= 26. A management action frame shorter than that (e.g. exactly 24 bytes, the minimum a malicious peer can send) causes a 1-2 byte out-of-bounds read.
This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass attacker/user-influenced frame buffers and lengths straight through.
Add the missing length check before frame_body is dereferenced.
--- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +3 -0
@@ -1152,6 +1152,9 @@ int rtw_action_frame_parse(const u8 *frau8 c;u8 a =ACT_PUBLIC_MAX ; +if (frame_len <sizeof (struct ieee80211_hdr_3addr ) +2 ) +return false; + fc =le16_to_cpu (((struct ieee80211_hdr_3addr *)frame)->frame_control); if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE))
Greg Kroah-Hartman
maintainerPATCH 336/1424 thermal/drivers/imx: Disable clock on runtime resume failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit bcc6d886e5006a4656901d2d7fb6a215c96068a0 upstream.
imx_thermal_runtime_resume() enables the thermal clock before powering up the sensor and enabling measurements.
If either regmap_write() fails, the function returns with the clock still enabled. This leaves the clock enable count unbalanced after a failed runtime resume.
Disable the clock on those failure paths before returning the error.
--- drivers/thermal/imx_thermal.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/thermal/imx_thermal.c +7 -2
@@ -851,12 +851,12 @@ static int __maybe_unused imx_thermal_ru ret =regmap_write (map, socdata->sensor_ctrl +REG_CLR , socdata->power_down_mask);if (ret) -return ret; + goto disable_clk; ret =regmap_write (map, socdata->sensor_ctrl +REG_SET , socdata->measure_temp_mask);if (ret) -return ret; + goto disable_clk;/* * According to the temp sensor designers, it may require up to ~17us
@@ -865,6 +865,11 @@ static int __maybe_unused imx_thermal_ruusleep_range (20 ,50 );return 0 ; + +disable_clk: +clk_disable_unprepare (data->thermal_clk); + +return ret; }static const struct dev_pm_ops imx_thermal_pm_ops = {
Greg Kroah-Hartman
maintainerPATCH 337/1424 thermal/drivers/qoriq: Disable clock on resume failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit fcbf9964b67a6d6704c50ed28daa24c3b164f01c upstream.
qoriq_tmu_resume() enables the TMU clock before clearing the power-down bit and enabling monitoring.
If either register update fails, the function returns with the clock still enabled. This leaves the clock enable count unbalanced after a failed resume.
Disable the clock on those failure paths before returning the error.
--- drivers/thermal/qoriq_thermal.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/thermal/qoriq_thermal.c +11 -2
@@ -380,11 +380,20 @@ static int __maybe_unused qoriq_tmu_resuif (data->ver >TMU_VER1 ) { ret =regmap_clear_bits (data->regmap,REGS_TMR ,TMR_CMD );if (ret) -return ret; + goto disable_clk; }/* Enable monitoring */ -return regmap_update_bits (data->regmap,REGS_TMR ,TMR_ME ,TMR_ME ); + ret =regmap_update_bits (data->regmap,REGS_TMR ,TMR_ME ,TMR_ME ); +if (ret) + goto disable_clk; + +return 0 ; + +disable_clk: +clk_disable_unprepare (data->clk); + +return ret; } static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
Greg Kroah-Hartman
maintainerPATCH 338/1424 ublk: clear VM_MAYWRITE on read-only ublk char device mmap
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kanishka De Silva <[email protected]>
commit 6e2b571b0a54755b06e092501913e1dfefe75d6c upstream.
ublk_ch_mmap() rejects mmap requests with VM_WRITE set, but never clears VM_MAYWRITE on the resulting read-only mapping. This allows a userspace daemon to mmap the per-queue command buffer PROT_READ, then upgrade it to PROT_WRITE via mprotect(), since VM_MAYWRITE was never cleared.
The command buffer holds struct ublksrv_io_desc entries that are kernel-written ABI; a writable mapping lets an unprivileged daemon process corrupt fields such as addr, op_flags, nr_sectors, and start_sector.
Same bug class as the drm/panthor and drm/vc4 VM_MAYWRITE fixes, and the 2026-08-13 ptp/vmclock fix (a5edadbae57e).
Verified via mprotect() PoC: before the fix, a PROT_READ mapping can be upgraded to PROT_READ|PROT_WRITE and a write into the command buffer corrupts io_desc fields (confirmed under KASAN). After the fix, mprotect() returns -EACCES.
--- drivers/block/ublk_drv.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/block/ublk_drv.c +6 -0
@@ -1437,6 +1437,12 @@ static int ublk_ch_mmap(struct file *filif (vma->vm_flags &VM_WRITE )return -EPERM ; +/* +* The per-queue command buffer is kernel-written ABI; prevent +* the daemon from upgrading to writable via mprotect(). +*/ +vm_flags_clear (vma,VM_MAYWRITE ); + end =UBLKSRV_CMD_BUF_OFFSET + ub->dev_info.nr_hw_queues * max_sz;if (phys_off <UBLKSRV_CMD_BUF_OFFSET || phys_off >= end)return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 339/1424 spi: bcm63xx-hsspi: disable clocks on resume failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit 3b0cee02664041aea7e4f787c66cb86c82eb4e97 upstream.
bcm63xx_hsspi_resume() enables the HSSPI clock, and optionally the PLL clock, before restarting the SPI controller queue.
If spi_controller_resume() fails, the function currently reports success and leaves those clocks enabled. Propagate the error and disable the clocks before returning.
--- drivers/spi/spi-bcm63xx-hsspi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/spi/spi-bcm63xx-hsspi.c +7 -1
@@ -921,7 +921,13 @@ static int bcm63xx_hsspi_resume(struct d } } -spi_controller_resume (host); + ret =spi_controller_resume (host); +if (ret) { +if (bs->pll_clk) +clk_disable_unprepare (bs->pll_clk); +clk_disable_unprepare (bs->clk); +return ret; + }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 340/1424 spi: bcm63xx: disable clock on resume failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit 2b62c2c134fa32d9d3a9e7323c8ac74518eeb4ac upstream.
bcm63xx_spi_resume() enables the controller clock before restarting the SPI controller queue.
If spi_controller_resume() fails, the function currently reports success and leaves the clock enabled. Propagate the error and disable the clock before returning.
--- drivers/spi/spi-bcm63xx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/spi/spi-bcm63xx.c +5 -1
@@ -661,7 +661,11 @@ static int bcm63xx_spi_resume(struct devif (ret)return ret; -spi_controller_resume (host); + ret =spi_controller_resume (host); +if (ret) { +clk_disable_unprepare (bs->clk); +return ret; + }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 341/1424 spi: bcmbca-hsspi: disable clocks on resume failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit d2f5a606710ad70c341dc609430a20a5645618d5 upstream.
bcmbca_hsspi_resume() enables the HSSPI clock, and optionally the PLL clock, before restarting the SPI controller queue.
If spi_controller_resume() fails, the function currently reports success and leaves those clocks enabled. Propagate the error and disable the clocks before returning.
--- drivers/spi/spi-bcmbca-hsspi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/spi/spi-bcmbca-hsspi.c +7 -1
@@ -621,7 +621,13 @@ static int bcmbca_hsspi_resume(struct de } } -spi_controller_resume (host); + ret =spi_controller_resume (host); +if (ret) { +if (bs->pll_clk) +clk_disable_unprepare (bs->pll_clk); +clk_disable_unprepare (bs->clk); +return ret; + }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 342/1424 scsi: target: iscsi: Reserve a terminator byte for the login payload
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sujal Tuladhar <[email protected]>
commit f4825922d2fb371e2b969697d792077f1b62b62c upstream.
iscsi_target_check_login_request() rejects a login PDU whose DataSegmentLength exceeds MAX_KEY_VALUE_PAIRS, but the test is '>' and login->req_buf is allocated with exactly MAX_KEY_VALUE_PAIRS bytes. Since iscsit_get_login_rx() receives payload_length + padding bytes, where
padding = ((-payload_length) & 3);
any payload_length from 8189 to 8192 fills the whole 8192 byte buffer. The write stays in bounds, but no byte is left for a NUL terminator.
The buffer is subsequently consumed as a C string. In the CHAP path chap_check_algorithm() calls kstrdup(a_str), and extract_param() calls strstr(in_buf, pattern) followed by strlen_semi(), none of which take a length. convert_null_to_semi() additionally rewrites every embedded NUL to ';', so even a payload made of well formed NUL separated key=value records is left without a terminator. These walk past the end of the object into adjacent slab memory. It is reachable by an unauthenticated initiator against a portal configured for CHAP; when authentication is not required iscsi_login_zero_tsih_s2() rewrites AuthMethod to None and the CHAP path is never entered.
Allocate one extra byte. kzalloc() zeroes it and nothing ever writes to it, as every writer copies to offset 0 for at most MAX_KEY_VALUE_PAIRS bytes, so the buffer is always terminated.
--- drivers/target/iscsi/iscsi_target_login.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/target/iscsi/iscsi_target_login.c +1 -1
@@ -48,7 +48,7 @@ static struct iscsi_login *iscsi_login_i login->conn = conn; login->first_request =1 ; - login->req_buf =kzalloc (MAX_KEY_VALUE_PAIRS ,GFP_KERNEL ); + login->req_buf =kzalloc (MAX_KEY_VALUE_PAIRS +1 ,GFP_KERNEL );if (!login->req_buf) {pr_err ("Unable to allocate memory for response buffer.\n" ); goto out_login;
Greg Kroah-Hartman
maintainerPATCH 343/1424 scsi: pm8001: Use rollback index when freeing MSI-X vectors
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 3f92a64545165bdbb36dee8fa35626b295463313 upstream.
pm8001_request_msix() unwinds previously registered handlers with free_irq() when request_irq() fails. The rollback loop uses the failing index i for every iteration instead of the already registered vector index j.
That passes the wrong IRQ/dev_id pair to free_irq() and leaves the earlier handlers installed. Use j for both pci_irq_vector() and the matching irq_vector entry in the rollback loop.
--- drivers/scsi/pm8001/pm8001_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_init.c +2 -2
@@ -1014,8 +1014,8 @@ static u32 pm8001_request_msix(struct pm &(pm8001_ha->irq_vector[i]));if (rc) {for (j =0 ; j < i; j++) { -free_irq (pci_irq_vector (pm8001_ha->pdev, i), - &(pm8001_ha->irq_vector[i])); +free_irq (pci_irq_vector (pm8001_ha->pdev, j), + &pm8001_ha->irq_vector[j]); }pci_free_irq_vectors (pm8001_ha->pdev);break ;
Greg Kroah-Hartman
maintainerPATCH 344/1424 mm/damon/sysfs-schemes: kobject_del() scheme dirs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 05fb6ac98c49be870c5f9ccdfdf95f0107e564ae upstream.
On CONFIG_DEBUG_KOBJECT_RELEASE enabled kernel, lack of kobject_del() could cause directories creation failures due to the name conflicts. Fix those issues for scheme directories by adding kobject_del() calls.
--- mm/damon/sysfs-schemes.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
mm/damon/sysfs-schemes.c +4 -1
@@ -1402,6 +1402,7 @@ void damon_sysfs_schemes_rm_dirs(structfor (i =0 ; i < schemes->nr; i++) {damon_sysfs_scheme_rm_dirs (schemes_arr[i]); +kobject_del (&schemes_arr[i]->kobj);kobject_put (&schemes_arr[i]->kobj); } schemes->nr =0 ;
@@ -1439,13 +1440,15 @@ static int damon_sysfs_schemes_add_dirs( goto out; err =damon_sysfs_scheme_add_dirs (scheme);if (err) - goto out; + goto del_out; schemes_arr[i] = scheme; schemes->nr++; }return 0 ; +del_out: +kobject_del (&scheme->kobj); out:damon_sysfs_schemes_rm_dirs (schemes);kobject_put (&scheme->kobj);
Greg Kroah-Hartman
maintainerPATCH 345/1424 mm/damon/sysfs-schemes: kobject_del() scheme filter dirs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 3c453bddacd4c04ecb38cf79dbfa41e7dfe0531b upstream.
On CONFIG_DEBUG_KOBJECT_RELEASE enabled kernel, lack of kobject_del() could cause directories creation failures due to the name conflicts. Fix those issues for scheme filter directories by adding kobject_del() calls.
--- mm/damon/sysfs-schemes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
mm/damon/sysfs-schemes.c +3 -1
@@ -513,8 +513,10 @@ static void damon_sysfs_scheme_filters_rstruct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;int i; -for (i =0 ; i < filters->nr; i++) +for (i =0 ; i < filters->nr; i++) { +kobject_del (&filters_arr[i]->kobj);kobject_put (&filters_arr[i]->kobj); + } filters->nr =0 ;kfree (filters_arr); filters->filters_arr =NULL ;
Greg Kroah-Hartman
maintainerPATCH 346/1424 mm/damon/sysfs-schemes: kobject_del() scheme region dirs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit f3ec3271210781c255e737498b84d5790e8176b4 upstream.
On CONFIG_DEBUG_KOBJECT_RELEASE enabled kernel, lack of kobject_del() could cause directories creation failures due to the name conflicts. Fix those issues for scheme region directories by adding kobject_del() calls.
This issue was discovered [1] by Sashiko, though its analysis was partially incorrect.
--- mm/damon/sysfs-schemes.c | 1 + 1 file changed, 1 insertion(+)
mm/damon/sysfs-schemes.c +1 -0
@@ -151,6 +151,7 @@ static void damon_sysfs_scheme_regions_rlist_for_each_entry_safe (r, next, ®ions->regions_list, list) {list_del (&r->list); +kobject_del (&r->kobj);kobject_put (&r->kobj); regions->nr_regions--; }
Greg Kroah-Hartman
maintainerPATCH 347/1424 mm/damon/sysfs: kobject_del() region and target (error) dirs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 2603ef6f6ec3d3f7de2d6a07e7c9a683cebac419 upstream.
On CONFIG_DEBUG_KOBJECT_RELEASE enabled kernel, lack of kobject_del() could cause directories creation failures due to the name conflicts. Fix those issues for the normal creation path of region directories and the error path of target directories, by adding kobject_del() calls.
--- mm/damon/sysfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
mm/damon/sysfs.c +6 -2
@@ -107,8 +107,10 @@ static void damon_sysfs_regions_rm_dirs(struct damon_sysfs_region **regions_arr = regions->regions_arr;int i; -for (i =0 ; i < regions->nr; i++) +for (i =0 ; i < regions->nr; i++) { +kobject_del (®ions_arr[i]->kobj);kobject_put (®ions_arr[i]->kobj); + } regions->nr =0 ;kfree (regions_arr); regions->regions_arr =NULL ;
@@ -343,13 +345,15 @@ static int damon_sysfs_targets_add_dirs( err =damon_sysfs_target_add_dirs (target);if (err) - goto out; + goto del_out; targets_arr[i] = target; targets->nr++; }return 0 ; +del_out: +kobject_del (&target->kobj); out:damon_sysfs_targets_rm_dirs (targets);kobject_put (&target->kobj);
Greg Kroah-Hartman
maintainerPATCH 348/1424 mm/damon/sysfs: kobject_del() target (normal), context and kdamond dirs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
commit 263af33a72d1995ae6cdc22b08d527e2bda17259 upstream.
Patch series "mm/damon/sysfs: kobject_del() directories that users can create/remove".
DAMON sysfs interface allows users to create and remove arbitrary number of directories on sysfs, using a few files having 'nr_' prefix. For example, 'nr_kdamonds'. When the user writes a number 'N' to the files, directories having name starting from '0' to 'N - 1' are created in the same directory. The pre-existing number-named directories are removed before creating the new directories.
For the removal of the existing directories, DAMON sysfs interface use only kobject_put(). Because DAMON sysfs interface is the only kernel component that manages the directories, there is no problem in normal situations. However, if CONFIG_DEBUG_KOBJECT_RELEASE is enabled, the removal of dirs are delayed. Let's suppose a user writes a non-zero number to the 'nr_*' files while there are pre-existing number-named directories, on the config enabled kernel. DAMON sysfs interface decreases the reference counts of the existing directories and immediately creates new directories. Because the removal of the sysfs directories is delayed, it shows some pre-existing directories of the same names when it tries to create the new directories, and fails.
For example, the issue can be triggered like below:
# grep DEBUG_KOBJECT_RELEASE /boot/config-$(uname -r)
CONFIG_DEBUG_KOBJECT_RELEASE=y
# ls
nr_kdamonds
# echo 1 > nr_kdamonds
# echo 1 > nr_kdamonds
bash: echo: write error: File exists
# dmesg
[...]
[ 300.880458] kobject: kobject_add_internal failed for 0 with -EEXIST, don't try to register things with the same name in the same directory.
[...]Some of the error handling paths of the directories also lack the kobject_del() call. If the user uses nr_* file right after the errors, similar issues can happen.
This doesn't cause catastrophic issues like kernel panics or memory corruptions. Users can work around by removing all directories first (write 0 to the nr_* files) and then create new directories after confirming the old directories are gone. But, this is definitely a bug that causes a bad user experience.
Fix the issues by calling kobject_del() before creating new directories.
This patch (of 11)
On CONFIG_DEBUG_KOBJECT_RELEASE enabled kernel, lack of kobject_del() could cause directories creation failures due to the name conflicts. Fix those issues for normal creation paths of target, context and kdamond directories, and error paths of context and kdamond directories by adding kobject_del() calls.
Note that this fix for target directories is not complete since it has a similar issue in the damon_sysfs_targets_add_dirs() error path. Because the normal path issue and the error path issue are introduced by different commits, this commit is fixing only the normal path issue. A commit for the error path will be added next.
--- mm/damon/sysfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
mm/damon/sysfs.c +9 -2
@@ -307,6 +307,7 @@ static void damon_sysfs_targets_rm_dirs(for (i =0 ; i < targets->nr; i++) {damon_sysfs_target_rm_dirs (targets_arr[i]); +kobject_del (&targets_arr[i]->kobj);kobject_put (&targets_arr[i]->kobj); } targets->nr =0 ;
@@ -833,6 +834,7 @@ static void damon_sysfs_contexts_rm_dirsfor (i =0 ; i < contexts->nr; i++) {damon_sysfs_context_rm_dirs (contexts_arr[i]); +kobject_del (&contexts_arr[i]->kobj);kobject_put (&contexts_arr[i]->kobj); } contexts->nr =0 ;
@@ -871,13 +873,15 @@ static int damon_sysfs_contexts_add_dirs err =damon_sysfs_context_add_dirs (context);if (err) - goto out; + goto del_out; contexts_arr[i] = context; contexts->nr++; }return 0 ; +del_out: +kobject_del (&context->kobj); out:damon_sysfs_contexts_rm_dirs (contexts);kobject_put (&context->kobj);
@@ -1638,6 +1642,7 @@ static void damon_sysfs_kdamonds_rm_dirsfor (i =0 ; i < kdamonds->nr; i++) {damon_sysfs_kdamond_rm_dirs (kdamonds_arr[i]); +kobject_del (&kdamonds_arr[i]->kobj);kobject_put (&kdamonds_arr[i]->kobj); } kdamonds->nr =0 ;
@@ -1693,13 +1698,15 @@ static int damon_sysfs_kdamonds_add_dirs err =damon_sysfs_kdamond_add_dirs (kdamond);if (err) - goto out; + goto del_out; kdamonds_arr[i] = kdamond; kdamonds->nr++; }return 0 ; +del_out: +kobject_del (&kdamond->kobj); out:damon_sysfs_kdamonds_rm_dirs (kdamonds);kobject_put (&kdamond->kobj);
Greg Kroah-Hartman
maintainerPATCH 349/1424 futex: Prevent rcuwait use-after-free during requeue PI
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yao Kai <[email protected]>
commit a3b8d46fe401cba3a5c46dea610e6eb3dc15370e upstream.
On PREEMPT_RT, FUTEX_CMP_REQUEUE_PI can trigger a KASAN report (slab-out-of-bounds) in futex_requeue_pi_complete() invocation of rcuwait_wake_up().
The futex_q used by futex_wait_requeue_pi() is allocated on the waiter's stack. An early wakeup can race with a PI requeue as follows:
waiter requeue task
------ ------------futex_wait_requeue_pi()
futex_do_wait()
schedule()
futex_requeue
futex_proxy_trylock_atomic()
futex_requeue_pi_prepare()
Q_REQUEUE_PI_NONE -> Q_REQUEUE_PI_IN_PROGRESS
* timeout/ signal wakes waiter *
futex_requeue_pi_wakeup_sync()
Q_REQUEUE_PI_IN_PROGRESS -> Q_REQUEUE_PI_WAIT
requeue_pi_wake_futex
futex_requeue_pi_complete()
cmpxchg Q_REQUEUE_PI_WAIT -> Q_REQUEUE_PI_LOCKED
rcuwait_wait_event()
if (atomic_read(&q->requeue_state) != Q_REQUEUE_PI_WAIT)
break /* no schedule() */ /* q.pi_state->owner == current */
futex_private_hash_put()
/* return from syscall */
rcuwait_wake_up(&q->requeue_wait)
/* q is gone */futex_requeue_pi_complete() publishes Q_REQUEUE_PI_LOCKED before calling rcuwait_wake_up(). The waiter observes this state in rcuwait_wait_event() before invoking schedule() in rcuwait_wait_event(). Here, the waiter is free leave the syscall before requeue task can complete the wake.
To address this race skip rcuwait_wake_up() in the Q_REQUEUE_PI_LOCKED case.
This state is only published by requeue_pi_wake_futex(), which saves q->task before futex_requeue_pi_complete() and wakes the waiter via wake_up_state().
This wake is intended to wake the waiter from its futex_do_wait() sleep. If the waiter is still sleeping there, it can not get into the Q_REQUEUE_PI_WAIT state (and require this removed wake). Should the waiter be woken up from futex_do_wait() by other means (as in this example) and sleep in futex_requeue_pi_wakeup_sync() then the wake_up_state() from requeue_pi_wake_futex() will wake it, too. Should the waiter task terminate before wake_up_state() had a chance to wake the task then the task pointer does not become invalid because the futex_hash_bucket::lock is held and the task pointer is RCU protected.
[bigeasy: Updated comment and commit message]
--- kernel/futex/requeue.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/futex/requeue.c +10 -2
@@ -147,8 +147,16 @@ static inline void futex_requeue_pi_comp }while (!atomic_try_cmpxchg (&q->requeue_state, &old, new));#ifdef CONFIG_PREEMPT_RT -/* If the waiter interleaved with the requeue let it know */ -if (unlikely (old ==Q_REQUEUE_PI_WAIT )) +/* +* The waiter in futex_requeue_pi_wakeup_sync() can interleave with the +* wake below: It will assign Q_REQUEUE_PI_IN_PROGRESS and here it will +* be updated to Q_REQUEUE_PI_LOCKED (locked = 1). The rcuwait_wait_event() +* will already read Q_REQUEUE_PI_LOCKED and skip the schedule() invocation, +* leading to an access of futex_q::requeue_wait after the waiter returned. +* In this case only we skip the wake here and rely on following wake in +* requeue_pi_wake_futex() to perform the wake if needed. +*/ +if (unlikely (old ==Q_REQUEUE_PI_WAIT ) && new !=Q_REQUEUE_PI_LOCKED )rcuwait_wake_up (&q->requeue_wait);#endif }
Greg Kroah-Hartman
maintainerPATCH 350/1424 HID: rmi: fix OOB access with undersized RMI reports
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Jie Law <[email protected]>
commit 4956993bb3befdf791d71a4952d8d13bcfd44c7b upstream.
The hid-rmi driver sizes its writeReport/readReport buffer purely from the report descriptor supplied by the device, with no minimum bound:
data->input_report_size = hid_report_len(input_report); data->output_report_size = hid_report_len(output_report); alloc_size = data->output_report_size + data->input_report_size; data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); data->readReport = data->writeReport + data->output_report_size;
but then reads and writes fixed offsets into it. A device declaring a 1-byte output and a 1-byte input report makes hid_report_len() return 2 for each, so alloc_size is 4, while rmi_set_page() -- reached unconditionally at probe time through rmi_input_configured() -- stores writeReport[4] and rmi_hid_read_block() stores writeReport[0..5]. Since readReport lives at writeReport + output_report_size, those stores also corrupt the window the next reply is parsed out of.
The read path is worse: the copy length comes from readReport[1], which the device fills in and can be up to 255, and the copy starts at &readReport[2] with no regard for input_report_size, so it runs past the end of the allocation into adjacent slab objects. This does not even need a lying device -- rmi_f01_probe() issues a fixed 21-byte register read, so any device declaring an input report smaller than 23 bytes reads out of bounds even when it answers truthfully. Those bytes become the register values the RMI core acts on: rmi_f01_probe() prints them to the kernel log as the product id and exports them through the mode 0444 sysfs attribute of the same name, and rmi_driver_set_irq_bits() sends them back to the device as the interrupt mask, so an undersized report descriptor leaks heap contents both to unprivileged userspace and to the device itself.
The write path has no bound either: rmi_hid_write_block() copies an unbounded len to &writeReport[4], and the largest caller a device can drive at probe time is rmi_driver_set_irq_bits(), whose length is derived from the interrupt source counts the device declares in its Page Description Table.
Finally, the read loop cannot terminate on a zero-length reply: such a reply copies nothing and advances neither bytes_read nor bytes_needed, and because a reply did arrive the one second wait_event_timeout() does not fire either, so a device answering 0 forever keeps the loop running inside the probe worker with page_mutex held. khungtaskd does not notice, because every reply wakes the task.
Reject reports too small for what the driver builds -- 6 output bytes for the write reports and 3 input bytes for the read handshake -- at probe time, clamp the write and the read copy to the report sizes the device declared, and treat a zero-length reply as an error. A device refused this way is started as an ordinary HID device, like one that does not carry the RMI report ids at all.
RMI_DEVICE must not be left set in device_flags on that path, because rmi_input_configured() would then run the RMI setup and reach rmi_set_page(), which writes the writeReport buffer the refusal just skipped allocating. The bit can arrive set: rmi_probe() copies id->driver_data into device_flags before the report checks, and a bind through the new_id sysfs attribute can supply driver_data with RMI_DEVICE (BIT(0)) set. Strip the bit where driver_data is copied, so RMI_DEVICE keeps meaning exactly "this probe validated the reports"; the three jumps to start that predate this patch are covered as well.
The error path also clears RMI_READ_DATA_PENDING on its way out, because that flag is what the wait at the top of the loop tests: leaving it set would make every later wait_event_timeout() return immediately on the stale reply and kill the read path for the rest of the device's life.
Clamping does not regress working hardware: the read loop already handles a reply carrying fewer bytes than requested, and a write longer than the output report was overrunning the buffer already.
Verified on v6.12.69 and on v6.12.105 built with CONFIG_KASAN=y and booted kasan_multi_shot, whose hid-rmi.c is identical to mainline here. An emulated RMI4 device driven over /dev/uhid, and the same device again over dummy_hcd plus raw-gadget, give identical results:
BUG: KASAN: slab-out-of-bounds in rmi_hid_read_block+0x409/0x750 [hid_rmi] Read of size 21 at addr ffff88800bf33bba by task kworker/0:3/285 __asan_memcpy+0x23/0x60 rmi_hid_read_block+0x409/0x750 [hid_rmi] rmi_f01_probe+0x5dd/0x1dc0 [rmi_core] BUG: KASAN: slab-out-of-bounds in rmi_hid_write_block+0x1a9/0x350 [hid_rmi] Write of size 35 at addr ffff88810a2b24ac by task kworker/1:10/666 __asan_memcpy+0x3c/0x60 rmi_hid_write_block+0x1a9/0x350 [hid_rmi] rmi_driver_set_irq_bits+0x1f6/0x4d0 [rmi_core] rmi_driver_probe+0x636/0xbf0 [rmi_core] rmi_input_configured+0x184/0x2e0 [hid_rmi] rmi_probe+0x952/0xcf0 [hid_rmi]
and, for the zero-length reply, a probe worker left in D state in rmi_hid_read_block() after 225 replies at 200 ms intervals.
After this change the undersized descriptor is refused at probe with "rmi reports too small (out=2 in=2)", the oversized read and write are both rejected, the zero-length reply fails the read with -EIO while later reads on the same device keep working, and a device declaring reports large enough for a 21-byte register read still probes normally and reports its real product id. A device bound through new_id with RMI_DEVICE in its driver_data no longer reaches rmi_set_page() with an unallocated writeReport either.
--- drivers/hid/hid-rmi.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-)
drivers/hid/hid-rmi.c +43 -3
@@ -235,7 +235,23 @@ static int rmi_hid_read_block(struct rmibreak ; } - read_input_count = data->readReport[1 ]; + read_input_count =min_t (int, data->readReport[1 ], + data->input_report_size -2 ); +if (!read_input_count) { +/* +* A zero length reply advances neither +* bytes_read nor bytes_needed, and because a +* reply did arrive the wait above does not +* time out either, so a device answering 0 +* forever would spin here indefinitely with +* page_mutex held. +*/ +hid_warn (hdev,"%s: zero-length read reply\n" , + __func__); +clear_bit (RMI_READ_DATA_PENDING , &data->flags); + ret = -EIO ; +break ; + }memcpy (buf + bytes_read, &data->readReport[2 ],min (read_input_count, bytes_needed));
@@ -271,6 +287,11 @@ static int rmi_hid_write_block(struct rm goto exit; } +if (len +4 > data->output_report_size) { + ret = -EINVAL ; + goto exit; + } + data->writeReport[0 ] =RMI_WRITE_REPORT_ID ; data->writeReport[1 ] = len; data->writeReport[2 ] = addr &0xFF ;
@@ -668,8 +689,16 @@ static int rmi_probe(struct hid_device *return ret; } -if (id->driver_data) - data->device_flags = id->driver_data; +/* +* RMI_DEVICE can only mean "this probe validated the RMI reports and +* allocated writeReport": every bail-out to start below skips that +* allocation, and device_flags left carrying RMI_DEVICE from +* driver_data would send rmi_input_configured() into rmi_set_page() +* with writeReport still NULL. A bind through the new_id sysfs +* attribute can supply driver_data with the bit set, so do not let +* driver_data grant it. +*/ + data->device_flags = id->driver_data & ~RMI_DEVICE ;/* * Check for the RMI specific report ids. If they are misisng
@@ -698,6 +727,17 @@ static int rmi_probe(struct hid_device * data->output_report_size =hid_report_len (output_report); +/* +* The write reports built by this driver occupy 6 bytes and the read +* handshake looks at the first 3 bytes of an input report, so refuse +* to drive a device whose reports cannot hold them. +*/ +if (data->output_report_size <6 || data->input_report_size <3 ) { +hid_err (hdev,"rmi reports too small (out=%u in=%u)\n" , + data->output_report_size, data->input_report_size); + goto start; + } + data->device_flags |=RMI_DEVICE ; alloc_size = data->output_report_size + data->input_report_size;
Greg Kroah-Hartman
maintainerPATCH 351/1424 HID: wacom: validate report length in wacom_intuos_pro2_bt_irq
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit a8e04f3f894ccb52cfcd7e60125a9f35da4a616d upstream.
wacom_intuos_pro2_bt_irq() receives the wire report length in len but never consults it before parsing. After the report-id gate it unconditionally calls wacom_intuos_pro2_bt_pen() and then, selected by features.type, a fixed chain of sub-parsers, none of which receive len:
wacom_intuos_pro2_bt_pen(wacom);
if (type == INTUOSP2_BT || type == INTUOSP2S_BT) {
wacom_intuos_pro2_bt_touch(wacom);
wacom_intuos_pro2_bt_pad(wacom);
wacom_intuos_pro2_bt_battery(wacom);
} else {
wacom_intuos_gen3_bt_pad(wacom);
wacom_intuos_gen3_bt_battery(wacom);
}Each sub-parser dereferences wacom->data at fixed offsets. The furthest byte touched on each branch is:
INTUOSP2_BT / INTUOSP2S_BT: wacom_intuos_pro2_bt_pad() reads data[285]
(the touchring byte), so the report must be at least 286 bytes;
INTUOSHT3_BT ("gen3"): wacom_intuos_gen3_bt_battery() reads data[45],
so the report must be at least 46 bytes.
features.type is selected from the VID/PID id_table entry and wacom_setup_device_quirks() force-registers the pen/pad/touch inputs for that type independent of the report descriptor, so a malicious or malfunctioning paired/spoofed Bluetooth peripheral can advertise that VID/PID and send an undersized report that still satisfies the data[0] == 0x80/0x81 gate. The driver then reads past the received report and forwards the bytes to userspace via evdev (MSC_SERIAL / ABS_MISC / ABS_WHEEL on the pen and pad input nodes), an out-of-bounds read with a concrete userspace read-back channel, and a true out-of-bounds read on transports whose backing buffer is sized to the (small) report descriptor rather than a fixed-size staging buffer.
This is the same class of bug commit 2f1763f62909 ("HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq") already hardened in the sibling wacom_intuos_bt_irq(), which guards each report id against its minimum length before parsing.
Guard wacom_intuos_pro2_bt_irq() the same way: before parsing, reject reports shorter than the furthest offset the selected branch actually dereferences, warn, and bail out. Because the whole pen/touch/pad/ battery chain runs unconditionally per branch, a single up-front check against the maximum offset (286 bytes for INTUOSP2_BT/INTUOSP2S_BT, 46 bytes for the gen3 branch) bounds every sub-parser. Returning 0 on a short report also skips those calls for the same malformed report, which is the safe, conservative behavior.
--- drivers/hid/wacom_wac.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/hid/wacom_wac.c +13 -0
@@ -1594,6 +1594,19 @@ static int wacom_intuos_pro2_bt_irq(strureturn 0 ; } +if (wacom->features.type ==INTUOSP2_BT || + wacom->features.type ==INTUOSP2S_BT ) { +if (len <286 ) { +dev_warn (wacom->pen_input->dev.parent, +"Pro2 BT report too short: %zu bytes\n" , len); +return 0 ; + } + }else if (len <46 ) { +dev_warn (wacom->pen_input->dev.parent, +"Pro2 BT report too short: %zu bytes\n" , len); +return 0 ; + } +wacom_intuos_pro2_bt_pen (wacom);if (wacom->features.type ==INTUOSP2_BT || wacom->features.type ==INTUOSP2S_BT ) {
Greg Kroah-Hartman
maintainerPATCH 352/1424 dm: fix race when loading and unloading a table
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 5380c7f6335cc6d77eb77d065105e81155c4d9d3 upstream.
If the userspace calls two concurrent table load ioctls and one of them succeeds and the other fails, there is a race condition because dm_setup_md_queue walks &md->table_devices without any lock. If the walk races with dm_table_destroy -> free_devices -> dm_put_table_device, there is access to invalid memory.
Fix this race by extending the lock over the list walk.
--- drivers/md/dm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/md/dm.c +8 -4
@@ -2369,9 +2369,10 @@ int dm_setup_md_queue(struct mapped_devi*/ mutex_lock (&md->table_devices_lock); r =add_disk (md->disk); -mutex_unlock (&md->table_devices_lock); -if (r) +if (r) { +mutex_unlock (&md->table_devices_lock);return r; + }/* * Register the holder relationship for devices added before the disk
@@ -2382,18 +2383,21 @@ int dm_setup_md_queue(struct mapped_deviif (r) goto out_undo_holders; } +mutex_unlock (&md->table_devices_lock); r =dm_sysfs_init (md);if (r) - goto out_undo_holders; + goto lock_out_undo_holders; md->type = type; +return 0 ; +lock_out_undo_holders: +mutex_lock (&md->table_devices_lock); out_undo_holders:list_for_each_entry_continue_reverse (td, &md->table_devices, list)bd_unlink_disk_holder (td->dm_dev.bdev, md->disk); -mutex_lock (&md->table_devices_lock);del_gendisk (md->disk);mutex_unlock (&md->table_devices_lock);return r;
Greg Kroah-Hartman
maintainerPATCH 353/1424 dm: fix resume-vs-remove race
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 44b43ec132f1cf3275ecc182d0c82f50c3c4c3d5 upstream.
If the user issues the resume ioctl and the remove ioctl at the same time, it may be possible that the device is resumed after it is suspended in __dm_destroy. The result is that the table is destroyed without calling the postsuspend method.
Dm targets expect that they may be removed only after the postsuspend method method was called. If we break this expectation, it can cause misbehavior in various targets. For example - in the dm-integrity target, the reboot notifier is not unregistered, leading to use-after-free.
Fix this bug by refusing to resume if the device is being destroyed.
--- drivers/md/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/dm.c +1 -1
@@ -2873,7 +2873,7 @@ retry: r = -EINVAL ;mutex_lock_nested (&md->suspend_lock,SINGLE_DEPTH_NESTING ); -if (!dm_suspended_md (md)) +if (!dm_suspended_md (md) ||test_bit (DMF_FREEING , &md->flags)) goto out;if (dm_suspended_internally_md (md)) {
Greg Kroah-Hartman
maintainerPATCH 354/1424 dmaengine: dw-edma: Fix HDMA channel status register access
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit ef1b080e03acc83d5bde841da67036985acd50dc upstream.
GET_CH_32() takes the direction before the channel ID, but dw_hdma_v0_core_ch_status() passed them in the opposite order. This can make the status callback read another HDMA channel status register.
Use the same argument order as the other HDMA register accesses.
--- drivers/dma/dw-edma/dw-hdma-v0-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/dw-edma/dw-hdma-v0-core.c +1 -1
@@ -79,7 +79,7 @@ static enum dma_status dw_hdma_v0_core_cu32 tmp; tmp =FIELD_GET (HDMA_V0_CH_STATUS_MASK , -GET_CH_32 (dw, chan->id, chan->dir, ch_stat)); +GET_CH_32 (dw, chan->dir, chan->id, ch_stat));if (tmp ==1 )return DMA_IN_PROGRESS ;
Greg Kroah-Hartman
maintainerPATCH 355/1424 dmaengine: dw-edma: Complete descriptors before pausing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit c154060016a9db2ac889bfdb0a3c1322f9be8ded upstream.
If PAUSE is requested while the final burst of a descriptor is in flight, the DONE interrupt takes the PAUSE path without checking whether the descriptor has been depleted. The depleted descriptor remains on the issued list and the channel enters EDMA_ST_PAUSE.
On resume, dw_edma_start_transfer() can select that depleted descriptor again even though no burst remains, leaving the channel in an invalid busy state.
Check for descriptor completion before acknowledging PAUSE. If there is no work to start on resume, leave the channel idle. Also ignore DONE interrupts while the channel is paused so a stale or repeated interrupt cannot change its state or start queued work.
--- drivers/dma/dw-edma/dw-edma-core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/dma/dw-edma/dw-edma-core.c +14 -6
@@ -271,7 +271,8 @@ static int dw_edma_device_resume(struct err = -EPERM ; }else { chan->status =EDMA_ST_BUSY ; -dw_edma_start_transfer (chan); +if (!dw_edma_start_transfer (chan)) + chan->status =EDMA_ST_IDLE ; }return err;
@@ -621,10 +622,16 @@ static void dw_edma_done_interrupt(strucunsigned long flags;spin_lock_irqsave (&chan->vc.lock, flags); +if (chan->status ==EDMA_ST_PAUSE ) { +spin_unlock_irqrestore (&chan->vc.lock, flags); +return ; + } + vd =vchan_next_desc (&chan->vc);if (vd) {switch (chan->request) {case EDMA_REQ_NONE : +case EDMA_REQ_PAUSE : desc =vd2dw_edma_desc (vd);if (!desc->chunks_alloc) { dw_hdma_set_callback_result(vd,
@@ -633,6 +640,12 @@ static void dw_edma_done_interrupt(strucvchan_cookie_complete (vd); } +if (chan->request ==EDMA_REQ_PAUSE ) { + chan->request =EDMA_REQ_NONE ; + chan->status =EDMA_ST_PAUSE ; +break ; + } +/* Continue transferring if there are remaining chunks or issued requests. */ chan->status =dw_edma_start_transfer (chan) ?EDMA_ST_BUSY :EDMA_ST_IDLE ;
@@ -645,11 +658,6 @@ static void dw_edma_done_interrupt(struc chan->status =EDMA_ST_IDLE ;break ; -case EDMA_REQ_PAUSE : - chan->request =EDMA_REQ_NONE ; - chan->status =EDMA_ST_PAUSE ; -break ; -default :break ; }
Greg Kroah-Hartman
maintainerPATCH 356/1424 dmaengine: dw-edma: Initialize IRQ data before requesting IRQs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 647217abea849d3d45f8cb0b8ee5b78d50f26985 upstream.
dw_edma_irq_request() passes struct dw_edma_irq to request_irq() before dw_edma_channel_setup() fills the back pointer. A shared interrupt can therefore enter the handler with dw_irq->dw still NULL, leading to a NULL pointer dereference.
Set the back pointer before installing each handler.
--- drivers/dma/dw-edma/dw-edma-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/dw-edma/dw-edma-core.c +2 -1
@@ -793,7 +793,6 @@ static int dw_edma_channel_setup(structelse irq->rd_mask |=BIT (chan->id); - irq->dw = dw;memcpy (&chan->msi, &irq->msi,sizeof (chan->msi)); dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
@@ -880,6 +879,7 @@ static int dw_edma_irq_request(struct dwif (chip->nr_irqs ==1 ) {/* Common IRQ shared among all channels */ irq = chip->ops->irq_vector (dev,0 ); + dw->irq[0 ].dw = dw; err =request_irq (irq, dw_edma_interrupt_common,IRQF_SHARED , dw->name, &dw->irq[0 ]);if (err) {
@@ -905,6 +905,7 @@ static int dw_edma_irq_request(struct dwfor (i =0 ; i < (*wr_alloc + *rd_alloc); i++) { irq = chip->ops->irq_vector (dev, i); + dw->irq[i].dw = dw; err = request_irq(irq, i < *wr_alloc ? dw_edma_interrupt_write :
Greg Kroah-Hartman
maintainerPATCH 357/1424 cpuidle: dt_idle_genpd: kfree() the original name allocation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
commit 2b0ac85512b7f67479127b2713254490662eb13d upstream.
dt_idle_pd_alloc() kasprintf()s the full node path, then points pd->name at kbasename() of that string. dt_idle_pd_free() kfree()s pd->name, which is no longer the start of the allocation.
Copy the basename instead.
--- drivers/cpuidle/dt_idle_genpd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/cpuidle/dt_idle_genpd.c +1 -2
@@ -99,7 +99,7 @@ struct generic_pm_domain *dt_idle_pd_allif (!pd) goto out; - pd->name =kasprintf (GFP_KERNEL ,"%pOF" , np); + pd->name =kstrdup (kbasename (of_node_full_name (np)),GFP_KERNEL );if (!pd->name) goto free_pd;
@@ -112,7 +112,6 @@ struct generic_pm_domain *dt_idle_pd_all goto free_name; pd->free_states = pd_free_states; - pd->name =kbasename (pd->name); pd->states = states; pd->state_count = state_count;
Greg Kroah-Hartman
maintainerPATCH 358/1424 block: flag zoned disks with GENHD_FL_NO_PART
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Le Moal <[email protected]>
commit 3f9c7a108c0e8f14425384912017071b71341e3b upstream.
Zoned block devices do not support partitions. However, the partition table is nevertheless still inspected, and any partition found ignored with a warning in add_partition(). While this is generally not a problem, and in fact beneficial to the user as it indicates an invalid use of a zoned block device, scanning for a partition table on the device may result in issuing read operations to offline zones (e.g. after a disk head is depopulated for disks that support head management operations).
Since partitions are ignored anyway, completely disable partition scanning for zoned gendisks by setting the flag GENHD_FL_NO_PART in __add_disk(). The existing check in add_partition() is left as-is to ensure that we still get a warning if for whatever reason, despite GENHD_FL_NO_PART, we still endup trying to add partitions.
Flagging zoned disks with GENHD_FL_NO_PART also has the benefit to expose through sysfs the ext_range attribute with the value of 1 instead of the default DISK_MAX_PARTS, thus correctly advertizing the fact that zoned disks do not support partitions.
--- block/genhd.c | 7 +++++++ 1 file changed, 7 insertions(+)
block/genhd.c +7 -0
@@ -467,6 +467,13 @@ int __must_check device_add_disk(struct goto out_device_del;/* +* We do not support partitions with zoned block devices, so do not try +* to scan the partitions table. +*/ +if (blk_queue_is_zoned (disk->queue)) + disk->flags |=GENHD_FL_NO_PART ; + +/* * avoid probable deadlock caused by allocating memory with * GFP_KERNEL in runtime_resume callback of its all ancestor * devices
Greg Kroah-Hartman
maintainerPATCH 359/1424 ata: ahci: work around lost interrupts on Marvell 88SE61xx
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hajo Noerenberg <[email protected]>
commit dc3565a4ae538e584e5e63b3b3cd1eaf502593c1 upstream.
ahci_single_level_irq_intr() services the ports first and clears the global HOST_IRQ_STAT afterwards, as recommended by AHCI 1.1 section 10.6.2. The Marvell 88SE6111/6121/6145 family stops reporting interrupts for a port when HOST_IRQ_STAT is cleared while PxIS still holds bits:
PxIS keeps its content, HOST_IRQ_STAT reads back as 0, the port is never looked at again, and the command in flight only ends in a timeout.
Measured on a Seagate Blackarmor NAS440 (Marvell 88F6281 Kirkwood, 88SE6121 rev B2 behind PCIe) by polling the AHCI registers from userspace while an IDENTIFY was outstanding:
t=303.046 irqs 127 PxIS 0x00000000 PxCI 0x00000001
IDENTIFY issued
t=303.057 irqs 128 PxIS 0x00000020 PxCI 0x00000000
CI cleared, DPS set, one interrupt taken ... PxIS stays 0x00000020, HOST_IRQ_STAT stays 0 ...
t~308.05 qc timeout after 5000 msecs
The command had completed - PxCI was clear and PxIS had DPS set - so ahci_qc_complete() would have completed it. It never got the chance because the handler read HOST_IRQ_STAT as 0 and returned IRQ_NONE.
Marvell's own driver for these chips clears the two registers in the opposite order and says so ("clear global before channel"), and ahci_xgene handles its broken edge latch the same way. Since the reordering costs at most one spurious interrupt per valid one on conforming controllers, do it in a private interrupt handler selected for board_ahci_mv instead of changing libahci for everyone.
With this applied, SATA-2 and SATA-3 disks work at 3.0 Gbps on the 88SE6121 without the drive-side 1.5 Gbps jumper that was needed before. Time from link up to a successful IDENTIFY:
WDC WD5000AADS-00S9B0 port 0 7 ms (never identified before) WDC WD3202ABYS-01B7A0 port 1 28 ms WDC WD30EFRX-68EUZN0 port 1 200 ms (3 TB, HPA detection ok)
Only the 88SE6121 was tested; board_ahci_mv also covers the 88SE6145, which Marvell's driver treats identically.
--- drivers/ata/ahci.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
drivers/ata/ahci.c +49 -0
@@ -1647,6 +1647,51 @@ static irqreturn_t ahci_thunderx_irq_han }#endif +/* +* The Marvell 88SE6111/6121/6145 ("Thor") family stops reporting interrupts +* for a port when HOST_IRQ_STAT is cleared while PxIS still holds bits: PxIS +* keeps its content, HOST_IRQ_STAT reads back as 0, the port is never looked +* at again and the command in flight only ends in a timeout. On a 88SE6121 +* this makes every SATA-2 or SATA-3 disk fail to IDENTIFY, while SATA-1 disks +* happen to win the race often enough to work. +* +* Clearing the host status before servicing the ports avoids it. Marvell's +* own driver for these chips does the same and says so ("clear global before +* channel"), and ahci_xgene handles its broken edge latch the same way. The +* price is at most one spurious interrupt per valid one, which is why this is +* not the generic behaviour - see AHCI 1.1 section 10.6.2. +* +* Link: https://bugzilla.kernel.org/show_bug.cgi?id=216094 +*/ +static irqreturn_t ahci_mv_irq_handler (int irq,void *dev_instance) +{ +struct ata_host *host = dev_instance; +struct ahci_host_priv *hpriv = host->private_data; +void __iomem *mmio = hpriv->mmio; +unsigned int rc; +u32 irq_stat, irq_masked; + + irq_stat =readl (mmio +HOST_IRQ_STAT ); +if (!irq_stat) +return IRQ_NONE ; + + irq_masked = irq_stat & hpriv->port_map; + +spin_lock (&host->lock); + +/* +* Use the unmasked value to clear the interrupt, as a spurious pending +* event on a dummy port might cause a screaming IRQ. +*/ +writel (irq_stat, mmio +HOST_IRQ_STAT ); + + rc =ahci_handle_port_intr (host, irq_masked); + +spin_unlock (&host->lock); + +return IRQ_RETVAL (rc); +} +static void ahci_remap_check (struct pci_dev *pdev,int bar,struct ahci_host_priv *hpriv) {
@@ -1890,6 +1935,10 @@ static int ahci_init_one(struct pci_devreturn -ENOMEM ; hpriv->flags |= (unsigned long )pi.private_data; +/* the Marvell "Thor" family needs HOST_IRQ_STAT cleared first */ +if (board_id == board_ahci_mv) + hpriv->irq_handler = ahci_mv_irq_handler; +/* MCP65 revision A1 and A2 can't do MSI */ if (board_id == board_ahci_mcp65 && (pdev->revision ==0xa1 || pdev->revision ==0xa2 ))
Greg Kroah-Hartman
maintainerPATCH 360/1424 ima: Check for ERR_PTR from dentry_path() in validate_hash_algo()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
commit 8861f6d5c0678a7c5089c7b272509fc5931b8437 upstream.
dentry_path() returns ERR_PTR(-ENAMETOOLONG) when the path exceeds the buffer. validate_hash_algo() passes the result straight to integrity_audit_msg() without checking. ERR_PTR is not NULL, so integrity_audit_message() sees a valid pointer and calls strlen() on it, which faults:
BUG: unable to handle page fault for address: ffffffffffffffdc
RIP: 0010:strlen+0x30/0xa0
Call Trace:
audit_log_untrustedstring+0x19/0x30
integrity_audit_message+0x366/0x4f0
ima_inode_setxattr+0x512/0x5f0Check for IS_ERR() and use NULL instead, which makes the audit message skip the name= field instead of crashing.
--- security/integrity/ima/ima_appraise.c | 2 ++ 1 file changed, 2 insertions(+)
security/integrity/ima/ima_appraise.c +2 -0
@@ -754,6 +754,8 @@ static int validate_hash_algo(struct denreturn -EACCES ; path =dentry_path (dentry, pathbuf,PATH_MAX ); +if (IS_ERR (path)) + path =NULL ;integrity_audit_msg (AUDIT_INTEGRITY_DATA ,d_inode (dentry), path,"set_data" , errmsg, -EACCES ,0 );
Greg Kroah-Hartman
maintainerPATCH 361/1424 kprobes: Protect kprobe_blacklist with RCU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 0c4256196b3a105307e2235fbfd85e768bbcdd0f upstream.
__within_kprobe_blacklist() traverses kprobe_blacklist without holding kprobe_mutex. When a module is unloaded, kprobe_remove_area_blacklist() removes blacklist entries and immediately frees them with kfree(). A concurrent call to within_kprobe_blacklist() can therefore dereference freed memory.
Furthermore, within_kprobe_blacklist() can be called in atomic or non-preemptible contexts where the sleeping kprobe_mutex cannot be taken.
Protect kprobe_blacklist with RCU. Use guard(rcu)() and list_for_each_entry_rcu() for traversal, list_add_tail_rcu() for insertions, list_del_rcu() for deletions, and kfree_rcu() to reclaim entries safely after a grace period.
--- include/linux/kprobes.h | 1 + kernel/kprobes.c | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-)
include/linux/kprobes.h +1 -0
@@ -186,6 +186,7 @@ struct kprobe_blacklist_entry {struct list_head list;unsigned long start_addr;unsigned long end_addr; +struct rcu_head rcu; };#ifdef CONFIG_KPROBES
kernel/kprobes.c +10 -4
@@ -1394,8 +1394,14 @@ static bool __within_kprobe_blacklist(un/* * If 'kprobe_blacklist' is defined, check the address and * reject any probe registration in the prohibited area. +* Note: this can return true during transition period where +* (start_addr, end_addr) in the black list is shrinking +* but old entry has not been removed yet. This is acceptable +* because the worst case is that we reject more probes than +* we should. */ -list_for_each_entry (ent, &kprobe_blacklist, list) { +guard (rcu)(); +list_for_each_entry_rcu (ent, &kprobe_blacklist, list) {if (addr >= ent->start_addr && addr < ent->end_addr)return true; }
@@ -2487,7 +2493,7 @@ int kprobe_add_ksym_blacklist(unsigned l ent->start_addr = entry; ent->end_addr = entry + size;INIT_LIST_HEAD (&ent->list); -list_add_tail (&ent->list, &kprobe_blacklist); +list_add_tail_rcu (&ent->list, &kprobe_blacklist);return (int )size; }
@@ -2516,8 +2522,8 @@ static void kprobe_remove_area_blacklistlist_for_each_entry_safe (ent, n, &kprobe_blacklist, list) {if (ent->start_addr < start || ent->start_addr >= end)continue ; -list_del (&ent->list); -kfree (ent); +list_del_rcu (&ent->list); +kfree_rcu (ent, rcu); } }
Greg Kroah-Hartman
maintainerPATCH 362/1424 Input: aiptek - validate raw macro indices before updating state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 95dffe32a66cbed07fbfa7afed39d56d5014e04f ]
aiptek_irq() derives macro key indices directly from tablet reports and then uses them to index macroKeyEvents[]. Report types 4 and 5 also save the derived value in aiptek->lastMacro and later use that state to release the previous key.
Validate the raw macro index once before it enters that state machine, so lastMacro only ever stores an in-range macro key. Keep direct bounds checks for report type 6, which reads the macro number from the packet body and uses it immediately.
--- drivers/input/tablet/aiptek.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/input/tablet/aiptek.c +9 -4
@@ -658,6 +658,8 @@ static void aiptek_irq(struct urb *urb) pck = (data[1 ] & aiptek->curSetting.stylusButtonUpper) !=0 ?1 :0 ; macro = dv && p && tip && !(data[3 ] &1 ) ? (data[3 ] >>1 ) :-1 ; +if (macro >=ARRAY_SIZE (macroKeyEvents)) + macro =-1 ; z =get_unaligned_le16 (data +4 );if (dv) {
@@ -699,7 +701,9 @@ static void aiptek_irq(struct urb *urb) left = (data[1 ]& aiptek->curSetting.mouseButtonLeft) !=0 ?1 :0 ; right = (data[1 ] & aiptek->curSetting.mouseButtonRight) !=0 ?1 :0 ; middle = (data[1 ] & aiptek->curSetting.mouseButtonMiddle) !=0 ?1 :0 ; - macro = dv && p && left && !(data[3 ] &1 ) ? (data[3 ] >>1 ) :0 ; + macro = dv && p && left && !(data[3 ] &1 ) ? (data[3 ] >>1 ) :-1 ; +if (macro >=ARRAY_SIZE (macroKeyEvents)) + macro =-1 ;if (dv) {/* If the selected tool changed, reset the old
@@ -737,11 +741,11 @@ static void aiptek_irq(struct urb *urb)*/ else if (data[0] == 6) { macro =get_unaligned_le16 (data +1 ); -if (macro >0 ) { +if (macro >0 && macro -1 <ARRAY_SIZE (macroKeyEvents)) {input_report_key (inputdev, macroKeyEvents[macro -1 ],0 ); } -if (macro <25 ) { +if (macro +1 <ARRAY_SIZE (macroKeyEvents)) {input_report_key (inputdev, macroKeyEvents[macro +1 ],0 ); }
@@ -760,7 +764,8 @@ static void aiptek_irq(struct urb *urb) aiptek->curSetting.toolMode; } -input_report_key (inputdev, macroKeyEvents[macro],1 ); +if (macro <ARRAY_SIZE (macroKeyEvents)) +input_report_key (inputdev, macroKeyEvents[macro],1 );input_report_abs (inputdev,ABS_MISC ,1 |AIPTEK_REPORT_TOOL_UNKNOWN );input_sync (inputdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 363/1424 rtc: rzn1: Fix weekday underflow when alarm crosses month boundary
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lad Prabhakar <[email protected]>
commit 022a2839a52006531804a8db55d3228084400b48 upstream.
rzn1_rtc_set_alarm() calculates the alarm weekday from the difference between the alarm day and the current day of the month. When the alarm crosses a month boundary, this difference can become negative. Since days_ahead is unsigned, it underflows and results in an incorrect weekday being programmed into RZN1_RTC_ALW.
The RTC core already provides a fully populated struct rtc_time for the alarm, including the correct tm_wday. Use tm->tm_wday directly instead of recalculating the weekday from the day-of-month.
This avoids the underflow and ensures alarms scheduled across a month boundary use the correct weekday.
--- drivers/rtc/rtc-rzn1.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/rtc/rtc-rzn1.c +1 -6
@@ -219,7 +219,6 @@ static int rzn1_rtc_set_alarm(struct devstruct rzn1_rtc *rtc =dev_get_drvdata (dev);struct rtc_time *tm = &alrm->time, tm_now;unsigned long alarm, farest; -unsigned int days_ahead, wday;int ret; ret =rzn1_rtc_read_time (dev, &tm_now);
@@ -232,13 +231,9 @@ static int rzn1_rtc_set_alarm(struct devif (time_after (alarm, farest))return -ERANGE ; -/* Convert alarm day into week day */ - days_ahead = tm->tm_mday - tm_now.tm_mday; - wday = (tm_now.tm_wday + days_ahead) %7 ; -writel (bin2bcd (tm->tm_min), rtc->base +RZN1_RTC_ALM );writel (bin2bcd (tm->tm_hour), rtc->base +RZN1_RTC_ALH ); -writel (BIT (wday), rtc->base +RZN1_RTC_ALW ); +writel (BIT (tm->tm_wday), rtc->base +RZN1_RTC_ALW );rzn1_rtc_alarm_irq_enable (dev, alrm->enabled);
Greg Kroah-Hartman
maintainerPATCH 364/1424 rtc: rzn1: Disable alarm interrupt before reprogramming alarm registers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lad Prabhakar <[email protected]>
commit 51458d5b0a1cfb1b6013400abc95aadf16ed2a57 upstream.
rzn1_rtc_set_alarm() updates RZN1_RTC_ALM, RZN1_RTC_ALH and RZN1_RTC_ALW using separate MMIO writes without first disabling the alarm interrupt. If a previous alarm is still enabled, the interrupt can fire while the alarm registers contain a mixture of old and newly written values.
Fix this by disabling the alarm interrupt before reprogramming ALM, ALH and ALW with a call to rzn1_rtc_alarm_irq_enable().
--- drivers/rtc/rtc-rzn1.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/rtc/rtc-rzn1.c +5 -0
@@ -231,6 +231,11 @@ static int rzn1_rtc_set_alarm(struct devif (time_after (alarm, farest))return -ERANGE ; +/* Disable alarm interrupts before reprogramming the alarm. */ + ret =rzn1_rtc_alarm_irq_enable (dev,0 ); +if (ret) +return ret; +writel (bin2bcd (tm->tm_min), rtc->base +RZN1_RTC_ALM );writel (bin2bcd (tm->tm_hour), rtc->base +RZN1_RTC_ALH );writel (BIT (tm->tm_wday), rtc->base +RZN1_RTC_ALW );
Greg Kroah-Hartman
maintainerPATCH 365/1424 perf/x86/intel: Fix kernel address leakages in LBR stack
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
commit e2b0575900ff72aa82748af96e7bd564ade5157a upstream.
Before Arch LBR gained CPL filtering support, a user-only branch stack could still contain kernel addresses. As a result, kernel branch records may be exposed to user space even when PERF_SAMPLE_BRANCH_USER is requested.
For example, on Intel Tiger Lake, the following command can still report SYSRET/ERET entries with kernel-space from addresses:
$ ./perf record -e cycles:p -o - --branch-filter any,save_type,u -- \
./perf bench syscall basic --loop 1000 | \
./perf script -i - --fields brstack|tr ' ' '\n'| \
grep -E '0x[89a-f][0-9a-f]{15}' Total time: 0.000 [sec]
0.219000 usecs/op
4,566,210 ops/sec[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.551 MB - ] 0xffffffff93c001c8/0x7f12a2b1d647/P/-/-/16959/SYSRET/- 0xffffffff93c001c8/0x7f12a2b1d5c2/P/-/-/17535/SYSRET/- 0xffffffff93c01928/0x7f12a2861000/P/-/-/6719/ERET/- 0xffffffff93c01928/0x7f12a297a000/P/-/-/8575/ERET/-
The problem is that intel_pmu_lbr_filter() does not fully validate the privilege level of sampled entries. It filters some mismatches based on the branch type and the to address, but it does not reject entries whose from address violates the requested branch privilege filter.
Fix this by extending software filtering to validate both from and to addresses against br_sel. Any LBR entry contains kernel address does not match the requested user filter is dropped. This prevents kernel addresses from appearing in user-only branch stacks.
--- arch/x86/events/intel/lbr.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/events/intel/lbr.c +9 -3
@@ -1124,7 +1124,7 @@ intel_pmu_lbr_filter(struct cpu_hw_event {u64 from, to;int br_sel = cpuc->br_sel; -int i, j, type, to_plm; +int i, j, type, from_plm, to_plm;bool compress = false;/* if sampling all branches, then nothing to filter */
@@ -1156,8 +1156,14 @@ intel_pmu_lbr_filter(struct cpu_hw_event type |=X86_BR_NO_TX ; } -/* if type does not correspond, then discard */ -if (type ==X86_BR_NONE || (br_sel & type) != type) { + from_plm =kernel_ip (from) ?X86_BR_KERNEL :X86_BR_USER ; +/* +* If type does not correspond, then discard. +* Specifically reject entries whose from address is in +* kernel space when only X86_BR_USER is requested. +*/ +if (type ==X86_BR_NONE || (br_sel & type) != type || + (!(br_sel &X86_BR_KERNEL ) && (from_plm &X86_BR_KERNEL ))) { cpuc->lbr_entries[i].from =0 ; compress = true; }
Greg Kroah-Hartman
maintainerPATCH 366/1424 perf hisi-ptt: Fix PTT trace TLP header parsing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sizhe Liu <[email protected]>
commit 2b8a2e5d424f0b3369054305d0bf6a5b9faee6c1 upstream.
TLP Headers traced by HiSilicon PCIe tune and trace device (PTT) in 4DW format are shown in the document as below:
bits [31:30] [ 29:25 ][24][23][22][21][ 20:11 ][ 10:0 ]
|-----|---------|---|---|---|---|-------------|-------------|
DW0 [ Fmt ][ Type ][T9][T8][TH][SO][ Length ][ Time ]
DW1 [ Header DW1 ]
DW2 [ Header DW2 ]
DW3 [ Header DW3 ]Problem:
The DW0 bit field layout of the hisi_ptt_4dw union does not match the actual bit ordering in little-endian memory, causing incorrect field decoding.
Test on Kunpeng 930 SOC, generating data flow with iperf commands:
- server side:
iperf -s
- client side:
iperf -c $ip_addr -t 30
Trace the TLP headers with hisi_ptt on server side at the same time:
perf record -e hisi_ptt12_0/type=4,filter=0x05101,direction=2,format=0/ \
--max-size 50M -o perf.data &
The trace aims to capture completion TLPs, learn more in the document:
https://docs.kernel.org/trace/hisi-ptt.html
Decode perf.data with hisi_ptt decoder:
perf report -D
The hisi_ptt decoder produces the following result:
[...perf headers and other information]
. ... HISI PTT data: size 8388608 bytes
. 00000000: 68 87 20 94 Format 3 Type 1a T9 0 T8 1 TH 1 SO 1 Length 10 Time 4a1 . 00000004: 40 00 00 00 Header DW1 . 00000008: 40 00 01 51 Header DW2 . 0000000c: 00 00 00 00 Header DW3
[...other hisi_ptt TLP headers]
According to PCIe r5.0 sec 2.2.1, the Fmt & Type of Cpl/CplD is supposed to be 8b'00001010' / 8b'01001010'
However, the Format & Type decoder analyzing result is 8b'01111010'. It does not match field encodings of any TLP.
Correct decoder result should be:
[...perf headers and other information]
. ... HISI PTT data: size 8388608 bytes
. 00000000: 94 20 87 68 Format 2 Type a T9 0 T8 0 TH 0 SO 1 Length 10 Time 768 . 00000004: 00 00 00 40 Header DW1 . 00000008: 51 01 00 40 Header DW2 . 0000000c: 00 00 00 00 Header DW3
[...other hisi_ptt TLP headers]
To solve the problem:
1. Drop the union and C bitfield struct, store the raw DW value in a plain uint32_t, and extract the fields with FIELD_GET() against GENMASK/BIT masks declared in the header so they can be reused by other translation units. The masks are portable across endianness and compilers.
2. Print all DW hex values in big-endian byte order for readability, matching the bit field layout shown in the 4DW format diagram.
3. Read the DW value with get_unaligned_le32() instead of an unaligned pointer cast, avoiding both strict-aliasing violations and alignment hazards on hosts that do not support unaligned access.
--- Documentation/trace/hisi-ptt.rst | 28 ++++----- tools/perf/util/hisi-ptt-decoder/hisi-ptt-pkt-decoder.c | 47 ++++++++-------- tools/perf/util/hisi-ptt-decoder/hisi-ptt-pkt-decoder.h | 12 ++++ 3 files changed, 50 insertions(+), 37 deletions(-)
Documentation/trace/hisi-ptt.rst +14 -14
@@ -285,20 +285,20 @@ according to the format described previo [...perf headers and other information] . ... HISI PTT data: size 4194304 bytes . 00000000: 00 00 00 00 Prefix - . 00000004: 01 00 00 60 Header DW0 - . 00000008: 0f 1e 00 01 Header DW1 - . 0000000c: 04 00 00 00 Header DW2 - . 00000010: 40 00 81 02 Header DW3 - . 00000014: 33 c0 04 00 Time + . 00000004: 60 00 00 01 Header DW0 + . 00000008: 01 00 1e 0f Header DW1 + . 0000000c: 00 00 00 04 Header DW2 + . 00000010: 02 81 00 40 Header DW3 + . 00000014: 00 04 c0 33 Time . 00000020: 00 00 00 00 Prefix - . 00000024: 01 00 00 60 Header DW0 - . 00000028: 0f 1e 00 01 Header DW1 - . 0000002c: 04 00 00 00 Header DW2 - . 00000030: 40 00 81 02 Header DW3 - . 00000034: 02 00 00 00 Time + . 00000024: 60 00 00 01 Header DW0 + . 00000028: 01 00 1e 0f Header DW1 + . 0000002c: 00 00 00 04 Header DW2 + . 00000030: 02 81 00 40 Header DW3 + . 00000034: 00 00 00 02 Time . 00000040: 00 00 00 00 Prefix - . 00000044: 01 00 00 60 Header DW0 - . 00000048: 0f 1e 00 01 Header DW1 - . 0000004c: 04 00 00 00 Header DW2 - . 00000050: 40 00 81 02 Header DW3 + . 00000044: 60 00 00 01 Header DW0 + . 00000048: 01 00 1e 0f Header DW1 + . 0000004c: 00 00 00 04 Header DW2 + . 00000050: 02 81 00 40 Header DW3 [...]
tools/perf/util/hisi-ptt-decoder/hisi-ptt-pkt-decoder.c +24 -23
81 lines not on this page · raw message
tools/perf/util/hisi-ptt-decoder/hisi-ptt-pkt-decoder.h +12 -0
@@ -9,12 +9,24 @@#include <stddef.h> #include <stdint.h> +#include <linux/bits.h> +#include <linux/bitfield.h> #define HISI_PTT_8DW_CHECK_MASK GENMASK(31, 11)#define HISI_PTT_IS_8DW_PKT GENMASK(31, 11)#define HISI_PTT_MAX_SPACE_LEN 10#define HISI_PTT_FIELD_LENTH 4 +/* Header DW0 fields for 4DW format */ +#define HISI_PTT_HEAD0_4DW_TIME GENMASK_U32(10, 0) +#define HISI_PTT_HEAD0_4DW_LEN GENMASK_U32(20, 11) +#define HISI_PTT_HEAD0_4DW_SO BIT_U32(21) +#define HISI_PTT_HEAD0_4DW_TH BIT_U32(22) +#define HISI_PTT_HEAD0_4DW_T8 BIT_U32(23) +#define HISI_PTT_HEAD0_4DW_T9 BIT_U32(24) +#define HISI_PTT_HEAD0_4DW_TYPE GENMASK_U32(29, 25) +#define HISI_PTT_HEAD0_4DW_FORMAT GENMASK_U32(31, 30) +enum hisi_ptt_pkt_type {HISI_PTT_4DW_PKT ,HISI_PTT_8DW_PKT ,
Greg Kroah-Hartman
maintainerPATCH 367/1424 i2c: core: fix debugfs UAF on adapter removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasileios Almpanis <[email protected]>
commit b15b548d52b43ba8ac4652bc2c7244a8dd1e9622 upstream.
i2c_del_adapter() frees the adapter's debugfs directory before it unregisters the adapter device, but the new_device sysfs attribute stays writable until device_del(). A write racing with removal still reaches i2c_device_probe(), which passes the freed adap->debugfs to debugfs_create_dir() as the new client's parent:
BUG: KASAN: slab-use-after-free in lookup_noperm_common+0x407/0x430 Read of size 4 at addr ffff88803ef87810 by task syz.0.61/6090 lookup_noperm_common+0x407/0x430 simple_start_creating+0x9c/0x110 debugfs_start_creating+0xdb/0x1a0 debugfs_create_dir+0x24/0x350 i2c_device_probe+0x814/0xbf0
It's technically possible to create a client after i2c_deregister_clients has run. That client will never be unregistered and make wait_for_completion hang.
Close the window by removing the new_device attribute at the start of i2c_del_adapter(). device_remove_file() will drain any clients left.
--- drivers/i2c/i2c-core-base.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/i2c/i2c-core-base.c +6 -0
@@ -1808,6 +1808,12 @@ void i2c_del_adapter(struct i2c_adapterreturn ; } +/* +* This drains any in-flight writers, so all +* clients will be caught by i2c_deregister_clients(). +*/ +device_remove_file (&adap->dev, &dev_attr_new_device); +i2c_acpi_remove_space_handler (adap);i2c_deregister_clients (adap);
Greg Kroah-Hartman
maintainerPATCH 368/1424 i2c: mux: Fix channel node leak on adapter add failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmad Byagowi <[email protected]>
commit 385c7af4e3b95d0769fd211831674e83b16a2ebf upstream.
i2c_mux_add_adapter() takes a reference to the Device Tree channel node before registering the new adapter. If adapter registration fails, the error path frees the private data without dropping that reference.
Release the channel node before freeing the private data.
--- drivers/i2c/i2c-mux.c | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/i2c-mux.c +1 -0
@@ -433,6 +433,7 @@ int i2c_mux_add_adapter(struct i2c_mux_creturn 0 ; err_free_priv: +of_node_put (priv->adap.dev.of_node);kfree (priv);return ret; }
Greg Kroah-Hartman
maintainerPATCH 369/1424 arm64: mm: Fix the lockless page-table walk in show_pte()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit a77644d009dece1104b6fcc6e322b0e4503db0d6 upstream.
show_pte() walks page tables locklessly and can run with interrupts enabled. A concurrent teardown can free a table page while it is being walked. It can also clear a parent entry after show_pte() checked it; the regular pXd_offset() helpers then reread the cleared entry and can derive a bogus lower-level pointer and fault again.
Use the lockless offset helpers with the saved parent entries, as gup_fast() does, and pass the saved PMD to pte_offset_map().
For task page tables, arm64 selects MMU_GATHER_RCU_TABLE_FREE. Disable local interrupts around the walk to hold off RCU-deferred table frees and block the tlb_remove_table_sync_one() IPI until the walk is finished.
Place the IRQ guard after the header print. This does not make the output a consistent snapshot, but prevents the task page-table walk from dereferencing a released table page or deriving a pointer from a different parent value.
--- arch/arm64/mm/fault.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
arch/arm64/mm/fault.c +8 -4
@@ -15,6 +15,7 @@#include <linux/mm.h> #include <linux/hardirq.h> #include <linux/init.h> +#include <linux/irqflags.h> #include <linux/kasan.h> #include <linux/kprobes.h> #include <linux/uaccess.h>
@@ -156,6 +157,9 @@ static void show_pte(unsigned long addr)pr_alert ("%s pgtable: %luk pages, %llu-bit VAs, pgdp=%016lx\n" , mm == &init_mm ?"swapper" :"user" ,PAGE_SIZE /SZ_1K , vabits_actual,mm_to_pgd_phys (mm)); + +guard (irqsave)(); + pgdp =pgd_offset (mm, addr); pgd =READ_ONCE (*pgdp);pr_alert ("[%016lx] pgd=%016llx" , addr,pgd_val (pgd));
@@ -169,25 +173,25 @@ static void show_pte(unsigned long addr)if (pgd_none (pgd) ||pgd_bad (pgd))break ; - p4dp =p4d_offset (pgdp, addr); + p4dp =p4d_offset_lockless (pgdp, pgd, addr); p4d =READ_ONCE (*p4dp);pr_cont (", p4d=%016llx" ,p4d_val (p4d));if (p4d_none (p4d) ||p4d_bad (p4d))break ; - pudp =pud_offset (p4dp, addr); + pudp =pud_offset_lockless (p4dp, p4d, addr); pud =READ_ONCE (*pudp);pr_cont (", pud=%016llx" ,pud_val (pud));if (pud_none (pud) ||pud_bad (pud))break ; - pmdp =pmd_offset (pudp, addr); + pmdp =pmd_offset_lockless (pudp, pud, addr); pmd =READ_ONCE (*pmdp);pr_cont (", pmd=%016llx" ,pmd_val (pmd));if (pmd_none (pmd) ||pmd_bad (pmd))break ; - ptep =pte_offset_map (pmdp, addr); + ptep =pte_offset_map (&pmd, addr);if (!ptep)break ;
Greg Kroah-Hartman
maintainerPATCH 370/1424 ALSA: harmony: initialize locks before requesting IRQ
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 33abb7491e89285a41565670945293dda841afc4 upstream.
snd_harmony_create() registers the IRQ before initializing h->lock and h->mixer_lock. A pending interrupt can invoke the handler while these locks are uninitialized.
Initialize both locks before requesting the IRQ so the handler always sees valid lock state.
--- sound/parisc/harmony.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/parisc/harmony.c +3 -3
@@ -889,6 +889,9 @@ snd_harmony_create(struct snd_card *card goto free_and_ret; } +spin_lock_init (&h->mixer_lock); +spin_lock_init (&h->lock); + err =request_irq (padev->irq, snd_harmony_interrupt,0 ,"harmony" , h);if (err) {
@@ -898,9 +901,6 @@ snd_harmony_create(struct snd_card *card } h->irq = padev->irq; -spin_lock_init (&h->mixer_lock); -spin_lock_init (&h->lock); - err =snd_device_new (card,SNDRV_DEV_LOWLEVEL , h, &ops);if (err <0 ) goto free_and_ret;
Greg Kroah-Hartman
maintainerPATCH 371/1424 ALSA: pcm: Fix race between non-atomic ops and trigger-start
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit acac7b5e07349a9d10d78873afb4b93cd1dc721f upstream.
We protect the races of the concurrent state transitions between atomic PCM ops, but the checks between the non-atomic ops (hw_params, hw_free and prepare) and the atomic ops aren't perfect; there is a check of the conflicting PCM state at the beginning of hw_params & co, but the atomic PCM ops can be still issued during the non-atomic PCM operations. An example such scenario is that a thread A re-issues the PREPARE or HW_PARAMS for the already prepared stream, while another thread B triggers the PCM start in the middle of the prepare operation. Although this usually doesn't lead to much serious issues, it can give some inconsistency as reported by syzkaller (such as ODEBUG warning).
There are various atomic PCM ops, and basically the only problem is the PCM start as it operates from the PREPARED state. Other trigger commands (stop, etc) are for the running or the other special state, hence they are filtered as pre-condition.
This patch is for preventing the PCM trigger-start during the non- atomic operations in order to address the problems above. Fortunately, the hw_params, hw_free and prepare operations call snd_pcm_buffer_access_lock(), and this can be used for checking the concurrent operations at the PCM trigger -- which sets the runtime->buffer_accessing to a negative (if possible), so the PCM trigger just needs to check the runtime->buffer_accessing value; if it's negative, it means the concurrent non-atomic PCM ops is running.
--- sound/core/pcm_native.c | 2 ++ 1 file changed, 2 insertions(+)
sound/core/pcm_native.c +2 -0
@@ -1430,6 +1430,8 @@ static int snd_pcm_pre_start(struct snd_struct snd_pcm_runtime *runtime = substream->runtime;if (runtime->state !=SNDRV_PCM_STATE_PREPARED )return -EBADFD ; +if (atomic_read (&runtime->buffer_accessing) <0 ) +return -EBADFD ;/* during hw_params, hw_free or prepare */ if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK && !snd_pcm_playback_data (substream))return -EPIPE ;
Greg Kroah-Hartman
maintainerPATCH 372/1424 nvme-tcp: check the data direction of a C2HData PDU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit f83af377c148f6ad94b41c0e8313f12adf45e1c1 upstream.
nvme_tcp_handle_c2h_data() finds the request by command id and checks that it has a payload, but it does not check that the command asked for data to be read. A controller that answers a write command with C2HData therefore reaches nvme_tcp_recv_data(), where _copy_to_iter() hits WARN_ON_ONCE(i->data_source) and returns 0. The receive path turns that into -EFAULT and resets the controller.
No data is copied, so this is not memory corruption. What a controller gets is a kernel warning it can raise at will, which is fatal on a host booted with panic_on_warn.
The send path already knows the direction - it consults rq_data_dir() when it builds a command - and nvme_tcp_handle_r2t() checks the length and the offset of the request it names. The C2HData path does not check the direction at all.
Reject a C2HData PDU whose command is not a read. Rejecting it fails the command and resets the controller, as the neighbouring check in this function does; what goes away is the warning.
[ 6.885580] ------------[ cut here ]------------ [ 6.886457] WARNING: lib/iov_iter.c:193 at _copy_to_iter+0x289/0x1330, CPU#0: kworker/0:1H/71 [ 6.888137] CPU: 0 UID: 0 PID: 71 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMETCP-gf5098b6bae76 #1 PREEMPT(lazy) [ 6.891165] Workqueue: nvme_tcp_wq nvme_tcp_io_work [ 6.891875] RIP: 0010:_copy_to_iter+0x289/0x1330 [ 6.903739] Call Trace: [ 6.904085] <TASK> [ 6.909254] __skb_datagram_iter+0x433/0x820 [ 6.911026] skb_copy_datagram_iter+0x37/0x120 [ 6.911622] nvme_tcp_recv_skb+0xa07/0x4320 [ 6.913378] __tcp_read_sock+0x1ab/0x810 [ 6.915788] nvme_tcp_try_recv+0x152/0x1e0 [ 6.918222] nvme_tcp_io_work+0x1e4/0x6c0 [ 6.926906] </TASK> [ 6.927226] ---[ end trace 0000000000000000 ]--- [ 6.927878] nvme nvme0: queue 1 failed to copy request 0x71 data [ 6.928709] nvme nvme0: receive failed: -14
--- drivers/nvme/host/tcp.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/nvme/host/tcp.c +7 -0
@@ -609,6 +609,13 @@ static int nvme_tcp_handle_c2h_data(strureturn -ENOENT ; } +if (rq_data_dir (rq) !=READ ) { +dev_err (queue->ctrl->ctrl.device, +"queue %d tag %#x unexpected data for a write\n" , +nvme_tcp_queue_id (queue), rq->tag); +return -EIO ; + } + req =blk_mq_rq_to_pdu (rq);if (!blk_rq_payload_bytes (rq) || !req->curr_bio || !req->data_len) { dev_err(queue->ctrl->ctrl.device,
Greg Kroah-Hartman
maintainerPATCH 373/1424 nvmet-tcp: fix out-of-bounds write when receiving an over-long PDU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivam Kumar <[email protected]>
commit 14cc5a7e77731497d5bea70f3bb05df7eda982e4 upstream.
nvmet_tcp_try_recv_pdu() reads a PDU header into the fixed 128-byte queue->pdu union, then computes the remaining payload length as
queue->left = hdr->hlen - queue->offset + hdgst;
and reads that many more bytes into &queue->pdu + queue->offset, without ever bounding the result against sizeof(queue->pdu).
A struct nvme_tcp_icreq_pdu is itself 128 bytes, exactly the size of the union. Once a header digest has been negotiated (hdgst = 4), a second ICReq passes the hlen == nvmet_tcp_pdu_size() check but yields queue->left = 128 - 8 + 4 = 124, so bytes 8..132 are written into the 128-byte buffer -- 4 bytes past its end, over queue->hdr_digest and queue->data_digest. Those bytes are attacker-controlled (an ICReq carries no digest), and the duplicate ICReq is only rejected later, after the overflow. A remote unauthenticated host can thus corrupt kernel memory adjacent to the receive buffer.
Reject any PDU whose declared length would read past the end of queue->pdu before the second recv.
--- drivers/nvme/target/tcp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/nvme/target/tcp.c +2 -0
@@ -1231,6 +1231,8 @@ recv: } queue->left = hdr->hlen - queue->offset + hdgst; +if (queue->left >sizeof (queue->pdu) - queue->offset) +return -EPROTO ; goto recv; }
Greg Kroah-Hartman
maintainerPATCH 374/1424 nvmet-tcp: reject unsolicited H2CData PDUs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivam Kumar <[email protected]>
commit db62b35cbca052860c519cbcabe7650708528738 upstream.
nvmet_tcp_handle_h2c_data_pdu() accepts an H2CData PDU after only checking that its TTAG is a valid in-range command index and that the command's data buffers are mapped. It never checks that the target has actually solicited that data by sending an R2T for the command.
A remote host can abuse this. It submits a write command that takes the R2T path and, before the target transmits the R2T, sends an H2CData PDU for that command's tag. The data completes the command early, and when the command then fails synchronously (e.g. a length mismatch caught by nvmet_check_transfer_len()), it is completed a second time. Each completion calls nvmet_tcp_queue_response(), so the same command is added to queue->resp_list twice while it is still linked; the second llist_add() makes the node point to itself (lentry->next == lentry).
nvmet_tcp_process_resp_list() then walks that self-referential node and adds the command to resp_send_list twice. With CONFIG_DEBUG_LIST this trips the "list_add double add" check (kernel BUG); without it the loop never terminates and the nvmet_tcp workqueue wedges (soft-lockup). It is remotely triggerable and needs no authentication on an allow_any_host subsystem.
Track whether an R2T has been transmitted for a command and reject an H2CData PDU that arrives before it. The flag is cleared on command reuse (nvmet_tcp_get_cmd() zeroes cmd->flags) and stays set across the multiple H2CData PDUs of a single solicited transfer.
--- drivers/nvme/target/tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/nvme/target/tcp.c +8 -0
@@ -88,6 +88,7 @@ enum nvmet_tcp_recv_state {enum {NVMET_TCP_F_INIT_FAILED = (1 <<0 ), +NVMET_TCP_F_R2T_SENT = (1 <<1 ), };struct nvmet_tcp_cmd {
@@ -761,6 +762,7 @@ static int nvmet_try_send_r2t(struct nvmreturn -EAGAIN ; cmd->queue->snd_cmd =NULL ; + cmd->flags |=NVMET_TCP_F_R2T_SENT ;return 1 ; }
@@ -1036,6 +1038,12 @@ static int nvmet_tcp_handle_h2c_data_pdu cmd = &queue->connect; } +if (unlikely (!(cmd->flags &NVMET_TCP_F_R2T_SENT ))) { +pr_err ("queue %d: unsolicited H2CData (ttag %u)\n" , + queue->idx, data->ttag); + goto err_proto; + } +if (le32_to_cpu (data->data_offset) != cmd->rbytes_done) { pr_err("ttag %u unexpected data offset %u (expected %u)\n", data->ttag, le32_to_cpu(data->data_offset),
Greg Kroah-Hartman
maintainerPATCH 375/1424 Revert "irqchip/mbigen: Fix mbigen node address layout"
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: caina <[email protected]>
commit e67091609cf85962f64391c1b0f93d4cbfcd4e22 upstream.
This reverts commit 6be6cba9c4371d27f78d900ccfe34bb880d9ee20.
Commit 6be6cba9c437 ("irqchip/mbigen: Fix mbigen node address layout") appears to cause a regression on Hi1616.
On-board hns NIC has two ports, enahisic2i0 and enahisic2i1, both behind mbigen-v2. Port 0 works; port 1 cannot pass any traffic.
Their interrupt pins fall on different mbigen nodes:
enahisic2i0: pins 1152-1198 -> all in node 9
enahisic2i1: pins 1200-1246 -> node 9 (1200-1215) + node 10 (1216-1246)
(nid = (hwirq - 64) / 128 + 1; pin 1215 = node 9, pin 1216 = node 10)
/proc/interrupts shows the break happens exactly at the node boundary:
enahisic2i1-rx0 pin 1200 count 102 <- node 9 enahisic2i1-rx5 pin 1215 count 1 <- node 9, last pin enahisic2i1-tx5 pin 1216 count 0 <- node 10, first pin enahisic2i1-rx6 pin 1218 count 0 <- node 10
...all node 10 pins stay at zero.
Port 0 (entirely node 9) is unaffected. Reverting the commit restores normal operation.
The commit assumes CLEAR occupies a full 4 KB page at [0xa000, 0xb000) and collides with node 10, so node 10+ gets shifted by 0x1000.
But get_mbigen_clear_reg() uses flat, chip-wide addressing -- it never multiplies by the node ID:
*addr = (hwirq / 32) * 4 + REG_MBIGEN_CLEAR_OFFSET; /* 0xa000 */
Over the valid hwirq range [64, 1407], CLEAR only spans 0xa008-0xa0af (168 bytes). Node 10's registers are:
TYPE: 0xa000-0xa00f (16 B) overlaps CLEAR by 8 B (0xa008-0xa00f)
VEC: 0xa200-0xa3ff (512 B) no overlap with CLEARShifting the whole page moves VEC from 0xa200 to 0xb200. The hardware reads the event ID from the fixed silicon address 0xa200 on interrupt firing, but software wrote it to 0xb200 -- so the hardware gets an uninitialised value and the interrupt is lost.
The only real overlap is 8 bytes of TYPE. It can only trigger when a single mbigen instance has devices on both node 1 (CLEAR 0xa008) and node 10 (TYPE 0xa008). On Hi1616 those nodes are on separate mbigen instances, so it never triggers.
--- drivers/irqchip/irq-mbigen.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
drivers/irqchip/irq-mbigen.c +4 -16
@@ -64,20 +64,6 @@ struct mbigen_device {void __iomem *base; }; -static inline unsigned int get_mbigen_node_offset (unsigned int nid) -{ -unsigned int offset = nid *MBIGEN_NODE_OFFSET ; - -/* -* To avoid touched clear register in unexpected way, we need to directly -* skip clear register when access to more than 10 mbigen nodes. -*/ -if (nid >= (REG_MBIGEN_CLEAR_OFFSET /MBIGEN_NODE_OFFSET )) - offset +=MBIGEN_NODE_OFFSET ; - -return offset; -} -static inline unsigned int get_mbigen_vec_reg (irq_hw_number_t hwirq) {unsigned int nid, pin;
@@ -86,7 +72,8 @@ static inline unsigned int get_mbigen_ve nid = hwirq /IRQS_PER_MBIGEN_NODE +1 ; pin = hwirq %IRQS_PER_MBIGEN_NODE ; -return pin *4 +get_mbigen_node_offset (nid) +REG_MBIGEN_VEC_OFFSET ; +return pin *4 + nid *MBIGEN_NODE_OFFSET + +REG_MBIGEN_VEC_OFFSET ; } static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
@@ -101,7 +88,8 @@ static inline void get_mbigen_type_reg(i *mask =1 << (irq_ofst %32 ); ofst = irq_ofst /32 *4 ; - *addr = ofst +get_mbigen_node_offset (nid) +REG_MBIGEN_TYPE_OFFSET ; + *addr = ofst + nid *MBIGEN_NODE_OFFSET + +REG_MBIGEN_TYPE_OFFSET ; } static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
Greg Kroah-Hartman
maintainerPATCH 376/1424 mm/hugetlb: fix missing migratable flag on same-node hugetlb migration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wupeng Ma <[email protected]>
commit 8ee1ef0f2f8ce29338f4ab00a3d344c010208058 upstream.
Commit ba23f58de896 ("mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio") moved setting of the migratable flag and active-list placement from folio_putback_active_hugetlb(dst) into move_hugetlb_state(), so that the freshly allocated destination folio is handled where allocation is known to have succeeded.
Unfortunately, the new code was appended after the existing temporary-folio block in move_hugetlb_state(), which contains an early return added earlier by commit 5af1ab1d24e08 ("mm/hugetlb: optimize the surplus state transfer code in move_hugetlb_state()"):
if (folio_test_hugetlb_temporary(new_folio)) {
...
if (new_nid == old_nid)
return; <-- skips the new code
...
}
/* added by ba23f58 */
folio_set_hugetlb_migratable(new_folio);
list_move_tail(&new_folio->lru, ...&h->hugepage_activelist);When the destination folio is temporary (i.e. the hugetlb pool was exhausted and the migration callback fell back to alloc_migrate_hugetlb_folio()) and the migration does not cross a node -- the common case, and always true on a single-NUMA system -- move_hugetlb_state() returns before setting the migratable flag or adding the new folio to the active list. The destination folio is then installed in the page table but cannot be isolated afterwards, since folio_isolate_hugetlb() rejects folios without the migratable flag; a subsequent soft-offline, hard-offline or memory-hotplug offline of that folio fails with -EBUSY.
This was reproduced on a single-NUMA arm64 VM: a second MADV_SOFT_OFFLINE on an already-migrated hugetlb page returned EBUSY and logged "hugepage isolation failed".
Keep the surplus adjustment, which is the only part that depends on the node crossing, guarded by `if (new_nid != old_nid)', while making the migratable flag and active-list placement unconditional. This preserves the cleanup intent of ba23f58 and closes the early-return hole.
--- mm/hugetlb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
mm/hugetlb.c +7 -7
@@ -7353,14 +7353,14 @@ void move_hugetlb_state(struct folio *ol* There is no need to transfer the per-node surplus state * when we do not cross the node. */ -if (new_nid == old_nid) -return ; -spin_lock_irq (&hugetlb_lock); -if (h->surplus_huge_pages_node[old_nid]) { - h->surplus_huge_pages_node[old_nid]--; - h->surplus_huge_pages_node[new_nid]++; +if (new_nid != old_nid) { +spin_lock_irq (&hugetlb_lock); +if (h->surplus_huge_pages_node[old_nid]) { + h->surplus_huge_pages_node[old_nid]--; + h->surplus_huge_pages_node[new_nid]++; + } +spin_unlock_irq (&hugetlb_lock); } -spin_unlock_irq (&hugetlb_lock); }/*
Greg Kroah-Hartman
maintainerPATCH 377/1424 nvdimm/btt: reject an arena whose nfree is below the lane count
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 6a1f2e5ed9267ca19187038ac635393c165213ac upstream.
The BTT info block's nfree field, the number of reserve free blocks, is read from the medium without validation. btt_freelist_init() and btt_rtt_init() size the per-lane freelist[] and rtt[] arrays by nfree, but the I/O path indexes them by the lane from nd_region_acquire_lane(), which is bounded by nd_region->num_lanes (ND_MAX_LANES), not by nfree. A crafted or foreign arena whose nfree is below the lane count makes freelist[lane]/rtt[lane] run past the allocation: an out-of-bounds write.
btt.rst documents the nlanes = min(nfree, num_cpus) invariant, which the code does not currently honor: num_lanes is ND_MAX_LANES regardless of nfree. Reject an arena whose nfree is below num_lanes at discovery, before the per-lane arrays are allocated, enforcing that invariant.
--- drivers/nvdimm/btt.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/nvdimm/btt.c +8 -0
@@ -886,6 +886,14 @@ static int discover_arenas(struct btt *b arena->external_lba_start = cur_nlba;parse_arena_meta (arena, super, cur_off); +if (arena->nfree < btt->nd_region->num_lanes) { +dev_err (to_dev (arena), +"nfree %u smaller than lane count %d\n" , + arena->nfree, btt->nd_region->num_lanes); + ret = -ENODEV ; + goto out; + } + ret =log_set_indices (arena);if (ret) { dev_err(to_dev(arena),
Greg Kroah-Hartman
maintainerPATCH 378/1424 parisc: eisa: Fix infinite loop when parsing invalid IRQ value
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pei Xiao <[email protected]>
commit 8b585431a16cfb9d8f2955a9fa0787ce3dceb3c2 upstream.
When an invalid value is passed via the "eisa_irq_edge=" kernel command line parameter (e.g. "eisa_irq_edge=16,5"), eisa_irq_setup() prints an error message and continues without advancing the current position. As a result the same invalid value is parsed again and again, causing an infinite loop while the kernel boots.
Advance to the next comma-separated entry, or stop parsing when there is no next entry, before continuing so that the remaining entries are processed normally.
--- drivers/parisc/eisa.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/parisc/eisa.c +5 -0
@@ -442,6 +442,11 @@ static int __init eisa_irq_setup(char *s val = (int )simple_strtoul (cur, &pe,0 );if (val >15 || val <0 ) {printk (KERN_ERR "eisa: EISA irq value are 0-15\n" ); + cur =strchr (cur,',' ); +if (cur) + cur++; +else +break ;continue ; }if (val ==2 ) {
Greg Kroah-Hartman
maintainerPATCH 379/1424 parisc: Fix alignment of asm statements in head.S
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit 04cf68c9a76e3c6b67ad056a66a14923abf85925 upstream.
All assembler statements need to be 4-byte aligned. Prevent a possible misalignment if someone changes the preceeding string and it's length is then suddenly not a multiple of 4 any longer.
--- arch/parisc/kernel/head.S | 1 + 1 file changed, 1 insertion(+)
arch/parisc/kernel/head.S +1 -0
@@ -105,6 +105,7 @@ $iodc_panic: or %r10,%r10,%r10 /* qemu idle sleep */ msg1: .ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n" msg1_end: + .align 4 $cpu_ok: #endif
Greg Kroah-Hartman
maintainerPATCH 380/1424 powerpc/mm: fix wrong addr_pfn tracking in compound vmemmap population
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <[email protected]>
commit 89a4ae32764172468dea303eb6ae90fe6c859712 upstream.
vmemmap_populate_compound_pages() uses addr_pfn to determine the PFN offset within a compound page and to decide whether the current vmemmap slot should be populated as a head page mapping or should reuse a tail page mapping.
However, addr_pfn is advanced manually in parallel with addr. The loop itself progresses in vmemmap address space, so each PAGE_SIZE step in addr covers PAGE_SIZE / sizeof(struct page) struct page slots. Since addr_pfn is compared against nr_pages in data-PFN units, it should advance by the same number of PFNs. The existing manual increments do not match that and therefore do not reliably track the PFN corresponding to the current addr.
As a result, pfn_offset can be computed from the wrong PFN and the code can make the head/tail decision for the wrong compound-page position.
Fix this by deriving addr_pfn directly from the current vmemmap address instead of carrying it as loop state.
--- arch/powerpc/mm/book3s64/radix_pgtable.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
arch/powerpc/mm/book3s64/radix_pgtable.c +1 -6
@@ -1318,7 +1318,6 @@ int __meminit vmemmap_populate_compound_* covering out both edges. */ unsigned long addr; -unsigned long addr_pfn = start_pfn;unsigned long next;pgd_t *pgd;p4d_t *p4d;
@@ -1339,7 +1338,6 @@ int __meminit vmemmap_populate_compound_if (pmd_leaf (READ_ONCE (*pmd))) {/* existing huge mapping. Skip the range */ - addr_pfn += (PMD_SIZE >>PAGE_SHIFT ); next =pmd_addr_end (addr, end);continue ; }
@@ -1352,11 +1350,11 @@ int __meminit vmemmap_populate_compound_* page whose VMEMMAP_RESERVE_NR pages were mapped and * this request fall in those pages. */ - addr_pfn +=1 ; next = addr +PAGE_SIZE ;continue ; }else {unsigned long nr_pages =pgmap_vmemmap_nr (pgmap); +unsigned long addr_pfn =page_to_pfn ((struct page *)addr);unsigned long pfn_offset = addr_pfn -ALIGN_DOWN (addr_pfn, nr_pages);pte_t *tail_page_pte;
@@ -1380,7 +1378,6 @@ int __meminit vmemmap_populate_compound_if (!pte)return -ENOMEM ; - addr_pfn +=2 ; next = addr +2 *PAGE_SIZE ;continue ; }
@@ -1396,7 +1393,6 @@ int __meminit vmemmap_populate_compound_return -ENOMEM ;vmemmap_verify (pte, node, addr, addr +PAGE_SIZE ); - addr_pfn +=1 ; next = addr +PAGE_SIZE ;continue ; }
@@ -1406,7 +1402,6 @@ int __meminit vmemmap_populate_compound_return -ENOMEM ;vmemmap_verify (pte, node, addr, addr +PAGE_SIZE ); - addr_pfn +=1 ; next = addr +PAGE_SIZE ;continue ; }
Greg Kroah-Hartman
maintainerPATCH 381/1424 powerpc/pseries: Handle and log pseries-wdt registration failures
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sourabh Jain <[email protected]>
commit e65b526affa621b50646cafdf6b06505af07032e upstream.
The pseries watchdog initialization registers the pseries-wdt platform device using platform_device_register_simple(), but currently ignores its return value.
Check the returned pointer for errors, log a descriptive error message when registration fails, and propagate the failure code to the caller. This avoids silently ignoring platform device registration failures.
--- arch/powerpc/platforms/pseries/setup.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pseries/setup.c +12 -2
@@ -193,8 +193,18 @@ static void __init fwnmi_init(void)*/ static __init int pseries_wdt_init (void ) { -if (firmware_has_feature (FW_FEATURE_WATCHDOG )) -platform_device_register_simple ("pseries-wdt" ,0 ,NULL ,0 ); +struct platform_device *pdev; + +if (!firmware_has_feature (FW_FEATURE_WATCHDOG )) +return 0 ; + + pdev =platform_device_register_simple ("pseries-wdt" ,0 ,NULL ,0 ); + +if (IS_ERR (pdev)) { +pr_err ("Failed to register pseries-wdt platform device\n" ); +return PTR_ERR (pdev); + } +return 0 ; }machine_subsys_initcall (pseries, pseries_wdt_init);
Greg Kroah-Hartman
maintainerPATCH 382/1424 powerpc/pseries: Move H_WATCHDOG definitions to a common header
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sourabh Jain <[email protected]>
commit 516a254918453ec99660201263d01189c082332c upstream.
The H_WATCHDOG input and output definitions are currently local to the pseries watchdog driver. The next patch in this series also needs these definitions to issue H_WATCHDOG hypercalls outside the watchdog driver.
Move the H_WATCHDOG definitions to a new common header, asm/papr-watchdog.h, so they can be shared without duplicating the PAPR watchdog definitions.
No functional changes.
--- arch/powerpc/include/asm/papr-watchdog.h | 58 +++++++++++++++++++++++++++++++ drivers/watchdog/pseries-wdt.c | 53 ---------------------------- 2 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 arch/powerpc/include/asm/papr-watchdog.h
arch/powerpc/include/asm/papr-watchdog.h new file +58 -0
@@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_POWERPC_PAPR_WATCHDOG_H +#define _ASM_POWERPC_PAPR_WATCHDOG_H + +/* +* H_WATCHDOG Input +* +* R4: "flags": +* +* Bits 48-55: "operation" +*/ +#define PSERIES_WDTF_OP_START 0x100UL/* start timer */ +#define PSERIES_WDTF_OP_STOP 0x200UL/* stop timer */ +#define PSERIES_WDTF_OP_QUERY 0x300UL/* query timer capabilities */ + +/* +* Bits 56-63: "timeoutAction" (for "Start Watchdog" only) +*/ +#define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL/* poweroff */ +#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL/* restart */ +#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL/* dump + restart */ + +/* +* H_WATCHDOG Output +* +* R3: Return code +* +* H_SUCCESS The operation completed. +* +* H_BUSY The hypervisor is too busy; retry the operation. +* +* H_PARAMETER The given "flags" are somehow invalid. Either the +* "operation" or "timeoutAction" is invalid, or a +* reserved bit is set. +* +* H_P2 The given "watchdogNumber" is zero or exceeds the +* supported maximum value. +* +* H_P3 The given "timeoutInMs" is below the supported +* minimum value. +* +* H_NOOP The given "watchdogNumber" is already stopped. +* +* H_HARDWARE The operation failed for ineffable reasons. +* +* H_FUNCTION The H_WATCHDOG hypercall is not supported by this +* hypervisor. +* +* R4: +* +* - For the "Query Watchdog Capabilities" operation, a 64-bit +* structure: +*/ +#define PSERIES_WDTQ_MIN_TIMEOUT (cap) (((cap) >> 48) & 0xffff) +#define PSERIES_WDTQ_MAX_NUMBER (cap) (((cap) >> 32) & 0xffff) + +#endif /* _ASM_POWERPC_PAPR_WATCHDOG_H */
drivers/watchdog/pseries-wdt.c +1 -52
62 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 383/1424 powerpc/crash: stop watchdogs before booting kdump kernel
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sourabh Jain <[email protected]>
commit fb43ba4256543ce18ca0540fc37022bda438a293 upstream.
On pseries LPAR systems, watchdog timers configured from userspace can remain active after a kernel panic. When a panic triggers kdump, the crashing kernel jumps directly to the kdump kernel without stopping active watchdogs. As a result, the watchdogs remain active after the kdump kernel starts.
If dump capture takes longer than the watchdog timeout, PHYP resets the LPAR before the dump is fully captured, causing dump capture to fail.
Fix this by issuing the H_WATCHDOG hcall during the crash shutdown sequence to stop all active watchdogs before booting the kdump kernel.
--- arch/powerpc/include/asm/papr-watchdog.h | 6 ++++++ arch/powerpc/platforms/pseries/setup.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+)
arch/powerpc/include/asm/papr-watchdog.h +6 -0
@@ -22,6 +22,12 @@#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL/* dump + restart */ /* +* R5: "watchdogNumber": +* PAPR says use -1 (all ones) to stop all watchdogs. +*/ +#define PSERIES_WDT_NUM_ALL ((unsigned long)-1) + +/* * H_WATCHDOG Output * * R3: Return code
arch/powerpc/platforms/pseries/setup.c +14 -0
@@ -76,6 +76,7 @@#include <asm/dtl.h> #include <asm/hvconsole.h> #include <asm/setup.h> +#include <asm/papr-watchdog.h> #include "pseries.h"
@@ -187,6 +188,16 @@ static void __init fwnmi_init(void)#endif } +static void pseries_crash_stop_watchdogs (void ) +{ +long rc; + + rc =plpar_hcall_norets_notrace (H_WATCHDOG ,PSERIES_WDTF_OP_STOP , +PSERIES_WDT_NUM_ALL ); +if (rc !=H_SUCCESS && rc !=H_NOOP ) +pr_warn ("Could not stop watchdogs before kdump rc=%ld\n" , rc); +} +/* * Affix a device for the first timer to the platform bus if * we have firmware support for the H_WATCHDOG hypercall.
@@ -205,6 +216,9 @@ static __init int pseries_wdt_init(void)return PTR_ERR (pdev); } +if (crash_shutdown_register (pseries_crash_stop_watchdogs)) +pr_warn ("Could not register watchdog crash shutdown handler\n" ); +return 0 ; }machine_subsys_initcall (pseries, pseries_wdt_init);
Greg Kroah-Hartman
maintainerPATCH 384/1424 s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 4400270ec0348d05dc0439d8f0130853ce7f9e20 upstream.
In vfio_ap_mdev_set_kvm(), kvm->arch.crypto.pqap_hook is set to &matrix_mdev->pqap_hook before the update locks are acquired and the mdev list is checked for a conflicting assignment. If another mdev is already attached to the same KVM instance, the function returns -EPERM without restoring the hook pointer, leaving kvm->arch.crypto.pqap_hook pointing at the failing matrix_mdev instead of the mdev that legitimately owns the KVM.
Since matrix_mdev->kvm is never set on this error path, vfio_ap_mdev_unset_kvm() will not clean up the hook when matrix_mdev is later closed. If matrix_mdev is subsequently freed, any PQAP instruction executed by the guest will dereference the stale pointer through pqap_hook_rwsem, resulting in a use-after-free.
Since kvm->arch.crypto.pqap_hook is only set in the vfio_ap_mdev_set_kvm() function and is cleared in the vfio_ap_mdev_unset_kvm() function, a check for 'kvm->arch.crypto.pqap_hook != NULL' is all that is needed to determine whether it belongs to another mdev. This will alleviate the need to iterate the matrix_dev->mdev_list list to see if the kvm object is assigned to another mdev.This was introduced in v3 to alleviate the need to take the mdevs_lock while iterating the list; however, this did not prevent a potential race condition.
The pqap_hook_rwsem(write) is now performed inside get_update_locks_for_kvm(), which is updated to acquire pqap_hook_rwsem(write) between kvm->lock and mdevs_lock. This ordering is consistent with the PQAP intercept path, which acquires pqap_hook_rwsem in read mode while srcu is held under vcpu->mutex, establishing the
dependency: kvm->lock -> vcpu->mutex -> srcu -> pqap_hook_rwsem(read).
The pqap_hook_rwsem is now released inside the release_update_locks_for_kvm(), which is updated to release pqap_hook_rwsem(write) between mdevs_lock and kvm->lock.
Additionally, kvm_put_kvm() in vfio_ap_mdev_unset_kvm() is moved after release_update_locks_for_kvm(). Previously it was called while kvm->lock was held; if it were ever the last reference, kvm_destroy_vm() would run under kvm->lock, which would deadlock.
Message-ID: <[email protected]>
--- drivers/s390/crypto/vfio_ap_ops.c | 45 ++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 25 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +20 -25
@@ -48,15 +48,19 @@ static void vfio_ap_mdev_reset_queue(str* 1. matrix_dev->guests_lock: required to use the KVM pointer to update a KVM * guest's APCB. * 2. kvm->lock: required to update a guest's APCB -* 3. matrix_dev->mdevs_lock: required to access data stored in a matrix_mdev +* 3. kvm->arch.crypto.pqap_hook_rwsem: required to update pqap_hook and +* serialize against PQAP intercepts +* 4. matrix_dev->mdevs_lock: required to access data stored in a matrix_mdev * -* Note: If @kvm is NULL, the KVM lock will not be taken. +* Note: If @kvm is NULL, the KVM lock and pqap_hook_rwsem will not be taken. */ static inline void get_update_locks_for_kvm (struct kvm *kvm) {mutex_lock (&matrix_dev->guests_lock); -if (kvm) +if (kvm) {mutex_lock (&kvm->lock); +down_write (&kvm->arch.crypto.pqap_hook_rwsem); + }mutex_lock (&matrix_dev->mdevs_lock); }
@@ -68,16 +72,19 @@ static inline void get_update_locks_for_* * The proper unlocking order is: * 1. matrix_dev->mdevs_lock -* 2. kvm->lock -* 3. matrix_dev->guests_lock +* 2. kvm->arch.crypto.pqap_hook_rwsem +* 3. kvm->lock +* 4. matrix_dev->guests_lock * -* Note: If @kvm is NULL, the KVM lock will not be released. +* Note: If @kvm is NULL, the KVM lock and pqap_hook_rwsem will not be released. */ static inline void release_update_locks_for_kvm (struct kvm *kvm) {mutex_unlock (&matrix_dev->mdevs_lock); -if (kvm) +if (kvm) { +up_write (&kvm->arch.crypto.pqap_hook_rwsem);mutex_unlock (&kvm->lock); + }mutex_unlock (&matrix_dev->guests_lock); }
@@ -1609,26 +1616,17 @@ static const struct attribute_group *vfistatic int vfio_ap_mdev_set_kvm (struct ap_matrix_mdev *matrix_mdev,struct kvm *kvm) { -struct ap_matrix_mdev *m; -if (kvm->arch.crypto.crycbd) { -down_write (&kvm->arch.crypto.pqap_hook_rwsem); - kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook; -up_write (&kvm->arch.crypto.pqap_hook_rwsem); -get_update_locks_for_kvm (kvm); - -list_for_each_entry (m, &matrix_dev->mdev_list, node) { -if (m != matrix_mdev && m->kvm == kvm) { -release_update_locks_for_kvm (kvm); -return -EPERM ; - } +if (kvm->arch.crypto.pqap_hook) { +release_update_locks_for_kvm (kvm); +return -EPERM ; } + kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;kvm_get_kvm (kvm); matrix_mdev->kvm = kvm;vfio_ap_mdev_update_guest_apcb (matrix_mdev); -release_update_locks_for_kvm (kvm); }
@@ -1671,18 +1669,15 @@ static void vfio_ap_mdev_unset_kvm(strucstruct kvm *kvm = matrix_mdev->kvm;if (kvm && kvm->arch.crypto.crycbd) { -down_write (&kvm->arch.crypto.pqap_hook_rwsem); - kvm->arch.crypto.pqap_hook =NULL ; -up_write (&kvm->arch.crypto.pqap_hook_rwsem); -get_update_locks_for_kvm (kvm); + kvm->arch.crypto.pqap_hook =NULL ;kvm_arch_crypto_clear_masks (kvm);vfio_ap_mdev_reset_queues (matrix_mdev); -kvm_put_kvm (kvm); matrix_mdev->kvm =NULL ;release_update_locks_for_kvm (kvm); +kvm_put_kvm (kvm); } }
Greg Kroah-Hartman
maintainerPATCH 385/1424 s390/vfio-ap: Fix stale do_remove flag across iterations in vfio_ap_mdev_cfg_remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit b1f092d94f621307927f145e3cc31893da51fc08 upstream.
The do_remove flag in vfio_ap_mdev_cfg_remove() is initialised to zero before the loop that iterates over the list of matrix mdevs, but is never reset at the start of each iteration. Since do_remove is OR-accumulated across iterations, a positive result from one mdev carries over to subsequent mdevs.
The fix is to set the do_remove flag with the first call to bitmap_and; for example: do_remove = bitmap_an rather than do_remove |= bitmap_and.
--- drivers/s390/crypto/vfio_ap_ops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -2353,15 +2353,15 @@ static void vfio_ap_mdev_cfg_remove(unsiDECLARE_BITMAP (aprem,AP_DEVICES );DECLARE_BITMAP (aqrem,AP_DOMAINS );DECLARE_BITMAP (cdrem,AP_DOMAINS ); -int do_remove =0 ; +int do_remove;list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) {mutex_lock (&matrix_mdev->kvm->lock);mutex_lock (&matrix_dev->mdevs_lock); - do_remove |=bitmap_and (aprem, ap_remove, - matrix_mdev->matrix.apm, -AP_DEVICES ); + do_remove =bitmap_and (aprem, ap_remove, + matrix_mdev->matrix.apm, +AP_DEVICES ); do_remove |=bitmap_and (aqrem, aq_remove, matrix_mdev->matrix.aqm,AP_DOMAINS );
Greg Kroah-Hartman
maintainerPATCH 386/1424 s390/vfio-ap: Fix control domain removal in vfio_ap_mdev_cfg_remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 6b8a02e216f6b520cc029e43ddc83956605135d5 upstream.
The vfio_ap_config_remove function uses the bitmap_andnot function to clear bits from the matrix_mdev->matrix.adm bitmap (specifies the control domains assigned to the mdev). This prevents the explicitly unplugged control domains from being removed the KVM guest. The bitmap_and function is used instead.
--- drivers/s390/crypto/vfio_ap_ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +3 -3
@@ -2365,9 +2365,9 @@ static void vfio_ap_mdev_cfg_remove(unsi do_remove |=bitmap_and (aqrem, aq_remove, matrix_mdev->matrix.aqm,AP_DOMAINS ); - do_remove |=bitmap_andnot (cdrem, cd_remove, - matrix_mdev->matrix.adm, -AP_DOMAINS ); + do_remove |=bitmap_and (cdrem, cd_remove, + matrix_mdev->matrix.adm, +AP_DOMAINS );if (do_remove) vfio_ap_mdev_hot_unplug_cfg(matrix_mdev, aprem, aqrem,
Greg Kroah-Hartman
maintainerPATCH 387/1424 s390/vfio-ap: Fix dereference matrix_mdev->kvm without checking for NULL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit d50346801b4f144e42b49cd4f1496010498ab114 upstream.
The ap_driver structure has two fields which are function pointers to callbacks:
* .on_config_changed: called at the start of the AP bus scan function to notify the device driver that the host AP configuration has changed and the associated AP devices will be added or removed accordingly. This gives the implementor a chance to evaluate the configuration changes and respond to them before the associated devices are added or removed.
* .on_scan_complete: Called at the end of the AP bus scan function to notify the device driver that the host AP configuration has changed and the AP devices have been added or removed accordingly. This gives the implementor the opportunity to respond to the changes after the associated devices are added or removed.
These two callbacks are implemented in the vfio_ap device driver via the vfio_ap_on_cfg_changed and vfio_ap_on_scan_complete functions respectively.
Within the call stack of these two callback functions the matrix_mdev->kvm->lock mutex is taken without checking whether matrix_mdev->kvm is NULL or not. If matrix_mdev->kvm has never been set, trying to take the lock will trigger a NULL pointer dereference. This patch adds checks for matrix_mdev->kvm == NULL before taking the matrix_mdev->kvm->lock mutex.
Note that the matrix_mdev->kvm->lock mutex taken in the vfio_ap_mdev_hot_plug_config function is moved to the calling function along with the matrix_dev->mdevs_lock which is needed there to access the fields of the matrix_mdev. It makes little sense to make the change the check for matrix_mdev->kvm there before taking the kvm->lock mutex only to have to move it out via another patch, so it is done in this patch.
It is important to make note of the following:
1. The matrix_dev->guests_lock is acquired at the start of both callback functions. This ensures that matrix_mdev will not be removed via the vfio_ap_mdev_remove function because it too takes matrix_dev_guests_lock before removing the object; so, matrix_mdev will be available for the duration of the callback functions.
2. The matrix_dev->mdevs_lock mutex must be taken in order to access fields within the matrix_mdev structure
3. matrix_mdev->kvm->lock mutex must be taken before the matrix_dev->mdevs_lock to prevent a lockdep splat.
4: The kvm->lock must be held while plugging the guest's AP configuration
into its SIE state description via the vfio_ap_mdev_update_guest_apcb function.
5. The vfio_ap_mdev_update_guest_apcb checks matrix_mdev->kvm to verify it is not NULL before doing the hot plug of the guest's AP configuration.
--- drivers/s390/crypto/vfio_ap_ops.c | 39 +++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +30 -9
@@ -2355,8 +2355,20 @@ static void vfio_ap_mdev_cfg_remove(unsiDECLARE_BITMAP (cdrem,AP_DOMAINS );int do_remove; +/* +* It is safe to traverse this list here because the +* required guard - matrix_dev->guests_lock - is taken in the +* vfio_ap_on_cfg_changed function prior to this function getting +* called. +*/ list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { -mutex_lock (&matrix_mdev->kvm->lock); +/* +* The mdevs_lock must be held to access fields within matrix_mdev, +* and kvm->lock must be taken before mdevs_lock to satisfy the lock +* ordering requirement and prevent a lockdep splat. +*/ +if (matrix_mdev->kvm) +mutex_lock (&matrix_mdev->kvm->lock);mutex_lock (&matrix_dev->mdevs_lock); do_remove = bitmap_and(aprem, ap_remove,
@@ -2374,7 +2386,8 @@ static void vfio_ap_mdev_cfg_remove(unsi cdrem);mutex_unlock (&matrix_dev->mdevs_lock); -mutex_unlock (&matrix_mdev->kvm->lock); +if (matrix_mdev->kvm) +mutex_unlock (&matrix_mdev->kvm->lock); } }
@@ -2571,9 +2584,6 @@ static void vfio_ap_mdev_hot_plug_cfg(stDECLARE_BITMAP (apm_filtered,AP_DEVICES );bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false; -mutex_lock (&matrix_mdev->kvm->lock); -mutex_lock (&matrix_dev->mdevs_lock); - filter_adapters =bitmap_intersects (matrix_mdev->matrix.apm, matrix_mdev->apm_add,AP_DEVICES ); filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
@@ -2591,9 +2601,6 @@ static void vfio_ap_mdev_hot_plug_cfg(stvfio_ap_mdev_update_guest_apcb (matrix_mdev);reset_queues_for_apids (matrix_mdev, apm_filtered); - -mutex_unlock (&matrix_dev->mdevs_lock); -mutex_unlock (&matrix_mdev->kvm->lock); } void vfio_ap_on_scan_complete(struct ap_config_info *new_config_info,
@@ -2604,15 +2611,29 @@ void vfio_ap_on_scan_complete(struct ap_mutex_lock (&matrix_dev->guests_lock);list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { +/* +* The mdevs_lock must be held to access fields within matrix_mdev, +* and kvm->lock must be taken before mdevs_lock to satisfy the lock +* ordering requirement and prevent a lockdep splat. +*/ +if (matrix_mdev->kvm) +mutex_lock (&matrix_mdev->kvm->lock); +mutex_lock (&matrix_dev->mdevs_lock); +if (bitmap_empty (matrix_mdev->apm_add,AP_DEVICES ) &&bitmap_empty (matrix_mdev->aqm_add,AP_DOMAINS ) &&bitmap_empty (matrix_mdev->adm_add,AP_DOMAINS )) -continue ; + goto do_unlock;vfio_ap_mdev_hot_plug_cfg (matrix_mdev);bitmap_clear (matrix_mdev->apm_add,0 ,AP_DEVICES );bitmap_clear (matrix_mdev->aqm_add,0 ,AP_DOMAINS );bitmap_clear (matrix_mdev->adm_add,0 ,AP_DOMAINS ); + +do_unlock: +mutex_unlock (&matrix_dev->mdevs_lock); +if (matrix_mdev->kvm) +mutex_unlock (&matrix_mdev->kvm->lock); }mutex_unlock (&matrix_dev->guests_lock);
Greg Kroah-Hartman
maintainerPATCH 388/1424 s390/vfio-ap: Fix hot-unplug skipped when last AP adapter or domain removed
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 917f509bfb88048094dbb85c4e9dbc4d6fe4a886 upstream.
The vfio_ap_mdev_hot_unplug_cfg() function uses the return value of bitmap_andnot() to determine whether the guest APCB needs to be updated. However, bitmap_andnot() returns false when the resulting destination bitmap is empty. This means that if the only adapter, domain or control domain assigned to an mdev is removed from the host's AP configuration, the bit is correctly cleared from the shadow APCB, but bitmap_andnot() returns false because the result is an empty bitmap. Consequently, do_hotplug remains 0 and vfio_ap_mdev_update_guest_apcb() is never called, leaving the KVM guest with stale hardware access to the unplugged AP devices.
Fix this by replacing the bitmap_andnot() return value check with bitmap_intersects() to determine whether the shadow APCB actually overlaps with the removal mask. If there is an intersection, call bitmap_andnot() solely for its side effect of clearing the bits, then unconditionally set do_hotplug to trigger the guest APCB update.
--- drivers/s390/crypto/vfio_ap_ops.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +17 -13
@@ -2309,24 +2309,28 @@ static void vfio_ap_mdev_hot_unplug_cfg(unsigned long *aqrem, unsigned long *cdrem) { - int do_hotplug = 0; + bool do_hotplug = false; -if (!bitmap_empty (aprem,AP_DEVICES )) { - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.apm, - matrix_mdev->shadow_apcb.apm, - aprem,AP_DEVICES ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.apm, aprem,AP_DEVICES )) { +bitmap_andnot (matrix_mdev->shadow_apcb.apm, + matrix_mdev->shadow_apcb.apm, + aprem,AP_DEVICES ); + do_hotplug = true; } -if (!bitmap_empty (aqrem,AP_DOMAINS )) { - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.aqm, - matrix_mdev->shadow_apcb.aqm, - aqrem,AP_DEVICES ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.aqm, aqrem,AP_DOMAINS )) { +bitmap_andnot (matrix_mdev->shadow_apcb.aqm, + matrix_mdev->shadow_apcb.aqm, + aqrem,AP_DOMAINS ); + do_hotplug = true; } -if (!bitmap_empty (cdrem,AP_DOMAINS )) - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.adm, - matrix_mdev->shadow_apcb.adm, - cdrem,AP_DOMAINS ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.adm, cdrem,AP_DOMAINS )) { +bitmap_andnot (matrix_mdev->shadow_apcb.adm, + matrix_mdev->shadow_apcb.adm, + cdrem,AP_DOMAINS ); + do_hotplug = true; + }if (do_hotplug)vfio_ap_mdev_update_guest_apcb (matrix_mdev);
Greg Kroah-Hartman
maintainerPATCH 389/1424 s390/vfio-ap: Fix NULL deref in status_show() during queue probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit dd6f4ef6f8a37412909ad787c837332fb070159c upstream.
When vfio_ap_mdev_probe_queue() creates the sysfs attribute group, the queue's driver data has not yet been set. A concurrent read of the 'status' attribute can therefore call dev_get_drvdata() and get NULL, which is then passed directly to vfio_ap_mdev_for_queue() where q->apqn is unconditionally dereferenced, causing a NULL pointer dereference.
Fix this by acquiring the update locks before calling sysfs_create_group(). The status_show() function acquires guests_lock before reading the driver data, so any concurrent read will block until after dev_set_drvdata() has been called and the update locks are released.
As a bonus, the APQN no longer needs to be read from the queue struct after allocation — it can be read directly from apdev before allocation and stored in a local variable, which is then assigned to q->apqn once the allocation succeeds.
--- drivers/s390/crypto/vfio_ap_ops.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +29 -4
@@ -2065,6 +2065,23 @@ static ssize_t status_show(struct devicemutex_lock (&matrix_dev->mdevs_lock); q =dev_get_drvdata (&apdev->device); + +/* +* Make sure the drvdata has been set before proceeding. There is a +* possibility that the drvdata was not set if the vfio_ap_queue object +* could not be allocated when the queue device was probed. In that case, +* the locks used in vfio_ap_mdev_probe_queue() are released prior to +* removing the sysfs status attribute to avoid a lockdep +* splat. That opens a very small window where the status attribute is +* still available without the vfio_ap_queue object having been +* stored in the device drvdata. In that case, indicate the queue is not +* assigned. +*/ +if (!q) { + nchars =sysfs_emit (buf,"%s\n" ,AP_QUEUE_UNASSIGNED ); + goto done; + } + matrix_mdev =vfio_ap_mdev_for_queue (q);/* If the queue is assigned to the matrix mediated device, then
@@ -2092,6 +2109,7 @@ static ssize_t status_show(struct device AP_QUEUE_UNASSIGNED); } +done:mutex_unlock (&matrix_dev->mdevs_lock);return nchars;
@@ -2165,14 +2183,17 @@ void vfio_ap_mdev_unregister(void)int vfio_ap_mdev_probe_queue (struct ap_device *apdev) { -int ret; +int ret, apqn;struct vfio_ap_queue *q;DECLARE_BITMAP (apm_filtered,AP_DEVICES );struct ap_matrix_mdev *matrix_mdev; + apqn =to_ap_queue (&apdev->device)->qid; + matrix_mdev =get_update_locks_by_apqn (apqn); + ret =sysfs_create_group (&apdev->device.kobj, &vfio_queue_attr_group);if (ret) -return ret; + goto err_release_locks; q =kzalloc (sizeof (*q),GFP_KERNEL );if (!q) {
@@ -2180,11 +2201,10 @@ int vfio_ap_mdev_probe_queue(struct ap_d goto err_remove_group; } - q->apqn =to_ap_queue (&apdev->device)->qid; + q->apqn = apqn; q->saved_isc =VFIO_AP_ISC_INVALID ;memset (&q->reset_status,0 ,sizeof (q->reset_status));INIT_WORK (&q->reset_work, apq_reset_check); - matrix_mdev =get_update_locks_by_apqn (q->apqn);if (matrix_mdev) {vfio_ap_mdev_link_queue (matrix_mdev, q);
@@ -2213,8 +2233,13 @@ done:return ret; err_remove_group: +release_update_locks_for_mdev (matrix_mdev);sysfs_remove_group (&apdev->device.kobj, &vfio_queue_attr_group);return ret; + +err_release_locks: +release_update_locks_for_mdev (matrix_mdev); +return ret; }void vfio_ap_mdev_remove_queue (struct ap_device *apdev)
Greg Kroah-Hartman
maintainerPATCH 390/1424 s390/vfio-ap: fix potential use of uninitialized apm_filtered bitmap
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit bf09b9d7cd7890bc3a3b7eb63d5ece15f88bfde7 upstream.
The DECLARE_BITMAP(apm_filtered, AP_DEVICES) macro allocates the bitmap on the stack without zero-initializing it.
In vfio_ap_mdev_hot_plug_cfg(), the vfio_ap_mdev_filter_matrix() function is only called to initialize and populate apm_filtered if either filter_adapters or filter_domains is true. If the hot plug configuration change only adds control domains (meaning filter_cdoms is true, but filter_adapters and filter_domains are both false), vfio_ap_mdev_filter_matrix() is bypassed.
Consequently, apm_filtered is passed to reset_queues_for_apids() with uninitialized stack garbage. This can cause reset_queues_for_apids() to interpret arbitrary stack garbage bits as valid APIDs to reset, potentially performing unintended guest hardware queue resets.
Fix this by zero-initializing the apm_filtered bitmap at the beginning of vfio_ap_mdev_hot_plug_cfg() using bitmap_zero().
--- drivers/s390/crypto/vfio_ap_ops.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +9 -0
@@ -2613,6 +2613,15 @@ static void vfio_ap_mdev_hot_plug_cfg(stDECLARE_BITMAP (apm_filtered,AP_DEVICES );bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false; +/* +* Zero out the apm_filtered bitmap in case there are no adapters or +* domains to be added, but only control domains. In that case, +* vfio_ap_mdev_filter_matrix() - which initializes apm_filtered - will +* not get called and the reset_queues_for_apids will crash because it +* will access an uninitialized bitmap. +*/ +bitmap_zero (apm_filtered,AP_DEVICES ); + filter_adapters =bitmap_intersects (matrix_mdev->matrix.apm, matrix_mdev->apm_add,AP_DEVICES ); filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
Greg Kroah-Hartman
maintainerPATCH 391/1424 s390/vfio-ap: Fix required lock not held during update of ap_matrix_mdev object
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 5883528250be57fa92270459b33603ff52de0a91 upstream.
In the vfio_ap_mdev_cfg_add function, the apm_add, aqm_add and adm_add fields of an ap_matrix_mdev object fields are modified while not holding the matrix_dev->mdevs_lock. This lock must be held while making these to guard against a race condition with another caller that may be concurrently modifying these fields or any of the fields in the matrix_mdev->matrix.
--- drivers/s390/crypto/vfio_ap_ops.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +8 -0
@@ -2541,12 +2541,20 @@ static void vfio_ap_mdev_cfg_add(unsignevfio_ap_filter_apid_by_qtype (apm_add, aqm_add);list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { +/* +* The mdevs_lock must be held in order to access fields +* within matrix_mdev +*/ +mutex_lock (&matrix_dev->mdevs_lock); +bitmap_and (matrix_mdev->apm_add, matrix_mdev->matrix.apm, apm_add,AP_DEVICES );bitmap_and (matrix_mdev->aqm_add, matrix_mdev->matrix.aqm, aqm_add,AP_DOMAINS );bitmap_and (matrix_mdev->adm_add, matrix_mdev->matrix.adm, adm_add,AP_DEVICES ); + +mutex_unlock (&matrix_dev->mdevs_lock); } }
Greg Kroah-Hartman
maintainerPATCH 392/1424 mtd: afs: validate v2 image info bounds
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e9290031f736e99ad17c25c00311c92c266843b7 upstream.
The AFS v2 parser uses footer[8] to locate the image information block inside the current erase block, then uses the image information region_count to walk entries from a fixed local array. The footer offset and region count come from flash contents and are not checked against the erase block or the local image-info array before use.
Reject v2 entries whose image information offset would underflow the erase block calculation, and reject region counts that cannot fit in the local image-info array before walking region entries.
--- drivers/mtd/parsers/afs.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/mtd/parsers/afs.c +7 -0
@@ -235,6 +235,9 @@ static int afs_parse_v2_partition(structpr_debug ("Parsing v2 partition @%08x-%08x\n" , off, off + mtd->erasesize); +if (mtd->erasesize <sizeof (footer)) +return -EINVAL ; +/* First read the footer */ ptr = off + mtd->erasesize -sizeof (footer); ret =mtd_read (mtd, ptr,sizeof (footer), &sz, (u_char *)footer);
@@ -245,6 +248,8 @@ static int afs_parse_v2_partition(struct } name = (char *) &footer[0 ]; version = footer[9 ]; +if (footer[8 ] > mtd->erasesize -sizeof (footer)) +return -EINVAL ; ptr = off + mtd->erasesize -sizeof (footer) - footer[8 ]; pr_debug("found image \"%s\", version %08x, info @%08x\n",
@@ -278,6 +283,8 @@ static int afs_parse_v2_partition(struct entrypoint = imginfo[pad]; attributes = imginfo[pad+1 ]; region_count = imginfo[pad+2 ]; +if (region_count > (ARRAY_SIZE (imginfo) - pad -3 ) /4 ) +return -EINVAL ; block_start = imginfo[20 ]; block_end = imginfo[21 ];
Greg Kroah-Hartman
maintainerPATCH 393/1424 mtd: mtdoops: free page bitmap when the backing MTD is removed
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 956e7da12c114f13c63d126ab1d79c3b6a819060 upstream.
mtdoops_notify_add() allocates oops_page_used when the configured MTD device is registered. mtdoops_notify_remove() detaches from that device but leaves the bitmap allocated. If the same MTD device is later registered again, the add path allocates a new bitmap and overwrites the old pointer, leaking one vmalloc allocation per remove/add cycle.
This is only visible when the backing MTD device can disappear and be registered again while mtdoops remains loaded, so the usual static MTD case does not expose it.
Free the bitmap after unregistering the dumper and flushing the pending workers, then clear the pointer and page count before a later attach can allocate fresh state. Clearing the pointer also keeps the module exit path from freeing the same bitmap a second time after a remove event.
--- drivers/mtd/mtdoops.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/mtd/mtdoops.c +3 -0
@@ -393,6 +393,9 @@ static void mtdoops_notify_remove(struct cxt->mtd =NULL ;flush_work (&cxt->work_erase);flush_work (&cxt->work_write); +vfree (cxt->oops_page_used); + cxt->oops_page_used =NULL ; + cxt->oops_pages =0 ; }
Greg Kroah-Hartman
maintainerPATCH 394/1424 mtd: rawnand: validate ONFI extended parameter page sections
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e5e415262330bd70f983e091d8919d9dcd99e475 upstream.
nand_flash_detect_ext_param_page() allocates the length declared by the ONFI parameter page, then treats the data as a fixed header followed by variable-length sections. It reads that header and advances over sections without first proving that the fixed page and each current section fit in the allocation.
Reject pages shorter than the fixed header, track the remaining variable area while walking sections, and require the ECC section to contain every field read from struct onfi_ext_ecc_info. Use device-scoped diagnostics that identify the malformed ONFI section.
--- drivers/mtd/nand/raw/nand_onfi.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/mtd/nand/raw/nand_onfi.c +25 -2
@@ -35,16 +35,21 @@ static int nand_flash_detect_ext_param_p struct nand_onfi_params *p) {struct nand_device *base = &chip->base; +struct mtd_info *mtd =nand_to_mtd (chip);struct nand_ecc_props requirements;struct onfi_ext_param_page *ep;struct onfi_ext_section *s;struct onfi_ext_ecc_info *ecc; +size_t remaining, section_len;uint8_t *cursor;int ret;int len;int i; len =le16_to_cpu (p->ext_param_page_length) *16 ; +if (len <sizeof (*ep)) +return -EINVAL ; + ep =kmalloc (len,GFP_KERNEL );if (!ep)return -ENOMEM ;
@@ -77,11 +82,29 @@ static int nand_flash_detect_ext_param_p/* find the ECC section. */ cursor = (uint8_t *)(ep +1 ); + remaining = len -sizeof (*ep);for (i =0 ; i <ONFI_EXT_SECTION_MAX ; i++) { s = ep->sections + i; -if (s->type ==ONFI_SECTION_TYPE_2 ) + section_len = s->length *16 ; +if (section_len > remaining) { +dev_dbg (&mtd->dev, +"ONFI extended parameter section %d exceeds page\n" , + i); + goto ext_out; + } + +if (s->type ==ONFI_SECTION_TYPE_2 ) { +if (section_len <sizeof (*ecc)) { +dev_dbg (&mtd->dev, +"ONFI extended parameter ECC section %d is too short\n" , + i); + goto ext_out; + }break ; - cursor += s->length *16 ; + } + + cursor += section_len; + remaining -= section_len; }if (i ==ONFI_EXT_SECTION_MAX ) {pr_debug ("We can not find the ECC section.\n" );
Greg Kroah-Hartman
maintainerPATCH 395/1424 batman-adv: fix stale receive device on merged fragments
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit ad46c907d7d9975a285c1e89a4adde652eaa93f5 upstream.
Fragment reassembly reuses the skb from the highest-numbered buffered fragment as the merged packet. When that fragment was received on a hard interface which is deleted before the chain completes, the merged skb can re-enter the receive path with a stale skb->dev and skb_iif.
batadv_batman_skb_recv() passes such merged packets through the normal receive handlers again. DAT and bridge loop avoidance both derive the ARP header length from skb->dev, so they can dereference the freed net_device before the packet reaches the local mesh interface.
Refresh the receive device metadata from the current receive device before running the packet handlers. This keeps internally reinjected merged fragments consistent with the normal receive path after hard interface teardown.
--- net/batman-adv/main.c | 4 ++++ 1 file changed, 4 insertions(+)
net/batman-adv/main.c +4 -0
@@ -457,6 +457,10 @@ int batadv_batman_skb_recv(struct sk_bufif (!skb) goto err_put; +/* Merged fragments re-enter here with reused skb metadata. */ + skb->dev = dev; + skb->skb_iif = dev->ifindex; +/* packet should hold at least type and version */ if (unlikely (!pskb_may_pull (skb,2 ))) goto err_free;
Greg Kroah-Hartman
maintainerPATCH 396/1424 batman-adv: dat: avoid unaligned fault in IP extraction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 0121afa52cdb88cfb4d5d7bd126a23a9100121d8 upstream.
Independent of the alignment of the ARP packet in the SKB, either the batadv_arp_ip_src or the batadv_arp_ip_dst will have an unaligned access (on HW without native unaligned read support).
Use get_unaligned() to handle this properly on all architectures.
--- net/batman-adv/distributed-arp-table.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/batman-adv/distributed-arp-table.c +6 -2
@@ -250,7 +250,10 @@ static u8 *batadv_arp_hw_src(struct sk_b*/ static __be32 batadv_arp_ip_src (struct sk_buff *skb,int hdr_size) { -return *(__force __be32 *)(batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ); +u8 *src =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ; +__be32 *ip = (__force __be32 *)src; + +return get_unaligned (ip); }/**
@@ -275,8 +278,9 @@ static u8 *batadv_arp_hw_dst(struct sk_bstatic __be32 batadv_arp_ip_dst (struct sk_buff *skb,int hdr_size) {u8 *dst =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN *2 +4 ; +__be32 *ip = (__force __be32 *)dst; -return *(__force __be32 *)dst; +return get_unaligned (ip); }/**
Greg Kroah-Hartman
maintainerPATCH 397/1424 batman-adv: bla: fix freeing of claims on meshif deletion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 8d128c932bced74e3b1625ba3d7c78ef122a88a7 upstream.
When the mesh interface is getting deleted, then batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could make sure that all claims gets removed. But this function is only executed when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is always setting it to NULL before it is (indirectly) called, it was never actually executed.
But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the moment too fragile because the BLA code is not handling the rehashing in batadv_bla_update_orig_address(). The stored backbone address doesn't have to be the one actually used for the hash bucket selection during the initial adding of the backbone. The batadv_handle_unclaim() can therefore fail to find the respective backbone for the unclaim and then stop the deletion.
But the actual backbone_gw object is not needed for the unclaim because all relevant information is always provided by the caller. And the check for the existence of the backbone_gw doesn't provide any additional security check for the deletion of a claim.
--- net/batman-adv/bridge_loop_avoidance.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +1 -9
@@ -941,26 +941,18 @@ static bool batadv_handle_unclaim(struct const u8 *backbone_addr, const u8 *claim_addr, unsigned short vid) { - struct batadv_bla_backbone_gw *backbone_gw; - /* unclaim in any case if it is our own */ if (primary_if && batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr)) batadv_bla_send_claim(bat_priv, claim_addr, vid, BATADV_CLAIM_TYPE_UNCLAIM); - backbone_gw =batadv_backbone_hash_find (bat_priv, backbone_addr, vid); - -if (!backbone_gw) -return true; -/* this must be an UNCLAIM frame */ batadv_dbg (BATADV_DBG_BLA , bat_priv,"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n" , __func__, - claim_addr,batadv_print_vid (vid), backbone_gw->orig); + claim_addr,batadv_print_vid (vid), backbone_addr);batadv_bla_del_claim (bat_priv, claim_addr, vid); -batadv_backbone_gw_put (backbone_gw);return true; }
Greg Kroah-Hartman
maintainerPATCH 398/1424 batman-adv: bla: prevent CRC corruptions after claim flush
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 89f3502ff6878798be96461b2eebd64ba3c3874c upstream.
When batadv_bla_del_backbone_claims() tried to remove all claims of a backbone, it sets the CRC to 0. It assumes that the it had the last reference of the claims because batadv_claim_release() (which runs after the last reference was released), is XORing the crc16 of the claim address with the backbone CRC.
If there would be a parallel holder of any of these references, it could happen that the backbone CRC is (0 ^ crc16(delayed_released_claim)). Which is the wrong starting point for the new claims it may receive when the remote answers the claim request from batadv_bla_send_request().
This reinitializations can be completely dropped to avoid this problem. batadv_claim_release() will take care of fixing the backbone CRC.
--- net/batman-adv/bridge_loop_avoidance.c | 5 ----- 1 file changed, 5 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +0 -5
@@ -323,11 +323,6 @@ batadv_bla_del_backbone_claims(struct ba }spin_unlock_bh (list_lock); } - -/* all claims gone, initialize CRC */ -spin_lock_bh (&backbone_gw->crc_lock); - backbone_gw->crc =BATADV_BLA_CRC_INIT ; -spin_unlock_bh (&backbone_gw->crc_lock); }/**
Greg Kroah-Hartman
maintainerPATCH 399/1424 clk: qcom: gcc-msm8916: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit c5339edc6abb601ea10df910ea0b1592fa1016f3 upstream.
According to the APQ8016E TRM, the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8916.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8916.c +3 -2
@@ -1589,9 +1589,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .parent_data = &(const struct clk_parent_data ){
Greg Kroah-Hartman
maintainerPATCH 400/1424 clk: qcom: gcc-msm8939: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit fc611445b021262b0d4ace6f716a360663816287 upstream.
MSM8939 is similar to MSM8916, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8939.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8939.c +3 -2
@@ -1916,9 +1916,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .ops = &clk_branch2_ops,
Greg Kroah-Hartman
maintainerPATCH 401/1424 clk: rockchip: rk3588: Dont change PLL rates when setting dclk_vop2_src
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Stuebner <[email protected]>
commit 13b10571cc353448275365ede1a5396d20dfe839 upstream.
dclk_vop2_src currently has the CLK_SET_RATE_PARENT flag set, which is very different from dclk_vop0_src or dclk_vop1_src, which don't have it.
With this flag in dclk_vop2_src, actually setting the clock then results in a lot of other peripherals breaking, because setting the rate results in the PLL source getting changed:
[ 14.898718] clk_core_set_rate_nolock: setting rate for dclk_vop2 to 152840000 [ 15.155017] clk_change_rate: setting rate for pll_gpll to 1680000000
[ clk adjusting every gpll user ]
This includes possibly the other vops, i2s, spdif and even the uarts. Among other possible things, this breaks the uart console on a board I use. Sometimes it recovers later on, but there will be a big block of garbled output for a while at least.
Shared PLLs should not be changed by individual users, so drop this flag from dclk_vop2_src.
--- drivers/clk/rockchip/clk-rk3588.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/rockchip/clk-rk3588.c +1 -1
@@ -2117,7 +2117,7 @@ static struct rockchip_clk_branch rk3588COMPOSITE (DCLK_VOP1_SRC ,"dclk_vop1_src" , gpll_cpll_v0pll_aupll_p,0 ,RK3588_CLKSEL_CON (111 ),14 ,2 ,MFLAGS ,9 ,5 ,DFLAGS ,RK3588_CLKGATE_CON (52 ),11 ,GFLAGS ), -COMPOSITE (DCLK_VOP2_SRC ,"dclk_vop2_src" , gpll_cpll_v0pll_aupll_p,CLK_SET_RATE_PARENT |CLK_SET_RATE_NO_REPARENT , +COMPOSITE (DCLK_VOP2_SRC ,"dclk_vop2_src" , gpll_cpll_v0pll_aupll_p,CLK_SET_RATE_NO_REPARENT ,RK3588_CLKSEL_CON (112 ),5 ,2 ,MFLAGS ,0 ,5 ,DFLAGS ,RK3588_CLKGATE_CON (52 ),12 ,GFLAGS ), COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", dclk_vop0_p,
Greg Kroah-Hartman
maintainerPATCH 402/1424 clk: qcom: gcc-mdm9607: Drop incorrect apss_tcu_clk_src
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 38d06956f60675f906dc3f5b70b3b52103b86a7d upstream.
This clock does not exist on the specified address on MDM9607. Reading/writing the registers always results in 0 or crashes. The math in the frequency table is also broken. GPLL2 on MDM9607 runs at 480 MHz, so:
- F(155000000, P_GPLL2, 6, 0, 0), // 480 MHz/6 = 80 MHz, not 155 MHz
- F(310000000, P_GPLL2, 3, 0, 0), // 480 MHz/3 = 160 MHz, not 310 MHz
Presumably, this definition was mistakenly copied as-is from gcc-msm8916 (which uses 930 MHz for GPLL2). There are no branch consumers of this root clock inside gcc-mdm9607 (notably, gcc_apss_tcu_clk has bimc_ddr_clk_src as parent instead of this clock), so we can just drop it.
It seems like this clock does exist on this SoC on a different address, but since there is no user and reference code for it, it is still better to drop it.
--- drivers/clk/qcom/gcc-mdm9607.c | 35 ----------------------------------- 1 file changed, 35 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -35
@@ -158,20 +158,6 @@ static const struct clk_parent_data gcc_ { .hw = &gpll2.clkr.hw }, }; -static const struct parent_map gcc_xo_gpll0_gpll1_gpll2_map[] = { - {P_XO ,0 }, - {P_GPLL0 ,1 }, - {P_GPLL1 ,2 }, - {P_GPLL2 ,3 }, -}; - -static const struct clk_parent_data gcc_xo_gpll0_gpll1_gpll2[] = { - { .fw_name ="xo" }, - { .hw = &gpll0.clkr.hw }, - { .hw = &gpll1_vote.hw }, - { .hw = &gpll2.clkr.hw }, -}; -static const struct freq_tbl ftbl_apss_ahb_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (50000000 ,P_GPLL0 ,16 ,0 ,0 ),
@@ -674,26 +660,6 @@ static struct clk_rcg2 sdcc2_apps_clk_sr }, }; -static const struct freq_tbl ftbl_gcc_apss_tcu_clk[] = { -F (155000000 ,P_GPLL2 ,6 ,0 ,0 ), -F (310000000 ,P_GPLL2 ,3 ,0 ,0 ), -F (400000000 ,P_GPLL0 ,2 ,0 ,0 ), - { } -}; - -static struct clk_rcg2 apss_tcu_clk_src = { - .cmd_rcgr =0x1207c , - .hid_width =5 , - .parent_map = gcc_xo_gpll0_gpll1_gpll2_map, - .freq_tbl = ftbl_gcc_apss_tcu_clk, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="apss_tcu_clk_src" , - .parent_data = gcc_xo_gpll0_gpll1_gpll2, - .num_parents =4 , - .ops = &clk_rcg2_ops, - }, -}; -static const struct freq_tbl ftbl_gcc_usb_hs_system_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (57140000 ,P_GPLL0 ,14 ,0 ,0 ),
@@ -1511,7 +1477,6 @@ static struct clk_regmap *gcc_mdm9607_cl [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, - [APSS_TCU_CLK_SRC] = &apss_tcu_clk_src.clkr, [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
Greg Kroah-Hartman
maintainerPATCH 403/1424 clk: qcom: gcc-mdm9607: Drop incorrect system_noc_bfdcd_clk_src
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 17784427df923a0573a7ea83f9198456ff1ec1a5 upstream.
This clock does not exist on MDM9607. Reading/writing the registers always results in 0.
Presumably, this definition was mistakenly copied from gcc-msm8916. On MSM8916, this root clock is used for multimedia subsystems (camera, display, video). MDM9607 has none of that, so this clock was probably omitted in the hardware.
There are no users inside gcc-mdm9607, so we can just drop it.
--- drivers/clk/qcom/gcc-mdm9607.c | 13 ------------- 1 file changed, 13 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -13
@@ -240,18 +240,6 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_s }, }; -static struct clk_rcg2 system_noc_bfdcd_clk_src = { - .cmd_rcgr =0x26004 , - .hid_width =5 , - .parent_map = gcc_xo_gpll0_bimc_map, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="system_noc_bfdcd_clk_src" , - .parent_data = gcc_xo_gpll0_bimc, - .num_parents =ARRAY_SIZE (gcc_xo_gpll0_bimc), - .ops = &clk_rcg2_ops, - }, -}; -static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (50000000 ,P_GPLL0 ,16 ,0 ,0 ),
@@ -1450,7 +1438,6 @@ static struct clk_regmap *gcc_mdm9607_cl [BIMC_PLL_VOTE] = &bimc_pll_vote, [BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr, [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr, - [SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr, [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
Greg Kroah-Hartman
maintainerPATCH 404/1424 clk: qcom: gcc-mdm9607: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 944d0fb38cffe57a1d1ebf82c5c077bad82dcdbb upstream.
MDM9607 is similar to MSM8909, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-mdm9607.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +3 -2
@@ -744,9 +744,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x1004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x1004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .parent_data = &(const struct clk_parent_data ){
Greg Kroah-Hartman
maintainerPATCH 405/1424 clk: qcom: gcc-mdm9607: Fix halt_reg for gcc_apss_axi_clk
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit ca7e6cc30cde4f0cbeff2e205a84bedf431e9156 upstream.
gcc_apss_axi_clk specifies a halt_reg of 0x4601c, but this is already used by gcc_apss_ahb_clk. The correct value according to the downstream driver is 0x46020.
--- drivers/clk/qcom/gcc-mdm9607.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -1
@@ -1414,7 +1414,7 @@ static struct clk_branch gcc_apss_ahb_cl };static struct clk_branch gcc_apss_axi_clk = { - .halt_reg =0x4601c , + .halt_reg =0x46020 , .halt_check =BRANCH_HALT_VOTED , .clkr = { .enable_reg =0x45004 ,