6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 236/1887 tipc: prevent GCM nonce reuse on peer key changes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
[ Upstream commit 512ccd3d0e91e791fb37442aa0a2599aca19783d ]
TIPC can encrypt traffic between nodes using a different transmit key for each node. In this mode, the AES-GCM nonce for a packet sent to a known peer consists of a 32-bit prefix (a per-key salt XOR the peer's address) followed by a 64-bit counter. That counter is stored in the peer's RX crypto object. When the peer reports a change in which key it uses to receive packets, TIPC resets this counter. The sender can still be using the same TX key and salt, so subsequent packets reuse earlier nonces. This nonce reuse breaks confidentiality and exposes GCM's authentication key. This makes forgeries trivial: an attacker can exploit CTR malleability to alter captured ciphertexts and use the recovered authentication key to compute a valid tag for the modified ciphertext, under the same key and nonce.
Use the TX key's existing aead->seqno counter instead. All encryptions using that key object share the same atomic counter, so concurrent encryptions get distinct nonce counter values. The counter survives key activation and peer reconnection, and peer key-status reports cannot reset it. This prevents those transitions from causing nonce reuse while the same TX key remains installed.
The nonce format is unchanged, and receivers do not require consecutive counter values, so sharing the counter across peers remains compatible with existing receivers. A pre-existing check still invokes key revocation in the unlikely event that the counter wraps to zero.
--- net/tipc/crypto.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-)
net/tipc/crypto.c +5 -15
@@ -144,7 +144,7 @@ struct tipc_tfm {* @rcu: struct rcu_head * @key: the aead key * @gen: the key's generation -* @seqno: the key seqno (cluster scope) +* @seqno: the per-key TX nonce counter * @refcnt: the key reference counter */ struct tipc_aead {
@@ -190,7 +190,6 @@ struct tipc_crypto_stats {* @rekeying_intv: rekeying interval (in minutes) * @stats: the crypto statistics * @name: the crypto name -* @sndnxt: the per-peer sndnxt (TX) * @timer1: general timer 1 (jiffies) * @timer2: general timer 2 (jiffies) * @working: the crypto is working or not
@@ -219,7 +218,6 @@ struct tipc_crypto {struct tipc_crypto_stats __percpu *stats;char name[48 ]; -atomic64_t sndnxt____cacheline_aligned ;unsigned long timer1;unsigned long timer2;union {
@@ -1060,14 +1058,11 @@ static int tipc_ehdr_build(struct net *net, struct tipc_aead *aead,WARN_ON (skb_headroom (skb) < ehsz); ehdr = (struct tipc_ehdr *)skb_push (skb, ehsz); -/* Obtain a seqno first: -* Use the key seqno (= cluster wise) if dest is unknown or we're in -* cluster key mode, otherwise it's better for a per-peer seqno! +/* +* Keep the nonce unique for the lifetime of the TX key, +* including key state changes and peer reconnection. */ -if (!__rx || aead->mode ==CLUSTER_KEY ) - seqno =atomic64_inc_return (&aead->seqno); -else - seqno =atomic64_inc_return (&__rx->sndnxt); + seqno =atomic64_inc_return (&aead->seqno);/* Revoke the key if seqno is wrapped around */ if (unlikely (!seqno))
@@ -1246,7 +1241,6 @@ void tipc_crypto_key_flush(struct tipc_crypto *c)tipc_crypto_key_set_state (c,0 ,0 ,0 );for (k =KEY_MIN ; k <=KEY_MAX ; k++)tipc_crypto_key_detach (c->aead[k], &c->lock); -atomic64_set (&c->sndnxt,0 );spin_unlock_bh (&c->lock); }
@@ -1393,8 +1387,6 @@ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx,* It also considers if peer has no key, then we need to make own master key * (if any) taking over i.e. starting grace period and also trigger key * distributing process. -* -* The "per-peer" sndnxt is also reset when the peer key has switched. */ static void tipc_crypto_key_synch (struct tipc_crypto *rx,struct sk_buff *skb) {
@@ -1445,7 +1437,6 @@ static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb)if (cur)tipc_aead_users_dec (tx->aead[cur],0 ); -atomic64_set (&rx->sndnxt,0 );/* Mark the point TX key users changed */ tx->timer1 = jiffies;
@@ -1510,7 +1501,6 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,tipc_crypto_key_set_state (c,0 ,0 ,0 );atomic_set (&c->key_distr,0 );atomic_set (&c->peer_rx_active,0 ); -atomic64_set (&c->sndnxt,0 ); c->timer1 = jiffies; c->timer2 = jiffies; c->rekeying_intv =TIPC_REKEYING_INTV_DEF ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 237/1887 net/sched: fq_codel: match the no-drop threshold to the packet size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit d031465acc362866f27e4f8f79cfecf1037fe2e5 ]
commit d9ebd8f9aa8b ("net/sched: fq_codel: clamp default quantum and mtu") clamped both q->quantum and q->cparams.mtu to [256, FQ_CODEL_QUANTUM_MAX]. The two fields mean different things: quantum is a DRR credit that wants the 256 floor, but cparams.mtu is the CoDel no-drop threshold (codel_impl.h "*backlog <= params->mtu"). On a link whose maximum transmitted packet size is below 256, the floor extends CoDel's minimum-backlog exemption beyond one packet and delays drop or mark eligibility by several small packets.
Split the clamp. quantum keeps [256, FQ_CODEL_QUANTUM_MAX]; cparams.mtu tracks psched_mtu() (the device MTU plus its hard-header length) with only the upper bound that guards the original overflow (psched_mtu() wrapping to ~2 GiB on a huge-MTU device).
Conditions to recreate the bug: attach an fq_codel qdisc on a link whose MTU plus hard_header_len is below 256 (e.g. a CAN interface). At that MTU the no-drop threshold must equal the device MTU plus its hard-header length; before this patch it was forced to 256. Basic Testing done: with dev->mtu=100 and hard_header_len=14, a return probe on fq_codel_init() observed cparams.mtu change from 256 to 114
--- net/sched/sch_fq_codel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/sched/sch_fq_codel.c +2 -2
@@ -503,8 +503,8 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, q->flows_cnt =1024 ; q->memory_limit =32 <<20 ;/* 32 MBytes */ q->drop_batch_size =64 ; - mtu =clamp_t (u32,psched_mtu (qdisc_dev (sch)),256 ,FQ_CODEL_QUANTUM_MAX ); - q->quantum = mtu; + mtu =min_t (u32,psched_mtu (qdisc_dev (sch)),FQ_CODEL_QUANTUM_MAX ); + q->quantum =clamp_t (u32, mtu,256 ,FQ_CODEL_QUANTUM_MAX );INIT_LIST_HEAD (&q->new_flows);INIT_LIST_HEAD (&q->old_flows);codel_params_init (&q->cparams);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 238/1887 net/sched: sch_codel: match the no-drop threshold to the packet size
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 54518e0e827f4ca9229ae657022c60bf60f5c1bf ]
commit 6439461f1618 ("net/sched: sch_codel: clamp default mtu to avoid disabling CoDel") clamped q->params.mtu to [256, 1 << 20]. The value is the CoDel no-drop threshold (codel_impl.h "*backlog <= params->mtu"), so on a link whose maximum transmitted packet size is below 256 the floor extends CoDel's minimum-backlog exemption beyond one packet and delays drop or mark eligibility by several small packets.
Keep the upper bound that guards the original overflow (psched_mtu() wrapping to ~2 GiB on a huge-MTU device) but drop the 256 floor, so the threshold tracks the real device packet size.
Conditions to recreate the bug: attach a codel qdisc on a link whose MTU plus hard_header_len is below 256 (e.g. a CAN interface). At that MTU the no-drop threshold must equal the device MTU plus its hard-header length; before this patch it was forced to 256. Requires CAP_NET_ADMIN in a user namespace.
--- net/sched/sch_codel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_codel.c +1 -1
@@ -228,7 +228,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt,codel_params_init (&q->params);codel_vars_init (&q->vars);codel_stats_init (&q->stats); - q->params.mtu =clamp_t (u32,psched_mtu (qdisc_dev (sch)),256 ,1 <<20 ); + q->params.mtu =min_t (u32,psched_mtu (qdisc_dev (sch)),1 <<20 );if (opt) {int err =codel_change (sch, opt, extack);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 239/1887 net: bcmgenet: fix NULL dereference in set_coalesce before first open
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 19419faf58dfe5bcc8a9e60e622976c5f8e3ddc1 ]
The Rx ring priv and index are only set in bcmgenet_init_rx_ring(), which runs at open. Setting the Rx coalescing parameters on an interface that was never opened, e.g. "ethtool -C eth0 rx-usecs 50", dereferences a NULL ring->priv. The oops happens with RTNL held, so networking stays stuck until a reboot:
Unable to handle kernel paging request at virtual address 0000000000002788 pc : bcmgenet_set_rx_coalesce.isra.0+0x10/0x88 lr : bcmgenet_set_coalesce+0xe8/0x180 Call trace: bcmgenet_set_rx_coalesce.isra.0+0x10/0x88 (P) __ethnl_set_coalesce.isra.0+0x490/0x570 ethnl_set_coalesce+0x48/0xc0 ethnl_default_set_doit+0xf4/0x230 genl_family_rcv_msg_doit+0xe8/0x160 genl_rcv_msg+0x220/0x2a0 netlink_rcv_skb+0x68/0x140 genl_rcv+0x40/0x60 netlink_unicast+0x338/0x3c0 netlink_sendmsg+0x19c/0x3f8 __sock_sendmsg+0x64/0xc0 __sys_sendto+0x124/0x198 __arm64_sys_sendto+0x30/0x48
Set priv and index at probe. Writing the registers while the interface is down is harmless because open resets the MAC and bcmgenet_init_rx_coalesce() reapplies the stored values.
It was observed on a Raspberry Pi CM4, but should apply to all other genet devices.
--- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +4 -1
@@ -4079,8 +4079,11 @@ static int bcmgenet_probe(struct platform_device *pdev)netif_set_real_num_rx_queues (priv->dev, priv->hw_params->rx_queues +1 );/* Set default coalescing parameters */ -for (i =0 ; i <= priv->hw_params->rx_queues; i++) +for (i =0 ; i <= priv->hw_params->rx_queues; i++) { + priv->rx_rings[i].priv = priv; + priv->rx_rings[i].index = i; priv->rx_rings[i].rx_max_coalesced_frames =1 ; + }/* Initialize u64 stats seq counter for 32bit machines */ for (i =0 ; i <=GENET_MAX_MQ_CNT ; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 240/1887 tcp: refresh TS.Recent for accepted old ACKs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Jo <[email protected]>
[ Upstream commit 1b92780ae4fc3be64f05d97ed8833c445e73b0cf ]
A TCP packet can carry new data while acknowledging traffic in the opposite direction. With overlapping traffic in both directions, a delayed packet's acknowledgment can be older than one Linux has already accepted, even when that packet fills a gap in the received data.
Linux accepts the data, but tcp_ack() takes the old_ack path and skips updating TS.Recent, the timestamp saved for outgoing acknowledgments. The reply therefore echoes an older timestamp. If the sender uses this echo to measure round-trip time after a long idle period, its estimate includes the idle time and can reduce its sending rate.
Update TS.Recent in old_ack using tcp_replace_ts_recent(), before SACK processing can trigger a transmission. This reuses the existing timestamp and sequence checks, including PAWS protection against old duplicate packets. ACK validation already rejects old ACKs in SYN_RECV before this path, so no additional state check is needed.
Echoing the timestamp of the packet that fills the receive gap follows RFC 7323 section 4.3. In a socket reproduction with 300 seconds idle, controlled reordering and retransmission to exercise timestamp-based RTT sampling, the sender's smoothed round-trip time was 37.5 seconds without the fix and 15.5 ms with it.
--- net/ipv4/tcp_input.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/ipv4/tcp_input.c +6 -0
@@ -4024,6 +4024,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)return 1 ; old_ack: +/* An old ACK can carry new data. Update TS.Recent before SACK +* processing can trigger a retransmission. +*/ +if (flag &FLAG_UPDATE_TS_RECENT ) +tcp_replace_ts_recent (tp,TCP_SKB_CB (skb)->seq); +/* If data was SACKed, tag it and see if we should send more data. * If data was DSACKed, see if we can undo a cwnd reduction. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 241/1887 ipvs: fix missing counter decrement in lblc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit bdac17779f46817f60103baf09f0370546c3f023 ]
LBLC may delete cache entries for destinations that are removed or overloaded and replace them with available ones. But ip_vs_lblc_new() forgets to decrement the tbl->entries counter after calling ip_vs_lblc_del(). This can lead to increased shrinking of the cache with every new garbage collection.
--- net/netfilter/ipvs/ip_vs_lblc.c | 1 + 1 file changed, 1 insertion(+)
net/netfilter/ipvs/ip_vs_lblc.c +1 -0
@@ -205,6 +205,7 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,if (en->dest == dest)return en;ip_vs_lblc_del (en); +atomic_dec (&tbl->entries); } en =kmalloc (sizeof (*en),GFP_ATOMIC );if (!en)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 242/1887 ipvs: do not create invisible templates
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit 616cf5c06934364ab1002b420ebe975850b4b208 ]
The IP_VS_CONN_F_ONE_PACKET flag was implemented for normal connections. When conn template inherits this flag from dest->conn_flags it will not be hashed. As result, we will create new template for every new normal connection.
Fix it to allow one template to be used by many normal connections.
--- net/netfilter/ipvs/ip_vs_conn.c | 3 +++ 1 file changed, 3 insertions(+)
net/netfilter/ipvs/ip_vs_conn.c +3 -0
@@ -591,6 +591,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)if (cp->protocol !=IPPROTO_UDP ) conn_flags &= ~IP_VS_CONN_F_ONE_PACKET ; flags = cp->flags; +/* Only visible templates can control multiple connections */ +if (flags &IP_VS_CONN_F_TEMPLATE ) + conn_flags &= ~IP_VS_CONN_F_ONE_PACKET ;/* Bind with the destination and its corresponding transmitter */ if (flags &IP_VS_CONN_F_SYNC ) {/* Synced conns are hashed, so they can not get this flag */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 243/1887 ipvs: filter some flags received in the backup server
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit f96e91748f6304668fe647e686d199d7207d36f1 ]
While the IPVS SYNC protocol is not secure by design we can still protect the backup server from messages that can wreak havoc.
This commit addresses problems from received connection flags or their combinations. We now drop messages as follows:
1. the NO_CPORT+TEMPLATE combination allows lookups for normal connections to hit template which can break in many ways. While the master does not sync connections with NO_CPORT flag, i.e. before they are established, we still accept NO_CPORT without TEMPLATE.
2. ONE_PACKET: it is not sent by master, so we do not expect it in backup. Before now it was ignored by IP_VS_CONN_F_BACKUP_MASK for protocol v1 while protocol v0 created connections that are not hashed and dropped immediately. Better to apply the IP_VS_CONN_F_BACKUP_MASK also to the flags from v0 messages for consistency with v1.
--- net/netfilter/ipvs/ip_vs_sync.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-)
net/netfilter/ipvs/ip_vs_sync.c +30 -3
@@ -950,6 +950,21 @@ static void ip_vs_proc_conn(struct netns_ipvs *ipvs, struct ip_vs_conn_param *paip_vs_conn_put (cp); } +/* Check for incompatible flags */ +static bool ip_vs_sync_validate_flags (u32 flags) +{ +/* We do not expect NO_CPORT, especially to allow lookups +* to hit templates +*/ +if (flags &IP_VS_CONN_F_NO_CPORT ) { +if (flags &IP_VS_CONN_F_TEMPLATE ) +return false; + } +if (flags &IP_VS_CONN_F_ONE_PACKET ) +return false; +return true; +} +/* * Process received multicast message for Version 0 */
@@ -973,8 +988,7 @@ static void ip_vs_process_message_v0(struct netns_ipvs *ipvs, const char *bufferreturn ; } s = (struct ip_vs_sync_conn_v0 *) p; - flags =ntohs (s->flags) |IP_VS_CONN_F_SYNC ; - flags &= ~IP_VS_CONN_F_HASHED ; + flags =ntohs (s->flags);if (flags &IP_VS_CONN_F_SEQ_MASK ) { opt = (struct ip_vs_sync_conn_options *)&s[1 ]; p +=FULL_CONN_SIZE ;
@@ -987,6 +1001,13 @@ static void ip_vs_process_message_v0(struct netns_ipvs *ipvs, const char *buffer p +=SIMPLE_CONN_SIZE ; } +if (!ip_vs_sync_validate_flags (flags)) { +IP_VS_DBG (2 ,"BACKUP v0, Invalid flags 0x%X\n" , flags); +continue ; + } + flags &=IP_VS_CONN_F_BACKUP_MASK ; + flags |=IP_VS_CONN_F_SYNC ; + state =ntohs (s->state);if (!(flags &IP_VS_CONN_F_TEMPLATE )) { pp =ip_vs_proto_get (s->protocol);
@@ -1142,7 +1163,13 @@ static inline int ip_vs_proc_sync_conn(struct netns_ipvs *ipvs, __u8 *p, __u8 *m }/* Get flags and Mask off unsupported */ - flags =ntohl (s->v4.flags) &IP_VS_CONN_F_BACKUP_MASK ; + flags =ntohl (s->v4.flags); +if (!ip_vs_sync_validate_flags (flags)) { +IP_VS_DBG (3 ,"BACKUP, Invalid flags 0x%X\n" , flags); + retc =25 ; + goto out; + } + flags &=IP_VS_CONN_F_BACKUP_MASK ; flags |=IP_VS_CONN_F_SYNC ; state =ntohs (s->v4.state);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 244/1887 netfilter: bpf: reject invalid NAT manipulation types
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 16d464013ec2267b00a83f4bfbb97b3ecc63bfa7 ]
As bpf_ct_set_nat_info() is not validating the NAT manipulation type a wrong value can be passed directly to nf_nat_setup_info(). This triggers the WARN_ON() at nf_nat_setup_info() and if panic_on_warn isn't set, then IPS_SRC_NAT_DONE is set without adding nat_bysource and conntrack cleanup tries to unlink an uninitialized hlist node.
Fix this by checking that NAT manipulation type is correct before calling nf_nat_setup_info(). In addition, if the WARN_ON is hit, return NF_DROP instead of continuing with the processing to avoid similar situations in the future.
--- net/netfilter/nf_nat_bpf.c | 3 +++ net/netfilter/nf_nat_core.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-)
net/netfilter/nf_nat_bpf.c +3 -0
@@ -41,6 +41,9 @@ int bpf_ct_set_nat_info(struct nf_conn___init *nfct,if (proto !=NFPROTO_IPV4 && proto !=NFPROTO_IPV6 )return -EINVAL ; +if (manip !=NF_NAT_MANIP_SRC && manip !=NF_NAT_MANIP_DST ) +return -EINVAL ; +memset (&range,0 ,sizeof (struct nf_nat_range2 )); range.flags =NF_NAT_RANGE_MAP_IPS ; range.min_addr = *addr;
net/netfilter/nf_nat_core.c +3 -2
@@ -588,8 +588,9 @@ nf_nat_setup_info(struct nf_conn *ct,if (nf_ct_is_confirmed (ct))return NF_ACCEPT ; -WARN_ON (maniptype !=NF_NAT_MANIP_SRC && - maniptype !=NF_NAT_MANIP_DST ); +if (WARN_ON (maniptype !=NF_NAT_MANIP_SRC && + maniptype !=NF_NAT_MANIP_DST )) +return NF_DROP ;if (WARN_ON (nf_nat_initialized (ct, maniptype)))return NF_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 245/1887 net: sparx5: make ports inherit the switch base mac address type
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Quentin Freimanis <[email protected]>
[ Upstream commit 5642b1648d5c4561d8ed7a410d0a7017f706604d ]
When the switch uses a random base MAC address it does not mark each port's address as random:
$ dmesg | grep "MAC addr" sparx5-switch e00c0000.switch: MAC addr was not set, use random MAC $ cat /sys/class/net/eth0/addr_assign_type 0
0 is NET_ADDR_PERM, so userspace thinks this is a stable address.
With a random MAC reported as NET_ADDR_PERM, systemd's MACAddressPolicy=persistent [1] leaves it unchanged, so a DHCP client gets a new IP address every boot and a static reservation can't be used. Reporting it as NET_ADDR_RANDOM makes systemd replace it with a stable address derived from the interface name and machine-id.
--- drivers/net/ethernet/microchip/sparx5/sparx5_main.c | 1 + drivers/net/ethernet/microchip/sparx5/sparx5_main.h | 1 + drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c | 1 + 3 files changed, 3 insertions(+)
drivers/net/ethernet/microchip/sparx5/sparx5_main.c +1 -0
@@ -828,6 +828,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)dev_info (sparx5->dev,"MAC addr was not set, use random MAC\n" );eth_random_addr (sparx5->base_mac); sparx5->base_mac[5 ] =0 ; + sparx5->base_mac_assign_type =NET_ADDR_RANDOM ; } sparx5->fdma_irq =platform_get_irq_byname (sparx5->pdev,"fdma" );
drivers/net/ethernet/microchip/sparx5/sparx5_main.h +1 -0
@@ -255,6 +255,7 @@ struct sparx5 {struct notifier_block switchdev_blocking_nb;/* Switch state */ u8 base_mac[ETH_ALEN ]; +u8 base_mac_assign_type;/* Associated bridge device (when bridged) */ struct net_device *hw_bridge_dev;/* Bridged interfaces */
drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c +1 -0
@@ -270,6 +270,7 @@ struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno) ndev->ethtool_ops = &sparx5_ethtool_ops;eth_hw_addr_gen (ndev, sparx5->base_mac, portno +1 ); + ndev->addr_assign_type = sparx5->base_mac_assign_type;return ndev; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 246/1887 net: add and use skb_get_hash_net
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit b975d3ee5962237c1e2f5d5aeeaaf0dc2173486c ]
Years ago flow dissector gained ability to delegate flow dissection to a bpf program, scoped per netns.
Unfortunately, skb_get_hash() only gets an sk_buff argument instead of both net+skb. This means the flow dissector needs to obtain the netns pointer from somewhere else.
The netns is derived from skb->dev, and if that is not available, from skb->sk. If neither is set, we hit a (benign) WARN_ON_ONCE().
Trying both dev and sk covers most cases, but not all, as recently reported by Christoph Paasch.
In case of nf-generated tcp reset, both sk and dev are NULL:
WARNING: .. net/core/flow_dissector.c:1104
skb_flow_dissect_flow_keys include/linux/skbuff.h:1536 [inline] skb_get_hash include/linux/skbuff.h:1578 [inline] nft_trace_init+0x7d/0x120 net/netfilter/nf_tables_trace.c:320 nft_do_chain+0xb26/0xb90 net/netfilter/nf_tables_core.c:268 nft_do_chain_ipv4+0x7a/0xa0 net/netfilter/nft_chain_filter.c:23 nf_hook_slow+0x57/0x160 net/netfilter/core.c:626 __ip_local_out+0x21d/0x260 net/ipv4/ip_output.c:118 ip_local_out+0x26/0x1e0 net/ipv4/ip_output.c:127 nf_send_reset+0x58c/0x700 net/ipv4/netfilter/nf_reject_ipv4.c:308 nft_reject_ipv4_eval+0x53/0x90 net/ipv4/netfilter/nft_reject_ipv4.c:30 [..]
syzkaller did something like this:
table inet filter {
chain input {
type filter hook input priority filter; policy accept; meta nftrace set 1
tcp dport 42 reject with tcp reset
}
chain output {
type filter hook output priority filter; policy accept; # empty chain is enough
}
}
... then sends a tcp packet to port 42.
Initial attempt to simply set skb->dev from nf_reject_ipv4 doesn't cover all cases: skbs generated via ipv4 igmp_send_report trigger similar splat.
Moreover, Pablo Neira found that nft_hash.c uses __skb_get_hash_symmetric() which would trigger same warn splat for such skbs.
Lets allow callers to pass the current netns explicitly. The nf_trace infrastructure is adjusted to use the new helper.
__skb_get_hash_symmetric is handled in the next patch.
Stable-dep-of: 8ec454dcd00c ("ipv6: sr: use skb_get_hash_net() in seg6_make_flowlabel()")
--- include/linux/skbuff.h | 12 ++++++++++-- net/core/flow_dissector.c | 15 +++++++++++---- net/netfilter/nf_tables_trace.c | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-)
include/linux/skbuff.h +10 -2
@@ -1487,7 +1487,7 @@ __skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)__skb_set_hash (skb, hash, true, is_l4); } -void __skb_get_hash (struct sk_buff *skb); +void __skb_get_hash_net (const struct net *net,struct sk_buff *skb);u32 __skb_get_hash_symmetric (const struct sk_buff *skb);u32 skb_get_poff (const struct sk_buff *skb); u32 __skb_get_poff(const struct sk_buff *skb, const void *data,
@@ -1567,10 +1567,18 @@ void skb_flow_dissect_hash(const struct sk_buff *skb,struct flow_dissector *flow_dissector, void *target_container); +static inline __u32 skb_get_hash_net (const struct net *net,struct sk_buff *skb) +{ +if (!skb->l4_hash && !skb->sw_hash) +__skb_get_hash_net (net, skb); + +return skb->hash; +} +static inline __u32 skb_get_hash (struct sk_buff *skb) {if (!skb->l4_hash && !skb->sw_hash) -__skb_get_hash (skb); +__skb_get_hash_net (NULL , skb);return skb->hash; }
net/core/flow_dissector.c +11 -4
@@ -1760,7 +1760,8 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)EXPORT_SYMBOL_GPL (__skb_get_hash_symmetric);/** -* __skb_get_hash: calculate a flow hash +* __skb_get_hash_net: calculate a flow hash +* @net: associated network namespace, derived from @skb if NULL * @skb: sk_buff to calculate flow hash from * * This function calculates a flow hash based on src/dst addresses
@@ -1768,18 +1769,24 @@ EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);* on success, zero indicates no valid hash. Also, sets l4_hash in skb * if hash is a canonical 4-tuple hash over transport ports. */ -void __skb_get_hash (struct sk_buff *skb) +void __skb_get_hash_net (const struct net *net,struct sk_buff *skb) {struct flow_keys keys;u32 hash; +memset (&keys,0 ,sizeof (keys)); + +__skb_flow_dissect (net, skb, &flow_keys_dissector, + &keys,NULL ,0 ,0 ,0 , +FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL ); +__flow_hash_secret_init (); - hash =___skb_get_hash (skb, &keys, &hashrnd); + hash =__flow_hash_from_keys (&keys, &hashrnd);__skb_set_sw_hash (skb, hash,flow_keys_have_l4 (&keys)); } -EXPORT_SYMBOL (__skb_get_hash); +EXPORT_SYMBOL (__skb_get_hash_net);__u32 skb_get_hash_perturb (const struct sk_buff *skb,const siphash_key_t *perturb)
net/netfilter/nf_tables_trace.c +1 -1
@@ -289,7 +289,7 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,net_get_random_once (&trace_key,sizeof (trace_key)); info->skbid = (u32 )siphash_3u32 (hash32_ptr (skb), -skb_get_hash (skb), +skb_get_hash_net (nft_net (pkt), skb), skb->skb_iif, &trace_key); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 247/1887 ipv6: sr: use skb_get_hash_net() in seg6_make_flowlabel()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 8ec454dcd00ce3375119111c6394964455b36d0d ]
Since commit d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") __skb_flow_dissect() needs a net pointer, either from skb->dev, skb->sk, or since commit 3cbf4ffba5ee ("net: plumb network namespace into __skb_flow_dissect") a caller provided pointer.
syzbot was able to reach seg6_make_flowlabel() with an skb having neither skb->dev nor skb->sk set: a TIPC UDP bearer sends a discovery message through an IPv4 route using seg6 encap, while net.ipv6.seg6_flowlabel is set to 1.
seg6_make_flowlabel() already has a net pointer, use skb_get_hash_net().
WARNING: net/core/flow_dissector.c:1131 at __skb_flow_dissect+0x910/0x5368 net/core/flow_dissector.c:1126, CPU#0: syz.0.17/4930 Call trace: __skb_flow_dissect+0x910/0x5368 net/core/flow_dissector.c:1126 (P) __skb_get_hash_net+0xe0/0x29c net/core/flow_dissector.c:1903 skb_get_hash include/linux/skbuff.h:1663 [inline] seg6_make_flowlabel+0xcc/0x1ec net/ipv6/seg6_iptunnel.c:132 __seg6_do_srh_encap+0x320/0xbf4 net/ipv6/seg6_iptunnel.c:161 seg6_do_srh+0x4b4/0xa44 net/ipv6/seg6_iptunnel.c:431 seg6_output_core+0x164/0x688 net/ipv6/seg6_iptunnel.c:681 seg6_output+0x44/0x1ac net/ipv6/seg6_iptunnel.c:744 lwtunnel_output+0x3d0/0x664 net/core/lwtunnel.c:356 dst_output include/net/dst.h:470 [inline] ip_local_out+0x110/0x148 net/ipv4/ip_output.c:131 iptunnel_xmit+0x50c/0xd38 net/ipv4/ip_tunnel_core.c:97 udp_tunnel_xmit_skb+0x220/0x348 net/ipv4/udp_tunnel_core.c:187 tipc_udp_xmit+0x75c/0x9c0 net/tipc/udp_media.c:202 tipc_udp_send_msg+0x214/0x374 net/tipc/udp_media.c:274 tipc_bearer_xmit_skb+0x260/0x3b0 net/tipc/bearer.c:576 tipc_enable_bearer net/tipc/bearer.c:366 [inline] __tipc_nl_bearer_enable+0xc90/0xfb0 net/tipc/bearer.c:1048 tipc_nl_bearer_enable+0x2c/0x48 net/tipc/bearer.c:1057 genl_family_rcv_msg_doit+0x1e4/0x2d4 net/netlink/genetlink.c:1114
--- net/ipv6/seg6_iptunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/seg6_iptunnel.c +1 -1
@@ -116,7 +116,7 @@ static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,u32 hash;if (do_flowlabel >0 ) { - hash =skb_get_hash (skb); + hash =skb_get_hash_net (net, skb); hash =rol32 (hash,16 ); flowlabel = (__force __be32 )hash &IPV6_FLOWLABEL_MASK ; }else if (!do_flowlabel && skb->protocol ==htons (ETH_P_IPV6 )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 248/1887 i2c: at91: release DMA channels when probe defers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongjian Dai <[email protected]>
[ Upstream commit c98bf3b86609a18ab16d067280257326e557c636 ]
at91_twi_probe_master() can return -EPROBE_DEFER from at91_init_twi_recovery_info() after at91_twi_configure_dma() has already claimed the tx/rx DMA channels. at91_twi_probe() then returns without releasing them, and since dma_request_chan() is not devres-managed the channels leak on every deferred probe attempt.
Release the channels before deferring the probe.
--- drivers/i2c/busses/i2c-at91-master.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-at91-master.c +7 -1
@@ -919,8 +919,14 @@ int at91_twi_probe_master(struct platform_device *pdev,at91_calc_twi_clock (dev); rc =at91_init_twi_recovery_info (pdev, dev); -if (rc == -EPROBE_DEFER ) +if (rc == -EPROBE_DEFER ) { +/* +* The DMA channels were already set up above, release them +* before deferring the probe so they are not leaked. +*/ +at91_twi_dma_release (dev);return rc; + } dev->adapter.algo = &at91_twi_algorithm; dev->adapter.quirks = &at91_twi_quirks;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 249/1887 perf: Fix race between perf_event_exit_task() and perf_pending_task()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luo Gengkun <[email protected]>
[ Upstream commit ffb684f2aa141eeb0caa6308422e7e05d1ded7c4 ]
A race condition exists between perf_event_exit_task() and perf_pending_task() during begin_new_exec().
During begin_new_exec(), perf_event_exit_task() may be called, and the PF_EXITING flag is not set on task. So perf_sigtrap() continues to execute and triggers WARN_ON_ONCE(event->ctx->task != current).
Since both task exit and exec paths can call perf_event_exit_task() which sets ctx->task to TASK_TOMBSTONE, fix this by explicitly checking if event->ctx->task equals TASK_TOMBSTONE and dropping the redundant PF_EXITING check.
--- kernel/events/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/events/core.c +4 -2
@@ -6596,9 +6596,11 @@ static void perf_sigtrap(struct perf_event *event) {/* * Both perf_pending_task() and perf_pending_irq() can race with the -* task exiting. +* task exiting or exec-ing. We can determine if such a race has +* occurred by checking if perf_event_exit_task(), which will set +* ctx->task to TASK_TOMBSTONE, has already been called. */ -if (current->flags &PF_EXITING ) +if (event->ctx->task ==TASK_TOMBSTONE )return ;/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 250/1887 PCI: Accept AtomicOps already enabled by the hypervisor
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikola Prica <[email protected]>
[ Upstream commit 40cce45b921f7930886bcba43069edc579725457 ]
pci_enable_atomic_ops_to_root() currently fails when no Root Port is visible. That is common in passthrough guests (ESXi, Hyper-V): the Endpoint is assigned to the VM, but the Root Port above it is not visible in the guest topology.
In those setups the hypervisor may already have enabled AtomicOp Requester Enable on the device. If PCI_EXP_DEVCTL2_ATOMIC_REQ is set, treat AtomicOps as already enabled and return success instead of failing the Root Port walk.
After 1ae8c4ce1570 ("PCI: Enable AtomicOps only if Root Port supports them"), pci_enable_atomic_ops_to_root() always returns failure if the Root Port is not visible, so drivers don't use atomics when they could. On systems where the Root Port is not visible but *does* support AtomicOps, this is a regression: prior to 1ae8c4ce1570, it enabled AtomicOps in the endpoint and returned success.
--- drivers/pci/pci.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/pci/pci.c +14 -1
@@ -3822,8 +3822,21 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) } root =pcie_find_root_port (dev); -if (!root) +if (!root) { + +/* +* A hypervisor may expose a topology with the root port +* not visible to the guest. If the hypervisor has already +* set AtomicOp Requester Enable in the endpoint, we assume +* it has verified support in the root port, so it is safe +* for the driver to use AtomicOps. +*/ +pcie_capability_read_dword (dev,PCI_EXP_DEVCTL2 , &ctl2); +if (ctl2 &PCI_EXP_DEVCTL2_ATOMIC_REQ ) +return 0 ; +return -EINVAL ; + }pcie_capability_read_dword (root,PCI_EXP_DEVCAP2 , &cap);if ((cap & cap_mask) != cap_mask)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 251/1887 drm/amd/pm/si: Check AMD_IS_MOBILITY flag for PPSMC_SYSTEMFLAG_GPIO_DC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit cd883d0a3937df82a5ea03709ba8ba623b868419 upstream.
Unfortunately, some desktop boards eg. the FirePro D500 have the HARDWAREDC platform flag set and also have a battery power state configured in their VBIOS. This makes no sense for a desktop GPU and results in incorrect behaviour: the clocks are stuck at lowest.
We observed that the kernel driver can work around the issue in two possible ways:
1. Set PPSMC_SWSTATE_FLAG_DC on all power states
2. Clear PPSMC_SYSTEMFLAG_GPIO_DC
We think that the PPSMC_SYSTEMFLAG_GPIO_DC flag makes the SMC assume it's running on battery even though this is a desktop machine with no battery, and that's why it doesn't do DPM on power states without PPSMC_SYSTEMFLAG_GPIO_DC.
Issue was uncovered by "Fix updating clock limits from power states" because previously the limits for the battery state were not tracked separately. However, battery power state has lower frequencies and voltages, so the kernel doesn't set the DC flag on the current power state anymore. That causes the SMC to be stuck on the lowest clocks.
Let's clear PPSMC_SYSTEMFLAG_GPIO_DC on desktop GPUs. We can use the AMD_IS_MOBILITY flag to determine that.
--- drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +2 -1
@@ -5239,7 +5239,8 @@ static int si_init_smc_table(struct amdgbreak ; } -if (adev->pm.dpm.platform_caps &ATOM_PP_PLATFORM_CAP_HARDWAREDC ) +if ((adev->flags &AMD_IS_MOBILITY ) && + (adev->pm.dpm.platform_caps &ATOM_PP_PLATFORM_CAP_HARDWAREDC )) table->systemFlags |=PPSMC_SYSTEMFLAG_GPIO_DC ;if (adev->pm.dpm.platform_caps &ATOM_PP_PLATFORM_CAP_REGULATOR_HOT ) {
Greg Kroah-Hartman
maintainerPATCH 252/1887 drm/amd/pm/si: Fix updating clock limits on AC/DC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 08c9100f65299c64439e22e6057d750ae0e6c660 upstream.
Assume that the AC limits are the maximum of all power states, and the DC limits are the maximum of battery power states. This shouldn't make any difference in practice, but is cleaner and more robust against bogus information in the VBIOS.
--- drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-)
drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +18 -18
@@ -7211,6 +7211,19 @@ static void si_parse_pplib_non_clock_inf adev->pm.dpm.uvd_ps = rps; } +static void si_update_limits (struct amdgpu_clock_and_voltage_limits *limits, +struct rv7xx_pl *pl) +{ +if (pl->sclk > limits->sclk) + limits->sclk = pl->sclk; +if (pl->mclk > limits->mclk) + limits->mclk = pl->mclk; +if (pl->vddc > limits->vddc) + limits->vddc = pl->vddc; +if (pl->vddci > limits->vddci) + limits->vddci = pl->vddci; +} +static void si_parse_pplib_clock_info (struct amdgpu_device *adev,struct amdgpu_ps *rps,int index,union pplib_clock_info *clock_info)
@@ -7219,7 +7232,6 @@ static void si_parse_pplib_clock_info(ststruct evergreen_power_info *eg_pi =evergreen_get_pi (adev);struct si_power_info *si_pi =si_get_pi (adev);struct si_ps *ps =si_get_ps (rps); -struct amdgpu_clock_and_voltage_limits *limits;u16 leakage_voltage;struct rv7xx_pl *pl = &ps->performance_levels[index];int ret;
@@ -7284,26 +7296,14 @@ static void si_parse_pplib_clock_info(st* VBIOS can contain conflicting values between: * - the maximum allowed clocks and voltages on AC or DC * - the clocks and voltages in power states on AC or DC +* +* Assume that the AC limits are the maximum of all power states, +* and the DC limits are the maximum of battery power states. */ +si_update_limits (&adev->pm.dpm.dyn_state.max_clock_voltage_on_ac, pl);if ((rps->class &ATOM_PPLIB_CLASSIFICATION_UI_MASK ) == -ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE ) - limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; -else if ((rps->class &ATOM_PPLIB_CLASSIFICATION_UI_MASK ) ==ATOM_PPLIB_CLASSIFICATION_UI_BATTERY ) - limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; -else - limits =NULL ; - -if (limits) { -if (pl->sclk > limits->sclk) - limits->sclk = pl->sclk; -if (pl->mclk > limits->mclk) - limits->mclk = pl->mclk; -if (pl->vddc > limits->vddc) - limits->vddc = pl->vddc; -if (pl->vddci > limits->vddci) - limits->vddci = pl->vddci; - } +si_update_limits (&adev->pm.dpm.dyn_state.max_clock_voltage_on_dc, pl); }union pplib_power_state {
Greg Kroah-Hartman
maintainerPATCH 253/1887 drm/amdgpu/gfx6: fix firmware leak on teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Willian Oliveira <[email protected]>
commit cc172e177795c5f87bc2d71768d077e1c10633e8 upstream.
The firmware requested in gfx_v6_0_init_microcode() is not released when the GFX block is torn down, leaking the firmware resources.
Add gfx_v6_0_free_microcode() and call it from gfx_v6_0_sw_fini() to release the PFP, ME, CE and RLC firmware.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +9 -0
@@ -308,6 +308,14 @@ static const u32 verde_rlc_save_restore_ 0x00000000 }; +static void gfx_v6_0_free_microcode (struct amdgpu_device *adev) +{ +amdgpu_ucode_release (&adev->gfx.pfp_fw); +amdgpu_ucode_release (&adev->gfx.me_fw); +amdgpu_ucode_release (&adev->gfx.ce_fw); +amdgpu_ucode_release (&adev->gfx.rlc_fw); +} +static int gfx_v6_0_init_microcode (struct amdgpu_device *adev) {const char *chip_name;
@@ -3197,6 +3205,7 @@ static int gfx_v6_0_sw_fini(void *handleamdgpu_ring_fini (&adev->gfx.compute_ring[i]);amdgpu_gfx_rlc_fini (adev); +gfx_v6_0_free_microcode (adev);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 254/1887 drm/radeon: Read the VRAM VBIOS signature with readb()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imre Kaloz <[email protected]>
commit de1eab13efef83fd2b76f4688de5bf672644596f upstream.
igp_read_bios_from_vram() checked bios[0]/bios[1] with a plain __iomem load, which faults on sparc64 before the copy runs at all. radeon_read_bios() already reads its two signature bytes with readb() ahead of its own copy; use the same accessor here, keeping the check before the allocation.
--- drivers/gpu/drm/radeon/radeon_bios.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/radeon/radeon_bios.c +5 -1
@@ -49,6 +49,7 @@static bool igp_read_bios_from_vram (struct radeon_device *rdev) {uint8_t __iomem *bios; +uint8_t val1, val2;resource_size_t vram_base;resource_size_t size =256 *1024 ;/* ??? */
@@ -63,7 +64,10 @@ static bool igp_read_bios_from_vram(strureturn false; } -if (size ==0 || bios[0 ] !=0x55 || bios[1 ] !=0xaa ) { + val1 =readb (&bios[0 ]); + val2 =readb (&bios[1 ]); + +if (size ==0 || val1 !=0x55 || val2 !=0xaa ) {iounmap (bios);return false; }
Greg Kroah-Hartman
maintainerPATCH 255/1887 drm/amdgpu: fix IP instance memory leak on kobject add failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit f5a5add3605935163dd0f75749b6a7869e9765af upstream.
amdgpu_discovery_sysfs_ips() allocates ip_hw_instance with kzalloc_flex() and initializes its embedded kobject before calling kobject_add().
If kobject_add() fails, the return value is ignored and execution continues without dropping the initial kobject reference. The failed kobject is not retained in the kset list, so the normal sysfs teardown path cannot find it. As a result, ip_hw_instance_release() is never called and the ip_hw_instance allocation is leaked.
Call kobject_put() when kobject_add() fails so the initial reference is dropped and ip_hw_instance_release() can free the allocation. Keep the existing best-effort sysfs behavior by continuing with the remaining IP entries after the failed registration.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +2 -0
@@ -903,6 +903,8 @@ static int amdgpu_discovery_sysfs_ips(st ip_hw_instance->kobj.kset = &ip_hw_id->hw_id_kset; res =kobject_add (&ip_hw_instance->kobj,NULL ,"%d" , ip_hw_instance->num_instance); +if (res) +kobject_put (&ip_hw_instance->kobj); next_ip: ip_offset +=struct_size (ip, base_address, ip->num_base_address); }
Greg Kroah-Hartman
maintainerPATCH 256/1887 drm/amdgpu: fix ACP MFD device leak on init failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit f0013046151b7467e62c471c1c83d63ea255799c upstream.
acp_hw_init() registers ACP child devices with mfd_add_devices() before attaching them to the ACP power domain and initializing the hardware.
If attaching a child to the power domain fails, or if the ACP reset or clock enable operation times out, the failure path frees only the source cell, resource, and platform-data allocations. The child platform devices already registered by mfd_add_devices() remain registered and are never released.
Remove the children from the power domain and unregister the MFD devices on failures that occur after mfd_add_devices() succeeds. Keep mfd_add_devices() failures on the existing cleanup path since the MFD core already rolls back partially registered children itself.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +9 -4
@@ -324,7 +324,7 @@ static int acp_hw_init(void *handle) r =device_for_each_child (adev->acp.parent, &adev->acp.acp_genpd->gpd, acp_genpd_add_device);if (r) - goto failure; + goto failure_remove_mfd;break ; }default :
@@ -446,7 +446,7 @@ static int acp_hw_init(void *handle) r =device_for_each_child (adev->acp.parent, &adev->acp.acp_genpd->gpd, acp_genpd_add_device);if (r) - goto failure; + goto failure_remove_mfd; }/* Assert Soft reset of ACP */
@@ -464,7 +464,7 @@ static int acp_hw_init(void *handle)if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); r = -ETIMEDOUT ; - goto failure; + goto failure_remove_mfd; }udelay (100 ); }
@@ -482,7 +482,7 @@ static int acp_hw_init(void *handle)if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); r = -ETIMEDOUT ; - goto failure; + goto failure_remove_mfd; }udelay (100 ); }
@@ -492,6 +492,11 @@ static int acp_hw_init(void *handle)cgs_write_register (adev->acp.cgs_device, mmACP_SOFT_RESET, val);return 0 ; +failure_remove_mfd: +device_for_each_child (adev->acp.parent,NULL , + acp_genpd_remove_device); +mfd_remove_devices (adev->acp.parent); + failure:kfree (i2s_pdata);kfree (adev->acp.acp_res);
Greg Kroah-Hartman
maintainerPATCH 257/1887 binder: fix is_failure flag for superseded transaction cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomer Pomeranc <[email protected]>
commit 22c135635fdd9816c0ef140d6de7b2e4fdf73e89 upstream.
When a TF_UPDATE_TXN transaction supersedes a pending async transaction, binder_release_entire_buffer() is called with is_failure=false. Since the superseded transaction was never delivered, binder_apply_fd_fixups() was never called and no fds were installed in the target process.
With is_failure=false, the BINDER_TYPE_FDA cleanup handler interprets stale buffer contents as installed fd numbers and passes them to binder_deferred_fd_close(), closing unrelated file descriptors.
Pass is_failure=true since the transaction was never delivered to the target, matching the semantics of all other undelivered-transaction cleanup paths.
--- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/android/binder.c +1 -1
@@ -2833,7 +2833,7 @@ static int binder_proc_transaction(struc t_outdated->buffer =NULL ; buffer->transaction =NULL ;trace_binder_transaction_update_buffer_release (buffer); -binder_release_entire_buffer (proc,NULL , buffer, false); +binder_release_entire_buffer (proc,NULL , buffer, true);binder_alloc_free_buf (&proc->alloc, buffer);kfree (t_outdated);binder_stats_deleted (BINDER_STAT_TRANSACTION );
Greg Kroah-Hartman
maintainerPATCH 258/1887 binder: fix leaked fd fixups on TF_UPDATE_TXN supersede
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomer Pomeranc <[email protected]>
commit c4c02084d6687d5cd5edccaf52cc45e5160f1184 upstream.
When a TF_UPDATE_TXN transaction supersedes a pending async transaction in a frozen process, the outdated transaction is freed with kfree() directly. This skips binder_free_txn_fixups(), leaking all binder_txn_fd_fixup entries and their fget()'d struct file references.
The leaked file refcounts never reach zero, so the struct file objects are permanently pinned in memory. They survive process exit and accumulate across invocations until file-max exhaustion.
Every other transaction cleanup path (binder_free_transaction(), binder_transaction() error paths, binder_release_work()) correctly calls binder_free_txn_fixups(). Add the missing call before kfree() in the t_outdated cleanup block.
--- drivers/android/binder.c | 1 + 1 file changed, 1 insertion(+)
drivers/android/binder.c +1 -0
@@ -2835,6 +2835,7 @@ static int binder_proc_transaction(structrace_binder_transaction_update_buffer_release (buffer);binder_release_entire_buffer (proc,NULL , buffer, true);binder_alloc_free_buf (&proc->alloc, buffer); +binder_free_txn_fixups (t_outdated);kfree (t_outdated);binder_stats_deleted (BINDER_STAT_TRANSACTION ); }
Greg Kroah-Hartman
maintainerPATCH 259/1887 kgdboc: Fix tty driver reference leak in configure_kgdboc()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit ef3134cd0d4831ae2137aee2883987859b80b2c6 upstream.
tty_find_polling_driver() returns the tty driver with an extra reference taken by tty_driver_kref_get(). configure_kgdboc() stores it in kgdb_tty_driver but the reference is never dropped: it is leaked when kgdb_register_io_module() fails, when the configuration is cleared, and on every reconfigure.
Release the reference both when unconfiguring and on the error path.
--- drivers/tty/serial/kgdboc.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/tty/serial/kgdboc.c +9 -0
@@ -190,6 +190,11 @@ static void cleanup_kgdboc(void)return ;kgdboc_unregister_kbd ();kgdb_unregister_io_module (&kgdboc_io_ops); + +if (kgdb_tty_driver) { +tty_driver_kref_put (kgdb_tty_driver); + kgdb_tty_driver =NULL ; + } }static int configure_kgdboc (void )
@@ -250,6 +255,10 @@ nmi_con_failed:kgdb_unregister_io_module (&kgdboc_io_ops); noconfig:kgdboc_unregister_kbd (); +if (kgdb_tty_driver) { +tty_driver_kref_put (kgdb_tty_driver); + kgdb_tty_driver =NULL ; + } configured =0 ;return err;
Greg Kroah-Hartman
maintainerPATCH 260/1887 Input: atkbd - skip deactivate for Lenovo IdeaPad Slim 3 15IWC11
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martino Papero <[email protected]>
commit 3bf8d603fd45649c106cae6290a10f20b1bbb569 upstream.
The internal keyboard on the Lenovo IdeaPad Slim 3 15IWC11 (83RR) does not work correctly with the default i8042 settings. Using i8042.nopnp=1 and i8042.dumbkbd=1 restores keyboard input, but prevents the Caps Lock LED from working. Using i8042.nopnp=1 alone does not fix the keyboard.
The laptop works correctly when atkbd_deactivate_fixup is used instead. Add a DMI quirk for the 83RR to enable it.
This was tested without any i8042 command-line parameters. Keyboard input and the Caps Lock LED work correctly, including after suspend and resume and after a cold boot.
--- drivers/input/keyboard/atkbd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/input/keyboard/atkbd.c +8 -0
@@ -1955,6 +1955,14 @@ static const struct dmi_system_id atkbd_ .callback = atkbd_deactivate_fixup, }, { +/* Lenovo IdeaPad Slim 3 15IWC11 (83RR) */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), + DMI_MATCH(DMI_PRODUCT_NAME, "83RR"), + }, + .callback = atkbd_deactivate_fixup, + }, + {/* Xiaomi Book Pro 14 (TM2424) */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
Greg Kroah-Hartman
maintainerPATCH 261/1887 Input: i8042 - add nomux quirk for Fujitsu LIFEBOOK U7410
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lovekesh Solanki <[email protected]>
commit 495cd7f858b45d2ffa9b685bba3a8c23c1ca4dd3 upstream.
On the Fujitsu LIFEBOOK U7410 the internal keyboard and touchpad die shortly after boot if i8042 multiplexing controller is probed and switched to muxed mode. These multiplexing setup commands disturb the EC emulated keyboard and atkbd reports "Spurious ACK" and "Unknown key pressed" warnings, after which both keyboard and touchpad stop delivering events. Both touchpad and keyboard work in BIOS and GRUB.
Disabling multiplexer using i8042.nomux=1 makes both devices work on warm/cold boot.
Add a DMI quirk to force nomux mode for this model.
--- drivers/input/serio/i8042-acpipnpio.h | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/input/serio/i8042-acpipnpio.h +9 -0
@@ -671,6 +671,15 @@ static const struct dmi_system_id i8042_ .driver_data = (void *)(SERIO_QUIRK_NOAUX) }, { +/* Fujitsu LIFEBOOK U7410 */ +/* Mux mode also disturbs the EC keyboard, causing spurious ACKs */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"FUJITSU CLIENT COMPUTING LIMITED" ), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U7410"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX ) + }, + {/* Gigabyte M912 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
Greg Kroah-Hartman
maintainerPATCH 262/1887 Input: s6sy761 - fix resume ordering and restore sensing
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Heidelberg <[email protected]>
commit a215720959c5450b3699e243904b39c3f8f68888 upstream.
System suspend powers the controller off and resume powers it back on, but the resume path enables the interrupt before s6sy761_power_on() checks the boot. The firmware raises its boot-complete event on the interrupt line, the threaded handler consumes it, s6sy761_power_on() then reads an empty event and resume fails with -ENODEV, skipping the touch function setup:
s6sy761 2-0048: PM: dpm_run_callback(): s6sy761_resume [s6sy761] returns -19
Power the chip on first and only then unmask the interrupt. Once resume completes the boot handshake the chip comes back with sensing off, as at probe where input_open() turns it on, so the touchscreen stays dead after resume. Send SENSE_ON again when the input device is open.
Tested on a Pixel 3 XL over several s2idle cycles: resume succeeds and the touch function and sense status match the pre-suspend state.
--- drivers/input/touchscreen/s6sy761.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/input/touchscreen/s6sy761.c +13 -1
@@ -508,10 +508,22 @@ static int __maybe_unused s6sy761_suspenstatic int __maybe_unused s6sy761_resume (struct device *dev) {struct s6sy761_data *sdata =dev_get_drvdata (dev); +int err; + + err =s6sy761_power_on (sdata); +if (err) +return err;enable_irq (sdata->client->irq); -return s6sy761_power_on (sdata); +guard (mutex)(&sdata->input->mutex); + +if (!input_device_enabled (sdata->input)) +return 0 ; + + err =i2c_smbus_write_byte (sdata->client,S6SY761_SENSE_ON ); + +return err; }static const struct dev_pm_ops s6sy761_pm_ops = {
Greg Kroah-Hartman
maintainerPATCH 263/1887 Input: synaptics - add LEN205b entry to smbus_pnp_ids for ThinkPad T490
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lovekesh Solanki <[email protected]>
commit a961417c5ae77bbb728a23d9577ecd8f4d8a4b5a upstream.
Lenovo ThinkPad T490 has a Synaptics Touchpad that supports SMBus/RMI4 mode, but is not listed in smbus_pnp_ids table.
Add LEN205b to smbus_pnp_ids[] passlist.
--- drivers/input/mouse/synaptics.c | 1 + 1 file changed, 1 insertion(+)
drivers/input/mouse/synaptics.c +1 -0
@@ -190,6 +190,7 @@ static const char * const smbus_pnp_ids["LEN2054" ,/* E480 */ "LEN2055" ,/* E580 */ "LEN2058" ,/* E490 */ +"LEN205b" ,/* T490 */ "LEN2068" ,/* T14 Gen 1 */ "SYN1221" ,/* TUXEDO InfinityBook Pro 14 v5 */ "SYN3003", /* HP EliteBook 850 G1 */
Greg Kroah-Hartman
maintainerPATCH 264/1887 Input: synaptics - limit T440p InterTouch quirk to LEN0036
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphaël Larocque <[email protected]>
commit f0fd8993082ca229faa3f9844f1c9fe182eca20b upstream.
The ThinkPad L440 also uses board id 2722, but does not have the SMBus initialization problem seen on the T440p. On the L440, the SMBus companion becomes available shortly after psmouse probes, allowing the touchpad to use SMBus/RMI4 normally.
The T440p's quirk is currently applied to all Synaptics touchpads with board id 2722, unnecessarily disabling SMBus InterTouch on the L440, as reported by Daniel Salmun.
Restrict the quirk to PNP ID LEN0036, which identifies the T440p, so that other devices sharing board id 2722 retain their normal SMBus/RMI4 operation.
--- drivers/input/mouse/synaptics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/input/mouse/synaptics.c +4 -2
@@ -1811,8 +1811,10 @@ static int synaptics_setup_intertouch(streturn -ENXIO ; } -/* Disable intertouch on known-broken board revisions */ -if (info->board_id ==2722 ) { +/* Disable intertouch on known-broken T440p board revisions */ +if (info->board_id ==2722 && +psmouse_matches_pnp_id (psmouse, + (const char *const []){"LEN0036" ,NULL })) {psmouse_info (psmouse,"Disabling intertouch for board id %u\n" , info->board_id);
Greg Kroah-Hartman
maintainerPATCH 265/1887 nitro_enclaves: fix use-after-free on SLOT_ALLOC failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiao Wang <[email protected]>
commit 9bc184a2eda8b773c88ecbff934001ad649b9cc1 upstream.
When ne_create_vm_ioctl() fails the SLOT_ALLOC request after anon_inode_getfile() has succeeded, the error path calls fput(enclave_file) and then frees ne_enclave.
In normal userspace context, fput() defers the final __fput() via task_work. ne_enclave_release() therefore runs after ne_enclave has already been freed and dereferences ne_enclave->slot_uid, causing a
use-after-free: KASAN: slab-use-after-free in ne_enclave_release.
The enclave has no slot allocated and is not yet linked into the enclaves list on this error path, so ne_enclave_release() is expected to return early when slot_uid is zero. However, reading slot_uid already accesses the freed object.
Clear enclave_file->private_data before fput() on the error path. ne_enclave_release() then returns immediately when private_data is NULL, leaving the ioctl error path as the sole owner of ne_enclave. This is safe because the file has not been fd_install()'d yet.
Tested on an AWS EC2 m5.2xlarge with CONFIG_KASAN=y. Without the patch, the reproducer triggers a KASAN slab-use-after-free on every SLOT_ALLOC failure. With the patch, no KASAN report is produced and the SLOT_ALLOC error is still returned. Normal enclave creation and teardown are unaffected.
--- drivers/virt/nitro_enclaves/ne_misc_dev.c | 1 + 1 file changed, 1 insertion(+)
drivers/virt/nitro_enclaves/ne_misc_dev.c +1 -0
@@ -1710,6 +1710,7 @@ static int ne_create_vm_ioctl(struct ne_return enclave_fd; put_file: + enclave_file->private_data =NULL ;fput (enclave_file); put_fd:put_unused_fd (enclave_fd);
Greg Kroah-Hartman
maintainerPATCH 266/1887 USB: cdc-acm: fix racy TIOCMIWAIT implementation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit be4219dd98608736e13e0b790ef742b76a13254d upstream.
Check the wakeup condition after adding the task to the waitqueue and updating the task state to avoid missing a racing modem status update or disconnect.
Store the old icount on entry and do not update it in the completion handler to avoid missing events or reporting spurious ones (due to modem status changes before TIOCMIWAIT was called).
--- drivers/usb/class/cdc-acm.c | 36 +++++++++++++++++++----------------- drivers/usb/class/cdc-acm.h | 1 - 2 files changed, 19 insertions(+), 18 deletions(-)
drivers/usb/class/cdc-acm.c +19 -17
@@ -320,7 +320,6 @@ static void acm_process_notification(str difference = acm->ctrlin ^ newctrl;spin_lock_irqsave (&acm->read_lock, flags); acm->ctrlin = newctrl; - acm->oldcount = acm->iocount;if (difference &USB_CDC_SERIAL_STATE_DSR ) acm->iocount.dsr++;
@@ -1002,11 +1001,16 @@ static int wait_serial_change(struct acmDECLARE_WAITQUEUE (wait, current);struct async_icount old, new; - do { +spin_lock_irq (&acm->read_lock); + old = acm->iocount; +spin_unlock_irq (&acm->read_lock); + +add_wait_queue (&acm->wioctl, &wait); +for (;;) { +set_current_state (TASK_INTERRUPTIBLE ); +spin_lock_irq (&acm->read_lock); - old = acm->oldcount; new = acm->iocount; - acm->oldcount = new;spin_unlock_irq (&acm->read_lock); if ((arg & TIOCM_DSR) &&
@@ -1019,22 +1023,20 @@ static int wait_serial_change(struct acm old.rng != new.rng)break ; -add_wait_queue (&acm->wioctl, &wait); -set_current_state (TASK_INTERRUPTIBLE ); -schedule (); -remove_wait_queue (&acm->wioctl, &wait);if (acm->disconnected) { -if (arg &TIOCM_CD ) -break ; -else - rv = -ENODEV ; - }else { -if (signal_pending (current)) - rv = -ERESTARTSYS ; + rv = -ENODEV ; +break ; } - }while (!rv); - +schedule (); + +if (signal_pending (current)) { + rv = -ERESTARTSYS ; +break ; + } + } +__set_current_state (TASK_RUNNING ); +remove_wait_queue (&acm->wioctl, &wait);return rv; }
drivers/usb/class/cdc-acm.h +0 -1
@@ -90,7 +90,6 @@ struct acm {unsigned int ctrlin;/* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlout;/* output control lines (DTR, RTS) */ struct async_icount iocount;/* counters for control line changes */ -struct async_icount oldcount;/* for comparison of counter */ wait_queue_head_t wioctl;/* for ioctl */ unsigned int writesize;/* max packet size for the output bulk endpoint */ unsigned int readsize,ctrlsize;/* buffer sizes for freeing */
Greg Kroah-Hartman
maintainerPATCH 267/1887 USB: cdc-acm: skip URB restart in port_shutdown if disconnected
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuchao Zhang <[email protected]>
commit dc614d6bc991740d41d5a99ac7765c4b675dda88 upstream.
acm_port_shutdown() is called from the tty-port machinery whenever the last user closes the port. acm_disconnect() sets acm->disconnected and calls tty_port_tty_vhangup(), which eventually triggers port_shutdown(). At that point acm_disconnect() has already called acm_poison_urbs() and is about to free the control and read URBs.
However, acm_port_shutdown() unconditionally calls acm_unpoison_urbs() and, when the ALWAYS_POLL_CTRL quirk is set, immediately re-submits the ctrlurb and all read URBs. If the concurrent acm_disconnect() then frees those URBs and their DMA buffers while they are in-flight, the result is a use-after-free in acm_ctrl_irq() or acm_read_bulk_callback() accessing the freed DMA memory.
Fix by checking acm->disconnected after draining the delayed anchor and returning early: if we are in a disconnect path the URBs must remain poisoned and must not be resubmitted.
The early return is placed after the delayed-anchor drain loop because that loop only cancels write-side accounting (wb->use = false and autopm counter) and does not touch the hardware path.
--- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/class/cdc-acm.c +3 -0
@@ -776,6 +776,9 @@ static void acm_port_shutdown(struct ttyusb_autopm_put_interface_async (acm->control); } +if (acm->disconnected) +return ; +acm_unpoison_urbs (acm);if (acm->quirks &ALWAYS_POLL_CTRL ) {
Greg Kroah-Hartman
maintainerPATCH 268/1887 USB: serial: fix port tear down use-after-free
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 33c920f7c5952dfc42d1b8ea6efe16b1f0bb0c5b upstream.
Some drivers for multiport devices access port driver data from completion handlers of shared URBs submitted at attach() or first open() and stopped at disconnect() or last close(), respectively.
A simple NULL check before accessing the driver data makes sure that a port state container has at least been allocated, but a completion handler can still race with port tear down.
Reorder the disconnect handling so that ports are not deregistered (and their driver data freed) until after all ports have been hung up and the driver disconnect() callback has run so that all I/O has been stopped.
--- drivers/usb/serial/usb-serial.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/usb/serial/usb-serial.c +7 -2
@@ -1194,12 +1194,17 @@ static void usb_serial_disconnect(structusb_serial_port_poison_urbs (port);wake_up_interruptible (&port->port.delta_msr_wait);cancel_work_sync (&port->work); -if (device_is_registered (&port->dev)) -device_del (&port->dev); } +if (serial->type->disconnect) serial->type->disconnect (serial); +for (i =0 ; i < serial->num_ports; ++i) { + port = serial->port[i]; +if (device_is_registered (&port->dev)) +device_del (&port->dev); + } +release_sibling (serial, interface);/* let the last holder of this object cause it to be cleaned up */
Greg Kroah-Hartman
maintainerPATCH 269/1887 usb: storage: sierra_ms: reject short SWoC info transfers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Syed Labeeq Sajid Bukhari <[email protected]>
commit 8a0200d14acd9db388b85cd016e68a4e60d900ec upstream.
sierra_get_swoc_info() requests sizeof(struct swoc_info) (60) bytes from the device via usb_control_msg(), but its callers only treat a negative return value as failure. A device that answers the vendor-specific GetSwocInfo request with a short IN transfer is therefore accepted, leaving the tail of the freshly allocated (kmalloc(), non-zeroing) swoc_info buffer uninitialized.
truinst_show() subsequently prints swocInfo->rev, swocInfo->LinuxSKU and swocInfo->LinuxVer from that buffer into the world-readable (0444) "truinst" sysfs attribute. An emulated/malicious USB device (VID 0x1199, PID 0x0fff) can exploit this to disclose up to 5 bytes of stale kernel heap memory (kmalloc-64) to unprivileged userspace, once per sysfs read, indefinitely. On kernels built without init_on_alloc this leaks recently freed heap contents.
Only accept the transfer when the full structure was received. sierra_ms_init() already retries failed queries, so well-behaved devices are unaffected.
--- drivers/usb/storage/sierra_ms.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/usb/storage/sierra_ms.c +7 -0
@@ -77,6 +77,13 @@ static int sierra_get_swoc_info(struct usizeof (struct swoc_info ),/* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ +/* +* A short IN transfer leaves the tail of swocInfo uninitialized; +* only a full transfer is valid. +*/ +if (result !=sizeof (struct swoc_info )) +return -EIO ; + swocInfo->LinuxSKU =le16_to_cpu (swocInfo->LinuxSKU); swocInfo->LinuxVer =le16_to_cpu (swocInfo->LinuxVer);return result;
Greg Kroah-Hartman
maintainerPATCH 270/1887 usb: hub: use shorter 120ms post resume hold for SS root hubs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lovekesh Solanki <[email protected]>
commit 29480b05e6e226594dc11ccf2a036fbd5cdd0e42 upstream.
Holding a USB3 hub PM runtime reference for 200ms at hub resume triggers an AMD platform issue. Users running Android adb report crashes after adb has been polling and waking up the USB subsystem once a second for some time. Vendors are working on a solution. Disabling USB runtime PM is one way to prevent this issue, but it is also proven that reducing the hold time to 120ms in resume also mitigates it. See Link for more details.
Reducing the hold time to 120ms for the USB3 roothub is in itself a valid change and optimization, as the current 200ms is excessive: a root hub has no upstream suspended hub whose wake propagation needs to be accounted for, but still need some time for USB3 link training to complete.
Keep the 200ms hold for external hubs that commit 8f5b7e2bec1c ("usb: hub: fix detection of high tier USB3 devices behind suspended hubs") is intended for.
--- drivers/usb/core/hub.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/usb/core/hub.c +6 -1
@@ -69,8 +69,11 @@/* * Give SS hubs 200ms time after wake to train downstream links before * assuming no port activity and allowing hub to runtime suspend back. +* Root hubs have no upstream hub whose wake propagation needs to be +* accounted for, so they need less time, use 120ms for them. */ #define USB_SS_PORT_U0_WAKE_TIME 200/* ms */ +#define USB_SS_RH_PORT_U0_WAKE_TIME 120/* ms */ /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can
@@ -1332,7 +1335,9 @@ static void hub_activate(struct usb_hubqueue_delayed_work (system_power_efficient_wq, &hub->post_resume_work, -msecs_to_jiffies (USB_SS_PORT_U0_WAKE_TIME )); +msecs_to_jiffies (hdev->parent ? +USB_SS_PORT_U0_WAKE_TIME : +USB_SS_RH_PORT_U0_WAKE_TIME ));return ; }
Greg Kroah-Hartman
maintainerPATCH 271/1887 usb: octeon-hcd: fix the FIFO-flush timeout computation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Orgad Shaneh <[email protected]>
commit 4c7a1b9f1f1979f2b3b69428ada12680695159c2 upstream.
cvmx_wait_tx_rx() computes its 100us deadline from (u64)octeon_get_clock_rate - the address of the function, not its return value; the parentheses have been missing since the CVMX_WAIT_FOR_FIELD32 macro became a function. The cast makes it compile silently, and the resulting deadline is effectively infinite.
On a healthy controller the flush bit clears on the first read and nothing is noticed. On a controller whose PHY did not come up (for example when the reference-clock configuration is wrong for the board), txfflsh/rxfflsh never clear and probe spins forever in __delay() - observed as a hard hang with a soft-lockup splat on a CN5020 board, where the board watchdog then resets the system with no console output.
Call the function, restoring the 100us timeout the code always intended.
--- drivers/usb/host/octeon-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/host/octeon-hcd.c +1 -1
@@ -578,7 +578,7 @@ static int cvmx_wait_tx_rx(struct octeonint result;u64 address =CVMX_USBCX_GRSTCTL (usb->index);u64 done =cvmx_get_cycle () +100 * - (u64 )octeon_get_clock_rate /1000000 ; + (u64 )octeon_get_clock_rate () /1000000 ;union cvmx_usbcx_grstctl c;while (1 ) {
Greg Kroah-Hartman
maintainerPATCH 272/1887 usb: ohci-da8xx: disable controller wakeup on cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 901197dd4c7dcffbf97426487d4c047555c98554 upstream.
The OHCI core marks controllers with RemoteWakeupConnected as wakeup-capable. Probe enables wakeup, but neither removal nor a later notifier registration failure disables it, leaving the wakeup source attached.
Disable controller wakeup after removing the HCD on both paths.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/host/ohci-da8xx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/host/ohci-da8xx.c +2 -0
@@ -464,6 +464,7 @@ static int ohci_da8xx_probe(struct platf err_remove_hcd:usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller); err:usb_put_hcd (hcd);return error;
@@ -474,6 +475,7 @@ static int ohci_da8xx_remove(struct platstruct usb_hcd *hcd =platform_get_drvdata (pdev);usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller);usb_put_hcd (hcd);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 273/1887 usb: ohci-s3c2410: disable controller wakeup on removal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 8dd8451c527e2a723bca20da5a6d724b8592551f upstream.
Probe enables controller wakeup after the OHCI core marks controllers with RemoteWakeupConnected as wakeup-capable. Removal does not undo this, so the wakeup source can remain attached after driver unbind.
Disable controller wakeup after removing the HCD.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/host/ohci-s3c2410.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/ohci-s3c2410.c +1 -0
@@ -335,6 +335,7 @@ ohci_hcd_s3c2410_remove(struct platform_struct usb_hcd *hcd =platform_get_drvdata (dev);usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller);s3c2410_stop_hc (dev);usb_put_hcd (hcd);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 274/1887 usb: ohci-st: disable controller wakeup on removal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 08b2ccd7eb7e41f77a04a09112ca3edcc588e3f0 upstream.
Probe enables controller wakeup after the OHCI core marks controllers with RemoteWakeupConnected as wakeup-capable. Removal does not undo this, so the wakeup source can remain attached after driver unbind.
Disable controller wakeup after removing the HCD.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/host/ohci-st.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/ohci-st.c +1 -0
@@ -241,6 +241,7 @@ static int st_ohci_platform_remove(strucint clk;usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller);if (pdata->power_off) pdata->power_off (dev);
Greg Kroah-Hartman
maintainerPATCH 275/1887 usb: gadget: f_uac1_legacy: validate bRequest index in generic_{set,get}_cmd
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liu Chao <[email protected]>
commit 9062d50e75c24dc7911be05c9b1719b3b256af15 upstream.
generic_set_cmd() and generic_get_cmd() use the low nibble of ctrl->bRequest as an index into con->data[]:
u8 cmd = (ctrl->bRequest & 0x0F); /* 0 .. 15 */
...
con->data[cmd] = value; /* OOB when cmd >= 5 */struct usb_audio_control (include/linux/usb/audio.h) declares data as a 5-element array, so indices 5 through 15 write (or read) up to 44 bytes past the end of the array on the heap.
A malicious USB host can craft a class-specific SET_CUR / GET_CUR request with an arbitrary bRequest value, triggering the out-of-bounds access from an IRQ completion handler with no further preconditions.
Add an ARRAY_SIZE() guard to both functions.
--- drivers/usb/gadget/function/f_uac1_legacy.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/usb/gadget/function/f_uac1_legacy.c +6 -0
@@ -797,6 +797,9 @@ fail:static int generic_set_cmd (struct usb_audio_control *con,u8 cmd,int value) { +if (cmd >=ARRAY_SIZE (con->data)) +return -EINVAL ; + con->data[cmd] = value;return 0 ;
@@ -804,6 +807,9 @@ static int generic_set_cmd(struct usb_austatic int generic_get_cmd (struct usb_audio_control *con,u8 cmd) { +if (cmd >=ARRAY_SIZE (con->data)) +return -EINVAL ; +return con->data[cmd]; }
Greg Kroah-Hartman
maintainerPATCH 276/1887 usb: typec: anx7411 - stop the IRQ before destroying the workqueue
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
commit 469600d5d292b1482c90dd6853555821d11b8c5f upstream.
The IRQ is devm-managed, so it can still queue plat->work while remove() is tearing the queue down. Disable it first.
--- drivers/usb/typec/anx7411.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/usb/typec/anx7411.c +4 -1
@@ -1572,8 +1572,11 @@ static void anx7411_i2c_remove(struct i2anx7411_partner_unregister_altmode (plat);anx7411_unregister_partner (plat); -if (plat->workqueue) +if (plat->workqueue) { +disable_irq (plat->intp_irq); +cancel_work_sync (&plat->work);destroy_workqueue (plat->workqueue); + }if (plat->spi_client)i2c_unregister_device (plat->spi_client);
Greg Kroah-Hartman
maintainerPATCH 277/1887 usb: dwc3: am62: Fix runtime PM usage count leak on probe error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Radhey Shyam Pandey <[email protected]>
commit 3d9bbf0ffeb9b7ac1b6ad06b52e037870a7e0c63 upstream.
dwc3_ti_probe() takes a runtime PM reference with pm_runtime_get_noresume() before creating the dwc3 core child device, and releases it with pm_runtime_put_autosuspend() once probe has succeeded. The err_pm_disable error path only disables runtime PM, so the reference taken a few lines earlier is never dropped.
The usage counter lives in struct device and is not reset when the driver is unbound, so the leaked reference outlives the failed probe. If the device is probed again, through a manual rebind or a module reload, the counter starts at one instead of zero and the pm_runtime_put_autosuspend() on the success path can no longer bring it back down. The wrapper then stays runtime resumed for good and autosuspend never kicks in.
Drop the reference before disabling runtime PM, matching the ordering already used in dwc3_ti_remove().
--- drivers/usb/dwc3/dwc3-am62.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/dwc3/dwc3-am62.c +1 -0
@@ -243,6 +243,7 @@ static int dwc3_ti_probe(struct platform err_pm_disable:clk_disable_unprepare (am62->usb2_refclk); +pm_runtime_put_noidle (dev);pm_runtime_disable (dev);pm_runtime_set_suspended (dev);return ret;
Greg Kroah-Hartman
maintainerPATCH 278/1887 usb: gadget: aspeed-vhub: cancel wake work on device removal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 20388c8d1d74c203fec8194c45cd31afdfab934e upstream.
wake_work is armed from the gadget .wakeup callback to resume suspended downstream ports, and it is never cancelled in ast_vhub_remove(), so a work item queued before or during removal can run after devm has freed vhub and its ports, a use-after-free.
Cancelling the work alone is not sufficient: usb_gadget_wakeup() takes no lock and the unbind path never clears wakeup_en, so a remote-wakeup request in flight on another CPU can re-arm the work after the cancel and before vhub is freed.
ast_vhub_del_dev() already clears d->registered under vhub->lock before unregistering the gadget. Refuse the wakeup in ast_vhub_udc_wakeup() once d->registered is clear: the check and the schedule_work() are then atomic against the unbind, so a wakeup that passed before the flag was cleared is drained by the cancel_work_sync() after the del_dev loop, and one that arrives later returns without arming. Also move INIT_WORK() to the top of ast_vhub_probe(), since the probe error path reuses ast_vhub_remove() and would otherwise cancel a never-initialized work item.
This issue was found by an in-house static analysis tool.
--- drivers/usb/gadget/udc/aspeed-vhub/core.c | 4 ++++ drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +- drivers/usb/gadget/udc/aspeed-vhub/hub.c | 5 +++-- drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 + 4 files changed, 9 insertions(+), 3 deletions(-)
drivers/usb/gadget/udc/aspeed-vhub/core.c +4 -0
@@ -267,6 +267,9 @@ static int ast_vhub_remove(struct platfofor (i =0 ; i < vhub->max_ports; i++)ast_vhub_del_dev (&vhub->ports[i].dev); +/* Final drain; the worker takes vhub->lock, so stay outside of it */ +cancel_work_sync (&vhub->wake_work); +spin_lock_irqsave (&vhub->lock, flags);/* Mask & ack all interrupts */
@@ -327,6 +330,7 @@ static int ast_vhub_probe(struct platforreturn -ENOMEM ;spin_lock_init (&vhub->lock); +INIT_WORK (&vhub->wake_work, ast_vhub_wake_work); vhub->pdev = pdev; vhub->port_irq_mask =GENMASK (VHUB_IRQ_DEV1_BIT + vhub->max_ports -1 ,VHUB_IRQ_DEV1_BIT );
drivers/usb/gadget/udc/aspeed-vhub/dev.c +1 -1
@@ -281,7 +281,7 @@ static int ast_vhub_udc_wakeup(struct usint rc = -EINVAL ;spin_lock_irqsave (&d->vhub->lock, flags); -if (!d->wakeup_en) +if (!d->wakeup_en || !d->registered) goto err;DDBG (d,"Device initiated wakeup\n" );
drivers/usb/gadget/udc/aspeed-vhub/hub.c +3 -2
@@ -558,7 +558,7 @@ void ast_vhub_device_connect(struct ast_ast_vhub_send_host_wakeup (vhub); } -static void ast_vhub_wake_work (struct work_struct *work) +void ast_vhub_wake_work (struct work_struct *work) { struct ast_vhub *vhub = container_of(work, struct ast_vhub,
@@ -588,6 +588,8 @@ static void ast_vhub_wake_work(struct wovoid ast_vhub_hub_wake_all (struct ast_vhub *vhub) { +lockdep_assert_held (&vhub->lock); +/* * A device is trying to wake the world, because this * can recurse into the device, we break the call chain
@@ -1076,7 +1078,6 @@ static int ast_vhub_init_desc(struct astint ast_vhub_init_hub (struct ast_vhub *vhub) { vhub->speed =USB_SPEED_UNKNOWN ; -INIT_WORK (&vhub->wake_work, ast_vhub_wake_work);return ast_vhub_init_desc (vhub); }
drivers/usb/gadget/udc/aspeed-vhub/vhub.h +1 -0
@@ -546,6 +546,7 @@ void ast_vhub_hub_suspend(struct ast_vhuvoid ast_vhub_hub_resume (struct ast_vhub *vhub);void ast_vhub_hub_reset (struct ast_vhub *vhub);void ast_vhub_hub_wake_all (struct ast_vhub *vhub); +void ast_vhub_wake_work (struct work_struct *work);/* dev.c */ int ast_vhub_init_dev (struct ast_vhub *vhub,unsigned int idx);
Greg Kroah-Hartman
maintainerPATCH 279/1887 USB: gadget: dummy-hcd: Fix wait for outstanding request completions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern <[email protected]>
commit b263ff9b0fc5c1f371d65c4eb196b31263d039ff upstream.
The dummy-hcd driver emulates synchronize_irq() by waiting until its private callback_usage counter drops to 0 (with the private lock not held). This counter is incremented whenever a gadget driver callback occurs (which requires the private lock to be dropped), but not when a request completion handler is called.
This is an oversight. Request completion is triggered by timer interrupts (emulating device IRQs in a real UDC), and the interrupt handlers are supposed to have completed when the synchronize_irq() emulation routine returns -- they aren't supposed to be in the middle of a completion callback. If this happens it can lead to a gadget driver's unbind routine running before all outstanding request completions have finished, maybe even allowing the gadget driver's module to be unloaded while a completion handler is still running.
Fix the oversight by incrementing the callback_usage value across request completion callbacks.
--- drivers/usb/gadget/udc/dummy_hcd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/gadget/udc/dummy_hcd.c +4 -0
@@ -342,9 +342,11 @@ static void dummy_giveback(struct dummy {bool fifo = req == &dum->fifo_req; + ++dum->callback_usage;spin_unlock (&dum->lock);usb_gadget_giveback_request (_ep, &req->req);spin_lock (&dum->lock); + --dum->callback_usage;if (fifo) dum->fifo_req_busy =0 ; }
@@ -758,11 +760,13 @@ static int dummy_queue(struct usb_ep *_e req->req.complete = fifo_complete;list_add_tail (&req->queue, &ep->queue); + ++dum->callback_usage;spin_unlock (&dum->lock); _req->actual = _req->length; _req->status =0 ;usb_gadget_giveback_request (_ep, _req);spin_lock (&dum->lock); + --dum->callback_usage; }else list_add_tail (&req->queue, &ep->queue);spin_unlock_irqrestore (&dum->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 280/1887 usb: gadget: f_fs: Fix NULL pointer dereference in FUNCTIONFS_ENDPOINT_DESC
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuchao Zhang <[email protected]>
commit 9cd072788c76595529eb38f42bf94d23852f8534 upstream.
When user space sets up FunctionFS with only full-speed descriptors (e.g., flags = FUNCTIONFS_HAS_FS_DESC) and the gadget operates at a higher speed (such as USB_SPEED_HIGH or USB_SPEED_SUPER), config_ep_by_speed() detects that the function lacks descriptors for the current speed, logs a warning, and falls back to full-speed descriptors. The endpoint is then successfully enabled via usb_ep_enable(), and epfile->ep becomes valid.
However, when user space subsequently issues the FUNCTIONFS_ENDPOINT_DESC ioctl to query the endpoint descriptor, ffs_epfile_ioctl() selects the descriptor index solely based on gadget->speed:
switch (epfile->ffs->gadget->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
desc_idx = 2;
break;
case USB_SPEED_HIGH:
desc_idx = 1;
break;
default:
desc_idx = 0;
}
desc = epfile->ep->descs[desc_idx];
memcpy(&desc1, desc, desc->bLength);Because user space only supplied full-speed descriptors, epfile->ep->descs[1] is NULL. Dereferencing desc->bLength triggers an immediate kernel NULL pointer dereference panic.
Fix this by falling back through lower speed descriptors if the current speed descriptor was not supplied, matching the fallback logic in config_ep_by_speed() and historical f_fs behavior. If still missing, fall back to epfile->ep->ep->desc (the active descriptor), and return -EINVAL safely if no valid descriptor is found. In addition, mark desc as const to match struct usb_ep::desc and avoid discarding qualifiers.
--- drivers/usb/gadget/function/f_fs.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/usb/gadget/function/f_fs.c +13 -2
@@ -1351,8 +1351,9 @@ static long ffs_epfile_ioctl(struct filebreak ;case FUNCTIONFS_ENDPOINT_DESC : { +const struct usb_endpoint_descriptor *desc; +struct usb_endpoint_descriptor desc1;int desc_idx; -struct usb_endpoint_descriptor desc1, *desc;switch (epfile->ffs->gadget->speed) {case USB_SPEED_SUPER :
@@ -1366,7 +1367,17 @@ static long ffs_epfile_ioctl(struct file desc_idx =0 ; } - desc = epfile->ep->descs[desc_idx]; +do { + desc = epfile->ep->descs[desc_idx]; + }while (!desc && --desc_idx >=0 ); + +if (!desc) + desc = epfile->ep->ep->desc; +if (!desc) { + ret = -EINVAL ; +break ; + } +memcpy (&desc1, desc, desc->bLength);spin_unlock_irq (&epfile->ffs->eps_lock);
Greg Kroah-Hartman
maintainerPATCH 281/1887 usb: chipidea: tegra: disable runtime PM on resume failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit f1d6f7d25fe88ee49aaad96c8649e090fc3a4b68 upstream.
tegra_usb_probe() enables runtime PM before resuming the device. If pm_runtime_resume_and_get() fails, probe returns without disabling runtime PM. The later error paths reach pm_runtime_force_suspend(), but this early return bypasses that cleanup.
Disable runtime PM before returning the resume error. Do not use the fail_power_off path: the failed resume did not retain a usage reference, so its pm_runtime_put_sync_suspend() would be unbalanced.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/chipidea/ci_hdrc_tegra.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/chipidea/ci_hdrc_tegra.c +3 -1
@@ -307,8 +307,10 @@ static int tegra_usb_probe(struct platfopm_runtime_enable (&pdev->dev); err =pm_runtime_resume_and_get (&pdev->dev); -if (err) +if (err) { +pm_runtime_disable (&pdev->dev);return err; + }if (device_property_present (&pdev->dev,"nvidia,needs-double-reset" )) usb->needs_double_reset = true;
Greg Kroah-Hartman
maintainerPATCH 282/1887 usb: core: clear both ep_in and ep_out for non-ep0 control endpoints
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Peng <[email protected]>
commit 0e8baa78d872f2db440d8b9ded946ab8dceb89eb upstream.
In usb_enable_endpoint(), non-zero control endpoints (where usb_endpoint_xfer_control(&ep->desc) is true) populate both dev->ep_in[epnum] and dev->ep_out[epnum] with the same struct usb_host_endpoint pointer.
However, usb_disable_endpoint() only clears either dev->ep_out[epnum] or dev->ep_in[epnum] depending on the direction bit of epaddr when reset_hardware is set, leaving the opposite direction's array slot pointing to the disabled/freed endpoint.
Clear both dev->ep_out[epnum] and dev->ep_in[epnum] when disabling a non-ep0 control endpoint with reset_hardware set, and update the function kerneldoc accordingly.
Tested in QEMU against Linux 7.3.0-rc3 using dummy_hcd and raw-gadget to enumerate a USB device with a non-zero control endpoint (bEndpointAddress 0x01, bmAttributes USB_ENDPOINT_XFER_CONTROL), verifying that both dev->ep_in[1] and dev->ep_out[1] are cleared when the interface is disabled.
--- drivers/usb/core/message.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/usb/core/message.c +7 -1
@@ -1331,7 +1331,8 @@ static void remove_intf_ep_devs(struct u* * Disables the endpoint for URB submission and nukes all pending URBs. * If @reset_hardware is set then also deallocates hcd/hardware state -* for the endpoint. +* for the endpoint (clearing both ep_in and ep_out pointers for +* bidirectional non-ep0 control endpoints). */ void usb_disable_endpoint (struct usb_device *dev,unsigned int epaddr,bool reset_hardware)
@@ -1352,6 +1353,11 @@ void usb_disable_endpoint(struct usb_dev dev->ep_in[epnum] =NULL ; }if (ep) { +if (reset_hardware && epnum !=0 && +usb_endpoint_xfer_control (&ep->desc)) { + dev->ep_out[epnum] =NULL ; + dev->ep_in[epnum] =NULL ; + } ep->enabled =0 ;usb_hcd_flush_endpoint (dev, ep);if (reset_hardware)
Greg Kroah-Hartman
maintainerPATCH 283/1887 usb: typec: tcpm: recover after failure to start the frs ams
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amit Sunil Dhamne <[email protected]>
commit 90156585765b29304f07b0e4a1c56a969876fcfc upstream.
Reset the port if the tcpm fails to start the FAST_ROLE_SWAP AMS by initiating error recovery on it.
This helps in cases where some cables (incorrectly) signal an FRS to an FRS capable port during disconnection. The TCPC autonomously starts sourcing VBUS on detecting the FRS signal. However, the VBUS sourcing is left on when the FAST_ROLE_SWAP AMS fails to start (as tcpm_sink_tx_ok is 0 as CC is open due to the cable disconnect). This is because the code sets the state to INVALID_STATE without resetting the port state.
Log snippet before changes:
[ 101.401960] AMS FAST_ROLE_SWAP start [ 101.401971] Sink TX No Go [ 101.401982] sourcing vbus [ 101.401987] VBUS on [ 101.402159] VBUS on [ 109.257809] CC1: 0 -> 0, CC2: 5 -> 0 [state SNK_READY, polarity 1, disconnected] [ 111.267442] VBUS on
After changes:
[ 70.541211] AMS FAST_ROLE_SWAP start [ 70.541220] Sink TX No Go [ 70.541228] state change SNK_READY -> ERROR_RECOVERY [rev3 NONE_AMS] [ 70.541362] VBUS on [ 70.541365] sourcing vbus [ 70.541367] VBUS on [ 70.541374] state change ERROR_RECOVERY -> PORT_RESET [rev3 NONE_AMS] [ 70.541410] disable vbus discharge ret:0 [ 70.543028] Setting usb_comm capable false [ 70.544009] Setting voltage/current limit 0 mV 0 mA [ 70.544034] polarity 0 [ 70.544239] Requesting mux state 0, usb-role 0, orientation 0 [ 70.555550] cc:=0 [ 70.555595] pending state change PORT_RESET -> PORT_RESET_WAIT_OFF @ 100 ms [rev3 NONE_AMS] [ 70.555697] VBUS off [ 70.555702] VBUS VSAFE0V [ 70.555762] CC1: 5 -> 0, CC2: 0 -> 0 [state PORT_RESET, polarity 0, disconnected] [ 70.587794] VBUS off [ 70.587799] VBUS VSAFE0V [ 70.655672] state change PORT_RESET -> PORT_RESET_WAIT_OFF [delayed 100 ms] [ 70.655682] state change PORT_RESET_WAIT_OFF -> SNK_UNATTACHED [rev3 NONE_AMS] [ 70.655686] Start toggling [ 70.656274] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected]
--- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/tcpm/tcpm.c +1 -1
@@ -5540,7 +5540,7 @@ static void tcpm_pd_event_handler(struct port->upcoming_state =FR_SWAP_SEND ; ret =tcpm_ams_start (port,FAST_ROLE_SWAP );if (ret == -EAGAIN ) - port->upcoming_state =INVALID_STATE ; +tcpm_set_state (port,ERROR_RECOVERY ,0 ); }else {tcpm_log (port,"Discarding FRS_SIGNAL! Not in sink ready" ); }
Greg Kroah-Hartman
maintainerPATCH 284/1887 usb: typec: tipd: fix uninitialized typec_partner_desc in tps6598x_connect()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Radhey Shyam Pandey <[email protected]>
commit c4b27b3605788bbf9e4251f3cd4ab94645ab036f upstream.
tps6598x_connect() passes a stack-allocated typec_partner_desc to typec_register_partner() after initializing only usb_pd, accessory and identity.
typec_register_partner() copies attach and deattach from the descriptor into the partner. With those fields left unset, garbage function pointers may be stored and later invoked from typec_partner_link_device() when a USB device is linked to the port. Uninitialized pd_revision and usb_capability similarly leak stack data through partner sysfs.
Zero-initialize the descriptor so optional callbacks remain NULL and the remaining fields are zero.
--- drivers/usb/typec/tipd/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/typec/tipd/core.c +1 -2
@@ -231,7 +231,7 @@ static void tps6598x_set_data_role(strucstatic int tps6598x_connect (struct tps6598x *tps,u32 status) { -struct typec_partner_desc desc; +struct typec_partner_desc desc = { };enum typec_pwr_opmode mode;int ret;
@@ -242,7 +242,6 @@ static int tps6598x_connect(struct tps65 desc.usb_pd = mode ==TYPEC_PWR_MODE_PD ; desc.accessory =TYPEC_ACCESSORY_NONE ;/* XXX: handle accessories */ - desc.identity =NULL ;if (desc.usb_pd) { ret =tps6598x_read_partner_identity (tps);
Greg Kroah-Hartman
maintainerPATCH 285/1887 usb: typec: ucsi: Get the connector fwnode based on reg value
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prashanth K <[email protected]>
commit 6c51f09c6db5868a5090e8dd4d7764660c87f1ad upstream.
ucsi_find_fwnode() currently maps UCSI connectors to Device tree connector nodes based on the order in which connector child nodes are described in DT.
This can fail because the ordering of child nodes isn't guaranteed in Device-tree. For example, DTB may contain connector@1 before connector@0, causing connector numbers to be associated with the wrong fwnode. As a result, role switch and Type-C notifications can be delivered to the wrong remote endpoints.
Fix this by using the "reg" property of each connector to match its corresponding fwnode. While at it, if the reg property isn't present, then fall back to the old method.
--- drivers/usb/typec/ucsi/ucsi.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/usb/typec/ucsi/ucsi.c +14 -3
@@ -1092,10 +1092,21 @@ static struct fwnode_handle *ucsi_find_f {struct fwnode_handle *fwnode;int i =1 ; +int ret; +u32 port; -device_for_each_child_node (con->ucsi->dev, fwnode) -if (i++ == con->num) -return fwnode; +device_for_each_child_node (con->ucsi->dev, fwnode) { + ret =fwnode_property_read_u32 (fwnode,"reg" , &port); +if (ret <0 ) { +if (i == con->num) +return fwnode; + }else { +if (port == con->num -1 ) +return fwnode; + } + + i++; + }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 286/1887 usb: typec: ucsi: displayport: Current CAM OOB index fixup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jameson Thies <[email protected]>
commit ea31c6498c61307dc0d8ce338a7f268cb8cbdd57 upstream.
Update ucsi_displayport_enter() to return invalid error when the PPM reports an current alternate mode greater than or equal to UCSI_MAX_ALTMODES. While here, remove 0xff current cam assignment on failed GET_CURRENT_CAM response.
--- drivers/usb/typec/ucsi/displayport.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/usb/typec/ucsi/displayport.c +6 -3
@@ -71,11 +71,14 @@ static int ucsi_displayport_enter(structif (ret <0 ) {if (ucsi->version >0x0100 ) goto err_unlock; - cur =0xff ; } -if (cur <UCSI_MAX_ALTMODES ) { - ret = dp->con->port_altmode[cur] == alt ?0 : -EBUSY ; +if (cur !=0xff ) { +if (cur <UCSI_MAX_ALTMODES ) + ret = dp->con->port_altmode[cur] == alt ?0 : -EBUSY ; +else + ret = -EINVAL ; + goto err_unlock; }
Greg Kroah-Hartman
maintainerPATCH 287/1887 usb: cdns3: fix use-after-free in cdns3_gadget_exit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit ebe9b68c396792c15d0ac690d592e449e74ed804 upstream.
cdns3_gadget_start() arms two works on system_freezable_wq:pending_status_wq for the deferred ep0 status stage and aligned_buf_wq for realigned request buffers. Both handlers use the cdns3_device the works are embedded in, and cdns3_pending_setup_status_handler() also calls the ep0 request completion.
cdns3_gadget_exit() does not wait for these works. It frees all endpoints and aligned buffers and drops the last reference to the gadget device, which frees priv_dev, so a work queued before the exit can run after the free.
Fix this by waiting for both works after the gadget driver is unbound and the IRQ is freed, when no new work can be queued, and before the endpoints and buffers are released.
This issue was found by an in-house static analysis tool.
--- drivers/usb/cdns3/cdns3-gadget.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/cdns3/cdns3-gadget.c +4 -0
@@ -3265,6 +3265,10 @@ static void cdns3_gadget_exit(struct cdnusb_del_gadget (&priv_dev->gadget);devm_free_irq (cdns->dev, cdns->dev_irq, priv_dev); +/* The works can still be queued until the IRQ is freed. */ +cancel_work_sync (&priv_dev->pending_status_wq); +cancel_work_sync (&priv_dev->aligned_buf_wq); +cdns3_free_all_eps (priv_dev);while (!list_empty (&priv_dev->aligned_buf_list)) {
Greg Kroah-Hartman
maintainerPATCH 288/1887 usb: cdns3: Fix NULL pointer dereference in cdns3_pci_probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jie Deng <[email protected]>
commit e5052f2c5c73c1dcca42bafc0bc737af2b2af059 upstream.
The Cadence USBSS controller is a two-function PCI device. The first probed function allocates the driver data and stores it with pci_set_drvdata(), while the second function reuses it via pci_get_drvdata() when pci_is_enabled() reports that the first function has already been probed.
When the second function is probed while the first one has been enabled but has not yet set its driver data, pci_get_drvdata() returns NULL, and the subsequent wrap->devfn assignment dereferences a NULL pointer and crashes the kernel.
logs:
Call trace: cdns3_pci_probe+0xa4/0x300 local_pci_probe+0x44/0xa8 pci_call_probe+0x54/0x158 pci_device_probe+0x84/0x100 really_probe+0x184/0x3d0 __driver_probe_device+0x80/0x178 driver_probe_device+0x44/0xe8 __driver_attach+0xec/0x1f8 bus_for_each_dev+0x7c/0xe0 driver_attach+0x28/0x38 bus_add_driver+0x110/0x238 driver_register+0x64/0x128 __pci_register_driver+0x50/0x60 cdns3_pci_driver_init+0x28/0x38 do_one_initcall+0x5c/0x280 do_initcalls+0x104/0x1d8 kernel_init_freeable+0x140/0x218 kernel_init+0x28/0x1f8 ret_from_fork+0x10/0x20
Return -EPROBE_DEFER in this case so that probing is retried after the first function has completed its probe.
--- drivers/usb/cdns3/cdns3-pci-wrap.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/usb/cdns3/cdns3-pci-wrap.c +5 -0
@@ -99,6 +99,11 @@ static int cdns3_pci_probe(struct pci_deif (pci_is_enabled (func)) { wrap =pci_get_drvdata (func); +if (!wrap) { +dev_err (&pdev->dev, +"second function not initialized, retrying\n" ); +return -EPROBE_DEFER ; + } }else { wrap =kzalloc (sizeof (*wrap),GFP_KERNEL );if (!wrap)
Greg Kroah-Hartman
maintainerPATCH 289/1887 tty: vt: fix memory leak in vc_allocate()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
commit 5b114bfc1dfd88f9d50822d532f7f1fce0f7388a upstream.
If the screen buffer allocation fails in vc_allocate(), the error handling path jumps to err_free. However, this path fails to release the unicode screen map attached to vc->uni_pagedict_loc.
During the early stages of vc_allocate(), the unicode screen map is either newly allocated via con_set_default_unimap() or shares the default unicode map from a previously initialized console (which increments its refcount). If the subsequent kzalloc() for the screen buffer fails, the err_free path frees the vc structure but leaves the attached uni_pagedict with an elevated refcount. This results in an unreferenced object memory leak, as the reference to the dictionary is lost and its refcount can never reach zero.
This issue was discovered by DevGen (an automated virtual device modeling fuzzer based on Syzkaller). During fuzzing with kernel fault injection (failslab) enabled, the fuzzer forcefully failed the kzalloc() for the screen buffer, exposing this error-handling path leak.
Fix this by checking *vc->uni_pagedict_loc and calling con_free_unimap(vc) in the err_free path before kfree(vc). This safely decrements the refcount and releases the dictionary memory if this was the last reference. The explicit check is added to maintain consistency with other callers.
--- drivers/tty/vt/vt.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/tty/vt/vt.c +2 -0
@@ -1160,6 +1160,8 @@ int vc_allocate(unsigned int currcons) /return 0 ; err_free:visual_deinit (vc); +if (*vc->uni_pagedict_loc) +con_free_unimap (vc);kfree (vc); vc_cons[currcons].d =NULL ;return err;
Greg Kroah-Hartman
maintainerPATCH 290/1887 tty: amiserial: fix broken TIOCMIWAIT
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 615f35fd5aee169cc4881a8594f2fa234a4d0bb8 upstream.
A change replacing interruptible_sleep_on() inadvertently broke the TIOCMIWAIT implementation which now immediately returns -EIO (unless there is a racing modem status update).
Replace the old hangup (and signal) detection with a check for the TTY_IO_ERROR flag which is set on hangup.
--- drivers/tty/amiserial.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/tty/amiserial.c +4 -5
@@ -1140,11 +1140,6 @@ static int rs_ioctl(struct tty_struct *tlocal_irq_save (flags); cnow = info->icount;/* atomic copy */ local_irq_restore (flags); -if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - ret = -EIO ;/* no change => error */ -break ; - } if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
@@ -1152,6 +1147,10 @@ static int rs_ioctl(struct tty_struct *t ret =0 ;break ; } +if (tty_io_error (tty)) { + ret = -EIO ; +break ; + }schedule ();/* see if a signal did it */ if (signal_pending (current)) {
Greg Kroah-Hartman
maintainerPATCH 291/1887 tty: vcc: zero-initialize control packet in vcc_send_ctl()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Rogers <[email protected]>
commit 1f71f565e3585da1098ff19ca3c24687dab59185 upstream.
The stack-allocated struct vio_vcc pkt was partially initialized, leaving the tag.stype_env field uninitialized before being sent via ldc_write(), potentially leaking kernel stack data to the LDC peer.
--- drivers/tty/vcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/vcc.c +1 -1
@@ -492,7 +492,7 @@ static ssize_t domain_show(struct devicestatic int vcc_send_ctl (struct vcc_port *port,int ctl) { -struct vio_vcc pkt; +struct vio_vcc pkt = {};int rv; pkt.tag.type =VIO_TYPE_CTRL ;
Greg Kroah-Hartman
maintainerPATCH 292/1887 tty: vcc: hold port lock when clearing tty pointer in vcc_cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Rogers <[email protected]>
commit 03b49c991abb8d021ca6fe51cd173447236b0552 upstream.
vcc_cleanup() sets port->tty to NULL without holding port->lock, racing with vcc_event() LDC callbacks that read port->tty under port->lock and then use tty->port. This can cause a use-after-free when the callback dereferences tty->port after cleanup has already destroyed and freed it.
--- drivers/tty/vcc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/tty/vcc.c +2 -1
@@ -985,7 +985,8 @@ static void vcc_cleanup(struct tty_struc port =vcc_get (tty->index, true);if (port) { - port->tty =NULL ; +scoped_guard (spinlock_irqsave, &port->lock) + port->tty = NULL;if (port->removed) {vcc_table_remove (tty->index);
Greg Kroah-Hartman
maintainerPATCH 293/1887 tty: serial: qcom_geni_serial: Keep console RX functional after deep idle
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viken Dadhaniya <[email protected]>
commit 63ef71d1474b5417b5b2dec700cd251c44a570d9 upstream.
At baud rates up to 115200, the serial console uses only a 1 kBps keepalive vote for the GENI_TO_CORE ("qup-core") ICC path. This vote keeps the path active but does not request a QUP Core 2X clock rate.
When the CPU enters a deeper idle state, the missing Core clock vote can leave the console RX path unresponsive.
Use the 19.2 MHz Core 2X vote at low baud rates, while retaining the 50 MHz vote at higher baud rates, so that console RX remains functional after deep idle transitions.
--- drivers/tty/serial/qcom_geni_serial.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/tty/serial/qcom_geni_serial.c +2 -3
@@ -1056,9 +1056,8 @@ static void qcom_geni_serial_set_termios* Bump up BW vote on CPU and CORE path as driver supports FIFO mode * only. */ - avg_bw_core = (baud >115200 ) ?Bps_to_icc (CORE_2X_50_MHZ ) - :GENI_DEFAULT_BW ; - port->se.icc_paths[GENI_TO_CORE ].avg_bw = avg_bw_core; + avg_bw_core = baud >115200 ?CORE_2X_50_MHZ :CORE_2X_19_2_MHZ ; + port->se.icc_paths[GENI_TO_CORE ].avg_bw =Bps_to_icc (avg_bw_core); port->se.icc_paths[CPU_TO_GENI ].avg_bw =Bps_to_icc (baud);geni_icc_set_bw (&port->se);
Greg Kroah-Hartman
maintainerPATCH 294/1887 tty: abort break signalling on hangup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 845a2737e0f5ffe5ca8d38de556012b0c9472cdd upstream.
The break ioctls can race with hangup and end up calling into a tty driver for a device that is already gone or powered down.
Drivers must handle this race, but TCSBRK and TCSBRKP should still be aborted to avoid calling back into the driver after a user-controlled timeout (possibly even after the tty has been reopened).
Note that drivers should disable any break state on shutdown so just return on hangup (calling break_ctl() again is racy and will most likely fail for drivers handling the race).
--- drivers/tty/tty_io.c | 36 +++++++++++++++++++++++++++--------- include/linux/tty.h | 1 + 2 files changed, 28 insertions(+), 9 deletions(-)
drivers/tty/tty_io.c +27 -9
@@ -630,6 +630,8 @@ static void __tty_hangup(struct tty_strutty_ldisc_hangup (tty, cons_filp !=NULL ); +wake_up_interruptible (&tty->break_wait); +spin_lock_irq (&tty->ctrl.lock);clear_bit (TTY_THROTTLED , &tty->flags);clear_bit (TTY_DO_WRITE_WAKEUP , &tty->flags);
@@ -2457,6 +2459,7 @@ static int tiocgetd(struct tty_struct *t* send_break - performed time break * @tty: device to break on * @duration: timeout in mS +* @file: file object * * Perform a timed break on hardware that lacks its own driver level timed * break functionality.
@@ -2464,8 +2467,9 @@ static int tiocgetd(struct tty_struct *t* Locking: * @tty->atomic_write_lock serializes */ -static int send_break (struct tty_struct *tty,unsigned int duration) +static int send_break (struct file *file,struct tty_struct *tty,unsigned int duration) { +long timeout;int retval;if (tty->ops->break_ctl ==NULL )
@@ -2479,13 +2483,26 @@ static int send_break(struct tty_structreturn -EINTR ; retval = tty->ops->break_ctl (tty,-1 ); -if (!retval) { -msleep_interruptible (duration); - retval = tty->ops->break_ctl (tty,0 ); - }else if (retval == -EOPNOTSUPP ) { -/* some drivers can tell only dynamically */ - retval =0 ; +if (retval) { +if (retval == -EOPNOTSUPP ) { +/* some drivers can tell only dynamically */ + retval =0 ; + } + goto out_unlock; + } + + timeout =msecs_to_jiffies (duration); + timeout =wait_event_interruptible_timeout (tty->break_wait, +tty_hung_up_p (file), + timeout); +/* return early on hangup only */ +if (timeout >0 ) { + retval = -EIO ; + goto out_unlock; } + + retval = tty->ops->break_ctl (tty,0 ); +out_unlock:tty_write_unlock (tty);if (signal_pending (current))
@@ -2738,10 +2755,10 @@ long tty_ioctl(struct file *file, unsign* This is used by the tcdrain() termios function. */ if (!arg) -return send_break (tty,250 ); +return send_break (file, tty,250 );return 0 ;case TCSBRKP :/* support for POSIX tcsendbreak() */ -return send_break (tty, arg ? arg*100 :250 ); +return send_break (file, tty, arg ? arg *100 :250 );case TIOCMGET :return tty_tiocmget (tty, p);
@@ -3104,6 +3121,7 @@ struct tty_struct *alloc_tty_struct(struinit_ldsem (&tty->ldisc_sem);init_waitqueue_head (&tty->write_wait);init_waitqueue_head (&tty->read_wait); +init_waitqueue_head (&tty->break_wait);INIT_WORK (&tty->hangup_work, do_tty_hangup);mutex_init (&tty->atomic_write_lock);spin_lock_init (&tty->ctrl.lock);
include/linux/tty.h +1 -0
@@ -235,6 +235,7 @@ struct tty_struct {struct fasync_struct *fasync;wait_queue_head_t write_wait;wait_queue_head_t read_wait; +wait_queue_head_t break_wait;struct work_struct hangup_work;void *disc_data;void *driver_data;
Greg Kroah-Hartman
maintainerPATCH 295/1887 serial: 8250_bcm7271: fix use-after-free in brcmuart_remove()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 189b9dc8c96ec9486482f27c1372b04a7152175e upstream.
brcmuart_handle_irq() starts priv->hrt to work around a receive-timeout quirk of the 8250 core when hardware flow control is enabled; the timer callback brcmuart_hrtimer_func() dereferences priv.
brcmuart_remove() cancels the hrtimer before it unregisters the port, so a receive-timeout interrupt that arrives in between re-arms the timer. After devm frees priv, the callback runs on freed memory.
Unregister the port before cancelling the hrtimer. serial8250_unregister_port() shuts the port down and frees its IRQ, so brcmuart_handle_irq() can no longer restart the timer, and the final hrtimer_cancel() drains any timer that was armed before or during the unregister.
This issue was found by an in-house static analysis tool.
--- drivers/tty/serial/8250/8250_bcm7271.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/serial/8250/8250_bcm7271.c +1 -1
@@ -1153,8 +1153,8 @@ static int brcmuart_remove(struct platfostruct brcmuart_priv *priv =platform_get_drvdata (pdev);debugfs_remove_recursive (priv->debugfs_dir); -hrtimer_cancel (&priv->hrt);serial8250_unregister_port (priv->line); +hrtimer_cancel (&priv->hrt);brcmuart_free_bufs (&pdev->dev, priv);clk_disable_unprepare (priv->baud_mux_clk);if (priv->dma_enabled)
Greg Kroah-Hartman
maintainerPATCH 296/1887 serial: tegra: dont clear the Tx FIFO on an Rx-only reset
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Simon Gassner <[email protected]>
commit 8aebfde6e84dceb7d47fe8001e50b754eb45d5df upstream.
tegra_uart_fifo_reset() applies the Tegra30 workaround for "cannot clear the Tx FIFO while FIFO mode is enabled"
unconditionally: it leaves FIFO mode, writes the requested FCR clear bits, and re-enters FIFO mode. Leaving FIFO mode empties both FIFOs, so an Rx-only reset discards queued Tx data as well.
The break handler in tegra_uart_decode_rx_error() calls it with UART_FCR_CLEAR_RCVR only. On a half-duplex RS485 board whose Rx line is pulled low while the transceiver drives the bus, every transmission raises a spurious break, and all but the first character of the frame is lost.
Only take the FIFO-mode path when the caller actually asked for CLEAR_XMIT. Likewise only wait for TEMT in that case: with the Tx FIFO deliberately left intact, that loop would otherwise spin for a full frame time in hard IRQ context with the port lock held.
Tested on a Colibri T30 (Tegra30) with Rx DMA:
- Break during transmission: the reset still fires from tegra_uart_decode_rx_error(), and the complete frame now reaches the peer. Before this change only the character in the shift register was sent.
- Internal loopback with a generated break: the Rx FIFO is correctly cleared by the plain FCR write, and subsequent receive works with no frame, parity or overrun errors.
--- drivers/tty/serial/serial-tegra.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/tty/serial/serial-tegra.c +16 -2
@@ -307,11 +307,19 @@ static void tegra_uart_fifo_reset(struct {unsigned long fcr = tup->fcr_shadow;unsigned int lsr, tmout =10000 ; +bool clear_tx = !!(fcr_bits &UART_FCR_CLEAR_XMIT );if (tup->rts_active)set_rts (tup, false); -if (tup->cdata->allow_txfifo_reset_fifo_mode) { +/* +* Leaving FIFO mode below is a workaround for a Tegra30 +* restriction on clearing the Tx FIFO while FIFO mode is +* enabled. It empties both FIFOs, so applying it to an +* Rx-only reset would destroy an in-flight transmission. +* Only take that path when the caller asked for CLEAR_XMIT. +*/ +if (tup->cdata->allow_txfifo_reset_fifo_mode || !clear_tx) { fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR |UART_FCR_CLEAR_XMIT );tegra_uart_write (tup, fcr,UART_FCR ); }else {
@@ -336,9 +344,15 @@ static void tegra_uart_fifo_reset(struct*/ tegra_uart_wait_cycle_time (tup,32 ); +/* +* Only wait for the transmitter to drain when the Tx FIFO was +* part of the reset. For an Rx-only reset it is left intact, +* and waiting for TEMT here would spin for a full frame time. +*/ do { lsr =tegra_uart_read (tup,UART_LSR ); -if ((lsr &UART_LSR_TEMT ) && !(lsr &UART_LSR_DR )) +if ((!clear_tx || (lsr &UART_LSR_TEMT )) && + !(lsr &UART_LSR_DR ))break ;udelay (1 ); }while (--tmout);
Greg Kroah-Hartman
maintainerPATCH 297/1887 serial: vt8500: Fix clock reference leak in vt8500_serial_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 9d8955281d9229a899e2041659a59b389027b711 upstream.
of_clk_get() returns a clock with a reference that has to be released with clk_put(). If clk_prepare_enable() fails the function returns without doing so, leaking the reference.
Add the missing clk_put() on that error path.
--- drivers/tty/serial/vt8500_serial.c | 1 + 1 file changed, 1 insertion(+)
drivers/tty/serial/vt8500_serial.c +1 -0
@@ -682,6 +682,7 @@ static int vt8500_serial_probe(struct pl ret =clk_prepare_enable (vt8500_port->clk);if (ret) {dev_err (&pdev->dev,"failed to enable clock\n" ); +clk_put (vt8500_port->clk);return ret; }
Greg Kroah-Hartman
maintainerPATCH 298/1887 ASoC: qcom: lpass-cpu: use DAI table index for playback constraints
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zimeng Li <[email protected]>
commit ca51771c8efde5df05476ac98dd1b2af4e2b149f upstream.
The DAI ID is a hardware port ID and is not necessarily the index of the corresponding entry in variant->dai_driver.
When configuring a DAI with LPAIF_I2SCTL_MODE_QUAD01, the probe code currently uses dai_id to index variant->dai_driver. This is incorrect for platforms where DAI IDs are sparse. For example, the IPQ806x MI2S DAI has ID 4 while it is the only entry in the DAI driver table. If that DAI is configured for QUAD01 and probe reaches this branch, the code writes beyond that single entry via dai_driver[4] instead of updating the DAI being processed.
Use the loop index i when updating the current DAI's playback channel constraints, while retaining dai_id for indexing the hardware-port specific playback SD-line mode array.
This fixes the incorrect DAI table access for platforms where the DAI ID does not match its position in the driver table.
--- sound/soc/qcom/lpass-cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/qcom/lpass-cpu.c +2 -2
@@ -1228,8 +1228,8 @@ int asoc_qcom_lpass_cpu_platform_probe(s }if (drvdata->mi2s_playback_sd_mode[dai_id] ==LPAIF_I2SCTL_MODE_QUAD01 ) { - variant->dai_driver[dai_id].playback.channels_min =4 ; - variant->dai_driver[dai_id].playback.channels_max =4 ; + variant->dai_driver[i].playback.channels_min =4 ; + variant->dai_driver[i].playback.channels_max =4 ; } }
Greg Kroah-Hartman
maintainerPATCH 299/1887 ALSA: seq: Serialize compat port-info ioctls
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 95b2e0361c88753afa030c10698be0a1a5b67650 upstream.
The native sequencer ioctl path serializes handler calls with client->ioctl_mutex, but the translated port-info compat path invokes the same handlers through snd_seq_kernel_client_ctl() without taking that mutex.
This lets concurrent compat CREATE_PORT requests pass the port-count check before any request reaches the serialized insertion. The computed integer port index can then exceed the address field range and wrap to an existing index. Subsequent subscriber teardown can resolve the duplicate address to the wrong port and access a freed subscriber.
Take ioctl_mutex while dispatching converted port-info requests, matching the native ioctl path. All translated port-info commands share this helper, so their accesses to the client port state are serialized as well.
--- sound/core/seq/seq_compat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/core/seq/seq_compat.c +3 -1
@@ -44,7 +44,9 @@ static int snd_seq_call_port_info_ioctl( goto error; data->kernel =NULL ; - err =snd_seq_kernel_client_ctl (client->number, cmd, data); + scoped_guard(mutex, &client->ioctl_mutex) { + err =snd_seq_kernel_client_ctl (client->number, cmd, data); + }if (err <0 ) goto error;
Greg Kroah-Hartman
maintainerPATCH 300/1887 ALSA: ua101: reject mismatched capture/playback packet sizes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
commit 86f86e6fdedc33c5b8d38b9208b350f8accf57ee upstream.
detect_usb_format() cross-checks bSubframeSize, bBitResolution and tSamFreq between the capture and playback interfaces, but never relates the two endpoints' wMaxPacketSize and bNrChannels. Each playback URB gets a buffer of ua->playback.max_packet_bytes, while the number of bytes written into it is derived from the capture stream:capture_urb_complete() computes frames from the received capture packet and capture.frame_bytes, and start_usb_playback() and playback_work() multiply that by playback.frame_bytes.
A device declaring a large capture wMaxPacketSize with few capture channels and a small playback wMaxPacketSize with many playback channels therefore memset()s and memcpy()s past the end of the playback buffer, in open() of the PCM node the driver registers during probe. usb_submit_urb() rejects the over-long iso_frame_desc[0].length with -EMSGSIZE, but only after the write.
Reject such descriptors at probe time. Genuine UA-101/UA-1000 hardware declares proportional packet sizes and is unaffected.
BUG: KASAN: slab-out-of-bounds in start_usb_playback (sound/usb/misc/ua101.c:586) Write of size 2048 at addr ffff8881098f3c00 by task exploit/5021 Call Trace: __asan_memset (mm/kasan/shadow.c:84) start_usb_playback (sound/usb/misc/ua101.c:586) playback_pcm_open (sound/usb/misc/ua101.c:679) snd_pcm_open_substream (sound/core/pcm_native.c:2829) snd_pcm_open (sound/core/pcm_native.c:2865 sound/core/pcm_native.c:2932) snd_pcm_playback_open (sound/core/pcm_native.c:2891) snd_open (sound/core/sound.c:166) chrdev_open (fs/char_dev.c:411) do_dentry_open (fs/open.c:996) vfs_open (fs/open.c:1101) path_openat (fs/namei.c:4837 fs/namei.c:5000) do_file_open (fs/namei.c:5029) do_sys_openat2 (fs/open.c:1417) __x64_sys_openat (fs/open.c:1423 fs/open.c:1439 fs/open.c:1434) do_syscall_64 (arch/x86/entry/syscall_64.c:61 arch/x86/entry/syscall_64.c:84) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) The buggy address belongs to the object at ffff8881098f3c00 which belongs to the cache kmalloc-192 of size 192 The buggy address is located 0 bytes inside of allocated 168-byte region [ffff8881098f3c00, ffff8881098f3ca8)
--- sound/usb/misc/ua101.c | 9 +++++++++ 1 file changed, 9 insertions(+)
sound/usb/misc/ua101.c +9 -0
@@ -1022,6 +1022,15 @@ static int detect_usb_format(struct ua10 } ua->playback.usb_pipe =usb_sndisocpipe (ua->dev,usb_endpoint_num (epd)); ua->playback.max_packet_bytes =usb_endpoint_maxp (epd); + +if (ua->capture.max_packet_bytes / ua->capture.frame_bytes * + ua->playback.frame_bytes > ua->playback.max_packet_bytes) { +dev_err (&ua->dev->dev, +"playback packet size %u too small for %u capture frames\n" , + ua->playback.max_packet_bytes, + ua->capture.max_packet_bytes / ua->capture.frame_bytes); +return -ENXIO ; + }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 301/1887 Bluetooth: RFCOMM: Fix initial port reference race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 2d696c1ed3468dcb62578a3911e687110d463520 upstream.
For RFCOMM_RELEASE_ONHUP devices, rfcomm_tty_install() and __rfcomm_release_dev() both use RFCOMM_TTY_OWNED to decide who drops the initial tty_port reference. The release path tests the bit separately from the install path setting it, so both can drop that reference.
The synchronous hangup does not prevent this race: port->tty is not assigned until tty_port_open(), after installation. The following interleaving is possible:
1. Install and release each obtain a reference with rfcomm_dev_get().
2. Release observes RFCOMM_TTY_OWNED clear.
3. Install sets RFCOMM_TTY_OWNED and drops the initial reference.
4. Release drops the same initial reference again.
5. TTY cleanup drops its reference and frees the device.
6. Release performs its final tty_port_put() on the freed port.
KASAN reported:
BUG: KASAN: slab-use-after-free in tty_port_put+0x22/0x190 Write of size 4 at addr ffff8881001d3d5c by task poc/92 Call Trace: tty_port_put+0x22/0x190 rfcomm_dev_ioctl+0x1d4/0x1930 sock_do_ioctl+0x110/0x260 sock_ioctl+0x380/0x590 __x64_sys_ioctl+0x134/0x1c0 Allocated by task 88: rfcomm_dev_ioctl+0x8f6/0x1930 sock_do_ioctl+0x110/0x260 sock_ioctl+0x380/0x590 __x64_sys_ioctl+0x134/0x1c0 Freed by task 65: kfree+0x131/0x3c0 rfcomm_dev_destruct+0x23b/0x2f0 release_one_tty+0xc1/0x370 process_one_work+0x661/0x1090
Use test_and_set_bit() in both paths so that only the caller that changes RFCOMM_TTY_OWNED from clear to set drops the initial reference. Each path keeps its own lookup reference until release or TTY cleanup, preserving the existing callback ordering and error handling.
--- net/bluetooth/rfcomm/tty.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/bluetooth/rfcomm/tty.c +3 -4
@@ -465,7 +465,7 @@ static int __rfcomm_release_dev(void __u/* Shut down TTY synchronously before freeing rfcomm_dev */ tty_port_tty_vhangup (&dev->port); -if (!test_bit (RFCOMM_TTY_OWNED , &dev->status)) +if (!test_and_set_bit (RFCOMM_TTY_OWNED , &dev->status))tty_port_put (&dev->port);tty_port_put (&dev->port);
@@ -730,10 +730,9 @@ static int rfcomm_tty_install(struct tty* when the last process closes the tty. The behaviour is expected by * userspace. */ -if (test_bit (RFCOMM_RELEASE_ONHUP , &dev->flags)) { -set_bit (RFCOMM_TTY_OWNED , &dev->status); +if (test_bit (RFCOMM_RELEASE_ONHUP , &dev->flags) && + !test_and_set_bit (RFCOMM_TTY_OWNED , &dev->status))tty_port_put (&dev->port); - }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 302/1887 Bluetooth: hci_conn: Lock parent access during enhanced SCO setup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 024e05f73a4c1263d031614bc36700ec135eecb4 upstream.
Bluetooth: hci_conn: Lock parent access during enhanced SCO setup
hci_enhanced_setup_sync() runs on the request workqueue without the hci_dev_lock held by its caller when setup was queued. Its CVSD capability check and find_next_esco_param() dereference conn->parent while the receive workqueue can unlink and release that parent.
The following interleaving can cause a use-after-free:
hci_enhanced_setup_sync() hci_disconn_complete_evt()
load conn->parent
hci_dev_lock() hci_conn_del(ACL parent)
unlink SCO child drop link's parent reference clear child->parent release ACL parent
bt_link_release()
kfree(parent)
hci_dev_unlock()
read parent->features[0][3]
The reference held for the queued SCO child does not keep its ACL parent alive after unlinking. Commit 42de40abe25d ("Bluetooth: hci_conn: fix the SCO setup context lifetime") protects the child stored in the queued context, but leaves these parent accesses unprotected.
With a 40 ms diagnostic delay after loading conn->parent, an instrumented kernel based on fd179f8a05be, which already contains 42de40abe25d, reported:
BUG: KASAN: slab-use-after-free in hci_enhanced_setup_sync+0xda5/0xdf0 Read of size 1 at addr ffff888102204047 by task kworker/u17:0/93 Call Trace: hci_enhanced_setup_sync+0xda5/0xdf0 hci_cmd_sync_work+0x13c/0x290 process_one_work+0x6b4/0x10e0 Allocated by task 92: __hci_conn_add+0x304/0x1df0 hci_connect_acl+0x349/0x3e0 hci_connect_sco+0x3b/0x9a0 sco_sock_connect+0x475/0xca0 Freed by task 94: kfree+0x121/0x3c0 bt_link_release+0x79/0xa0 device_release+0xc8/0x240 kobject_put+0x14d/0x280 hci_conn_del+0x524/0xe30 hci_disconn_complete_evt+0x403/0x8c0 hci_event_packet+0x71b/0xb20 hci_rx_work+0x293/0x730
The accessed address is 71 bytes into the freed ACL parent, at its features[0][3] byte; the queued SCO child is a different object. The diagnostic preserves the loaded parent across the delay, matching the unmodified compiled capability check, and does not change the parent references or teardown path.
Hold hci_dev_lock() across the codec switch, including every call to find_next_esco_param(), and release it on all selection errors. Keep configure_datapath_sync() outside the critical section because it waits for HCI events. Preserve parameter selection and existing return values.
--- net/bluetooth/hci_conn.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
net/bluetooth/hci_conn.c +13 -5
@@ -412,11 +412,13 @@ static int hci_enhanced_setup_sync(struc cp.tx_bandwidth =cpu_to_le32 (0x00001f40 ); cp.rx_bandwidth =cpu_to_le32 (0x00001f40 ); +hci_dev_lock (hdev); +switch (conn->codec.id) {case BT_CODEC_MSBC :if (!find_next_esco_param (conn, esco_param_msbc,ARRAY_SIZE (esco_param_msbc))) -return -EINVAL ; + goto unlock; param = &esco_param_msbc[conn->attempt -1 ]; cp.tx_coding_format.id =0x05 ;
@@ -442,7 +444,7 @@ static int hci_enhanced_setup_sync(struccase BT_CODEC_TRANSPARENT :if (!find_next_esco_param (conn, esco_param_msbc,ARRAY_SIZE (esco_param_msbc))) -return -EINVAL ; + goto unlock; param = &esco_param_msbc[conn->attempt -1 ]; cp.tx_coding_format.id =0x03 ;
@@ -469,11 +471,11 @@ static int hci_enhanced_setup_sync(strucif (lmp_esco_capable (conn->link)) {if (!find_next_esco_param (conn, esco_param_cvsd,ARRAY_SIZE (esco_param_cvsd))) -return -EINVAL ; + goto unlock; param = &esco_param_cvsd[conn->attempt -1 ]; }else {if (conn->attempt >ARRAY_SIZE (sco_param_cvsd)) -return -EINVAL ; + goto unlock; param = &sco_param_cvsd[conn->attempt -1 ]; } cp.tx_coding_format.id =2 ;
@@ -496,9 +498,11 @@ static int hci_enhanced_setup_sync(struc cp.out_transport_unit_size =16 ;break ;default : -return -EINVAL ; + goto unlock; } +hci_dev_unlock (hdev); + cp.retrans_effort = param->retrans_effort; cp.pkt_type =__cpu_to_le16 (param->pkt_type); cp.max_latency =__cpu_to_le16 (param->max_latency);
@@ -507,6 +511,10 @@ static int hci_enhanced_setup_sync(strucreturn -EIO ;return 0 ; + +unlock: +hci_dev_unlock (hdev); +return -EINVAL ; }static bool hci_setup_sync_conn (struct hci_conn *conn,__u16 handle)
Greg Kroah-Hartman
maintainerPATCH 303/1887 Bluetooth: hci_core: Fix inquiry cache timestamps on 64-bit systems
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 74847177eca5638827ab74cdf77f0b10fc40ca6c upstream.
On 64-bit systems, outgoing BR/EDR connections always fall back to page scan repetition mode R2 with no clock offset once the system has been up for more than five minutes, even when inquiry found the peer only seconds earlier. This lengthens paging and can increase the risk of a Page Timeout.
The inquiry cache stores jiffies in __u32 timestamps, but its age helpers subtract them from unsigned long jiffies. INITIAL_JIFFIES casts -300 * HZ through unsigned int, so jiffies crosses 2^32 five minutes after boot on 64-bit systems. Assigning it to __u32 then drops the upper 32 bits. In one trace, a 7.6-second-old entry (HZ=1000) was reported as 2^32 + 7620 ticks old and rejected by hci_acl_create_conn_sync(). hci_inquiry() is affected by the same truncation when checking the whole cache. 32-bit systems are unaffected because unsigned long is 32 bits wide there.
Use unsigned long for both timestamps so they have the same width as jiffies on 32-bit and 64-bit systems, and update the debugfs format specifier accordingly.
--- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_debugfs.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
include/net/bluetooth/hci_core.h +2 -2
@@ -63,7 +63,7 @@ struct inquiry_entry {NAME_PENDING ,NAME_KNOWN , } name_state; -__u32 timestamp; +unsigned long timestamp;struct inquiry_data data; };
@@ -79,7 +79,7 @@ struct discovery_state {struct list_head all;/* All devices found during inquiry */ struct list_head unknown;/* Name state not known */ struct list_head resolve;/* Name needs to be resolved */ -__u32 timestamp; +unsigned long timestamp;bdaddr_t last_adv_addr;u8 last_adv_addr_type;s8 last_adv_rssi;
net/bluetooth/hci_debugfs.c +1 -1
@@ -367,7 +367,7 @@ static int inquiry_cache_show(struct seqlist_for_each_entry (e, &cache->all, all) {struct inquiry_data *data = &e->data; - seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", + seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %lu\n", &data->bdaddr, data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, data->dev_class[2],
Greg Kroah-Hartman
maintainerPATCH 304/1887 Bluetooth: hci_core: Serialize ACL scheduling with channel deletion
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit f4845ab191a4f686a5da481fbba90ed73bb693b0 upstream.
hci_chan_sent() selects a channel under RCU but drops the read lock before accessing chan->conn and returning the channel. The ACL and LE schedulers then use its packet queue and update its transmit counters without any protection against channel deletion.
After TX selects a channel and releases RCU, a disconnect command timeout on the separate request workqueue can run hci_conn_failed() and l2cap_conn_del(). hci_chan_del() can then unlink the channel, complete synchronize_rcu(), purge its queue and free it before TX resumes. This causes use-after-free both in hci_chan_sent() and in its callers.
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_chan_sent+0x892/0x9b0 Workqueue: hci0 hci_tx_work Call Trace: hci_chan_sent+0x892/0x9b0 hci_tx_work+0x5e6/0xb70 Allocated by task 91: hci_chan_create+0xe3/0x350 l2cap_conn_add.part.0+0x12/0xa30 l2cap_chan_connect+0x110d/0x1b60 l2cap_sock_connect+0x310/0x530 Freed by task 99: hci_chan_del+0x11f/0x170 l2cap_conn_del+0x4f1/0x800 l2cap_connect_cfm+0x88c/0xd30 hci_conn_failed+0x150/0x250 hci_abort_conn_sync+0x3e3/0x800 hci_cmd_sync_run+0x7e/0xc0 hci_abort_conn+0x105/0x1f0 disconnect_sync+0x157/0x290 hci_cmd_sync_work+0x13c/0x290
Hold the existing device mutex across channel selection and transmission in both schedulers to serialize them with channel teardown. Keep timeout handling outside the critical sections because hci_link_tx_to() acquires the same mutex. This also permits the transmit path to sleep, unlike extending the RCU read-side critical section across packet submission.
--- net/bluetooth/hci_core.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/bluetooth/hci_core.c +8 -0
@@ -3604,6 +3604,8 @@ static void hci_sched_acl_pkt(struct hci__check_timeout (hdev, cnt,ACL_LINK ); +hci_dev_lock (hdev); +while (hdev->acl_cnt && (chan =hci_chan_sent (hdev,ACL_LINK , "e))) {u32 priority = (skb_peek (&chan->data_q))->priority;
@@ -3635,6 +3637,8 @@ static void hci_sched_acl_pkt(struct hciif (cnt != hdev->acl_cnt)hci_prio_recalculate (hdev,ACL_LINK ); + +hci_dev_unlock (hdev); }static void hci_sched_acl (struct hci_dev *hdev)
@@ -3663,6 +3667,8 @@ static void hci_sched_le(struct hci_dev__check_timeout (hdev, *cnt,LE_LINK ); +hci_dev_lock (hdev); + tmp = *cnt;while (*cnt && (chan =hci_chan_sent (hdev,LE_LINK , "e))) {u32 priority = (skb_peek (&chan->data_q))->priority;
@@ -3691,6 +3697,8 @@ static void hci_sched_le(struct hci_devif (*cnt != tmp)hci_prio_recalculate (hdev,LE_LINK ); + +hci_dev_unlock (hdev); }/* Schedule CIS */
Greg Kroah-Hartman
maintainerPATCH 305/1887 Bluetooth: hci_core: Serialize fragmented ISO packet queueing
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 1a572db43c057566771b485598ad2e66cb390821 upstream.
The fragmented path in hci_queue_iso() calls __skb_queue_tail() without holding conn->data_q.lock. The socket lock serializes senders, but the transmit worker can concurrently remove packets from this queue using skb_dequeue().
After an insertion saves the old tail pointer, hci_sched_iso() can dequeue that packet and pass it to the driver. The driver can free the packet before the insertion resumes and writes to the old tail's next pointer, causing a use-after-free. Concurrent updates can also corrupt the queue.
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_send_iso+0xc7d/0xe10 Call Trace: hci_send_iso+0xc7d/0xe10 iso_sock_sendmsg+0x710/0x900 __sys_sendto+0x34a/0x3a0 Allocated by task 86: __alloc_skb+0xdd/0x820 alloc_skb_with_frags+0x7e/0x770 sock_alloc_send_pskb+0x67a/0x820 bt_skb_sendmsg.constprop.0+0xc0/0x6c0 iso_sock_sendmsg+0x44e/0x900 Freed by task 90: kmem_cache_free+0xcb/0x3d0 vhci_read+0x33f/0x4d0 vfs_read+0x177/0xa20
Hold the queue lock across the entire fragment batch, as hci_queue_acl() does, to serialize insertion against dequeue while preserving fragment ordering.
--- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+)
net/bluetooth/hci_core.c +4 -0
@@ -3291,6 +3291,8 @@ static void hci_queue_iso(struct hci_conskb_shinfo (skb)->frag_list =NULL ; +spin_lock_bh (&queue->lock); +__skb_queue_tail (queue, skb); do {
@@ -3305,6 +3307,8 @@ static void hci_queue_iso(struct hci_con__skb_queue_tail (queue, skb); }while (list); + +spin_unlock_bh (&queue->lock); } }
Greg Kroah-Hartman
maintainerPATCH 306/1887 Bluetooth: btintel: fix buffer over-read in btintel_hw_error()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chandrashekar Devegowda <[email protected]>
commit 40eb4b18ad167b63644c27fa67a7400ba050379a upstream.
The "Exception info %s" print uses skb->data + 1, but the 12-byte payload is not guaranteed to be NUL-terminated and can be read past its end.
Bound the print with "%.*s" and skb->len - 1.
--- drivers/bluetooth/btintel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/bluetooth/btintel.c +2 -1
@@ -248,7 +248,8 @@ static void btintel_hw_error(struct hci_ goto unlock; } -bt_dev_err (hdev,"Exception info %s" , (char *)(skb->data +1 )); +bt_dev_err (hdev,"Exception info %.*s" , (int )(skb->len -1 ), + (char *)(skb->data +1 ));kfree_skb (skb);
Greg Kroah-Hartman
maintainerPATCH 307/1887 ipvs: bound LBLCR and LBLC cache growth
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
[ Upstream commit 2a3c3de660f96865f303fd25f1285f2ffbfd521d ]
ip_vs_lblcr_new() and ip_vs_lblc_new() create cache entries for every previously unseen destination address. The table max_size only tells the periodic collector to reclaim entries after the cache has already exceeded the limit. It does not reclaim entries that the attacker continues to use.
Reject new cache entries once either table reaches max_size * 3 / 2. The extra headroom lets the periodic collector catch up while the existing scheduler fallback continues to use the selected destination when cache creation fails. New traffic therefore stays serviceable without growing the tables further.
--- net/netfilter/ipvs/ip_vs_lblc.c | 3 +++ net/netfilter/ipvs/ip_vs_lblcr.c | 3 +++ 2 files changed, 6 insertions(+)
net/netfilter/ipvs/ip_vs_lblc.c +3 -0
@@ -207,6 +207,9 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,ip_vs_lblc_del (en);atomic_dec (&tbl->entries); } +if (atomic_read (&tbl->entries) >= tbl->max_size *3 /2 ) +return NULL ; + en =kmalloc (sizeof (*en),GFP_ATOMIC );if (!en)return NULL ;
net/netfilter/ipvs/ip_vs_lblcr.c +3 -0
@@ -365,6 +365,9 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, en =ip_vs_lblcr_get (af, tbl, daddr);if (!en) { +if (atomic_read (&tbl->entries) >= tbl->max_size *3 /2 ) +return NULL ; + en =kmalloc (sizeof (*en),GFP_ATOMIC );if (!en)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 308/1887 nvme-multipath: fix underflow in ANA log bounds checks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 63fa2d9c9c37020bd2703fe2a6a38027b5abeb15 upstream.
The number of ANA groups advertised through Identify Controller sizes the ANA log buffer. The ANA log header and group descriptors independently supply the number of groups and namespace IDs to parse.
Both bounds checks subtract an untrusted object size from ana_log_size before comparing the current offset. If the object is larger than the buffer, the size_t subtraction underflows and lets the parser read beyond ana_log_buf.
Check the current offset before the first subtraction and compare each object size with the remaining buffer instead. This rejects inconsistent ANA data before dereferencing a truncated group descriptor or walking an oversized namespace ID array.
--- drivers/nvme/host/multipath.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/nvme/host/multipath.c +3 -2
@@ -616,7 +616,8 @@ static int nvme_parse_ana_log(struct nvmu32 nr_nsids;size_t nsid_buf_size; -if (WARN_ON_ONCE (offset > ctrl->ana_log_size -sizeof (*desc))) +if (WARN_ON_ONCE (offset > ctrl->ana_log_size || +sizeof (*desc) > ctrl->ana_log_size - offset))return -EINVAL ; nr_nsids =le32_to_cpu (desc->nnsids);
@@ -632,7 +633,7 @@ static int nvme_parse_ana_log(struct nvmreturn -EINVAL ; offset +=sizeof (*desc); -if (WARN_ON_ONCE (offset > ctrl->ana_log_size - nsid_buf_size)) +if (WARN_ON_ONCE (nsid_buf_size > ctrl->ana_log_size - offset))return -EINVAL ; error =cb (ctrl, desc, data);
Greg Kroah-Hartman
maintainerPATCH 309/1887 nvmet-auth: fix out-of-bounds write in nvmet_auth_challenge()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit fa6778e030bed9841ddcdf96bc7018da9ac03562 upstream.
nvmet_auth_challenge() receives its output buffer as a void pointer. sizeof(*d) therefore evaluates to one with GCC and undercounts the fixed challenge header by 15 bytes. A short AUTH_RECEIVE buffer can pass the check before the challenge is copied past the end of its allocation.
Use the typed challenge pointer when calculating the response size.
BUG: KASAN: slab-out-of-bounds in nvmet_execute_auth_receive (drivers/nvme/target/fabrics-cmd-auth.c:442 drivers/nvme/target/fabrics-cmd-auth.c:569) Write of size 32 by task kworker/1:1H/64 Workqueue: nvmet_tcp_wq nvmet_tcp_io_work Call Trace: nvmet_execute_auth_receive (drivers/nvme/target/fabrics-cmd-auth.c:442 drivers/nvme/target/fabrics-cmd-auth.c:569) nvmet_tcp_try_recv_pdu (drivers/nvme/target/tcp.c:1119 drivers/nvme/target/tcp.c:1243) nvmet_tcp_io_work (drivers/nvme/target/tcp.c:1350 drivers/nvme/target/tcp.c:1382 drivers/nvme/target/tcp.c:1445) process_one_work (kernel/workqueue.c:3322) worker_thread (kernel/workqueue.c:3405 kernel/workqueue.c:3486) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:158) ret_from_fork_asm (arch/x86/entry/entry_64.S:245) The buggy address is located 16 bytes inside of allocated 33-byte region [ffff888000554e80, ffff888000554ea1) Kernel panic - not syncing: KASAN: panic_on_warn set ...
--- drivers/nvme/target/fabrics-cmd-auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/target/fabrics-cmd-auth.c +1 -1
@@ -359,7 +359,7 @@ static int nvmet_auth_challenge(struct nstruct nvmet_ctrl *ctrl = req->sq->ctrl;int ret =0 ;int hash_len =nvme_auth_hmac_hash_len (ctrl->shash_id); -int data_size =sizeof (*d) + hash_len; +int data_size =sizeof (*data) + hash_len;if (ctrl->dh_tfm) data_size += ctrl->dh_keysize;
Greg Kroah-Hartman
maintainerPATCH 310/1887 mtd: rawnand: cadence: Initialize IRQ state before requesting IRQ
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 21f027016b1290d13c30b198ae7a00e6b3d1d5a5 upstream.
The Cadence NAND interrupt handler uses both the IRQ lock and completion object. Registering the IRQ before initializing them leaves a window in which a pending interrupt can access uninitialized synchronization state.
Initialize them before registering the handler.
--- drivers/mtd/nand/raw/cadence-nand-controller.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/mtd/nand/raw/cadence-nand-controller.c +3 -3
@@ -2847,6 +2847,9 @@ static int cadence_nand_init(struct cdns goto free_buf_desc; } +spin_lock_init (&cdns_ctrl->irq_lock); +init_completion (&cdns_ctrl->complete); +if (devm_request_irq (cdns_ctrl->dev, cdns_ctrl->irq, cadence_nand_isr,IRQF_SHARED ,"cadence-nand-controller" , cdns_ctrl)) {
@@ -2855,9 +2858,6 @@ static int cadence_nand_init(struct cdns goto free_buf; } -spin_lock_init (&cdns_ctrl->irq_lock); -init_completion (&cdns_ctrl->complete); - ret =cadence_nand_hw_init (cdns_ctrl);if (ret) goto disable_irq;
Greg Kroah-Hartman
maintainerPATCH 311/1887 mtd: rawnand: vf610_nfc: fix reads on chips with more than 64 bytes of OOB
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mehmet Fide <[email protected]>
commit 37adc9c5789c76db3b1ee7aeec3999b8503020d0 upstream.
The controller transfers 64 spare bytes per page and the driver only implements the matching 64-byte ECC layout, so attach_chip() shrinks mtd->oobsize when the chip provides more. That clamp does not survive:nand_scan_tail() runs nanddev_init() after ->attach_chip(), and it restores mtd->oobsize from the memory organization, which still holds the value detected from the chip. The driver then transfers writesize plus the chip's full OOB size, the hardware ECC parity ends up at a different offset than the layout the controller was set up for, and every ECC-protected read fails with -EBADMSG.
Measured on a Colibri VF61 (MX30LF4G28AC, 2048-byte pages, 112 bytes of OOB): with the clamp lost, UBI cannot read the erase counter headers of the pages U-Boot has just written, and the on-flash bad block table written by an older kernel reads back with ECC errors, so the board does not boot. Kernels before commit a7ab085d7c16 ("mtd: rawnand:
Initialize the nand_device object") are not affected because nothing overwrote the clamp there, which is why the same chip works with a v4.4 kernel and with U-Boot, whose copy of this driver has no memory organization to restore the value from. Edward Karpicz reported that the clamp no longer takes effect on this chip; see the link below.
Instead of modifying the memory organization, keep the detected OOB size and give the driver its own mtd_ooblayout_ops: the same layout the NAND core uses for large pages, but computed on the first 64 OOB bytes instead of the whole OOB, so the ECC bytes stay where U-Boot and the old kernels put them. The data paths transfer writesize plus those 64 bytes, as the controller always has.
Since mtd->oobsize now reports the chip's real spare size, fill the tail of oob_poi with 0xff after the 64 transferred bytes on ECC page
reads: the core may copy the full mtd->oobsize from it, which would otherwise expose whatever the buffer held before. 0xff also matches what a raw read returns from flash, since the write path only ever programs the first 64 spare bytes.
--- drivers/mtd/nand/raw/vf610_nfc.c | 72 ++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 12 deletions(-)
drivers/mtd/nand/raw/vf610_nfc.c +60 -12
@@ -504,6 +504,11 @@ static int vf610_nfc_exec_op(struct nand check_only); } +static unsigned int vf610_nfc_spare_size (struct mtd_info *mtd) +{ + return min_t(unsigned int, mtd->oobsize, 64); +} +static inline int vf610_nfc_correct_data (struct nand_chip *chip,uint8_t *dat,uint8_t *oob,int page) {
@@ -521,7 +526,7 @@ static inline int vf610_nfc_correct_datareturn ecc_count; nfc->data_access = true; -nand_read_oob_op (&nfc->chip, page,0 , oob, mtd->oobsize); +nand_read_oob_op (&nfc->chip, page,0 , oob,vf610_nfc_spare_size (mtd)); nfc->data_access = false;/*
@@ -529,7 +534,7 @@ static inline int vf610_nfc_correct_data* at least less then half of the ECC strength. */ return nand_check_erased_ecc_chunk (dat, nfc->chip.ecc.size, oob, - mtd->oobsize,NULL ,0 , +vf610_nfc_spare_size (mtd),NULL ,0 , flips_threshold); }
@@ -550,7 +555,7 @@ static int vf610_nfc_read_page(struct na {struct vf610_nfc *nfc =chip_to_nfc (chip);struct mtd_info *mtd =nand_to_mtd (chip); -int trfr_sz = mtd->writesize + mtd->oobsize; +int trfr_sz = mtd->writesize +vf610_nfc_spare_size (mtd);u32 row =0 , cmd1 =0 , cmd2 =0 , code =0 ;int stat;
@@ -576,11 +581,16 @@ static int vf610_nfc_read_page(struct na*/ vf610_nfc_rd_from_sram (buf, nfc->regs +NFC_MAIN_AREA (0 ), mtd->writesize, false); -if (oob_required) +if (oob_required) { +unsigned int spare =vf610_nfc_spare_size (mtd); +vf610_nfc_rd_from_sram (chip->oob_poi, nfc->regs +NFC_MAIN_AREA (0 ) + mtd->writesize, - mtd->oobsize, false); + spare, false); +/* Not transferred, and never written: reads back erased */ +memset (chip->oob_poi + spare,0xff , mtd->oobsize - spare); + } stat =vf610_nfc_correct_data (chip, buf, chip->oob_poi, page);
@@ -598,7 +608,7 @@ static int vf610_nfc_write_page(struct n {struct vf610_nfc *nfc =chip_to_nfc (chip);struct mtd_info *mtd =nand_to_mtd (chip); -int trfr_sz = mtd->writesize + mtd->oobsize; +int trfr_sz = mtd->writesize +vf610_nfc_spare_size (mtd);u32 row =0 , cmd1 =0 , cmd2 =0 , code =0 ;u8 status;int ret;
@@ -739,6 +749,49 @@ static void vf610_nfc_init_controller(st } } +/* +* With 64 byte OOB chips the core's large page layout matches what +* U-Boot uses, and on chips with more, U-Boot and older kernels clamped +* mtd->oobsize to 64. Modifying the OOB size is no longer possible, the +* actual chip geometry must be respected, so to avoid breaking those +* existing setups use our own layout: the core's large page one, +* computed over the first 64 spare bytes only. +*/ +static int vf610_nfc_ooblayout_ecc (struct mtd_info *mtd,int section, +struct mtd_oob_region *oobregion) +{ +struct nand_device *nand =mtd_to_nanddev (mtd); +unsigned int total_ecc_bytes = nand->ecc.ctx.total; + +if (section || !total_ecc_bytes) +return -ERANGE ; + + oobregion->length = total_ecc_bytes; + oobregion->offset =vf610_nfc_spare_size (mtd) - oobregion->length; + +return 0 ; +} + +static int vf610_nfc_ooblayout_free (struct mtd_info *mtd,int section, +struct mtd_oob_region *oobregion) +{ +struct nand_device *nand =mtd_to_nanddev (mtd); +unsigned int total_ecc_bytes = nand->ecc.ctx.total; + +if (section) +return -ERANGE ; + + oobregion->length =vf610_nfc_spare_size (mtd) - total_ecc_bytes -2 ; + oobregion->offset =2 ; + +return 0 ; +} + +static const struct mtd_ooblayout_ops vf610_nfc_ooblayout_ops = { + .ecc = vf610_nfc_ooblayout_ecc, + .free = vf610_nfc_ooblayout_free, +}; +static int vf610_nfc_attach_chip (struct nand_chip *chip) {struct mtd_info *mtd =nand_to_mtd (chip);
@@ -769,12 +822,7 @@ static int vf610_nfc_attach_chip(structreturn -ENXIO ; } -/* Only 64 byte ECC layouts known */ -if (mtd->oobsize >64 ) - mtd->oobsize =64 ; - -/* Use default large page ECC layout defined in NAND core */ -mtd_set_ooblayout (mtd,nand_get_large_page_ooblayout ()); +mtd_set_ooblayout (mtd, &vf610_nfc_ooblayout_ops);if (chip->ecc.strength ==32 ) { nfc->ecc_mode =ECC_60_BYTE ; chip->ecc.bytes =60 ;
Greg Kroah-Hartman
maintainerPATCH 312/1887 mtd: spinand: fix zero oobavail when no ECC engine is used
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuno Sá <[email protected]>
commit 636fe10d8f3559210ff63108a208d39ea2e9c3bd upstream.
Commit 00c15b78b4b4 ("mtd: spinand: Allow the case where there is no ECC engine") made the OOB free bytes count conditional on having an ECC engine so that probing would not fail when none is requested. However mtd->oobavail is still assigned from ret just after that block, and ret is 0 there, so the device ends up advertising no available OOB bytes at all.
mtd_oobavail() returns mtd->oobavail for MTD_OPS_AUTO_OOB, so a zero value makes every automatic OOB access fail with -EINVAL. JFFS2 fares
worse: it keeps its cleanmarker in the OOB area on NAND and refuses to mount outright, reporting "inconsistent device description".
No ECC engine also means no ooblayout was ever installed, which would make the count return -ENOTSUPP, so install the same fallback layout the on-die path already uses before counting unconditionally.
--- drivers/mtd/nand/spi/core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/mtd/nand/spi/core.c +9 -4
@@ -1276,12 +1276,17 @@ static int spinand_init(struct spinand_d mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; mtd->_resume = spinand_mtd_resume; -if (nand->ecc.engine) { - ret =mtd_ooblayout_count_freebytes (mtd); -if (ret <0 ) - goto err_cleanup_ecc_engine; +if (!nand->ecc.engine) { +if (spinand->eccinfo.ooblayout) +mtd_set_ooblayout (mtd, spinand->eccinfo.ooblayout); +else +mtd_set_ooblayout (mtd, &spinand_noecc_ooblayout); } + ret =mtd_ooblayout_count_freebytes (mtd); +if (ret <0 ) + goto err_cleanup_ecc_engine; + mtd->oobavail = ret;/* Propagate ECC information to mtd_info */
Greg Kroah-Hartman
maintainerPATCH 313/1887 wifi: cw1200: fix TX padding OOB read leaking heap data to device
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tianchu Chen <[email protected]>
commit 7c1611780823b76219cb1478db53dfd890c4a9a2 upstream.
The TX path rounds the transfer size up to the bus alignment (align_size(), up to 511 bytes for SDIO, 1 byte for SPI) but sends the padded length straight from the frame buffer, which has no room reserved for the padding. cw1200_data_write() therefore reads past the end of the frame and the bus transfer carries those bytes to the device. A bogus device can collect up to 511 bytes of kernel heap data per TX frame.
The RX path does not have this problem: it allocates the skb with the aligned length (alloc_len) before reading.
Compute the exact padding with the bus align_size() callback, make sure queued TX frames have tailroom for it, and zero the padding bytes before the transfer so nothing past the frame is exposed.
This is not expected to change driver behavior on most cases: frame contents and transfer sizes are unchanged, only the content of the padding bytes (previously undefined stale memory, now zero), which the device never reads since the WSM header carries the real frame length. The skb expansion can only fail under memory exhaustion, in which case the frame is dropped like on the existing error paths of cw1200_tx().
Discovered by Atuin - Automated Vulnerability Discovery Engine.
--- drivers/net/wireless/st/cw1200/bh.c | 8 +++++++- drivers/net/wireless/st/cw1200/txrx.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-)
drivers/net/wireless/st/cw1200/bh.c +7 -1
@@ -343,6 +343,7 @@ static int cw1200_bh_tx_helper(struct cw int *tx_burst) {size_t tx_len; +size_t aligned_len;u8 *data;int ret;struct wsm_hdr *wsm;
@@ -375,9 +376,14 @@ static int cw1200_bh_tx_helper(struct cwatomic_inc (&priv->bh_tx); - tx_len = priv->hwbus_ops->align_size ( + aligned_len = priv->hwbus_ops->align_size ( priv->hwbus_priv, tx_len); +/* Zero the bus alignment padding so no stale data is sent. */ +if (aligned_len > tx_len) +memset (data + tx_len,0 , aligned_len - tx_len); + tx_len = aligned_len; +/* Check if not exceeding CW1200 capabilities */ if (WARN_ON_ONCE (tx_len >EFFECTIVE_BUF_SIZE ))pr_debug ("Write aligned len: %zu\n" , tx_len);
drivers/net/wireless/st/cw1200/txrx.c +14 -0
@@ -14,6 +14,7 @@#include "wsm.h" #include "bh.h" #include "sta.h" +#include "hwbus.h" #include "debug.h" #define CW1200_INVALID_RATE_ID (0xFF)
@@ -716,6 +717,7 @@ void cw1200_tx(struct ieee80211_hw *dev,struct ieee80211_sta *sta;struct wsm_tx *wsm;bool tid_update = false; +size_t pad_len;u8 flags =0 ;int ret;
@@ -764,6 +766,18 @@ void cw1200_tx(struct ieee80211_hw *dev, sta = t.sta; +/* +* The bus transfer is padded up to the bus alignment and the +* padding is transferred from the frame buffer. Make sure the +* buffer has room for the padding so the device never receives +* data past the end of the frame. +*/ + pad_len = priv->hwbus_ops->align_size (priv->hwbus_priv, skb->len) - + skb->len; +if (skb_tailroom (skb) < pad_len && +pskb_expand_head (skb,0 , pad_len,GFP_ATOMIC )) + goto drop; +spin_lock_bh (&priv->ps_state_lock); { tid_update =cw1200_tx_h_pm_state (priv, &t);
Greg Kroah-Hartman
maintainerPATCH 314/1887 wifi: iwlegacy: 3945: free EEPROM data on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit f8ebe286394c0bbb4a6dbacb182a34ab6376922d upstream.
il3945_pci_probe() calls il_eeprom_init(), which allocates memory for the EEPROM data. The probe failure paths release this allocation with il_eeprom_free(), but the remove path does not free it after a successful probe.
As a result, the EEPROM data is leaked when the PCI device is removed.
Free the EEPROM data in il3945_pci_remove() before releasing the mac80211 hardware structure.
This issue was found by manual code inspection.
--- drivers/net/wireless/intel/iwlegacy/3945-mac.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/intel/iwlegacy/3945-mac.c +1 -0
@@ -3845,6 +3845,7 @@ il3945_pci_remove(struct pci_dev *pdev)il_free_channel_map (il);il_free_geos (il); +il_eeprom_free (il);kfree (il->scan_cmd);dev_kfree_skb (il->beacon_skb);ieee80211_free_hw (il->hw);
Greg Kroah-Hartman
maintainerPATCH 315/1887 wifi: mac80211: drain PS delivery work during station teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
commit 67a9e80c3ca20c9044cd6ee72cd6278dd19b5023 upstream.
Removing an AP or mesh station can notify the driver and wake TXQs after the station has already been removed from the driver, and can update num_sta_ps and the power-save queues after station cleanup has purged them.
sta_deliver_ps_frames() tests sta->dead only before it starts delivery. A worker that passes that test can be delayed while teardown sets sta->dead and removes the station from the driver; when it resumes it still runs the full delivery.
The existing cancel_work_sync() sits near the end of __cleanup_single_sta(), after the final driver state transition and after PS accounting and queue purging, so it drains the worker only once the state it has to protect has already changed. Before commit d34ba2168a3c ("mac80211: don't delay station destruction") cleanup was deferred through the same ordered workqueue as the delivery work, which kept the two ordered.
Cancel the work after setting sta->dead and before moving the driver state, and move the existing cancellation to the start of __cleanup_single_sta(). The first drain closes the driver-lifetime window; driver callbacks during the remaining state transitions can still queue drv_deliver_wk through ieee80211_sta_block_awake(), so retain the second drain at the start of __cleanup_single_sta(). That drain also covers insertion failures, which reach cleanup without setting sta->dead.
--- net/mac80211/sta_info.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/mac80211/sta_info.c +4 -2
@@ -122,6 +122,8 @@ static void __cleanup_single_sta(structstruct ieee80211_local *local = sdata->local;struct ps_data *ps; +cancel_work_sync (&sta->drv_deliver_wk); +if (test_sta_flag (sta,WLAN_STA_PS_STA ) ||test_sta_flag (sta,WLAN_STA_PS_DRIVER ) ||test_sta_flag (sta,WLAN_STA_PS_DELIVER )) {
@@ -162,8 +164,6 @@ static void __cleanup_single_sta(structif (ieee80211_vif_is_mesh (&sdata->vif))mesh_sta_cleanup (sta); -cancel_work_sync (&sta->drv_deliver_wk); -/* * Destroy aggregation state here. It would be nice to wait for the * driver to finish aggregation stop and then clean up, but for now
@@ -1303,6 +1303,8 @@ static void __sta_info_destroy_part2(str sta->dead = true; +cancel_work_sync (&sta->drv_deliver_wk); + local->num_sta--; local->sta_generation++;
Greg Kroah-Hartman
maintainerPATCH 316/1887 wifi: mac80211: minstrel_ht: validate fixed rate index
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 15fb9e3cea55fbc378261ce35a32b0f8828f0000 upstream.
The fixed_rate_idx debugfs file is a plain u32 attribute, so any value can be written to it. minstrel_ht_update_stats() then copies the value into mi->max_tp_rate[] and mi->max_prob_rate, and minstrel_ht_set_rate() uses MI_RATE_GROUP()/MI_RATE_IDX() to index minstrel_mcs_groups[] (42 entries) and mi->groups[].rates[] (10 entries) with it.
Writing e.g. 65535 selects group 4095 and rate index 15, far outside both arrays. The out-of-bounds entries are dereferenced and updated as struct minstrel_rate_stats (retry counts, etc.), so the invalid index corrupts adjacent kernel memory. With CONFIG_UBSAN_BOUNDS the access is reported as an array-index-out-of-bounds in minstrel_ht_set_rate().
Only a valid group/rate pair, or U32_MAX to disable fixed rate processing, can be used safely, so reject any other value when the debugfs file is written.
The file is only reachable through a root-only debugfs mount, so this is not a privilege boundary. The out-of-bounds access is still a bug that must not be reachable through a writable debugfs attribute.
--- net/mac80211/rc80211_minstrel_ht.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
net/mac80211/rc80211_minstrel_ht.c +28 -2
@@ -7,6 +7,7 @@#include <linux/types.h> #include <linux/skbuff.h> #include <linux/debugfs.h> +#include <linux/limits.h> #include <linux/random.h> #include <linux/moduleparam.h> #include <linux/ieee80211.h>
@@ -1977,14 +1978,39 @@ minstrel_ht_alloc(struct ieee80211_hw *h }#ifdef CONFIG_MAC80211_DEBUGFS +static int minstrel_ht_fixed_rate_idx_get (void *data,u64 *val) +{ + *val = *(u32 *)data; +return 0 ; +} + +static int minstrel_ht_fixed_rate_idx_set (void *data,u64 val) +{ +u32 idx = val; + +/* U32_MAX is the default and keeps fixed rate processing disabled */ +if (val !=U32_MAX && + (val >U16_MAX || +MI_RATE_GROUP (idx) >=ARRAY_SIZE (minstrel_mcs_groups) || +MI_RATE_IDX (idx) >=MCS_GROUP_RATES )) +return -EINVAL ; + + *(u32 *)data = idx; +return 0 ; +} + +DEFINE_DEBUGFS_ATTRIBUTE (minstrel_ht_fixed_rate_idx_fops, + minstrel_ht_fixed_rate_idx_get, + minstrel_ht_fixed_rate_idx_set,"%llu\n" ); +static void minstrel_ht_add_debugfs (struct ieee80211_hw *hw,void *priv,struct dentry *debugfsdir) {struct minstrel_priv *mp = priv; mp->fixed_rate_idx = (u32) -1 ; -debugfs_create_u32 ("fixed_rate_idx" ,S_IRUGO |S_IWUGO , debugfsdir, - &mp->fixed_rate_idx); +debugfs_create_file ("fixed_rate_idx" ,S_IRUGO |S_IWUGO , debugfsdir, + &mp->fixed_rate_idx, &minstrel_ht_fixed_rate_idx_fops); }#endif
Greg Kroah-Hartman
maintainerPATCH 317/1887 wifi: mac80211: release mesh path quota on failed additions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
commit 7325a44474f20c1393a1c114c6811abce6ddfaf4 upstream.
Repeated failed or duplicate mesh path additions can exhaust MESH_MAX_MPATHS while the path table holds fewer paths, which stops new paths to reachable destinations from being created.
mesh_path_add() reserves a slot before allocating and inserting a path. If allocation fails, the function returns without releasing the slot. If the rhashtable insertion reports an error or an existing destination, the function discards its candidate but retains the reservation. No new path is installed in any of these cases.
Release the reservation whenever the candidate is not installed.
--- net/mac80211/mesh_pathtbl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/mac80211/mesh_pathtbl.c +4 -1
@@ -407,8 +407,10 @@ struct mesh_path *mesh_path_add(struct ireturn ERR_PTR (-ENOSPC ); new_mpath =mesh_path_new (sdata, dst,GFP_ATOMIC ); -if (!new_mpath) +if (!new_mpath) { +atomic_dec (&sdata->u.mesh.mpaths);return ERR_PTR (-ENOMEM ); + } tbl = &sdata->u.mesh.mesh_paths;spin_lock_bh (&tbl->walk_lock);
@@ -421,6 +423,7 @@ struct mesh_path *mesh_path_add(struct iif (mpath) {kfree (new_mpath); +atomic_dec (&sdata->u.mesh.mpaths);if (IS_ERR (mpath))return mpath;
Greg Kroah-Hartman
maintainerPATCH 318/1887 wifi: mac80211: handle empty FILS association request payload
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 5bfd4b0b40b79781d900cb2f7da0685070f53c67 upstream.
fils_encrypt_assoc_req() accepts a (Re)Association Request frame whose last element is the FILS Session element. crypt_len is then zero and aes_siv_encrypt() is called with an empty plaintext.
kmemdup() returns ZERO_SIZE_PTR for a zero-length allocation, so the unconditional sg_init_one() puts an invalid page into the scatterlist. With CONFIG_DEBUG_SG this triggers a kernel BUG in sg_set_buf(); without the debug check the bogus page is handed to the crypto backend.
AES-SIV is defined for empty plaintext and the S2V result is then the complete output, so handle this case before the CTR step, which has nothing to encrypt.
--- net/mac80211/fils_aead.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/mac80211/fils_aead.c +8 -0
@@ -95,6 +95,14 @@ static int aes_siv_encrypt(const u8 *keyif (res)return res; +/* With an empty plaintext there is no ciphertext to produce and +* the S2V result is the complete output. +*/ +if (!plain_len) { +memcpy (out, v,AES_BLOCK_SIZE ); +return 0 ; + } +/* Use a temporary buffer of the plaintext to handle need for * overwriting this during AES-CTR. */
Greg Kroah-Hartman
maintainerPATCH 319/1887 USB: serial: cp210x: add Corsair AX1500i Power Supply
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Carrat <[email protected]>
commit d84e27d87738634b92001500435ae4dadba10a13 upstream.
The Corsair AX1500i power supply exposes its Corsair Link monitoring interface on a mini-USB port through an on-board CP2103, using a Corsair-specific product ID. Without the ID in the table no driver binds and no tty is created.
Tested by forcing the driver association with
echo 1b1c 1c02 > /sys/bus/usb-serial/drivers/cp210x/new_id
and then setting the serial port to 115200 8N1. Adding the ID is sufficient to talk to the device: the tty reaches a USB-to-SMBus bridge sitting behind the UART, which identifies itself as "USB to SMB Bridge (Firmware by Ross Fosler)" version 0.9 and relays PMBus reads to the power supply controller. Input voltage and current, input and output power, internal temperature and fan speed were all read back on an AX1500i.
[ 7.806181] usb 3-14: New USB device found, idVendor=1b1c, idProduct=1c02, bcdDevice= 1.00 [ 698.526754] usbcore: registered new interface driver cp210x [ 698.526767] usbserial: USB Serial support registered for cp210x [ 698.527863] cp210x 3-14:1.0: cp210x converter detected [ 698.529263] usb 3-14: cp210x converter now attached to ttyUSB0
The related AX1600i (1b1c:1c11, iProduct "USB API") is expected to be the same kind of device but has not been tested here, so it is not added.
--- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/cp210x.c +1 -0
@@ -223,6 +223,7 @@ static const struct usb_device_id id_tab { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1B1C, 0x1C02) }, /* Corsair AX1500i Power Supply */ { USB_DEVICE(0x1B93, 0x1013) }, /* Phoenix Contact UPS Device */ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
Greg Kroah-Hartman
maintainerPATCH 320/1887 USB: serial: quatech2: fix baud rate overflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit ec06546b43b612cefc851558981b4955c0ef9e46 upstream.
The requested baud rate is incorrectly truncated to 16 bits so that line speeds above 65535 bps cannot be set.
Use 32 bits for the rate while rejecting rates outside of [50,921600] to avoid having the 16-bit divisor overflow.
--- drivers/usb/serial/quatech2.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/usb/serial/quatech2.c +16 -3
@@ -54,6 +54,7 @@#define QT2_XMIT_FLUSH 0x05/* no following info */ #define QT2_CONTROL_ESCAPE 0xff/* pass through previous 2 control bytes */ +#define MIN_BAUD_RATE 50#define MAX_BAUD_RATE 921600#define DEFAULT_BAUD_RATE 9600
@@ -158,7 +159,7 @@ static inline int calc_baud_divisor(intstatic inline int qt2_set_port_config (struct usb_device *dev,unsigned char port_number, -u16 baudrate,u16 lcr) +speed_t baudrate,u16 lcr) {int divisor =calc_baud_divisor (baudrate);u16 index = ((u16) (lcr <<8 ) | (u16) (port_number));
@@ -267,9 +268,9 @@ static void qt2_set_termios(struct tty_sstruct usb_device *dev = port->serial->dev;struct qt2_port_private *port_priv;struct ktermios *termios = &tty->termios; -u16 baud;unsigned int cflag = termios->c_cflag;u16 new_lcr =0 ; +speed_t baud;int status; port_priv =usb_get_serial_port_data (port);
@@ -287,6 +288,18 @@ static void qt2_set_termios(struct tty_sif (!baud) baud =9600 ; +if (baud <MIN_BAUD_RATE || baud >MAX_BAUD_RATE ) { +if (old_termios) + baud =tty_termios_baud_rate (old_termios); +else + baud =clamp (baud,MIN_BAUD_RATE ,MAX_BAUD_RATE ); + +tty_encode_baud_rate (tty, baud, baud); + +if (!baud) + baud =9600 ; + } + status =qt2_set_port_config (dev, port_priv->device_port, baud, new_lcr);if (status <0 )
@@ -383,7 +396,7 @@ static int qt2_open(struct tty_struct *t port_priv->device_port = (u8 ) device_port;if (tty) -qt2_set_termios (tty, port, &tty->termios); +qt2_set_termios (tty, port,NULL );return 0 ;
Greg Kroah-Hartman
maintainerPATCH 321/1887 USB: serial: ssu100: fix baud rate overflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit afc235a217360c6859068d2e37a4df305c4d1be2 upstream.
The requested baud rate is incorrectly truncated to 16 bits so that line speeds above 65535 bps cannot be set.
Use 32 bits for the rate and remainder while rejecting rates outside of [50,460800] to avoid having the divisor or remainder overflow.
This issue was flagged by an LLM.
--- drivers/usb/serial/ssu100.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/usb/serial/ssu100.c +16 -2
@@ -34,6 +34,7 @@#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) +#define MIN_BAUD_RATE 50#define MAX_BAUD_RATE 460800#define ATC_DISABLED 0x00
@@ -219,9 +220,10 @@ static void ssu100_set_termios(struct tt {struct usb_device *dev = port->serial->dev;struct ktermios *termios = &tty->termios; -u16 baud, divisor, remainder; +speed_t baud, remainder;unsigned int cflag = termios->c_cflag;u16 urb_value =0 ;/* will hold the new flags */ +u16 divisor;int result;if (cflag &PARENB ) {
@@ -237,6 +239,18 @@ static void ssu100_set_termios(struct ttif (!baud) baud =9600 ; +if (baud <MIN_BAUD_RATE || baud >MAX_BAUD_RATE ) { +if (old_termios) + baud =tty_termios_baud_rate (old_termios); +else + baud =clamp (baud,MIN_BAUD_RATE ,MAX_BAUD_RATE ); + +tty_encode_baud_rate (tty, baud, baud); + +if (!baud) + baud =9600 ; + } +dev_dbg (&port->dev,"%s - got baud = %d\n" , __func__, baud);
@@ -312,7 +326,7 @@ static int ssu100_open(struct tty_structdev_dbg (&port->dev,"%s - set uart failed\n" , __func__);if (tty) -ssu100_set_termios (tty, port, &tty->termios); +ssu100_set_termios (tty, port,NULL );return usb_serial_generic_open (tty, port); }
Greg Kroah-Hartman
maintainerPATCH 322/1887 USB: serial: fix dynamic id driver deregistration race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 63594e8ffe097bc0b7639936f33799a7653dded2 upstream.
Only free the dynamic ids after having deregistered the driver and removed the "new_id" attribute to avoid leaking any id added by a racing write to the attribute.
--- drivers/usb/serial/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/serial/bus.c +1 -1
@@ -165,7 +165,7 @@ int usb_serial_bus_register(struct usb_svoid usb_serial_bus_deregister (struct usb_serial_driver *driver) { -free_dynids (driver);driver_unregister (&driver->driver); +free_dynids (driver); }
Greg Kroah-Hartman
maintainerPATCH 323/1887 USB: serial: fix driver deregistration order
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 646e5b28b4fdbc1b828a2398d6ced2c1dd308a46 upstream.
USB serial driver modules register one driver for the USB bus and one or more drivers for the ports on the USB serial bus.
When unloading a driver module, the USB driver must be deregistered before the USB serial bus drivers so that I/O is stopped before unbinding the ports to avoid use-after-free in completion handlers accessing port data.
Note that the "new_id" attributes must first be removed to prevent new ids from being added and triggering a probe of the USB driver after it has been deregistered.
--- drivers/usb/serial/bus.c | 4 ++++ drivers/usb/serial/usb-serial.c | 21 ++++++++++++++++++--- include/linux/usb/serial.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-)
drivers/usb/serial/bus.c +4 -0
@@ -169,3 +169,7 @@ void usb_serial_bus_deregister(struct usfree_dynids (driver); } +void usb_serial_bus_remove_new_id (struct usb_serial_driver *driver) +{ +driver_remove_file (&driver->driver, &driver_attr_new_id); +}
drivers/usb/serial/usb-serial.c +18 -3
@@ -1471,7 +1471,7 @@ int usb_serial_register_drivers(struct u {int rc;struct usb_driver *udriver; -struct usb_serial_driver *const *sd; +struct usb_serial_driver *const *sd, *const *s;/* * udriver must be registered before any of the serial drivers,
@@ -1523,9 +1523,11 @@ int usb_serial_register_drivers(struct ureturn 0 ; err_deregister_drivers: +for (s = serial_drivers; s < sd; ++s) +usb_serial_bus_remove_new_id (*s); +usb_deregister (udriver);while (sd-- > serial_drivers)usb_serial_deregister (*sd); -usb_deregister (udriver); err_free_driver:kfree (udriver);return rc;
@@ -1543,10 +1545,23 @@ EXPORT_SYMBOL_GPL(usb_serial_register_drvoid usb_serial_deregister_drivers (struct usb_serial_driver *const serial_drivers[]) {struct usb_driver *udriver = (*serial_drivers)->usb_driver; +struct usb_serial_driver *const *sd; + +/* +* udriver must be deregistered before the serial drivers so that +* I/O is stopped before unbinding the ports. +* +* Remove the new_id attributes to prevent ids from being added and +* triggering a probe of udriver after it has been deregistered. +*/ +for (sd = serial_drivers; *sd; ++sd) +usb_serial_bus_remove_new_id (*sd); + +usb_deregister (udriver);for (; *serial_drivers; ++serial_drivers)usb_serial_deregister (*serial_drivers); -usb_deregister (udriver); +kfree (udriver); }EXPORT_SYMBOL_GPL (usb_serial_deregister_drivers);
include/linux/usb/serial.h +1 -0
@@ -377,6 +377,7 @@ void usb_serial_handle_dcd_change(structint usb_serial_bus_register (struct usb_serial_driver *device);void usb_serial_bus_deregister (struct usb_serial_driver *device); +void usb_serial_bus_remove_new_id (struct usb_serial_driver *driver);extern struct bus_type usb_serial_bus_type;extern struct tty_driver *usb_serial_tty_driver;
Greg Kroah-Hartman
maintainerPATCH 324/1887 USB: serial: option: add support for SIMCom SIM8260C
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Dongdong <[email protected]>
commit 35c950c9ec2c4c4d45dc9b63cfe8fca774ce33a0 upstream.
Add support for SIMCom SIM8260C (1e0e:902b).
T: Bus=08 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=5000 MxCh= 0 D: Ver= 3.20 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1 P: Vendor=1e0e ProdID=902b Rev= 5.04 S: Manufacturer=SIMCOM S: Product=SDXLEMUR-LITE-MTP _SN:120696AB S: SerialNumber=0123456789ABCDEF C:* #Ifs= 8 Cfg#= 1 Atr=a0 MxPwr=896mA A: FirstIf#= 5 IfCount= 3 Cls=01(audio) Sub=00 Prot=20 I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=82(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=84(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan_simcom E: Ad=88(I) Atr=03(Int.) MxPS= 8 Ivl=32ms E: Ad=8e(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=0f(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 5 Alt= 0 #EPs= 0 Cls=01(audio) Sub=01 Prot=20 Driver=snd-usb-audio I:* If#= 6 Alt= 0 #EPs= 0 Cls=01(audio) Sub=02 Prot=20 Driver=snd-usb-audio I: If#= 6 Alt= 1 #EPs= 1 Cls=01(audio) Sub=02 Prot=20 Driver=snd-usb-audio E: Ad=05(O) Atr=0d(Isoc) MxPS= 34 Ivl=1ms I:* If#= 7 Alt= 0 #EPs= 0 Cls=01(audio) Sub=02 Prot=20 Driver=(none) I: If#= 7 Alt= 1 #EPs= 1 Cls=01(audio) Sub=02 Prot=20 Driver=(none) E: Ad=89(I) Atr=0d(Isoc) MxPS= 34 Ivl=1ms
--- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/serial/option.c +2 -0
@@ -2169,6 +2169,8 @@ static const struct usb_device_id option { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ .driver_info = RSVD(7) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x902b, 0xff), + .driver_info = RSVD(4) }, { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ .driver_info = RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */
Greg Kroah-Hartman
maintainerPATCH 325/1887 USB: serial: option: add Quectel EG060W
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlo Szelinsky <[email protected]>
commit cd243401994880b8b6810c53177bce56eebaece5 upstream.
Add Quectel EG060W with product ID 0x6004.
The three vendor-specific interfaces are DIAG, NMEA and AT; the CDC-NCM data interfaces are handled by the cdc_ncm driver.
T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2c7c ProdID=6004 Rev= 3.18 S: Manufacturer=Quectel S: Product=EG060W-EAAA S: SerialNumber=123456789ABCD C:* #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr= 2mA A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0d Prot=00 I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=82(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/serial/option.c +2 -0
@@ -281,6 +281,7 @@ static void option_instat_callback(struc#define QUECTEL_PRODUCT_EC200U 0x0901#define QUECTEL_PRODUCT_EG912Y 0x6001#define QUECTEL_PRODUCT_EC200S_CN 0x6002 +#define QUECTEL_PRODUCT_EG060W 0x6004#define QUECTEL_PRODUCT_EC200A 0x6005#define QUECTEL_PRODUCT_EG916Q 0x6007#define QUECTEL_PRODUCT_EM061K_LWW 0x6008
@@ -1269,6 +1270,7 @@ static const struct usb_device_id option { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200A, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG060W, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG912Y, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG916Q, 0xff, 0x00, 0x00) },
Greg Kroah-Hartman
maintainerPATCH 326/1887 USB: serial: option: add Compal EXM-G1x support
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Lin <[email protected]>
commit 7f11480cda081de78a05d8c97073df66326b50b3 upstream.
The Compal EXM-G1x is a Qualcomm SDX12-based LTE modem. Add support for its vendor-specific serial interfaces with protocols 0x30, 0x40, and 0x60.
Relevant output from usb-devices:
T: Bus=04 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=5000 MxCh= 0 D: Ver= 3.20 Cls=ef(misc ) Sub=02 Prot=01 MxPS= 9 #Cfgs= 1 P: Vendor=04b7 ProdID=8217 Rev=05.04 S: Manufacturer=COMPAL S: Product=EXM-G1x C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=896mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option I: If#= 4 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 8 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan
Tested on a Compal EXM-G1x modem.
--- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/option.c +3 -0
@@ -2434,6 +2434,9 @@ static const struct usb_device_id option .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ .driver_info = RSVD(3) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x30) }, /* Compal EXM-G1x */ + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x60) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */
Greg Kroah-Hartman
maintainerPATCH 327/1887 USB: serial: option: add Quectel RG660QB
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Sjoholm <[email protected]>
commit 6177bcd94be83f80a032c2e69a06606d325335b9 upstream.
Add support for the Quectel RG660QB 5G module (USB ID 2c7c:013d). The interface layout is the same as the RG650V:
If 0: DIAG ff/ff/30, 2 endpoints If 1: NMEA ff/00/00, 2 endpoints If 2: AT ff/00/00, 3 endpoints If 3: Modem ff/00/00, 3 endpoints If 4: QMI ff/ff/ff, 3 endpoints
Match the serial interfaces on class/subclass/protocol so that the QMI interface is left to qmi_wwan.
# lsusb -v -d 2c7c:013d
Bus 004 Device 002: ID 2c7c:013d Quectel Wireless Solutions Co., Ltd. RG660QB-EU Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 3.20
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 9
idVendor 0x2c7c Quectel Wireless Solutions Co., Ltd.
idProduct 0x013d
bcdDevice 6.06
iManufacturer 1 Quectel
iProduct 2 RG660QB-EU
iSerial 3 f50119d0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0105
bNumInterfaces 5
bConfigurationValue 1
iConfiguration 4 DIAG_SER_RMNET
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 896mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 48
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 6 CDEV Serial
** UNRECOGNIZED: 05 24 00 10 01
** UNRECOGNIZED: 05 24 01 00 00
** UNRECOGNIZED: 04 24 02 02
** UNRECOGNIZED: 05 24 06 00 00
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x000a 1x 10 bytes
bInterval 9
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 6 CDEV Serial
** UNRECOGNIZED: 05 24 00 10 01
** UNRECOGNIZED: 05 24 01 00 00
** UNRECOGNIZED: 04 24 02 02
** UNRECOGNIZED: 05 24 06 00 00
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x86 EP 6 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x000a 1x 10 bytes
bInterval 9
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x85 EP 5 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 4
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 7 RmNet
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x88 EP 8 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 9
bMaxBurst 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x87 EP 7 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 6
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x05 EP 5 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 0
bMaxBurst 2
Binary Object Store Descriptor:
bLength 5
bDescriptorType 15
wTotalLength 0x0023
bNumDeviceCaps 2
SuperSpeed USB Device Capability:
bLength 10
bDescriptorType 16
bDevCapabilityType 3
bmAttributes 0x00
wSpeedsSupported 0x000f
Device can operate at Low Speed (1Mbps)
Device can operate at Full Speed (12Mbps)
Device can operate at High Speed (480Mbps)
Device can operate at SuperSpeed (5Gbps)
bFunctionalitySupport 1
Lowest fully-functional device speed is Full Speed (12Mbps)
bU1DevExitLat 0 micro seconds
bU2DevExitLat 0 micro seconds
SuperSpeedPlus USB Device Capability:
bLength 20
bDescriptorType 16
bDevCapabilityType 10
bmAttributes 0x00000001
Sublink Speed Attribute count 1
Sublink Speed ID count 0
wFunctionalitySupport 0x1100
bmSublinkSpeedAttr[0] 0x000a4030
Speed Attribute ID: 0 10Gb/s Symmetric RX SuperSpeedPlus
bmSublinkSpeedAttr[1] 0x000a40b0
Speed Attribute ID: 0 10Gb/s Symmetric TX SuperSpeedPlus
Device Status: 0x0000
(Bus Powered)
Tested with an early sample of the module on a Quectel 5G EVB connected over USB 3 to a Raspberry Pi 5.
--- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/option.c +3 -0
@@ -261,6 +261,7 @@ static void option_instat_callback(struc#define QUECTEL_PRODUCT_EM060K_12a 0x012a#define QUECTEL_PRODUCT_EM060K_12b 0x012b#define QUECTEL_PRODUCT_EM060K_12c 0x012c +#define QUECTEL_PRODUCT_RG660QB 0x013d#define QUECTEL_PRODUCT_EG91 0x0191#define QUECTEL_PRODUCT_EG95 0x0195#define QUECTEL_PRODUCT_BG96 0x0296
@@ -1277,6 +1278,8 @@ static const struct usb_device_id option { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) },
Greg Kroah-Hartman
maintainerPATCH 328/1887 USB: serial: option: add Compal EXC-T1 support
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Lin <[email protected]>
commit b51faf3f2e307f114854bbe6d495f03cd5370686 upstream.
The Compal EXC-T1 is a Qualcomm MDM9207-based LTE modem which reports "EXC-x1" as its USB product string. It exposes diagnostic, modem, AT, and NMEA ports as vendor-specific interfaces with subclass 0x10 and protocols 0x01 through 0x04.
Add exact interface matches for these four ports, leaving the ff/ff/ff interface unbound.
Relevant output from usb-devices:
T: Bus=03 Lev=02 Prnt=03 Port=03 Cnt=01 Dev#= 6 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=04b7 ProdID=4d22 Rev=03.18 S: Manufacturer=CEI S: Product=EXC-x1 C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=10 Prot=01 Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=10 Prot=02 Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=10 Prot=03 Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=10 Prot=04 Driver=option I: If#= 4 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=10 Prot=05 Driver=qmi_wwan
Tested on a Compal EXC-T1 modem using an Ubuntu kernel build. The four serial interfaces bound to option and exposed ttyUSB3 through ttyUSB6.
--- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/serial/option.c +4 -0
@@ -2437,6 +2437,10 @@ static const struct usb_device_id option .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ .driver_info = RSVD(3) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x01) }, /* Compal EXC-T1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x02) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x03) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x04) }, { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x30) }, /* Compal EXM-G1x */ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x60) },
Greg Kroah-Hartman
maintainerPATCH 329/1887 thunderbolt: Fix KASAN reported use-after-free when request is canceled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
commit a02188ddc24b7872f0c5e0c5873f827318717803 upstream.
Alan reported that when doing stress testing sometimes KASAN notices use-after-free during control channel operation (stripped down keeping the relevant parts):
BUG: KASAN: slab-use-after-free in tb_cfg_request_sync+0x240/0x250 [thunderbolt] Read of size 24 at addr ffff88811067f290 by task kworker/u40:2/1760 <TASK> tb_cfg_request_sync+0x240/0x250 [thunderbolt] tb_cfg_read_raw+0x367/0x510 [thunderbolt] tb_cfg_read+0xec/0x240 [thunderbolt] tb_port_get_link_generation+0x258/0x420 [thunderbolt] tb_usb3_consumed_bandwidth+0x1c1/0x2c0 [thunderbolt] tb_tunnel_consumed_bandwidth+0xfd/0x910 [thunderbolt] tb_available_bandwidth+0x5f2/0xeb0 [thunderbolt] tb_recalc_estimated_bandwidth+0x2a0/0x1bc0 [thunderbolt] tb_handle_dp_bandwidth_request+0x1897/0x5e20 [thunderbolt] process_one_work+0x675/0x1230 worker_thread+0x5e6/0xf70 kthread+0x365/0x470 ret_from_fork+0x54d/0x710 ret_from_fork_asm+0x1a/0x30 </TASK> Allocated by task 1760: __kmalloc_cache_noprof+0x1ee/0x550 tb_cfg_read_raw+0x1d3/0x510 [thunderbolt] tb_cfg_read+0xec/0x240 [thunderbolt] tb_port_get_link_generation+0x258/0x420 [thunderbolt] tb_usb3_consumed_bandwidth+0x1c1/0x2c0 [thunderbolt] tb_tunnel_consumed_bandwidth+0xfd/0x910 [thunderbolt] tb_available_bandwidth+0x5f2/0xeb0 [thunderbolt] tb_recalc_estimated_bandwidth+0x2a0/0x1bc0 [thunderbolt] tb_handle_dp_bandwidth_request+0x1897/0x5e20 [thunderbolt] process_one_work+0x675/0x1230 worker_thread+0x5e6/0xf70 kthread+0x365/0x470 ret_from_fork+0x54d/0x710 ret_from_fork_asm+0x1a/0x30 Freed by task 926: kfree+0x18f/0x4a0 tb_cfg_request_put+0xb7/0xe0 [thunderbolt] tb_cfg_request_work+0x82/0x120 [thunderbolt] process_one_work+0x675/0x1230 worker_thread+0x5e6/0xf70 kthread+0x365/0x470 ret_from_fork+0x54d/0x710 ret_from_fork_asm+0x1a/0x30 Second to last potentially related work creation: __queue_work+0x575/0xd00 queue_work_on+0x77/0x80 tb_cfg_request_cancel+0xc7/0x260 [thunderbolt] tb_cfg_request_sync+0x1f6/0x250 [thunderbolt] tb_cfg_read_raw+0x367/0x510 [thunderbolt] tb_cfg_read+0xec/0x240 [thunderbolt] tb_port_get_link_generation+0x258/0x420 [thunderbolt] tb_usb3_consumed_bandwidth+0x1c1/0x2c0 [thunderbolt] tb_tunnel_consumed_bandwidth+0xfd/0x910 [thunderbolt] tb_available_bandwidth+0x5f2/0xeb0 [thunderbolt] tb_recalc_estimated_bandwidth+0x2a0/0x1bc0 [thunderbolt] tb_handle_dp_bandwidth_request+0x1897/0x5e20 [thunderbolt] process_one_work+0x675/0x1230 worker_thread+0x5e6/0xf70 kthread+0x365/0x470 ret_from_fork+0x54d/0x710 ret_from_fork_asm+0x1a/0x30
The last stack trace is helpful because it shows that we are cancelling a request and looking at tb_cfg_request_cancel() what might happen is that tb_cfg_request_work() completes right before tb_cfg_request_cancel() starts and because of this it will call schedule_work() queueing the same work to run again. However, it is already removed from the request_queue and reference count is dropped so when tb_cfg_request_work() triggers again it will access memory that is already released.
Fix this so that we first make sure a cancelled request is not handed away from tb_cfg_request_find() or scheduled to run. Then instead of relying on the worker to clean up the request we will do it in tb_cfg_request_cancel() after the work is canceled from running. Make tb_cfg_request_dequeue() release the request only if it was actually removed from the queue.
--- drivers/thunderbolt/ctl.c | 63 ++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 32 deletions(-)
drivers/thunderbolt/ctl.c +31 -32
@@ -65,7 +65,6 @@ struct tb_ctl { #define tb_ctl_dbg(ctl, format, arg...) \ dev_dbg(&(ctl)->nhi->pdev->dev, format, ## arg) -static DECLARE_WAIT_QUEUE_HEAD (tb_cfg_request_cancel_queue);/* Serializes access to request kref_get/put */ static DEFINE_MUTEX (tb_cfg_request_lock);
@@ -123,41 +122,42 @@ void tb_cfg_request_put(struct tb_cfg_restatic int tb_cfg_request_enqueue (struct tb_ctl *ctl,struct tb_cfg_request *req) { +tb_cfg_request_get (req); +WARN_ON (test_bit (TB_CFG_REQUEST_ACTIVE , &req->flags));WARN_ON (req->ctl); -mutex_lock (&ctl->request_queue_lock); +guard (mutex)(&ctl->request_queue_lock);if (!ctl->running) { -mutex_unlock (&ctl->request_queue_lock); +tb_cfg_request_put (req);return -ENOTCONN ; } req->ctl = ctl;list_add_tail (&req->list, &ctl->request_queue);set_bit (TB_CFG_REQUEST_ACTIVE , &req->flags); -mutex_unlock (&ctl->request_queue_lock);return 0 ; } -static void tb_cfg_request_dequeue (struct tb_cfg_request *req) +static bool tb_cfg_request_is_active (struct tb_cfg_request *req) { -struct tb_ctl *ctl = req->ctl; - -mutex_lock (&ctl->request_queue_lock); -if (!test_bit (TB_CFG_REQUEST_ACTIVE , &req->flags)) { -mutex_unlock (&ctl->request_queue_lock); -return ; - } +return test_bit (TB_CFG_REQUEST_ACTIVE , &req->flags); +} -list_del (&req->list); -clear_bit (TB_CFG_REQUEST_ACTIVE , &req->flags); -if (test_bit (TB_CFG_REQUEST_CANCELED , &req->flags)) -wake_up (&tb_cfg_request_cancel_queue); -mutex_unlock (&ctl->request_queue_lock); +static bool tb_cfg_request_is_canceled (struct tb_cfg_request *req) +{ +return test_bit (TB_CFG_REQUEST_CANCELED , &req->flags); } -static bool tb_cfg_request_is_active (struct tb_cfg_request *req) +static void tb_cfg_request_dequeue (struct tb_cfg_request *req) { -return test_bit (TB_CFG_REQUEST_ACTIVE , &req->flags); +struct tb_ctl *ctl = req->ctl; + +guard (mutex)(&ctl->request_queue_lock); +if (tb_cfg_request_is_active (req)) { +list_del (&req->list); +clear_bit (TB_CFG_REQUEST_ACTIVE , &req->flags); +tb_cfg_request_put (req); + } } static struct tb_cfg_request *
@@ -168,7 +168,7 @@ tb_cfg_request_find(struct tb_ctl *ctl,mutex_lock (&pkg->ctl->request_queue_lock);list_for_each_entry (iter, &pkg->ctl->request_queue, list) {tb_cfg_request_get (iter); -if (iter->match (iter, pkg)) { +if (!tb_cfg_request_is_canceled (iter) && iter->match (iter, pkg)) { req = iter;break ; }
@@ -495,8 +495,11 @@ static void tb_ctl_rx_callback(struct tb*/ req =tb_cfg_request_find (pkg->ctl, pkg);if (req) { -if (req->copy (req, pkg)) -schedule_work (&req->work); + scoped_guard(mutex, &pkg->ctl->request_queue_lock) { +if (!tb_cfg_request_is_canceled (req) && + req->copy (req, pkg)) +schedule_work (&req->work); + }tb_cfg_request_put (req); }
@@ -508,11 +511,10 @@ static void tb_cfg_request_work(struct w {struct tb_cfg_request *req =container_of (work,typeof (*req), work); -if (!test_bit (TB_CFG_REQUEST_CANCELED , &req->flags)) +if (!tb_cfg_request_is_canceled (req)) req->callback (req->callback_data);tb_cfg_request_dequeue (req); -tb_cfg_request_put (req); }/**
@@ -536,10 +538,9 @@ int tb_cfg_request(struct tb_ctl *ctl, sINIT_WORK (&req->work, tb_cfg_request_work);INIT_LIST_HEAD (&req->list); -tb_cfg_request_get (req); ret =tb_cfg_request_enqueue (ctl, req);if (ret) - goto err_put; +return ret; ret =tb_ctl_tx (ctl, req->request, req->request_size, req->request_type);
@@ -553,9 +554,6 @@ int tb_cfg_request(struct tb_ctl *ctl, s err_dequeue:tb_cfg_request_dequeue (req); -err_put: -tb_cfg_request_put (req); -return ret; }
@@ -569,9 +567,10 @@ err_put:*/ void tb_cfg_request_cancel (struct tb_cfg_request *req,int err) { -set_bit (TB_CFG_REQUEST_CANCELED , &req->flags); -schedule_work (&req->work); -wait_event (tb_cfg_request_cancel_queue, !tb_cfg_request_is_active (req)); + scoped_guard(mutex, &req->ctl->request_queue_lock) +set_bit (TB_CFG_REQUEST_CANCELED , &req->flags); +cancel_work_sync (&req->work); +tb_cfg_request_dequeue (req); req->result.err = err; }
Greg Kroah-Hartman
maintainerPATCH 330/1887 thunderbolt: Disable CL states for the Anker Prime TB5 dock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kurt Lieber <[email protected]>
commit 395e9f2967a7ac6898026e8f136c369805dc2fd9 upstream.
The Anker Prime TB5 dock identifies itself in the DROM as 01ea:83b5. Its router config space is an Intel Barlow Ridge 80G hub (8087:5786). The upstream lane adapter advertises CL0s, CL1, and CL2. With CLx left enabled, TMU uni-directional LowRes setup fails with -ENOTCONN, the USB3 and DisplayPort tunnels are aborted, and the router reconnects in a loop. Loading thunderbolt with clx=0 keeps the link up on this machine.
Match the DROM id together with the Barlow Ridge hub id and disable CL states for this dock only. QUIRK_NO_CLX takes the same early-out as the module parameter, without disabling CLx for every other router.
--- drivers/thunderbolt/quirks.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/thunderbolt/quirks.c +3 -0
@@ -92,6 +92,9 @@ static const struct tb_quirk tb_quirks[] quirk_usb3_maximum_bandwidth }, {0x8087 ,PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_40G_BRIDGE ,0x0000 ,0x0000 , quirk_usb3_maximum_bandwidth }, +/* CLx is unstable on the Anker Prime TB5 dock (DROM 01ea:83b5) */ + { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_80G_BRIDGE, 0x01ea, 0x83b5, + quirk_clx_disable },/* * Block Runtime PM in DP redrive mode for Intel Barlow Ridge host * controllers.
Greg Kroah-Hartman
maintainerPATCH 331/1887 thunderbolt: Reject oversized XDomain properties responses
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 80756e263846ab694984e749e8c626897331438f upstream.
tb_xdp_properties_request() allocates room for 45 data dwords in its 252-byte response buffer. The XDomain length field is six bits wide, however, and a malicious peer can set it to 63. After the fixed response fields are subtracted, the driver treats this as 48 data dwords.
Commit 322e93448d90 ("thunderbolt: Clamp XDomain response data copy to allocation size") only bounds the copy against data_len. If data_len is at least 48, memcpy() reads 192 bytes from the 180-byte res->data array, causing a 12-byte heap out-of-bounds read. Commit 4db2bd2ed478 ("thunderbolt: Limit XDomain response copy to actual frame size") limits the earlier copy but does not constrain this header-derived length.
Reject response data lengths that exceed the allocated source buffer before copying them into the assembled property block.
--- drivers/thunderbolt/xdomain.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/thunderbolt/xdomain.c +4 -0
@@ -377,6 +377,10 @@ static int tb_xdp_properties_request(str len +=sizeof (res->hdr.xd_hdr) /4 ; len -=sizeof (*res) /4 ; +if (len >TB_XDP_PROPERTIES_MAX_DATA_LENGTH ) { + ret = -EINVAL ; + goto err; + }if (res->offset != req.offset) { ret = -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 332/1887 iio: accel: kxcjk-1013: reject duplicate event disable
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiale Yao <[email protected]>
commit dd30c10ff60d2b30386c23bb7c61cc97f2385c97 upstream.
The IIO core does not filter duplicate writes to the event enable attribute. kxcjk1013_write_event_config() already ignores repeated enable requests, but a repeated disable request still calls kxcjk1013_set_power_state(data, false), dropping a runtime PM reference that was not acquired for this request. This can underflow the runtime PM usage count and trigger a "Runtime PM usage count underflow" warning.
Return early when the requested state already matches ev_enable_state.
--- drivers/iio/accel/kxcjk-1013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/accel/kxcjk-1013.c +1 -1
@@ -1051,7 +1051,7 @@ static int kxcjk1013_write_event_config(struct kxcjk1013_data *data =iio_priv (indio_dev);int ret; -if (state && data->ev_enable_state) +if (state == data->ev_enable_state)return 0 ;mutex_lock (&data->mutex);
Greg Kroah-Hartman
maintainerPATCH 333/1887 iio: accel: sca3000: fix frequency divider condition check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salah Triki <[email protected]>
commit d380bf5f94a892e546d9a94e8557ad866b043a2a upstream.
When setting the sampling frequency, the check for base_freq / 2 is followed by an independent if statement for base_freq / 4. If val equals base_freq / 2, the second check fails and falls through to the else if (val != base_freq) branch, returning -EINVAL erroneously.
Fix this by chaining the checks with else if.
--- drivers/iio/accel/sca3000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/accel/sca3000.c +1 -1
@@ -652,7 +652,7 @@ static int sca3000_write_raw_samp_freq(sif (val == base_freq /2 ) ctrlval |=SCA3000_REG_OUT_CTRL_BUF_DIV_2 ; -if (val == base_freq /4 ) +else if (val == base_freq /4 ) ctrlval |=SCA3000_REG_OUT_CTRL_BUF_DIV_4 ;else if (val != base_freq)return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 334/1887 iio: adc: sun4i-gpadc-iio: clean up on thermal zone registration failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit 2cdc7ef31827db4fbc6283750420639569e1f0e9 upstream.
If devm_thermal_of_zone_register() fails, probe returns without unregistering the IIO map array or disabling runtime PM.
Jump to err_map to release them.
--- drivers/iio/adc/sun4i-gpadc-iio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/iio/adc/sun4i-gpadc-iio.c +4 -4
@@ -645,10 +645,10 @@ static int sun4i_gpadc_probe(struct plat* thermal because no thermal DT node is found. */ if (IS_ERR (info->tzd) &&PTR_ERR (info->tzd) != -ENODEV ) { -dev_err (&pdev->dev, -"could not register thermal sensor: %ld\n" , -PTR_ERR (info->tzd)); -return PTR_ERR (info->tzd); + ret =dev_err_probe (&pdev->dev, +PTR_ERR (info->tzd), +"could not register thermal sensor\n" ); + goto err_map; } }
Greg Kroah-Hartman
maintainerPATCH 335/1887 iio: adc: sun4i-gpadc-iio: drop underflowing pm_runtime_put() calls
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit 8b958dd214ad0c003f56549e9e039cb8067dc1a2 upstream.
Neither the error path in sun4i_gpadc_probe() nor sun4i_gpadc_remove() ever holds a runtime PM usage count. So the pm_runtime_put() in both places always triggers the "Runtime PM usage count underflow!" warning on every failed probe and every unbind.
Drop both calls.
--- drivers/iio/adc/sun4i-gpadc-iio.c | 2 -- 1 file changed, 2 deletions(-)
drivers/iio/adc/sun4i-gpadc-iio.c +0 -2
@@ -664,7 +664,6 @@ err_map:if (!info->no_irq &&IS_ENABLED (CONFIG_THERMAL_OF ))iio_map_array_unregister (indio_dev); -pm_runtime_put (&pdev->dev);pm_runtime_disable (&pdev->dev);return ret;
@@ -675,7 +674,6 @@ static int sun4i_gpadc_remove(struct plastruct iio_dev *indio_dev =platform_get_drvdata (pdev);struct sun4i_gpadc_iio *info =iio_priv (indio_dev); -pm_runtime_put (&pdev->dev);pm_runtime_disable (&pdev->dev);if (!IS_ENABLED (CONFIG_THERMAL_OF ))
Greg Kroah-Hartman
maintainerPATCH 336/1887 iio: adc: xilinx-xadc: free IRQ before cancelling the unmask worker on unbind
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 0f3f427076240e75ff265e61645627a71ca4918c upstream.
The ZYNQ XADC alarm IRQ handler queues zynq_unmask_work via schedule_delayed_work(); that work is cleared by a devm callback. Register the devm callback before devm_request_irq() so the devres LIFO teardown frees the IRQ first, ensuring the handler can no longer queue work by the time the workqueue is cleared. Otherwise the handler could re-arm the work and run it after the xadc structure has been freed.
This issue was found by an in-house static analysis tool.
--- drivers/iio/adc/xilinx-xadc-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/iio/adc/xilinx-xadc-core.c +5 -4
@@ -1406,13 +1406,14 @@ static int xadc_probe(struct platform_de }if (irq >0 ) { - ret =devm_request_irq (dev, irq, xadc->ops->interrupt_handler, -0 ,dev_name (dev), indio_dev); +/* Clear out any work queued by the interrupt */ + ret =devm_add_action_or_reset (dev, xadc_cancel_delayed_work, + &xadc->zynq_unmask_work);if (ret)return ret; - ret =devm_add_action_or_reset (dev, xadc_cancel_delayed_work, - &xadc->zynq_unmask_work); + ret =devm_request_irq (dev, irq, xadc->ops->interrupt_handler, +0 ,dev_name (dev), indio_dev);if (ret)return ret; }
Greg Kroah-Hartman
maintainerPATCH 337/1887 iio: buffer: Ensure bounce buffer used for unaligned case is zeroed.
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonathan Cameron <[email protected]>
commit 5330036bc68d23672bfcc16c60c54701ae123083 upstream.
iio_push_to_buffers_with_ts_unaligned() leaks uninitialized heap memory to userspace if the data passed in is not a multiple of 8 bytes and the timestamp is enabled. Specify __GFP_ZERO for the devm_krealloc() to ensure any extra space is cleared.
--- drivers/iio/industrialio-buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iio/industrialio-buffer.c +2 -1
@@ -1905,7 +1905,8 @@ int iio_push_to_buffers_with_ts_unaligne bb =devm_krealloc (&indio_dev->dev, iio_dev_opaque->bounce_buffer, - indio_dev->scan_bytes,GFP_KERNEL ); + indio_dev->scan_bytes, +GFP_KERNEL | __GFP_ZERO);if (!bb)return -ENOMEM ; iio_dev_opaque->bounce_buffer = bb;
Greg Kroah-Hartman
maintainerPATCH 338/1887 iio: frequency: admv1013: fix wrong channel field used in admv1013_read_raw()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salah Triki <[email protected]>
commit 2093236e886ad9446ec3285ba520e024dd1464e1 upstream.
admv1013_read_raw() switches on chan->channel instead of chan->channel2 when handling IIO_CHAN_INFO_CALIBBIAS. The channel field only ever holds 0 or 1 (see ADMV1013_CHAN_CALIB()), while the IIO_MOD_I / IIO_MOD_Q modifiers are stored in channel2. As a result, the switch always falls through to the default case and calibbias reads always fail with -EINVAL, even though the corresponding admv1013_write_raw() path correctly uses channel2 and works as expected.
Fix the read path to switch on chan->channel2, matching the write path and the actual channel_spec definition.
--- drivers/iio/frequency/admv1013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/frequency/admv1013.c +1 -1
@@ -197,7 +197,7 @@ static int admv1013_read_raw(struct iio_switch (info) {case IIO_CHAN_INFO_CALIBBIAS : -switch (chan->channel) { +switch (chan->channel2) {case IIO_MOD_I : addr =ADMV1013_REG_OFFSET_ADJUST_I ;break ;
Greg Kroah-Hartman
maintainerPATCH 339/1887 iio: gyro: adis16136: fix unprotected debugfs reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arka Mondal <[email protected]>
commit 2b498df75d6c29aa3e760127ae0f0003df598b53 upstream.
The serial_number file operations are open coded and never call debugfs_file_get(), which debugfs_create_file_unsafe() requires. debugfs_remove_recursive() therefore does not wait for a read in progress, and unbind frees the iio_dev underneath it.
Use debugfs_create_file() instead.
--- drivers/iio/gyro/adis16136.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/gyro/adis16136.c +1 -1
@@ -145,7 +145,7 @@ static int adis16136_debugfs_init(structstruct adis16136 *adis16136 =iio_priv (indio_dev);struct dentry *d =iio_get_debugfs_dentry (indio_dev); -debugfs_create_file_unsafe ("serial_number" ,0400 , +debugfs_create_file ("serial_number" ,0400 , d, adis16136, &adis16136_serial_fops);debugfs_create_file_unsafe ("product_id" ,0400 , d, adis16136, &adis16136_product_id_fops);
Greg Kroah-Hartman
maintainerPATCH 340/1887 iio: imu: adis16400: fix unprotected debugfs reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arka Mondal <[email protected]>
commit d94787287a113a1326211647d5e0deed1e9de105 upstream.
adis16400_serial_number_fops is open coded and never calls debugfs_file_get(), so debugfs_remove_recursive() does not wait for a read in progress and unbind frees the iio_dev underneath it.
Commit ae1d37a9bb4b ("iio: imu: adis16400: use DEFINE_DEBUGFS_ATTRIBUTE instead of DEFINE_SIMPLE_ATTRIBUTE") converted product_id and flash_count to DEFINE_DEBUGFS_ATTRIBUTE, which protects itself, but moved all three files to debugfs_create_file_unsafe().
serial_number prints three registers as "%.4x-%.4x-%.4x" and DEFINE_DEBUGFS_ATTRIBUTE() formats a single u64, so it cannot be converted without changing what the file returns. adis16475 and adis16550 already use debugfs_create_file() for their open coded files. Use it here too.
--- drivers/iio/imu/adis16400.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/imu/adis16400.c +1 -1
@@ -279,7 +279,7 @@ static int adis16400_debugfs_init(structstruct dentry *d =iio_get_debugfs_dentry (indio_dev);if (st->variant->flags &ADIS16400_HAS_SERIAL_NUMBER ) -debugfs_create_file_unsafe ("serial_number" ,0400 , +debugfs_create_file ("serial_number" ,0400 , d, st, &adis16400_serial_number_fops);if (st->variant->flags &ADIS16400_HAS_PROD_ID ) debugfs_create_file_unsafe("product_id", 0400,
Greg Kroah-Hartman
maintainerPATCH 341/1887 iio: imu: adis16480: fix unprotected debugfs reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arka Mondal <[email protected]>
commit e1dea54496f90a62318cf4eeaa1e9ef8316e92b6 upstream.
The firmware_revision and firmware_date file operations are open coded and never call debugfs_file_get(), which debugfs_create_file_unsafe() requires. debugfs_remove_recursive() therefore does not wait for a read in progress, and unbind frees the iio_dev underneath it.
Use debugfs_create_file() instead.
--- drivers/iio/imu/adis16480.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iio/imu/adis16480.c +2 -2
@@ -302,9 +302,9 @@ static int adis16480_debugfs_init(structstruct adis16480 *adis16480 =iio_priv (indio_dev);struct dentry *d =iio_get_debugfs_dentry (indio_dev); -debugfs_create_file_unsafe ("firmware_revision" ,0400 , +debugfs_create_file ("firmware_revision" ,0400 , d, adis16480, &adis16480_firmware_revision_fops); -debugfs_create_file_unsafe ("firmware_date" ,0400 , +debugfs_create_file ("firmware_date" ,0400 , d, adis16480, &adis16480_firmware_date_fops);debugfs_create_file_unsafe ("serial_number" ,0400 , d, adis16480, &adis16480_serial_number_fops);
Greg Kroah-Hartman
maintainerPATCH 342/1887 iio: light: gp2ap020a00f: drain irq_work after free_irq
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 63213927b141085b6c8719b8037dab3074b7e0fe upstream.
The threaded IRQ handler queues data->work through irq_work_queue() so the trigger is polled from a per-CPU context. free_irq() does not flush an irq_work the handler already queued, so after gp2ap020a00f_remove() returns that work may still run and call iio_trigger_poll() on data->trig, which the devm cleanup has already freed, causing a use-after-free.
Add irq_work_sync(&data->work) after free_irq() in remove() and in the probe error path, mirroring commit 78601726d4a5 ("iio: trigger: sysfs:
fix use-after-free on remove").
Found by an in-house static analysis tool, confirmed by manual review.
--- drivers/iio/light/gp2ap020a00f.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/light/gp2ap020a00f.c +2 -0
@@ -1565,6 +1565,7 @@ error_trigger_unregister:iio_trigger_unregister (data->trig); error_free_irq:free_irq (client->irq, indio_dev); +irq_work_sync (&data->work); error_uninit_buffer:iio_triggered_buffer_cleanup (indio_dev); error_regulator_disable:
@@ -1587,6 +1588,7 @@ static void gp2ap020a00f_remove(struct iiio_device_unregister (indio_dev);iio_trigger_unregister (data->trig);free_irq (client->irq, indio_dev); +irq_work_sync (&data->work);iio_triggered_buffer_cleanup (indio_dev);regulator_disable (data->vled_reg); }
Greg Kroah-Hartman
maintainerPATCH 343/1887 iio: pressure: bmp280: fix out-of-bounds access in sampling frequency lookup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Su <[email protected]>
commit 56c423b233b214182c58c99861899327b45b0d6c upstream.
The sampling frequency tables store each frequency as an integer part and a fractional part in micro units. num_sampling_freq_avail is initialized to the number of flattened integer elements because read_avail() returns the table as a flat array.
bmp280_write_sampling_frequency(), however, indexes the same table as a two-dimensional array and uses num_sampling_freq_avail as the number of rows. Convert the flattened element count back to the number of rows before iterating over the table.
--- drivers/iio/pressure/bmp280-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/pressure/bmp280-core.c +1 -1
@@ -725,7 +725,7 @@ static int bmp280_write_sampling_frequen int val, int val2) {const int (*avail)[2 ] = data->chip_info->sampling_freq_avail; -const int n = data->chip_info->num_sampling_freq_avail; +const int n = data->chip_info->num_sampling_freq_avail /2 ;int ret, prev;int i;
Greg Kroah-Hartman
maintainerPATCH 344/1887 iio: proximity: isl29501: Fix return type of isl29501_register_write
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salah Triki <[email protected]>
commit e8dd273d199f5bbe295a8e3d8b777c5505b6b2e1 upstream.
isl29501_register_write() was returning a u32 instead of an int. Since the function returns negative error codes (such as -ERANGE or return values from i2c_smbus_write_byte_data()), returning an unsigned integer type prevents callers from correctly checking for negative error conditions.
Fix this by changing the function return type from u32 to int.
This was found through manual code review.
--- drivers/iio/proximity/isl29501.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/proximity/isl29501.c +1 -1
@@ -227,7 +227,7 @@ err:return ret; } -static u32 isl29501_register_write (struct isl29501_private *isl29501, +static int isl29501_register_write (struct isl29501_private *isl29501,enum isl29501_register_name name,u32 value) {
Greg Kroah-Hartman
maintainerPATCH 345/1887 iio: proximity: pulsedlight: fix iio_device left registered on PM setup failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit 4daa9ca557b4b98ae1ad38a6d1deaa3e31eb8edf upstream.
pm_runtime_set_active() failing in probe() jumps to error_unreg_buffer, which only calls iio_triggered_buffer_cleanup() -- it does not undo the iio_device_register() that already succeeded a few lines above. probe() then returns the error, the devm-managed indio_dev is freed, but the iio core still has it registered: the sysfs/chardev nodes stay live and point at freed memory.
Add an error_unreg_dev label that unregisters the iio device before falling through to the existing buffer cleanup, mirroring the teardown order already used in lidar_remove().
--- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +3 -1
@@ -299,12 +299,14 @@ static int lidar_probe(struct i2c_client ret =pm_runtime_set_active (&client->dev);if (ret) - goto error_unreg_buffer; + goto error_unreg_dev;pm_runtime_enable (&client->dev);pm_runtime_idle (&client->dev);return 0 ; +error_unreg_dev: +iio_device_unregister (indio_dev); error_unreg_buffer:iio_triggered_buffer_cleanup (indio_dev);
Greg Kroah-Hartman
maintainerPATCH 346/1887 iio: proximity: sx9324: Correct proximity channel resolution
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Jie <[email protected]>
commit fbf33cb18334e7cab1ed4ad2e9a98a1299ad874c upstream.
The proximity channels were previously defined with 12 realbits. However, PROXDIFF is read from RegDiffMsb (0x65) and RegDiffLsb (0x66). The SX9324 datasheet assigns bits 7:0 of each register to PROXDIFF and documents it as a signed two's-complement value (Revision 3, Section 8, Table 8, page 43). In contrast, RegOffsetMsb explicitly marks bits 7:6 as reserved. Thus, PROXDIFF is a 16-bit signed value.
With realbits = 12, sx_common_read_proximity() uses bit 11 as the sign bit in sign_extend32(), causing samples outside the 12-bit signed range to wrap into the [-2048, 2047] range.
Correct the realbits value to 16 to accurately reflect the hardware.
Tested on an SX9324-based device: a phase 0 DIFF readback of 0x7fff was reported as -1 before this change and as 32767 afterward.
--- drivers/iio/proximity/sx9324.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/proximity/sx9324.c +1 -1
@@ -223,7 +223,7 @@ static const struct iio_chan_spec_ext_in .scan_index = idx, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = 16, \ .storagebits = 16, \ .endianness = IIO_BE, \ }, \
Greg Kroah-Hartman
maintainerPATCH 347/1887 iio: proximity: vcnl3020: fix ISR bitmask check in IRQ handler
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salah Triki <[email protected]>
commit 7d38af8f20239a66e90de7632a79c9425256c574 upstream.
The threaded IRQ handler contained multiple issues in handling interrupt events and clearing status flags:
1. ISR bit check: The handler incorrectly checked the Interrupt Status Register (VCNL_ISR) against VCNL_ICR_THRES_EN (BIT(1)), which is a bitmask meant for the Control Register (VCNL_PS_ICR). In VCNL_ISR, BIT(1) corresponds only to low-threshold interrupts. A high-threshold interrupt (VCNL_INT_TH_HI, BIT(0)) on its own was completely ignored and returned IRQ_NONE.
2. Event direction & channel index: The handler unconditionally pushed a RISING event code on channel index 1. The driver only registers a single proximity channel (index 0), and low-threshold interrupts should be reported with IIO_EV_DIR_FALLING.
3. ISR clearing: The write-back to acknowledge the interrupt only preserved BIT(1) instead of masking against both valid status bits.
Fix this by checking both VCNL_INT_TH_HI and VCNL_INT_TH_LOW bits in VCNL_ISR, pushing separate IIO events with the correct direction and channel index (0), and properly clearing handled status bits.
--- drivers/iio/proximity/vcnl3020.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
drivers/iio/proximity/vcnl3020.c +17 -7
@@ -584,16 +584,26 @@ static irqreturn_t vcnl3020_handle_irq_treturn IRQ_HANDLED ; } -if (!(isr &VCNL_ICR_THRES_EN )) +if (!(isr & (VCNL_INT_TH_HI |VCNL_INT_TH_LOW )))return IRQ_NONE ; -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_PROXIMITY ,1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), -iio_get_time_ns (indio_dev)); +if (isr &VCNL_INT_TH_HI ) { +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_PROXIMITY ,0 , +IIO_EV_TYPE_THRESH , +IIO_EV_DIR_RISING ), +iio_get_time_ns (indio_dev)); + } + +if (isr &VCNL_INT_TH_LOW ) { +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_PROXIMITY ,0 , +IIO_EV_TYPE_THRESH , +IIO_EV_DIR_FALLING ), +iio_get_time_ns (indio_dev)); + } - rc =regmap_write (data->regmap,VCNL_ISR , isr &VCNL_ICR_THRES_EN ); + rc =regmap_write (data->regmap,VCNL_ISR , isr & (VCNL_INT_TH_HI |VCNL_INT_TH_LOW ));if (rc)dev_err (data->dev,"Error (%d) writing in reg (0x%x)\n" , rc,VCNL_ISR );
Greg Kroah-Hartman
maintainerPATCH 348/1887 iio: trigger: cancel reenable_work before freeing trigger
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 2a57b9246cecd5dd797a42eb310d6c8816f26d9e upstream.
iio_trigger_notify_done_atomic() defers ->reenable() into trig->reenable_work on the system workqueue, and the worker dereferences the owning trigger through container_of(). Nothing cancels this work before iio_trig_release() frees the trigger, so a worker armed by the last in-flight IRQ can outlive the free and touch freed memory.
Cancel it at the top of iio_trig_release(), which every free path reaches through the device core's final put_device().
Found by an in-house static analysis tool.
--- drivers/iio/industrialio-trigger.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/industrialio-trigger.c +2 -0
@@ -506,6 +506,8 @@ static void iio_trig_release(struct devistruct iio_trigger *trig =to_iio_trigger (device);int i; +cancel_work_sync (&trig->reenable_work); +if (trig->subirq_base) {for (i =0 ; i <CONFIG_IIO_CONSUMERS_PER_TRIGGER ; i++) { irq_modify_status(trig->subirq_base + i,
Greg Kroah-Hartman
maintainerPATCH 349/1887 jfs: fix array-index-out-of-bounds read in add_missing_indices
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Dutt <[email protected]>
[ Upstream commit 5dff41a86377563f7a2b968aae00d25b4ceb37c9 ]
stbl is s8 but it must contain offsets into slot which can go from 0 to 127.
Added a bound check for that error and return -EIO if the check fails. Also make jfs_readdir return with error if add_missing_indices returns with an error.
--- fs/jfs/jfs_dtree.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
fs/jfs/jfs_dtree.c +15 -3
@@ -2613,7 +2613,7 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)* fsck.jfs should really fix this, but it currently does not. * Called from jfs_readdir when bad index is detected. */ -static void add_missing_indices (struct inode *inode,s64 bn) +static int add_missing_indices (struct inode *inode,s64 bn) {struct ldtentry *d;struct dt_lock *dtlck;
@@ -2622,7 +2622,7 @@ static void add_missing_indices(struct inode *inode, s64 bn)struct lv *lv;struct metapage *mp;dtpage_t *p; -int rc; +int rc =0 ;s8 *stbl;tid_t tid;struct tlock *tlck;
@@ -2647,6 +2647,16 @@ static void add_missing_indices(struct inode *inode, s64 bn) stbl =DT_GETSTBL (p);for (i =0 ; i < p->header.nextindex; i++) { +if (stbl[i] <0 ) { +jfs_err ("jfs: add_missing_indices: Invalid stbl[%d] = %d for inode %ld, block = %lld" , + i, stbl[i], (long )inode->i_ino, (long long )bn); + rc = -EIO ; + +DT_PUTPAGE (mp); +txAbort (tid,0 ); + goto end; + } + d = (struct ldtentry *) &p->slot[stbl[i]]; index =le32_to_cpu (d->index);if ((index <2 ) || (index >=JFS_IP (inode)->next_index)) {
@@ -2664,6 +2674,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) (void )txCommit (tid,1 , &inode,0 ); end:txEnd (tid); +return rc; }/*
@@ -3017,7 +3028,8 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) }if (fix_page) { -add_missing_indices (ip, bn); +if ((rc =add_missing_indices (ip, bn))) + goto out; page_fixed =1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 350/1887 drm/amd/powerplay: fix VoltageObjectInfo zero-stride loop and OOB read
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 5d3cc8e388464f485d0944b87b8f9426e637d082 ]
Reject voltage objects whose usSize is smaller than the header or would advance the cursor past the table end, preventing an infinite loop or heap OOB read when the VBIOS supplies a malformed VoltageObjectInfo table.
--- drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c | 10 ++++++++-- drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +8 -2
@@ -269,15 +269,21 @@ static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3( unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);uint8_t *start = (uint8_t *)voltage_object_info_table; -while (offset < size) { +while (offset +sizeof (ATOM_VOLTAGE_OBJECT_HEADER_V3 ) <= size) {const ATOM_VOLTAGE_OBJECT_V3 *voltage_object = (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); +u16 obj_size; + + obj_size =le16_to_cpu (voltage_object->asGpioVoltageObj.sHeader.usSize); +if (obj_size <sizeof (voltage_object->asGpioVoltageObj.sHeader) || + offset + obj_size > size) +break ;if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType && voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)return voltage_object; - offset +=le16_to_cpu (voltage_object->asGpioVoltageObj.sHeader.usSize); + offset += obj_size; }return NULL ;
drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c +8 -3
@@ -36,16 +36,21 @@ static const union atom_voltage_object_v4 *pp_atomfwctrl_lookup_voltage_type_v4( offsetof(struct atom_voltage_objects_info_v4_1, voltage_object[0]);unsigned long start = (unsigned long )voltage_object_info_table; -while (offset < size) { +while (offset +sizeof (struct atom_voltage_object_header_v4 ) <= size) {const union atom_voltage_object_v4 *voltage_object = (const union atom_voltage_object_v4 *)(start + offset); +u16 obj_size; + + obj_size =le16_to_cpu (voltage_object->gpio_voltage_obj.header.object_size); +if (obj_size <sizeof (voltage_object->gpio_voltage_obj.header) || + offset + obj_size > size) +break ;if (voltage_type == voltage_object->gpio_voltage_obj.header.voltage_type && voltage_mode == voltage_object->gpio_voltage_obj.header.voltage_mode)return voltage_object; - offset +=le16_to_cpu (voltage_object->gpio_voltage_obj.header.object_size); - + offset += obj_size; }return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 351/1887 SUNRPC: fix gssx_dec_option_array error path bugs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
[ Upstream commit 5e9a94539b1ec17a89177d952badfd0d844d694a ]
Four coupled defects in the gssx XDR option-array decoder make the error paths unsafe: a NULL deref in the caller, a refcount leak on the decoded group_info, and a latent use-after-free that the leak fix would otherwise expose.
gssx_dec_option_array() sets oa->count = 1 before allocating oa->data. If that allocation fails, -ENOMEM is returned with oa->count == 1 and oa->data == NULL. All other error paths jump to free_oa: which frees oa->data and NULLs it but also leaves oa->count == 1. The caller trusts the count:
gssp_accept_sec_context_upcall()
gssx_dec_accept_sec_context()
gssx_dec_option_array() /* fails, count=1 data=NULL */
data = res.options.data[0].value /* NULL deref */
Independently, free_creds: releases the partially decoded svc_cred with a bare kfree(creds). gssx_dec_linux_creds() installs a groups_alloc() result into creds->cr_group_info; that object is kvmalloc-backed and refcounted, and only put_group_info() reaches kvfree(). A plain kfree(creds) drops the wrapper and leaks the group_info allocation.
The natural fix for the leak is to call free_svc_cred(creds) before kfree(creds), but free_svc_cred() invokes put_group_info() on creds->cr_group_info unconditionally when non-NULL. The existingout_free_groups: path in gssx_dec_linux_creds() already called groups_free() on that pointer without clearing it, so once free_svc_cred() is wired in, the subsequent put_group_info() would touch freed memory.
Fix all four together:
- Move the oa->count = 1 assignment below the oa->data allocation
so it is never set when oa->data is NULL.
- Reset oa->count to 0 at free_oa: so count and data stay coherent and the caller sees an empty option array.
- Call free_svc_cred(creds) before kfree(creds) at free_creds:
so the refcounted cr_group_info is released. free_svc_cred() either NULL-guards each field explicitly (cr_group_info has an if() check) or delegates to a helper that is NULL-safe itself (kfree for the string fields, gss_mech_put() which guards with if(gm) at gss_mech_switch.c:342), so it is safe to call on a partially decoded svc_cred where only cr_uid/cr_gid/cr_group_info have been written and everything else is zero from kzalloc.
- In gssx_dec_linux_creds()'s out_free_groups: path, release cr_group_info with put_group_info() rather than groups_free() so the teardown matches free_svc_cred()'s refcount-aware path, and clear the pointer so a later free_svc_cred() on the same creds does not release it a second time.
--- net/sunrpc/auth_gss/gss_rpc_xdr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/sunrpc/auth_gss/gss_rpc_xdr.c +6 -3
@@ -222,7 +222,8 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,return 0 ; out_free_groups: -groups_free (creds->cr_group_info); +put_group_info (creds->cr_group_info); + creds->cr_group_info =NULL ;return err; }
@@ -242,12 +243,12 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,return 0 ;/* we recognize only 1 currently: CREDS_VALUE */ - oa->count =1 ; - oa->data =kmalloc (sizeof (struct gssx_option ),GFP_KERNEL );if (!oa->data)return -ENOMEM ; + oa->count =1 ; + creds =kzalloc (sizeof (struct svc_cred ),GFP_KERNEL );if (!creds) { err = -ENOMEM ;
@@ -294,8 +295,10 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,return 0 ; free_creds: +free_svc_cred (creds);kfree (creds); free_oa: + oa->count =0 ;kfree (oa->data); oa->data =NULL ;return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 352/1887 SUNRPC: reject duplicate CREDS_VALUE options
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
[ Upstream commit 2e4ce62385c1b8a887c5370af058ac7b52a8eaf9 ]
gssx_dec_option_array() walks the wire-supplied option array and, for every entry whose name matches CREDS_VALUE, calls gssx_dec_linux_creds() on the same struct svc_cred. That helper unconditionally installs a fresh groups_alloc() result into creds->cr_group_info without releasing whatever pointer was already there:
for (i = 0; i < count; i++) {
... decode name ...
if (length == sizeof(CREDS_VALUE) &&
memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
err = gssx_dec_linux_creds(xdr, creds);
...
}
}A reply that carries two CREDS_VALUE entries therefore overwrites cr_group_info on the second iteration and orphans the group_info allocated by the first call. The earlier free_creds path only releases the last cr_group_info via free_svc_cred(), so the first allocation's refcount stays at one and its kvmalloc-backed storage is leaked. No in-tree caller of gssp_accept_sec_context_upcall() expects more than one CREDS_VALUE per reply.
Fix by tracking whether a CREDS_VALUE option has already been decoded and returning -EINVAL on any subsequent match, so the free_creds path releases the single group_info that was installed.
--- net/sunrpc/auth_gss/gss_rpc_xdr.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sunrpc/auth_gss/gss_rpc_xdr.c +6 -0
@@ -231,6 +231,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr, struct gssx_option_array *oa) {struct svc_cred *creds; +bool creds_decoded = false;u32 count, i;__be32 *p;int err;
@@ -281,9 +282,14 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,if (length ==sizeof (CREDS_VALUE ) &&memcmp (p,CREDS_VALUE ,sizeof (CREDS_VALUE )) ==0 ) {/* We have creds here. parse them */ +if (creds_decoded) { + err = -EINVAL ; + goto free_creds; + } err =gssx_dec_linux_creds (xdr, creds);if (err) goto free_creds; + creds_decoded = true; oa->data[0 ].value.len =1 ;/* presence */ }else {/* consume uninteresting buffer */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 353/1887 vc_screen: reload vc pointer before if (ret) in vcs_write() to avoid UAF
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yi Yang <[email protected]>
[ Upstream commit 226bd5603371cd9f6642cbb9e9a677f445de3530 ]
The reload of 'vc' added by commit 8fb9ea65c9d1 ("vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF") sits after the 'if (ret)' block, so the copy-failure break path exits the loop without reloading vc. If the vc was kfree()'d via vc_port_destruct during the unlocked copy_from_user() window, the post-loop
'if (written && vc) vcs_scr_updated(vc)' is reached with a stale non-NULL vc. The '&& vc' guard from commit a287620312dc ("vc_screen:
fix null-ptr-deref in vcs_notifier() during concurrent vcs_write") only handles the NULL case, not this stale-non-NULL case; vcs_notifier() then reads param->vc->vc_num from freed memory:
BUG: KASAN: slab-use-after-free in vcs_notifier+0x7c/0xd0 Read of size 2 at addr ffff888007149190 Call Trace: vcs_notifier+0x7c/0xd0 atomic_notifier_call_chain+0x70/0xa0 vcs_scr_updated+0x77/0xa0 vcs_write+0x71b/0x7e0 Allocated by task: vc_allocate -> con_install -> tty_open Freed by task: kfree <- vt_ioctl (VT_DISALLOCATE -> vc_port_destruct)
Move the reload to immediately after console_lock(), before 'if (ret)', so every break path below passes a fresh vc to the post-loop vcs_scr_updated().
--- drivers/tty/vt/vc_screen.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
drivers/tty/vt/vc_screen.c +13 -12
@@ -643,6 +643,19 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ret =copy_from_user (con_buf, buf, this_round);console_lock (); +/* The vc might have been freed or vcs_size might have changed +* while we slept to grab the user buffer; recheck here, before +* if (ret), so every break path below passes a fresh vc to the +* post-loop vcs_scr_updated(). Return data written so far. +*/ + vc =vcs_vc (inode, &viewed); +if (!vc) { +if (written) +break ; + ret = -ENXIO ; + goto unlock_out; + } +if (ret) { this_round -= ret;if (!this_round) {
@@ -655,18 +668,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) goto unlock_out; } } - -/* The vc might have been freed or vcs_size might have changed -* while we slept to grab the user buffer, so recheck. -* Return data written up to now on failure. -*/ - vc =vcs_vc (inode, &viewed); -if (!vc) { -if (written) -break ; - ret = -ENXIO ; - goto unlock_out; - } size =vcs_size (vc, attr, false);if (size <0 ) {if (written)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 354/1887 mtd: rawnand: vf610_nfc: fix false bitflips on reads of erased pages
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mehmet Fide <[email protected]>
[ Upstream commit 68fe2faf5c69d0e21f94cd695d28f0ba677d484f ]
When the ECC engine fails to decode a page, the driver re-reads the OOB area with the engine bypassed, but runs the erased-page check for the data area on the buffer left in the controller SRAM by the failed transfer.
That buffer does not hold what is on the flash: the failing engine writes a bogus single-bit "correction" into it. In the 60-byte ECC mode the all-0xff content of an erased page always decodes to the same error location, so every erased page shows one stale zero bit at data offset 0x5FD, which the erased-page check then reports as a corrected bitflip.
Edward Karpicz discovered this behaviour and identified the offset on a Colibri VF61; the analysis and the fix build on his finding. Measured with an instrumented driver on a Colibri VF50 (MX30LF1G18AC, 32-bit ECC): reading a 126 MiB partition with nanddump increased the corrected counter by 18035, exactly one per erased page, while raw reads of the same pages return clean 0xff. A v4.4 kernel on the VF61 (MX30LF4G28AC) accumulates the same false counts, so the behaviour follows the controller rather than the chip or the driver generation. Neither the Vybrid reference manual nor the published mask set errata (VFXXX_2N02G) document it. The 45-byte ECC mode is not affected.
Restoring the known byte is not enough: on pages that fail to decode with content other than all-0xff the engine writes its correction wherever the syndrome points (measured at a different offset on such a page), so the check has to run on what the flash holds. Re-read the data area with the ECC engine bypassed, exactly as already done for the OOB area. The corrected counter then stays at zero on both boards.
--- drivers/mtd/nand/raw/vf610_nfc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/mtd/nand/raw/vf610_nfc.c +11 -4
@@ -518,6 +518,7 @@ static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat,u8 ecc_status;u8 ecc_count;int flips_threshold = nfc->chip.ecc.strength /2 ; +int ret; ecc_status =vf610_nfc_read (nfc, ecc_status_off) &0xff ; ecc_count = ecc_status &ECC_STATUS_ERR_COUNT ;
@@ -525,15 +526,21 @@ static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat,if (!(ecc_status &ECC_STATUS_MASK ))return ecc_count; +/* The failed decode leaves a bogus correction in SRAM; re-read without ECC */ nfc->data_access = true; -nand_read_oob_op (&nfc->chip, page,0 , oob,vf610_nfc_spare_size (mtd)); + ret =nand_read_page_op (&nfc->chip, page,0 , dat, mtd->writesize); +if (!ret) + ret =nand_read_oob_op (&nfc->chip, page,0 , oob, +vf610_nfc_spare_size (mtd)); nfc->data_access = false; +if (ret) +return ret;/* -* On an erased page, bit count (including OOB) should be zero or -* at least less then half of the ECC strength. +* Run the erased-page check with the driver's historic threshold +* of half the ECC strength. */ -return nand_check_erased_ecc_chunk (dat, nfc->chip.ecc.size, oob, +return nand_check_erased_ecc_chunk (dat, mtd->writesize, oob,vf610_nfc_spare_size (mtd),NULL ,0 , flips_threshold); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 355/1887 tcp: introduce icsk->icsk_keepalive_timer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 08dfe370239e53494453cee1e2ded2cdaa1efd12 ]
sk->sk_timer has been used for TCP keepalives.
Keepalive timers are not in fast path, we want to use sk->sk_timer storage for retransmit timers, for better cache locality.
Create icsk->icsk_keepalive_timer and change keepalive code to no longer use sk->sk_timer.
Added space is reclaimed in the following patch.
This includes changes to MPTCP, which was also using sk_timer.
Alias icsk->mptcp_tout_timer and icsk->icsk_keepalive_timer for inet_sk_diag_fill() sake.
Backport to 6.1 as a dependency of 85c580b0d859 ("mptcp: prevent race between disconnect() and rtx"):
Keep icsk_timeout and the existing TCP retransmit timer. Update the existing inet_csk keepalive helpers in inet_connection_sock.c instead of introducing the newer TCP helpers, and use from_timer() in the callbacks. Adjust the DCCP callback, since DCCP still shares the inet_csk timer setup in this branch. Omit the absent net_cachelines document.
Also alias sk_timer as mptcp_retransmit_timer and move all MPTCP retransmit timer users there. The target directly stops this timer and the new mptcp_tout_timer, so both names must identify the timers actually in use. Initialize the MPTCP icsk_rto_min to this branch's TCP_RTO_MIN so the target restores a valid retransmit interval during disconnect. No functions are added.
[ sashal: Reduced backport -- upstream 08dfe370239e5 touches 11 file(s), this
backport carries 12. Not backported here:
Documentation/networking/net_cachelines/inet_connection_sock.rst This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: 85c580b0d859 ("mptcp: prevent race between disconnect() and rtx")
--- include/net/inet_connection_sock.h | 11 ++++++-- include/net/sock.h | 6 +++- net/dccp/timer.c | 4 ++- net/ipv4/inet_connection_sock.c | 10 +++---- net/ipv4/inet_diag.c | 4 +-- net/ipv4/tcp_ipv4.c | 4 +-- net/ipv4/tcp_timer.c | 5 ++-- net/ipv6/tcp_ipv6.c | 4 +-- net/mptcp/protocol.c | 28 +++++++++---------- net/mptcp/protocol.h | 2 +- .../selftests/bpf/progs/bpf_iter_tcp4.c | 4 +-- .../selftests/bpf/progs/bpf_iter_tcp6.c | 4 +-- 12 files changed, 49 insertions(+), 37 deletions(-)
include/net/inet_connection_sock.h +9 -2
@@ -63,6 +63,9 @@ struct inet_connection_sock_af_ops {* @icsk_bind2_hash: Bind node in the bhash2 table * @icsk_timeout: Timeout * @icsk_retransmit_timer: Resend (no ack) +* @icsk_delack_timer: Delayed ACK timer +* @icsk_keepalive_timer: Keepalive timer +* @mptcp_tout_timer: MPTCP timeout timer * @icsk_rto: Retransmit timeout * @icsk_pmtu_cookie Last pmtu seen by socket * @icsk_ca_ops Pluggable congestion control hook
@@ -89,8 +92,12 @@ struct inet_connection_sock {struct inet_bind_bucket *icsk_bind_hash;struct inet_bind2_bucket *icsk_bind2_hash;unsigned long icsk_timeout; -struct timer_list icsk_retransmit_timer; -struct timer_list icsk_delack_timer; +struct timer_list icsk_retransmit_timer; +struct timer_list icsk_delack_timer; +union { +struct timer_list icsk_keepalive_timer; +struct timer_list mptcp_tout_timer; + };__u32 icsk_rto;__u32 icsk_rto_min;__u32 icsk_delack_max;
include/net/sock.h +5 -1
@@ -315,6 +315,7 @@ struct sk_filter;* @sk_txrehash: enable TX hash rethink * @sk_filter: socket filtering instructions * @sk_timer: sock cleanup timer +* @mptcp_retransmit_timer: MPTCP retransmit timer * @sk_stamp: time stamp of last packet received * @sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only * @sk_tsflags: SO_TIMESTAMPING flags
@@ -459,7 +460,10 @@ struct sock {__u32 sk_dst_pending_confirm;u32 sk_pacing_status;/* see enum sk_pacing */ long sk_sndtimeo; -struct timer_list sk_timer; +union { +struct timer_list sk_timer; +struct timer_list mptcp_retransmit_timer; + };__u32 sk_priority;__u32 sk_mark;unsigned long sk_pacing_rate;/* bytes per second */
net/dccp/timer.c +3 -1
@@ -160,7 +160,9 @@ static void dccp_write_timer(struct timer_list *t)static void dccp_keepalive_timer (struct timer_list *t) { -struct sock *sk =from_timer (sk, t, sk_timer); +struct inet_connection_sock *icsk = +from_timer (icsk, t, icsk_keepalive_timer); +struct sock *sk = &icsk->icsk_inet.sk;pr_err ("dccp should not use a keepalive timer !\n" );sock_put (sk);
net/ipv4/inet_connection_sock.c +5 -5
@@ -749,7 +749,7 @@ void inet_csk_init_xmit_timers(struct sock *sk,timer_setup (&icsk->icsk_retransmit_timer, retransmit_handler,0 );timer_setup (&icsk->icsk_delack_timer, delack_handler,0 ); -timer_setup (&sk->sk_timer, keepalive_handler,0 ); +timer_setup (&icsk->icsk_keepalive_timer, keepalive_handler,0 ); icsk->icsk_pending = icsk->icsk_ack.pending =0 ; }EXPORT_SYMBOL (inet_csk_init_xmit_timers);
@@ -762,7 +762,7 @@ void inet_csk_clear_xmit_timers(struct sock *sk)sk_stop_timer (sk, &icsk->icsk_retransmit_timer);sk_stop_timer (sk, &icsk->icsk_delack_timer); -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &icsk->icsk_keepalive_timer); }EXPORT_SYMBOL (inet_csk_clear_xmit_timers);
@@ -777,18 +777,18 @@ void inet_csk_clear_xmit_timers_sync(struct sock *sk)sk_stop_timer_sync (sk, &icsk->icsk_retransmit_timer);sk_stop_timer_sync (sk, &icsk->icsk_delack_timer); -sk_stop_timer_sync (sk, &sk->sk_timer); +sk_stop_timer_sync (sk, &icsk->icsk_keepalive_timer); }void inet_csk_delete_keepalive_timer (struct sock *sk) { -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->icsk_keepalive_timer); }EXPORT_SYMBOL (inet_csk_delete_keepalive_timer);void inet_csk_reset_keepalive_timer (struct sock *sk,unsigned long len) { -sk_reset_timer (sk, &sk->sk_timer, jiffies + len); +sk_reset_timer (sk, &inet_csk (sk)->icsk_keepalive_timer, jiffies + len); }EXPORT_SYMBOL (inet_csk_reset_keepalive_timer);
net/ipv4/inet_diag.c +2 -2
@@ -310,11 +310,11 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, r->idiag_retrans = icsk->icsk_probes_out; r->idiag_expires =jiffies_delta_to_msecs (icsk->icsk_timeout - jiffies); - }else if (timer_pending (&sk->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { r->idiag_timer =2 ; r->idiag_retrans = icsk->icsk_probes_out; r->idiag_expires = -jiffies_delta_to_msecs (sk->sk_timer.expires - jiffies); +jiffies_delta_to_msecs (icsk->icsk_keepalive_timer.expires - jiffies); }if ((ext & (1 << (INET_DIAG_INFO -1 ))) && handler->idiag_info_size) {
net/ipv4/tcp_ipv4.c +2 -2
@@ -2647,9 +2647,9 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_timeout; - }else if (timer_pending (&sk->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sk->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires = jiffies;
net/ipv4/tcp_timer.c +3 -2
@@ -706,8 +706,9 @@ EXPORT_SYMBOL_GPL(tcp_set_keepalive);static void tcp_keepalive_timer (struct timer_list *t) { -struct sock *sk =from_timer (sk, t, sk_timer); -struct inet_connection_sock *icsk =inet_csk (sk); +struct inet_connection_sock *icsk = +from_timer (icsk, t, icsk_keepalive_timer); +struct sock *sk = &icsk->icsk_inet.sk;struct tcp_sock *tp =tcp_sk (sk);u32 elapsed;
net/ipv6/tcp_ipv6.c +2 -2
@@ -2001,9 +2001,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_timeout; - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires = jiffies;
net/mptcp/protocol.c +13 -15
@@ -426,9 +426,7 @@ static bool __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk,static void mptcp_stop_rtx_timer (struct sock *sk) { -struct inet_connection_sock *icsk =inet_csk (sk); - -sk_stop_timer (sk, &icsk->icsk_retransmit_timer); +sk_stop_timer (sk, &sk->mptcp_retransmit_timer);mptcp_sk (sk)->timer_ival =0 ; }
@@ -976,12 +974,11 @@ static void __mptcp_flush_join_list(struct sock *sk, struct list_head *join_liststatic bool mptcp_rtx_timer_pending (struct sock *sk) { -return timer_pending (&inet_csk (sk)->icsk_retransmit_timer); +return timer_pending (&sk->mptcp_retransmit_timer); }static void mptcp_reset_rtx_timer (struct sock *sk) { -struct inet_connection_sock *icsk =inet_csk (sk);unsigned long tout;/* prevent rescheduling on close */
@@ -989,7 +986,7 @@ static void mptcp_reset_rtx_timer(struct sock *sk)return ; tout =mptcp_sk (sk)->timer_ival; -sk_reset_timer (sk, &icsk->icsk_retransmit_timer, jiffies + tout); +sk_reset_timer (sk, &sk->mptcp_retransmit_timer, jiffies + tout); }bool mptcp_schedule_work (struct sock *sk)
@@ -2349,9 +2346,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,static void mptcp_retransmit_timer (struct timer_list *t) { -struct inet_connection_sock *icsk =from_timer (icsk, t, - icsk_retransmit_timer); -struct sock *sk = &icsk->icsk_inet.sk; +struct sock *sk =from_timer (sk, t, mptcp_retransmit_timer);struct mptcp_sock *msk =mptcp_sk (sk);bh_lock_sock (sk);
@@ -2369,7 +2364,9 @@ static void mptcp_retransmit_timer(struct timer_list *t)static void mptcp_tout_timer (struct timer_list *t) { -struct sock *sk =from_timer (sk, t, sk_timer); +struct inet_connection_sock *icsk = +from_timer (icsk, t, mptcp_tout_timer); +struct sock *sk = &icsk->icsk_inet.sk;mptcp_schedule_work (sk);sock_put (sk);
@@ -2801,7 +2798,7 @@ void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout)*/ timeout =inet_csk (sk)->icsk_mtup.probe_timestamp ? close_timeout : fail_tout; -sk_reset_timer (sk, &sk->sk_timer, timeout); +sk_reset_timer (sk, &inet_csk (sk)->mptcp_tout_timer, timeout); }static void mptcp_mp_fail_no_response (struct mptcp_sock *msk)
@@ -2919,6 +2916,8 @@ static int __mptcp_init_sock(struct sock *sk) msk->first_pending =NULL ; msk->rmem_fwd_alloc =0 ;WRITE_ONCE (msk->rmem_released,0 ); +/* MPTCP sockets do not go through tcp_init_sock(). */ +inet_csk (sk)->icsk_rto_min =TCP_RTO_MIN ; msk->timer_ival =TCP_RTO_MIN ;WRITE_ONCE (msk->first,NULL );
@@ -2931,9 +2930,8 @@ static int __mptcp_init_sock(struct sock *sk)mptcp_pm_data_init (msk);spin_lock_init (&msk->fallback_lock); -/* re-use the csk retrans timer for MPTCP-level retrans */ -timer_setup (&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer,0 ); -timer_setup (&sk->sk_timer, mptcp_tout_timer,0 ); +timer_setup (&sk->mptcp_retransmit_timer, mptcp_retransmit_timer,0 ); +timer_setup (&msk->sk.mptcp_tout_timer, mptcp_tout_timer,0 );return 0 ; }
@@ -3110,7 +3108,7 @@ static void __mptcp_destroy_sock(struct sock *sk)might_sleep ();mptcp_stop_rtx_timer (sk); -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->mptcp_tout_timer); msk->pm.status =0 ; sk->sk_prot->destroy (sk);
net/mptcp/protocol.h +1 -1
@@ -698,7 +698,7 @@ static inline void mptcp_stop_tout_timer(struct sock *sk)if (!inet_csk (sk)->icsk_mtup.probe_timestamp)return ; -sk_stop_timer (sk, &sk->sk_timer); +sk_stop_timer (sk, &inet_csk (sk)->mptcp_tout_timer);inet_csk (sk)->icsk_mtup.probe_timestamp =0 ; }
tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c +2 -2
@@ -103,9 +103,9 @@ static int dump_tcp_sock(struct seq_file *seq, struct tcp_sock *tp, }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_timeout; - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires =bpf_jiffies64 ();
tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c +2 -2
@@ -103,9 +103,9 @@ static int dump_tcp6_sock(struct seq_file *seq, struct tcp6_sock *tp, }else if (icsk->icsk_pending ==ICSK_TIME_PROBE0 ) { timer_active =4 ; timer_expires = icsk->icsk_timeout; - }else if (timer_pending (&sp->sk_timer)) { + }else if (timer_pending (&icsk->icsk_keepalive_timer)) { timer_active =2 ; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; }else { timer_active =0 ; timer_expires =bpf_jiffies64 ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 356/1887 mptcp: prevent race between disconnect() and rtx
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit 85c580b0d8590520ae00a15c29e9fb9c99427a3e ]
Sashiko noted that the two event can race, leading to inconsistent status. Prevent the race using the synchronous timer stop operation.
[ sashal: Use TCP_RTO_MIN for msk->timer_ival instead of
icsk->icsk_rto_min, as ea4eb2adb0d3 ("mptcp: honour configured min/max RTO in retransmit paths") is not in this tree. ]
--- net/mptcp/protocol.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/mptcp/protocol.c +8 -2
@@ -3269,6 +3269,7 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)static int mptcp_disconnect (struct sock *sk,int flags) { +struct inet_connection_sock *icsk =inet_csk (sk);struct mptcp_sock *msk =mptcp_sk (sk);/* We are on the fastopen error path. We can't call straight into the
@@ -3281,8 +3282,13 @@ static int mptcp_disconnect(struct sock *sk, int flags)mptcp_check_listen_stop (sk);inet_sk_state_store (sk,TCP_CLOSE ); -mptcp_stop_rtx_timer (sk); -mptcp_stop_tout_timer (sk); +/* The later subflow close can not kick again the tout timer, +* as the msk is already in closed status. +*/ + msk->timer_ival =TCP_RTO_MIN ; +sk_stop_timer_sync (sk, &sk->mptcp_retransmit_timer); + icsk->icsk_mtup.probe_timestamp =0 ; +sk_stop_timer_sync (sk, &icsk->mptcp_tout_timer);if (mptcp_sk (sk)->token)mptcp_event (MPTCP_EVENT_CLOSED ,mptcp_sk (sk),NULL ,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 357/1887 smb: client: split cifsFileInfo bitfields to avoid shared-byte RMW races
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <[email protected]>
[ Upstream commit 19465a9aeb664f1d710d0d22c07c31bfb7c85446 ]
The invalidHandle, swapfile, oplock_break_cancelled, offload, and status_file_deleted fields are stored in the same bitfield byte in struct cifsFileInfo, but are updated in different code paths that may run simultaneously, and are protected by different locks. Since bitfield assignments generate byte-level read-modify-write operations, a modification to one flag can overwrite a concurrent modification to another flag.
To avoid these races, convert these flags from a bitfield to separate bool fields.
--- fs/smb/client/cifsglob.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/smb/client/cifsglob.h +4 -4
@@ -1337,10 +1337,10 @@ struct cifsFileInfo {struct dentry *dentry;struct tcon_link *tlink;unsigned int f_flags; - bool invalidHandle:1; /* file closed via session abend */ - bool swapfile:1; - bool oplock_break_cancelled:1; - bool offload:1; /* offload final part of _put to a wq */ +bool invalidHandle;/* file closed via session abend */ +bool swapfile; +bool oplock_break_cancelled; +bool offload;/* offload final part of _put to a wq */ __u16 oplock_epoch;/* epoch from the lease break */ __u32 oplock_level;/* oplock/lease level from the lease break */ int count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 358/1887 wifi: wlcore: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit f00928012886a07ca6817ea70eb4856ce280ce05 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
wlcore_remove() returned zero unconditionally. With that converted to return void instead, the wl12xx and wl18xx driver can be converted to .remove_new trivially.
Stable-dep-of: a8b8881d0c1a ("wifi: wlcore: Fix runtime PM leak in wlcore_remove()")
--- drivers/net/wireless/ti/wl12xx/main.c | 6 +++--- drivers/net/wireless/ti/wl18xx/main.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 6 ++---- drivers/net/wireless/ti/wlcore/wlcore.h | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-)
drivers/net/wireless/ti/wl12xx/main.c +3 -3
@@ -1919,7 +1919,7 @@ static int wl12xx_probe(struct platform_device *pdev)return ret; } -static int wl12xx_remove (struct platform_device *pdev) +static void wl12xx_remove (struct platform_device *pdev) {struct wl1271 *wl =platform_get_drvdata (pdev);struct wl12xx_priv *priv;
@@ -1928,7 +1928,7 @@ static int wl12xx_remove(struct platform_device *pdev)kfree (priv->rx_mem_addr); -return wlcore_remove (pdev); +wlcore_remove (pdev); }static const struct platform_device_id wl12xx_id_table[] = {
@@ -1939,7 +1939,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table);static struct platform_driver wl12xx_driver = { .probe = wl12xx_probe, - .remove = wl12xx_remove, + .remove_new = wl12xx_remove, .id_table = wl12xx_id_table, .driver = { .name ="wl12xx_driver" ,
drivers/net/wireless/ti/wl18xx/main.c +1 -1
@@ -2033,7 +2033,7 @@ MODULE_DEVICE_TABLE(platform, wl18xx_id_table);static struct platform_driver wl18xx_driver = { .probe = wl18xx_probe, - .remove = wlcore_remove, + .remove_new = wlcore_remove, .id_table = wl18xx_id_table, .driver = { .name ="wl18xx_driver" ,
drivers/net/wireless/ti/wlcore/main.c +2 -4
@@ -6734,7 +6734,7 @@ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) }EXPORT_SYMBOL_GPL (wlcore_probe); -int wlcore_remove (struct platform_device *pdev) +void wlcore_remove (struct platform_device *pdev) {struct wlcore_platdev_data *pdev_data =dev_get_platdata (&pdev->dev);struct wl1271 *wl =platform_get_drvdata (pdev);
@@ -6749,7 +6749,7 @@ int wlcore_remove(struct platform_device *pdev)if (pdev_data->family && pdev_data->family->nvs_name)wait_for_completion (&wl->nvs_loading_complete);if (!wl->initialized) -return 0 ; +return ;if (wl->wakeirq >=0 ) {dev_pm_clear_wake_irq (wl->dev);
@@ -6769,8 +6769,6 @@ int wlcore_remove(struct platform_device *pdev)free_irq (wl->irq, wl);wlcore_free_hw (wl); - -return 0 ; }EXPORT_SYMBOL_GPL (wlcore_remove);
drivers/net/wireless/ti/wlcore/wlcore.h +1 -1
@@ -497,7 +497,7 @@ struct wl1271 { };int wlcore_probe (struct wl1271 *wl,struct platform_device *pdev); -int wlcore_remove (struct platform_device *pdev); +void wlcore_remove (struct platform_device *pdev);struct ieee80211_hw *wlcore_alloc_hw (size_t priv_size,u32 aggr_buf_size,u32 mbox_size);int wlcore_free_hw (struct wl1271 *wl);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 359/1887 wifi: wlcore: Fix runtime PM leak in wlcore_remove()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
[ Upstream commit a8b8881d0c1aff544fae190469d86db7b07f43a9 ]
pm_runtime_get_sync() keeps the runtime PM usage counter elevated even when it returns an error, so the reference taken at the beginning of wlcore_remove() has to be dropped on every exit path. When the device was not initialized the function returned early without doing so, leaking the reference.
Release it with pm_runtime_put_noidle() as done on the other early error paths of this driver.
--- drivers/net/wireless/ti/wlcore/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/ti/wlcore/main.c +3 -1
@@ -6748,8 +6748,10 @@ void wlcore_remove(struct platform_device *pdev)if (pdev_data->family && pdev_data->family->nvs_name)wait_for_completion (&wl->nvs_loading_complete); -if (!wl->initialized) +if (!wl->initialized) { +pm_runtime_put_noidle (wl->dev);return ; + }if (wl->wakeirq >=0 ) {dev_pm_clear_wake_irq (wl->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 360/1887 net: usb: qmi_wwan: add Quectel EG120K-EA
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gilberto Conde <[email protected]>
commit 0f2fd31f63c65c409bd336af3a42d478a9207c1f upstream.
Add support for the Quectel EG120K-EA LTE Cat.12 module (USB ID 2c7c:030b). Its QMI interface (interface 4) uses class/subclass/protocol ff/ff/ff like the other recent Quectel modules, so match it the same way.
The product ID is shared with the EM060K, which the option driver already knows and uses to claim the serial interfaces. Without a qmi_wwan entry the data interface is left unbound.
Tested on a GL.iNet GL-X2000, where the module is soldered down and enumerates at SuperSpeed: cdc-wdm0 and wwan0 appear and ModemManager brings up a data session.
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=5000 MxCh= 0 D: Ver= 3.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1 P: Vendor=2c7c ProdID=030b Rev= 5.04 S: Manufacturer=Quectel S: Product=EG120K-EA S: SerialNumber=45546267 C:* #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=896mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=40 Driver=option E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=82(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=84(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=88(I) Atr=03(Int.) MxPS= 8 Ivl=32ms E: Ad=8e(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms E: Ad=0f(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
I:* If#=12 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none)
E: Ad=89(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
--- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/usb/qmi_wwan.c +1 -0
@@ -1092,6 +1092,7 @@ static const struct usb_device_id produc {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x030b)}, /* Quectel EM060K/EG120K-EA */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */
Greg Kroah-Hartman
maintainerPATCH 361/1887 serial: imx: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit c066f87314b7fbbf4d72d38957436a98e7b7e503 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks.
To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove().
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 8b0b29fdcb47 ("serial: imx: serialize imx_uart_ports[] lifetime")
--- drivers/tty/serial/imx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/tty/serial/imx.c +2 -4
@@ -2534,13 +2534,11 @@ err_clk:return ret; } -static int imx_uart_remove (struct platform_device *pdev) +static void imx_uart_remove (struct platform_device *pdev) {struct imx_port *sport =platform_get_drvdata (pdev);uart_remove_one_port (&imx_uart_uart_driver, &sport->port); - -return 0 ; }static void imx_uart_restore_context (struct imx_port *sport)
@@ -2709,7 +2707,7 @@ static const struct dev_pm_ops imx_uart_static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, - .remove = imx_uart_remove, + .remove_new = imx_uart_remove, .driver = { .name ="imx-uart" ,
Greg Kroah-Hartman
maintainerPATCH 362/1887 serial: imx: serialize imx_uart_ports[] lifetime
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 8b0b29fdcb47907ae0296b8fe829e918e05e300f ]
imx_uart_probe() publishes its devm-allocated port in imx_uart_ports[] before uart_add_one_port() because console setup uses the table. The entry is not cleared when adding the port fails or after removal, leaving a dangling pointer.
A sibling probe can register the shared console through that stale entry. This was reproduced under KASAN on QEMU mcimx6ul-evk by unbinding a sibling UART, unbinding the console UART and rebinding the sibling.
Keep the entry valid through uart_remove_one_port(), then clear it. Protect port addition and removal together with their table updates so sibling operations cannot interleave. Reject an occupied slot rather than clobbering an active port during a duplicate-line probe.
--- drivers/tty/serial/imx.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/tty/serial/imx.c +17 -3
@@ -21,6 +21,7 @@#include <linux/clk.h> #include <linux/delay.h> #include <linux/ktime.h> +#include <linux/mutex.h> #include <linux/pinctrl/consumer.h> #include <linux/rational.h> #include <linux/slab.h>
@@ -2037,6 +2038,9 @@ static const struct uart_ops imx_uart_postatic struct imx_port *imx_uart_ports[UART_NR ]; +/* Held across uart_add/remove_one_port(); console callbacks must not take it. */ +static DEFINE_MUTEX (imx_uart_ports_lock); +#if IS_ENABLED (CONFIG_SERIAL_IMX_CONSOLE )static void imx_uart_console_putchar (struct uart_port *port,unsigned char ch) {
@@ -2522,11 +2526,19 @@ static int imx_uart_probe(struct platfor } } - imx_uart_ports[sport->port.line] = sport; -platform_set_drvdata (pdev, sport); - ret =uart_add_one_port (&imx_uart_uart_driver, &sport->port); + scoped_guard(mutex, &imx_uart_ports_lock) { +if (imx_uart_ports[sport->port.line]) { + ret = -EBUSY ; + }else { + imx_uart_ports[sport->port.line] = sport; + ret =uart_add_one_port (&imx_uart_uart_driver, + &sport->port); +if (ret) + imx_uart_ports[sport->port.line] =NULL ; + } + } err_clk:clk_disable_unprepare (sport->clk_ipg);
@@ -2538,7 +2550,9 @@ static void imx_uart_remove(struct platf {struct imx_port *sport =platform_get_drvdata (pdev); +guard (mutex)(&imx_uart_ports_lock);uart_remove_one_port (&imx_uart_uart_driver, &sport->port); + imx_uart_ports[sport->port.line] =NULL ; }static void imx_uart_restore_context (struct imx_port *sport)
Greg Kroah-Hartman
maintainerPATCH 363/1887 usb: gadget: at91_udc: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit cbd1b152519a581bfe14fb6b14ea6e57cca426c1 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks.
To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove().
In the error path emit an error message replacing the (less useful) message by the core. Apart from the improved error message there is no change in behaviour.
Stable-dep-of: c27d13ce4bab ("usb: gadget: at91_udc: drain polled-VBUS timer/work before udc is freed")
--- drivers/usb/gadget/udc/at91_udc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/gadget/udc/at91_udc.c +7 -6
@@ -1927,7 +1927,7 @@ err_unprepare_fclk:return retval; } -static int at91udc_remove (struct platform_device *pdev) +static void at91udc_remove (struct platform_device *pdev) {struct at91_udc *udc =platform_get_drvdata (pdev);unsigned long flags;
@@ -1935,8 +1935,11 @@ static int at91udc_remove(struct platforDBG ("remove\n" );usb_del_gadget_udc (&udc->gadget); -if (udc->driver) -return -EBUSY ; +if (udc->driver) { +dev_err (&pdev->dev, +"Driver still in use but removing anyhow\n" ); +return ; + }spin_lock_irqsave (&udc->lock, flags);pullup (udc,0 );
@@ -1946,8 +1949,6 @@ static int at91udc_remove(struct platforremove_debug_file (udc);clk_unprepare (udc->fclk);clk_unprepare (udc->iclk); - -return 0 ; }#ifdef CONFIG_PM
@@ -2003,7 +2004,7 @@ static int at91udc_resume(struct platfor#endif static struct platform_driver at91_udc_driver = { - .remove = at91udc_remove, + .remove_new = at91udc_remove, .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume,
Greg Kroah-Hartman
maintainerPATCH 364/1887 usb: gadget: at91_udc: drain polled-VBUS timer/work before udc is freed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit c27d13ce4bab80fbdf6523928071b6c24b37606c ]
In polled-VBUS mode (board.vbus_pin && board.vbus_polled), probe arms a self-restarting cycle: at91_vbus_timer() schedules vbus_timer_work, and at91_vbus_timer_work() calls at91_vbus_update() and re-arms the timer via mod_timer(). Both recover the same udc through container_of and dereference it on every iteration.
Neither teardown path cancels this cycle. udc is devm-allocated, so it is freed after at91udc_remove() returns, and is likewise freed when probe fails and devres runs. A timer callback or work item that is pending or running at either point dereferences the freed udc.
Add at91_udc_shutdown_vbus_timer() and call it from at91udc_remove() and from the usb_add_gadget_udc() failure path in probe; the remaining probe error paths fail before the timer is armed. timer_shutdown_sync() waits for a running callback and clears timer->function, which makes the work handler's mod_timer() a permanent no-op; cancel_work_sync() then drains any pending or running work whose re-arm attempt now does nothing. The timer must be shut down first, since cancelling the work alone would let the timer re-queue it. The guard mirrors probe: in IRQ mode the timer and work_struct are never initialized.
This does not require a fault; a normal driver unbind can interleave with an already queued work item.
This issue was found by an in-house static analysis tool.
--- drivers/usb/gadget/udc/at91_udc.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
drivers/usb/gadget/udc/at91_udc.c +19 -1
@@ -1796,6 +1796,19 @@ static void at91udc_of_init(struct at91_ udc->caps = match->data; } +/* +* The work handler re-arms this timer, so shut the timer down before +* draining the work; otherwise it restarts the polling cycle. +*/ +static void at91_udc_shutdown_vbus_timer (struct at91_udc *udc) +{ +if (!(udc->board.vbus_pin && udc->board.vbus_polled)) +return ; + +timer_shutdown_sync (&udc->vbus_timer); +cancel_work_sync (&udc->vbus_timer_work); +} +static int at91udc_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -1909,7 +1922,7 @@ static int at91udc_probe(struct platform } retval =usb_add_gadget_udc (dev, &udc->gadget);if (retval) - goto err_unprepare_iclk; + goto err_shutdown_vbus;dev_set_drvdata (dev, udc);device_init_wakeup (dev,1 );create_debug_file (udc);
@@ -1917,6 +1930,8 @@ static int at91udc_probe(struct platformINFO ("%s version %s\n" , driver_name,DRIVER_VERSION );return 0 ; +err_shutdown_vbus: +at91_udc_shutdown_vbus_timer (udc); err_unprepare_iclk:clk_unprepare (udc->iclk); err_unprepare_fclk:
@@ -1935,6 +1950,9 @@ static void at91udc_remove(struct platfoDBG ("remove\n" );usb_del_gadget_udc (&udc->gadget); + +at91_udc_shutdown_vbus_timer (udc); +if (udc->driver) {dev_err (&pdev->dev,"Driver still in use but removing anyhow\n" );
Greg Kroah-Hartman
maintainerPATCH 365/1887 USB: gadget: ffs: fix mm lifetime handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriel Prostitis <[email protected]>
[ Upstream commit 5eb5c72c72fef76cb765ef1669b62b6a3ba1bfc8 ]
io_data stores a pointer to the submitting task's mm_struct, but does not currently hold a reference to it while async requests are pending.
This can result in a use-after-free if the task exits before completion handling finishes.
Take a reference with mmgrab() when queuing the read request and release it with mmdrop() on request completion.
Stable-dep-of: e78dcb1f7ec2 ("usb: gadget: f_fs: Fix Use-After-Free in AIO error path")
--- drivers/usb/gadget/function/f_fs.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
drivers/usb/gadget/function/f_fs.c +20 -7
@@ -842,9 +842,15 @@ static void ffs_user_copy_worker(structunsigned long flags;if (io_data->read && ret >0 ) { -kthread_use_mm (io_data->mm); - ret =ffs_copy_to_iter (io_data->buf, ret, &io_data->data); -kthread_unuse_mm (io_data->mm); +if (mmget_not_zero (io_data->mm)) { +kthread_use_mm (io_data->mm); + ret =ffs_copy_to_iter (io_data->buf, ret, &io_data->data); +kthread_unuse_mm (io_data->mm); +mmput (io_data->mm); + }else { + ret = -EFAULT ; + } +mmdrop (io_data->mm); } io_data->kiocb->ki_complete (io_data->kiocb, ret);
@@ -1229,16 +1235,20 @@ static ssize_t ffs_epfile_write_iter(str kiocb->private = p; -if (p->aio) +if (p->aio) { +mmgrab (p->mm);kiocb_set_cancel_fn (kiocb, ffs_aio_cancel); + } res =ffs_epfile_io (kiocb->ki_filp, p);if (res == -EIOCBQUEUED )return res; -if (p->aio) +if (p->aio) { +mmdrop (p->mm);kfree (p); -else + }else { *from = p->data; + }return res; }
@@ -1275,14 +1285,17 @@ static ssize_t ffs_epfile_read_iter(stru kiocb->private = p; -if (p->aio) +if (p->aio) { +mmgrab (p->mm);kiocb_set_cancel_fn (kiocb, ffs_aio_cancel); + } res =ffs_epfile_io (kiocb->ki_filp, p);if (res == -EIOCBQUEUED )return res;if (p->aio) { +mmdrop (p->mm);kfree (p->to_free);kfree (p); }else {
Greg Kroah-Hartman
maintainerPATCH 366/1887 usb: gadget: f_fs: Fix Use-After-Free in AIO error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neill Kapron <[email protected]>
[ Upstream commit e78dcb1f7ec271449c54984dc90c62a5ba272de7 ]
In ffs_epfile_write_iter() and ffs_epfile_read_iter(), when ffs_epfile_io() fails with an error other than -EIOCBQUEUED, the io_data structure (p) is freed. However, for AIO operations, the kiocb cancel function was already armed and kiocb->private was set to p.
If a concurrent cancel operation (such as sys_io_cancel()) executes after ffs_epfile_io() fails but before the function frees p, a Use-After-Free can occur when the cancellation handler accesses the freed pointer.
To securely fix this race condition, we must properly un-arm the cancellation. Invoking kiocb->ki_complete() does exactly this by acquiring ctx->ctx_lock and safely removing the kiocb from the active sequence. In doing so, it ensures that a parallel io_cancel can no longer discover the kiocb, effectively closing the race window.
We then return -EIOCBQUEUED to notify the VFS layer that the kiocb has been consumed and it should avoid attempting to complete the request again or triggering subsequent completion handlers.
--- drivers/usb/gadget/function/f_fs.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/gadget/function/f_fs.c +4 -0
@@ -1244,8 +1244,10 @@ static ssize_t ffs_epfile_write_iter(strif (res == -EIOCBQUEUED )return res;if (p->aio) { + kiocb->ki_complete (kiocb, res);mmdrop (p->mm);kfree (p); +return -EIOCBQUEUED ; }else { *from = p->data; }
@@ -1295,9 +1297,11 @@ static ssize_t ffs_epfile_read_iter(strureturn res;if (p->aio) { + kiocb->ki_complete (kiocb, res);mmdrop (p->mm);kfree (p->to_free);kfree (p); +return -EIOCBQUEUED ; }else { *to = p->data; }
Greg Kroah-Hartman
maintainerPATCH 367/1887 usb: typec: tcpm: fix debug accessory mode detection for sink ports
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
[ Upstream commit f6ec9bb4acc7182b25a793ad094a764e1cb819a7 ]
The port in debug accessory mode can be either a source or sink. The previous tcpm_port_is_debug() function only checked for source port.
Commit 8db73e6a42b6 ("usb: typec: tcpm: allow sink (ufp) to toggle into accessory mode debug") changed the detection logic to support both roles, but left some logic in _tcpm_cc_change() unchanged, This causes the state machine to transition to an incorrect state when operating as a sink in debug accessory mode. Log as below:
[ 978.637541] CC1: 0 -> 5, CC2: 0 -> 5 [state TOGGLING, polarity 0, connected] [ 978.637567] state change TOGGLING -> SRC_ATTACH_WAIT [rev1 NONE_AMS] [ 978.637596] pending state change SRC_ATTACH_WAIT -> DEBUG_ACC_ATTACHED @ 180 ms [rev1 NONE_AMS] [ 978.647098] CC1: 5 -> 0, CC2: 5 -> 5 [state SRC_ATTACH_WAIT, polarity 0, connected] [ 978.647115] state change SRC_ATTACH_WAIT -> SRC_ATTACH_WAIT [rev1 NONE_AMS]
It should go to SNK_ATTACH_WAIT instead of SRC_ATTACH_WAIT state.
To fix this, add tcpm_port_is_debug_source() and tcpm_port_is_debug_sink() helper to explicitly identify the power mode in debug accessory mode. Update the state transition logic in _tcpm_cc_change() to ensure the state machine transitions comply with Type-C specification. Also update the logic in run_state_machine() to keep consistency.
[Backport to 6.12: This tree lacks 8db73e6a42b6 and the associated sink debug-accessory state-machine support. Retain only the source-debug macro extraction and source-side call-site updates. Keep tcpm_port_is_debug() source-only and omit the sink-debug macro and all sink/audio attachment transitions introduced by the upstream dependency. This preserves existing detection and state transitions while providing tcpm_port_is_debug_source() for cd3b9cea675b ("usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling"). No functions are added.]
Stable-dep-of: cd3b9cea675b ("usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling")
--- drivers/usb/typec/tcpm/tcpm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/usb/typec/tcpm/tcpm.c +7 -4
@@ -522,9 +522,12 @@ static const char * const pd_rev[] = { (tcpm_cc_is_source((port)->cc2) && \ !tcpm_cc_is_source((port)->cc1))) -#define tcpm_port_is_debug (port) \ +#define tcpm_port_is_debug_source (port) \ (tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2)) +#define tcpm_port_is_debug (port) \ + tcpm_port_is_debug_source(port) +#define tcpm_port_is_audio (port) \ (tcpm_cc_is_audio((port)->cc1) && tcpm_cc_is_audio((port)->cc2))
@@ -4023,7 +4026,7 @@ static void run_state_machine(struct tcptcpm_set_state (port,SNK_UNATTACHED ,PD_T_DRP_SNK );break ;case SRC_ATTACH_WAIT : -if (tcpm_port_is_debug (port)) +if (tcpm_port_is_debug_source (port))tcpm_set_state (port,DEBUG_ACC_ATTACHED ,PD_T_CC_DEBOUNCE );else if (tcpm_port_is_audio (port))
@@ -5035,7 +5038,7 @@ static void _tcpm_cc_change(struct tcpm_switch (port->state) {case TOGGLING : -if (tcpm_port_is_debug (port) ||tcpm_port_is_audio (port) || +if (tcpm_port_is_debug_source (port) ||tcpm_port_is_audio (port) ||tcpm_port_is_source (port))tcpm_set_state (port,SRC_ATTACH_WAIT ,0 );else if (tcpm_port_is_sink (port))
@@ -5043,7 +5046,7 @@ static void _tcpm_cc_change(struct tcpm_break ;case SRC_UNATTACHED :case ACC_UNATTACHED : -if (tcpm_port_is_debug (port) ||tcpm_port_is_audio (port) || +if (tcpm_port_is_debug_source (port) ||tcpm_port_is_audio (port) ||tcpm_port_is_source (port))tcpm_set_state (port,SRC_ATTACH_WAIT ,0 );break ;
Greg Kroah-Hartman
maintainerPATCH 368/1887 usb: typec: tcpm: constrain TCPM_SOURCING_VBUS event handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amit Sunil Dhamne <[email protected]>
[ Upstream commit cd3b9cea675bbfebc223f007dc2f4e79524fa54c ]
When a sink detach occurs while waiting for TX send status, the old TCPM_SOURCING_VBUS event along with TCPM_VBUS_EVENT and TCPM_CC_EVENT can be queued in port->pd_events. Because TCPM_SOURCING_VBUS is evaluated after TCPM_VBUS_EVENT and TCPM_CC_EVENT in tcpm_pd_event_handler(), a stale TCPM_SOURCING_VBUS event can override the detach handling and incorrectly set port->vbus_source and port->vbus_present to true.
Add a state guard to check that the port is either operating as a Source (tcpm_port_is_source(port)) or in a Fast Role Swap (FRS) state up to FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED before processing TCPM_SOURCING_VBUS. Otherwise, discard and log the event.
Log snippet for error condition before fix:
[72792.204955] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS] [72792.204960] sourcing vbus [72792.204962] VBUS on [72792.204970] AMS POWER_NEGOTIATION start [72792.204974] cc:=4 [72792.205319] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION] [72792.205325] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION] [72792.205332] PD TX, header: 0x11a1 [72792.216911] PD TX complete, status: 2 [72792.216957] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION] [72792.218005] VBUS off [72792.218013] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION] [72792.218020] VBUS VSAFE0V [72792.218024] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [rev3 POWER_NEGOTIATION] [72792.218458] CC1: 2 -> 0, CC2: 0 -> 0 [state SNK_UNATTACHED, polarity 0, disconnected] [72792.218467] VBUS on --> VBUS left on [72792.218980] disable vbus discharge ret:0 [72792.235193] Start toggling
After fix:
[ 1195.291691] state change SRC_ATTACHED -> SRC_STARTUP [rev3 NONE_AMS] [ 1195.291698] sourcing vbus [ 1195.291700] VBUS on [ 1195.291707] AMS POWER_NEGOTIATION start [ 1195.291710] cc:=4 [ 1195.291758] state change SRC_STARTUP -> AMS_START [rev3 POWER_NEGOTIATION] [ 1195.291794] state change AMS_START -> SRC_SEND_CAPABILITIES [rev3 POWER_NEGOTIATION] [ 1195.291798] PD TX, header: 0x11a1 [ 1195.297056] PD TX complete, status: 2 [ 1195.297092] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [rev3 POWER_NEGOTIATION] [ 1195.297177] VBUS off [ 1195.297184] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION] [ 1195.297227] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_SEND_CAPABILITIES, polarity 0, disconnected] [ 1195.307469] cc:=2 [ 1195.307544] pending state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED @ 650 ms [rev3 POWER_NEGOTIATION] [ 1195.307555] Discarding sourcing vbus! Invalid state SRC_SEND_CAPABILITIES [ 1195.957636] state change SRC_SEND_CAPABILITIES -> SNK_UNATTACHED [delayed 650 ms] [ 1195.957732] disable vbus discharge ret:0 [ 1195.970196] Start toggling [ 1195.970468] VBUS off [ 1196.051637] VBUS off [ 1196.051642] VBUS VSAFE0V
--- drivers/usb/typec/tcpm/tcpm.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
drivers/usb/typec/tcpm/tcpm.c +22 -6
@@ -5549,16 +5549,32 @@ static void tcpm_pd_event_handler(struct } }if (events &TCPM_SOURCING_VBUS ) { -tcpm_log (port,"sourcing vbus" );/* * In fast role swap case TCPC autonomously sources vbus. Set vbus_source -* true as TCPM wouldn't have called tcpm_set_vbus. +* true conditionally as TCPM wouldn't have called tcpm_set_vbus. +* If TCPM calls tcpm_set_vbus to source vbus, vbus_source would already +* be true. * -* When vbus is sourced on the command on TCPM i.e. TCPM called -* tcpm_set_vbus to source vbus, vbus_source would already be true. +* When TCPM_FRS_EVENT and TCPM_SOURCING_VBUS arrive simultaneously, +* handling TCPM_FRS_EVENT above transitions the state to AMS_START +* with upcoming_state FR_SWAP_SEND. */ - port->vbus_source = true; -_tcpm_pd_vbus_on (port); + +if (tcpm_port_is_source (port) || +tcpm_port_is_debug_source (port) || + (port->state ==AMS_START && port->upcoming_state ==FR_SWAP_SEND ) || + port->state ==FR_SWAP_SEND || + port->state ==FR_SWAP_SEND_TIMEOUT || + port->state ==FR_SWAP_SNK_SRC_TRANSITION_TO_OFF || + port->state ==FR_SWAP_SNK_SRC_NEW_SINK_READY || + port->state ==FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED ) { +tcpm_log (port,"sourcing vbus" ); + port->vbus_source = true; +_tcpm_pd_vbus_on (port); + }else { +tcpm_log (port,"Discarding sourcing vbus! Invalid state %s" , + tcpm_states[port->state]); + } }spin_lock (&port->pd_event_lock);
Greg Kroah-Hartman
maintainerPATCH 369/1887 xen/netfront: drop RX packets with a short Ethernet header
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik <[email protected]>
commit 089e58805c452e52179482b1025a8e309a57f801 upstream.
handle_incoming_queue() pulls pull_to bytes into the head before calling eth_type_trans(). pull_to is the length of the first RX slot, capped at RX_COPY_THRESHOLD, and that length comes from the backend. Nothing checks it against ETH_HLEN.
If the first slot is shorter than ETH_HLEN and more slots follow, the head ends up shorter than an Ethernet header while skb->len is longer, and eth_type_trans() BUG()s in __skb_pull(). If the whole packet is shorter than ETH_HLEN, eth_type_trans() reads the header past the end of the data instead.
Pull at least ETH_HLEN, and drop the packet if that fails, which also drops packets too short to hold an Ethernet header. This also checks the return value of the pull, which was ignored.
--- drivers/net/xen-netfront.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/net/xen-netfront.c +10 -2
@@ -1233,8 +1233,16 @@ static int handle_incoming_queue(structwhile ((skb =__skb_dequeue (rxq)) !=NULL ) {int pull_to =NETFRONT_SKB_CB (skb)->pull_to; -if (pull_to >skb_headlen (skb)) -__pskb_pull_tail (skb, pull_to -skb_headlen (skb)); +/* pull_to comes from the first slot's length, which the +* backend controls. Make sure the head holds at least an +* Ethernet header for eth_type_trans(). +*/ +if (!pskb_may_pull (skb,max (pull_to,ETH_HLEN ))) { +kfree_skb (skb); + packets_dropped++; + queue->info->netdev->stats.rx_errors++; +continue ; + }/* Ethernet work: Delayed to here as it peeks the header. */ skb->protocol =eth_type_trans (skb, queue->info->netdev);
Greg Kroah-Hartman
maintainerPATCH 370/1887 smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <[email protected]>
[ Upstream commit b8e5dc4f95e5484159b343903f302eb6d783f2e6 ]
When a file has the setuid or setgid bit set and is written to, the VFS strips those bits and issues a setattr with ATTR_KILL_SUID/ATTR_KILL_SGID together with an ATTR_MODE carrying the already-cleared mode.
Both cifs_setattr_unix() and cifs_setattr_nounix() unconditionally dropped ATTR_MODE in that case:
/* skip mode change if it's just for clearing setuid/setgid */ if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) attrs->ia_valid &= ~ATTR_MODE;
This is fine for the default mount, where the mode is only emulated via the DOS read-only attribute and cannot represent the setuid/setgid bits anyway. However, with the "cifsacl" or "modefromsid" mount options the mode is stored on the server through an ACL (id_mode_to_cifs_acl()), with the SMB3.1.1 POSIX extensions the mode is sent to the server directly, and with the SMB1 Unix extensions (cifs_setattr_unix) the mode is sent via CIFSSMBUnixSetPathInfo(). In all those cases dropping ATTR_MODE means the cleared mode is never pushed to the server, so the setuid/setgid bit survives the write.
This is a security issue: on local filesystems the setuid bit is stripped when a file is written, but over these cifs.ko mounts the bit persists on the server, potentially allowing an unexpected privilege escalation on subsequent execution.
Fix this in two places:
1. cifs_setattr_nounix(): only take the "skip mode change" shortcut when the mode is emulated via the DOS read-only attribute (i.e. neither cifsacl/modefromsid nor the SMB3.1.1 POSIX extensions are in effect), so that the cleared mode is propagated to the server in the ACL / POSIX cases.
2. cifs_setattr_unix(): this function is only called when Unix extensions are in effect, so the mode is always stored on the server. Remove the shortcut entirely so that the cleared mode is always pushed.
[ Backport note for 6.1: no sbflags local exists here, so test
cifs_sb->mnt_cifs_flags directly (same flag bits). Drop the upstream posix_extensions clause: 6.1 lacks d413eabff18d ("fs/smb/client:
implement chmod() for SMB3 POSIX Extensions"), so cifs_setattr_nounix() has no POSIX ATTR_MODE branch; match its CIFS_ACL/MODE_FROM_SID check. ]
--- fs/smb/client/inode.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
fs/smb/client/inode.c +23 -5
@@ -2827,9 +2827,13 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) goto out; } -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) - attrs->ia_valid &= ~ATTR_MODE ; +/* +* This function is only called when Unix extensions are in effect, +* so the mode is always sent to and stored on the server. Do not +* skip the mode change when clearing setuid/setgid bits: dropping +* ATTR_MODE here would leave those bits set on the server after a +* write, which is a security issue. +*/ args =kmalloc (sizeof (*args),GFP_KERNEL );if (args ==NULL ) {
@@ -3015,8 +3019,22 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)if (!(cifs_sb->mnt_cifs_flags &CIFS_MOUNT_SET_UID )) attrs->ia_valid &= ~(ATTR_UID |ATTR_GID ); -/* skip mode change if it's just for clearing setuid/setgid */ -if (attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) +/* +* Skip the mode change if it is only being done to clear the +* setuid/setgid bits *and* the mode is emulated via the DOS +* read-only attribute (the default, non-ACL case), which cannot +* represent the setuid/setgid bits anyway. +* +* When the mode is instead stored on the server - i.e. with the +* cifsacl or modefromsid mount options (via an ACL) - the cleared +* mode must be pushed to the server. Dropping ATTR_MODE here +* would leave the setuid/setgid bit set on the server after a +* write, which is a security issue (the bits are not stripped as +* they are on local filesystems). +*/ +if ((attrs->ia_valid & (ATTR_KILL_SUID |ATTR_KILL_SGID )) && + !(cifs_sb->mnt_cifs_flags & + (CIFS_MOUNT_CIFS_ACL |CIFS_MOUNT_MODE_FROM_SID ))) attrs->ia_valid &= ~ATTR_MODE ;if (attrs->ia_valid &ATTR_MODE ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 371/1887 bpf: Fix accesses to uninit stack slots
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrei Matei <[email protected]>
[ Upstream commit 6b4a64bafd107e521c01eec3453ce94a3fb38529 ]
Privileged programs are supposed to be able to read uninitialized stack memory (ever since 6715df8d5) but, before this patch, these accesses were permitted inconsistently. In particular, accesses were permitted above state->allocated_stack, but not below it. In other words, if the stack was already "large enough", the access was permitted, but otherwise the access was rejected instead of being allowed to "grow the stack". This undesired rejection was happening in two places:
- in check_stack_slot_within_bounds()
- in check_stack_range_initialized()
This patch arranges for these accesses to be permitted. A bunch of tests that were relying on the old rejection had to change; all of them were changed to add also run unprivileged, in which case the old behavior persists. One tests couldn't be updated - global_func16 - because it can't run unprivileged for other reasons.
This patch also fixes the tracking of the stack size for variable-offset reads. This second fix is bundled in the same commit as the first one because they're inter-related. Before this patch, writes to the stack using registers containing a variable offset (as opposed to registers with fixed, known values) were not properly contributing to the function's needed stack size. As a result, it was possible for a program to verify, but then to attempt to read out-of-bounds data at runtime because a too small stack had been allocated for it.
Each function tracks the size of the stack it needs in bpf_subprog_info.stack_depth, which is maintained by update_stack_depth(). For regular memory accesses, check_mem_access() was calling update_state_depth() but it was passing in only the fixed part of the offset register, ignoring the variable offset. This was incorrect; the minimum possible value of that register should be used instead.
This tracking is now fixed by centralizing the tracking of stack size in grow_stack_state(), and by lifting the calls to grow_stack_state() to check_stack_access_within_bounds() as suggested by Andrii. The code is now simpler and more convincingly tracks the correct maximum stack size. check_stack_range_initialized() can now rely on enough stack having been allocated for the access; this helps with the fix for the first issue.
A few tests were changed to also check the stack depth computation. The one that fails without this patch is verifier_var_off:stack_write_priv_vs_unpriv.
[ Resolved conflict in check_stack_write_var_off() by dropping grow_stack_state()
and omitting upstream dynptr logic not present in 6.1.y.
Adapted upstream test changes (progs/verifier_*.c) to 6.1.y's legacy test format in tools/testing/selftests/bpf/verifier/{basic_stack,raw_stack,var_off}.c. Omitted tests for features/files not present in 6.1.y (iters.c and verifier_int_ptr.c). ]
--- kernel/bpf/verifier.c | 66 ++++++++----------- .../selftests/bpf/progs/test_global_func16.c | 2 +- .../selftests/bpf/verifier/atomic_cmpxchg.c | 11 ---- .../selftests/bpf/verifier/basic_stack.c | 12 ++-- tools/testing/selftests/bpf/verifier/calls.c | 4 +- .../selftests/bpf/verifier/raw_stack.c | 8 ++- .../testing/selftests/bpf/verifier/var_off.c | 57 ++++++++++++---- 7 files changed, 89 insertions(+), 71 deletions(-)
kernel/bpf/verifier.c +26 -40
@@ -1026,7 +1026,10 @@ static int resize_reference_state(struct bpf_func_state *state, size_t n)return 0 ; } -static int grow_stack_state (struct bpf_func_state *state,int size) +/* Possibly update state->allocated_stack to be at least size bytes. Also +* possibly update the function's high-water mark in its bpf_subprog_info. +*/ +static int grow_stack_state (struct bpf_verifier_env *env,struct bpf_func_state *state,int size) {size_t old_n = state->allocated_stack /BPF_REG_SIZE , n = size /BPF_REG_SIZE ;
@@ -1038,6 +1041,11 @@ static int grow_stack_state(struct bpf_func_state *state, int size)return -ENOMEM ; state->allocated_stack = size; + +/* update known max for given subprogram */ +if (env->subprog_info[state->subprogno].stack_depth < size) + env->subprog_info[state->subprogno].stack_depth = size; +return 0 ; }
@@ -3214,9 +3222,6 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,struct bpf_reg_state *reg =NULL ;u32 dst_reg = insn->dst_reg; - err =grow_stack_state (state,round_up (slot +1 ,BPF_REG_SIZE )); -if (err) -return err;/* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0, * so it's aligned access and [off, off + size) are within stack limits */
@@ -3367,11 +3372,6 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env,if (value_reg &®ister_is_null (value_reg)) writing_zero = true; - err =grow_stack_state (state,round_up (-min_off,BPF_REG_SIZE )); -if (err) -return err; - -/* Variable offset writes destroy any spilled pointers in range. */ for (i = min_off; i < max_off; i++) {u8 new_type, *stype;
@@ -4406,20 +4406,6 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, strict); } -static int update_stack_depth (struct bpf_verifier_env *env, -const struct bpf_func_state *func, -int off) -{ -u16 stack = env->subprog_info[func->subprogno].stack_depth; - -if (stack >= -off) -return 0 ; - -/* update known max for given subprogram */ - env->subprog_info[func->subprogno].stack_depth = -off; -return 0 ; -} -/* starting from main bpf function walk all instructions of the function * and recursively walk all callees that given function can call. * Ignore jump and exit insns.
@@ -4849,13 +4835,14 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,* The minimum valid offset is -MAX_BPF_STACK for writes, and * -state->allocated_stack for reads. */ -static int check_stack_slot_within_bounds (s64 off, -struct bpf_func_state *state, -enum bpf_access_type t) +static int check_stack_slot_within_bounds (struct bpf_verifier_env *env, +s64 off, +struct bpf_func_state *state, +enum bpf_access_type t) {int min_valid_off; -if (t ==BPF_WRITE ) +if (t ==BPF_WRITE || env->allow_uninit_stack) min_valid_off = -MAX_BPF_STACK ;else min_valid_off = -state->allocated_stack;
@@ -4904,7 +4891,7 @@ static int check_stack_access_within_bounds( max_off = reg->smax_value + off + access_size; } - err =check_stack_slot_within_bounds (min_off, state, type); + err =check_stack_slot_within_bounds (env, min_off, state, type);if (!err && max_off >0 ) err = -EINVAL ;/* out of stack access into non-negative offsets */ if (!err && access_size <0 )
@@ -4924,8 +4911,10 @@ static int check_stack_access_within_bounds(verbose (env,"invalid variable-offset%s stack R%d var_off=%s size=%d\n" , err_extra, regno, tn_buf, access_size); } +return err; } -return err; + +return grow_stack_state (env, state,round_up (-min_off,BPF_REG_SIZE )); }/* check whether memory at (regno + off) is accessible for t = (read | write)
@@ -4940,7 +4929,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn {struct bpf_reg_state *regs =cur_regs (env);struct bpf_reg_state *reg = regs + regno; -struct bpf_func_state *state;int size, err =0 ; size =bpf_size_to_bytes (bpf_size);
@@ -5084,11 +5072,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regnif (err)return err; - state =func (env, reg); - err =update_stack_depth (env, state, off); -if (err) -return err; -if (t ==BPF_READ ) err =check_stack_read (env, regno, off, size, value_regno);
@@ -5281,7 +5264,8 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i/* When register 'regno' is used to read the stack (either directly or through * a helper function) make sure that it's within stack boundary and, depending -* on the access type, that all elements of the stack are initialized. +* on the access type and privileges, that all elements of the stack are +* initialized. * * 'off' includes 'regno->off', but not its dynamic part (if any). *
@@ -5364,8 +5348,11 @@ static int check_stack_range_initialized( slot = -i -1 ; spi = slot /BPF_REG_SIZE ; -if (state->allocated_stack <= slot) - goto err; +if (state->allocated_stack <= slot) { +verbose (env,"verifier bug: allocated_stack too small" ); +return -EFAULT ; + } + stype = &state->stack[spi].slot_type[slot %BPF_REG_SIZE ];if (*stype ==STACK_MISC ) goto mark;
@@ -5389,7 +5376,6 @@ static int check_stack_range_initialized( goto mark; } -err:if (tnum_is_const (reg->var_off)) {verbose (env,"invalid%s read from stack R%d off %d+%d size %d\n" , err_extra, regno, min_off, i - min_off, access_size);
@@ -5414,7 +5400,7 @@ static int check_stack_range_initialized(* helper may write to the entire memory range. */ } -return update_stack_depth (env, state, min_off); +return 0 ; } static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
tools/testing/selftests/bpf/progs/test_global_func16.c +1 -1
@@ -13,7 +13,7 @@ __noinline int foo(int (*arr)[10]) } SEC("cgroup_skb/ingress") -__failure __msg("invalid indirect read from stack") +__successint global_func16 (struct __sk_buff *skb) {int array[10 ];
tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c +0 -11
@@ -83,17 +83,6 @@ .result = REJECT, .errstr = "!read_ok", }, -{ - "Can't use cmpxchg on uninit memory", - .insns = { -BPF_MOV64_IMM (BPF_REG_0 ,3 ), -BPF_MOV64_IMM (BPF_REG_2 ,4 ), -BPF_ATOMIC_OP (BPF_DW ,BPF_CMPXCHG ,BPF_REG_10 ,BPF_REG_2 ,-8 ), - BPF_EXIT_INSN(), - }, - .result =REJECT , - .errstr = "invalid read from stack", -}, { "BPF_W cmpxchg should zero top 32 bits", .insns = {
tools/testing/selftests/bpf/verifier/basic_stack.c +8 -4
@@ -17,8 +17,10 @@ BPF_EXIT_INSN(), }, .fixup_map_hash_8b = { 2 }, - .errstr = "invalid indirect read from stack", - .result =REJECT , + .result = ACCEPT, + .retval = POINTER_VALUE, + .result_unpriv = REJECT, + .errstr_unpriv ="invalid indirect read from stack" , }, { "uninitialized stack2",
@@ -27,8 +29,10 @@BPF_LDX_MEM (BPF_DW ,BPF_REG_0 ,BPF_REG_2 ,-8 ), BPF_EXIT_INSN(), }, - .errstr ="invalid read from stack" , - .result = REJECT, + .result =ACCEPT , + .retval = POINTER_VALUE, + .result_unpriv = REJECT, + .errstr_unpriv = "invalid read from stack", }, { "invalid fp arithmetic",
tools/testing/selftests/bpf/verifier/calls.c +3 -1
@@ -1501,7 +1501,9 @@ .prog_type = BPF_PROG_TYPE_XDP, .fixup_map_hash_8b = { 23 }, .result = REJECT, - .errstr ="invalid read from stack R7 off=-16 size=8" , + .errstr = "R0 invalid mem access 'scalar'", + .result_unpriv = REJECT, + .errstr_unpriv ="invalid read from stack R7 off=-16 size=8" , }, { "calls: two calls that receive map_value via arg=ptr_stack_of_caller. test1",
tools/testing/selftests/bpf/verifier/raw_stack.c +5 -3
@@ -10,9 +10,11 @@BPF_LDX_MEM (BPF_DW ,BPF_REG_0 ,BPF_REG_6 ,0 ), BPF_EXIT_INSN(), }, - .result =REJECT , - .errstr = "invalid read from stack R6 off=-8 size=8", - .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result =ACCEPT , + .retval = POINTER_VALUE, + .result_unpriv = REJECT, + .errstr_unpriv = "invalid read from stack R6 off=-8 size=8", + .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, }, { "raw_stack: skb_load_bytes, negative len",
tools/testing/selftests/bpf/verifier/var_off.c +46 -11
79 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 372/1887 soc: qcom: geni-se: Correct QUP Core ICC vote constants
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viken Dadhaniya <[email protected]>
[ Upstream commit 1cd9b1be5a9c56fd69e3f555b200a1844f9b873e ]
The GENI_TO_CORE ("qup-core") ICC vote selects the QUP Core 2X clock rate. The CORE_2X_*_MHZ constants are expressed in Bps, but their values are several orders of magnitude too small. For example, the 50 MHz threshold is represented by 2500 rather than 25000000 Bps.
As a result, clients using these constants can severely under-vote the QUP Core clock.
Correct the constants to their intended Bps thresholds so that the ICC provider selects the corresponding QUP Core 2X clock rate. Drop the unused definitions.
--- include/linux/qcom-geni-se.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-)
include/linux/qcom-geni-se.h +5 -10
@@ -265,17 +265,12 @@ struct geni_se {#define QUP_SE_VERSION_2_5 0x20050000/* -* Define bandwidth thresholds that cause the underlying Core 2X interconnect -* clock to run at the named frequency. These baseline values are recommended -* by the hardware team, and are not dynamically scaled with GENI bandwidth -* beyond basic on/off. +* QUP Core 2X clock votes used by GENI clients through the "qup-core" ICC +* path. Values are in Bps and must be converted with Bps_to_icc() before +* setting avg_bw. */ -#define CORE_2X_19_2_MHZ 960 -#define CORE_2X_50_MHZ 2500 -#define CORE_2X_100_MHZ 5000 -#define CORE_2X_150_MHZ 7500 -#define CORE_2X_200_MHZ 10000 -#define CORE_2X_236_MHZ 16383 +#define CORE_2X_19_2_MHZ 9600000 +#define CORE_2X_50_MHZ 25000000#define GENI_DEFAULT_BW Bps_to_icc(1000)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 373/1887 usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiazi Liu <[email protected]>
[ Upstream commit 1ff77cbefe5a653ea12874c213ea4bd0d72c1067 ]
When dwc3_check_event_buf() reads a GEVNTCOUNT value exceeding the event buffer length, commit 63ccd26cd1f6 ("usb: dwc3: gadget: check that event count does not exceed event buffer length") returns IRQ_NONE without writing back GEVNTCOUNT. Since the DWC3 interrupt is level-triggered, the uncleared IRQ source keeps the line asserted, causing a tight IRQ storm that accumulates 99,900 unhandled interrupts and triggers spurious.c:184 BUG -> kernel panic.
The resulting call stack:
__report_bad_irq+0xac/0xc8 note_interrupt+0x340/0x468 handle_irq_event+0xac/0xc0 handle_fasteoi_irq+0x120/0x228 gic_handle_irq+0x68/0x108 ... kernel BUG at kernel/irq/spurious.c:184
To reproduce, write a bogus value exceeding the event buffer length directly to the GEVNTCOUNT register:
devmem <DWC3_BASE + 0xc40c> 4 0x1004
Write the bogus count back to GEVNTCOUNT to clear the IRQ source, consistent with the stale event clearing pattern in dwc3_event_buffers_setup(), and schedule error recovery to reinitialize the controller.
--- drivers/usb/dwc3/core.h | 19 +++++++ drivers/usb/dwc3/ep0.c | 9 ++++ drivers/usb/dwc3/gadget.c | 104 +++++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-)
drivers/usb/dwc3/core.h +19 -0
@@ -42,6 +42,7 @@#define DWC3_ENDPOINTS_NUM 32#define DWC3_XHCI_RESOURCES_NUM 2#define DWC3_ISOC_MAX_RETRIES 5 +#define DWC3_ERR_RECOVERY_MAX 3#define DWC3_SCRATCHBUF_SIZE 4096/* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096
@@ -817,6 +818,12 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; +enum dwc3_err_state { +DWC3_ERR_NONE =0 , +DWC3_ERR_RECOVERY , +DWC3_ERR_UNRECOVERABLE , +}; +/* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff)#define DWC3_TRB_SIZE_LENGTH (n) ((n) & DWC3_TRB_SIZE_MASK)
@@ -972,6 +979,7 @@ struct dwc3_scratchpad_array {/** * struct dwc3 - representation of our controller * @drd_work: workqueue used for role swapping +* @err_recovery_work: workqueue used for controller error recovery * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer * @scratchbuf: address of scratch buffer
@@ -983,6 +991,7 @@ struct dwc3_scratchpad_array {* @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching +* @connect_mutex: for the pull-up and err_recovery_work * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child
@@ -1041,6 +1050,9 @@ struct dwc3_scratchpad_array {* @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state +* @err_state: current error recovery state. +* @err_recovery_count: number of consecutive error recovery attempts until +* confirmed healthy and reset to 0 on reset event. * @speed: device speed (super, high, full, low) * @hwparams: copy of hwparams registers * @regset: debugfs pointer to regdump file
@@ -1133,6 +1145,7 @@ struct dwc3_scratchpad_array {*/ struct dwc3 {struct work_struct drd_work; +struct work_struct err_recovery_work;struct dwc3_trb *ep0_trb;void *bounce;void *scratchbuf;
@@ -1149,6 +1162,9 @@ struct dwc3 {/* mode switching lock */ struct mutex mutex; +/* serializes pull-up run/stop vs error recovery */ +struct mutex connect_mutex; +struct device *dev;struct device *sysdev;
@@ -1265,6 +1281,9 @@ struct dwc3 {enum dwc3_ep0_next ep0_next_event;enum dwc3_ep0_state ep0state;enum dwc3_link_state link_state; +enum dwc3_err_state err_state; + +u32 err_recovery_count;u16 u2sel;u16 u2pel;
drivers/usb/dwc3/ep0.c +9 -0
@@ -198,6 +198,11 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { + ret = -ESHUTDOWN ; + goto out; + } +if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {dev_err (dwc->dev,"%s: can't queue to disabled endpoint\n" , dep->name);
@@ -269,6 +274,10 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)int ret;spin_lock_irqsave (&dwc->lock, flags); +if (dwc->err_state !=DWC3_ERR_NONE ) { +spin_unlock_irqrestore (&dwc->lock, flags); +return -ESHUTDOWN ; + } ret =__dwc3_gadget_ep0_set_halt (ep, value);spin_unlock_irqrestore (&dwc->lock, flags);
drivers/usb/dwc3/gadget.c +102 -2
181 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 374/1887 tty: fix saved termios reset race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 8df07fe93573e9e548d6645273e9bcb6eb74059e ]
Resetting saved termios state on device registration is needed where a minor number can be reused for an entirely different device and where the old settings may prevent the port from even being opened (e.g. when CLOCAL is not set).
Not all TTY drivers guarantee that the minor number is no longer in use when registering devices however, something which can lead to a use-after-free when closing a TTY (and saving its termios) races with re-registration.
Add a new TTY_DRIVER_RESET_SAVED_TERMIOS flag to request that any saved termios state is reset on registration and only set it for drivers that make sure that the minor number is no longer in use.
--- drivers/staging/greybus/uart.c | 3 ++- drivers/tty/tty_io.c | 18 ++++++++++-------- drivers/usb/class/cdc-acm.c | 2 +- drivers/usb/serial/usb-serial.c | 3 ++- include/linux/tty_driver.h | 6 ++++++ 5 files changed, 21 insertions(+), 11 deletions(-)
drivers/staging/greybus/uart.c +2 -1
@@ -954,7 +954,8 @@ static int gb_tty_init(void) gb_tty_driver->minor_start =0 ; gb_tty_driver->type =TTY_DRIVER_TYPE_SERIAL ; gb_tty_driver->subtype =SERIAL_TYPE_NORMAL ; - gb_tty_driver->flags =TTY_DRIVER_REAL_RAW |TTY_DRIVER_DYNAMIC_DEV ; + gb_tty_driver->flags =TTY_DRIVER_REAL_RAW |TTY_DRIVER_DYNAMIC_DEV | +TTY_DRIVER_RESET_SAVED_TERMIOS ; gb_tty_driver->init_termios = tty_std_termios; gb_tty_driver->init_termios.c_cflag =B9600 |CS8 |CREAD |HUPCL |CLOCAL ;
drivers/tty/tty_io.c +10 -8
@@ -3272,14 +3272,16 @@ struct device *tty_register_device_attr(struct tty_driver *driver, goto err_put;if (!(driver->flags &TTY_DRIVER_DYNAMIC_ALLOC )) { -/* -* Free any saved termios data so that the termios state is -* reset when reusing a minor number. -*/ - tp = driver->termios[index]; -if (tp) { - driver->termios[index] =NULL ; -kfree (tp); +if (driver->flags &TTY_DRIVER_RESET_SAVED_TERMIOS ) { +/* +* Free any saved termios data so that the termios +* state is reset when reusing a minor number. +*/ + tp = driver->termios[index]; +if (tp) { + driver->termios[index] =NULL ; +kfree (tp); + } } retval =tty_cdev_add (driver, devt, index,1 );
drivers/usb/class/cdc-acm.c +1 -1
@@ -2119,7 +2119,7 @@ static int __init acm_init(void) {int retval; acm_tty_driver =tty_alloc_driver (ACM_TTY_MINORS ,TTY_DRIVER_REAL_RAW | -TTY_DRIVER_DYNAMIC_DEV ); +TTY_DRIVER_DYNAMIC_DEV |TTY_DRIVER_RESET_SAVED_TERMIOS );if (IS_ERR (acm_tty_driver))return PTR_ERR (acm_tty_driver); acm_tty_driver->driver_name = "acm",
drivers/usb/serial/usb-serial.c +2 -1
@@ -1321,7 +1321,8 @@ static int __init usb_serial_init(void)int result; usb_serial_tty_driver =tty_alloc_driver (USB_SERIAL_TTY_MINORS , -TTY_DRIVER_REAL_RAW |TTY_DRIVER_DYNAMIC_DEV ); +TTY_DRIVER_REAL_RAW |TTY_DRIVER_DYNAMIC_DEV | +TTY_DRIVER_RESET_SAVED_TERMIOS );if (IS_ERR (usb_serial_tty_driver))return PTR_ERR (usb_serial_tty_driver);
include/linux/tty_driver.h +6 -0
@@ -542,6 +542,11 @@ static inline void tty_set_operations(struct tty_driver *driver,* Do not create numbered ``/dev`` nodes. For example, create * ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a * driver for a single tty device is being allocated. +* +* TTY_DRIVER_RESET_SAVED_TERMIOS +* Reset any saved termios settings on device registration when reusing a +* minor number. Must only be set by drivers that guarantee that the minor +* number is no longer in use. */ #define TTY_DRIVER_INSTALLED 0x0001#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -551,6 +556,7 @@ static inline void tty_set_operations(struct tty_driver *driver,#define TTY_DRIVER_HARDWARE_BREAK 0x0020#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040#define TTY_DRIVER_UNNUMBERED_NODE 0x0080 +#define TTY_DRIVER_RESET_SAVED_TERMIOS 0x0200/* tty driver types */ #define TTY_DRIVER_TYPE_SYSTEM 0x0001
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 375/1887 perf: Require kernel access for text poke events
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengchuan Liang <[email protected]>
[ Upstream commit 357e8a77a501d96c9517f01f4a211eed5e9c9184 ]
Perf events with exclude_kernel=1 can be opened without kernel perf access. However, exclude_kernel does not suppress text-poke sideband records. Every PERF_RECORD_TEXT_POKE is marked PERF_RECORD_MISC_KERNEL and contains a raw kernel instruction address.
An unprivileged task can therefore open and mmap a task-local software event with text_poke=1. Both opening a count-only tracepoint event and configuring UDP GRO for ESP-in-UDP cause updates to inline static calls; the observer receives the relocated addresses of the modified instructions. For a known kernel image, any such address reveals the runtime kernel text base despite KASLR.
Call perf_allow_kernel() whenever attr.text_poke is set, regardless of exclude_kernel. Events that neither monitor kernel execution nor request text-poke records retain their existing permissions.
--- kernel/events/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/core.c +1 -1
@@ -12458,7 +12458,7 @@ SYSCALL_DEFINE5(perf_event_open,if (err)return err; -if (!attr.exclude_kernel) { +if (!attr.exclude_kernel || attr.text_poke) { err =perf_allow_kernel (&attr);if (err)return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 376/1887 arm64/fpsimd: signal: Forbid non-streaming SVE payload on SME-only systems
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
[ Upstream commit e060d9069b49fe55f38057dfe592068014652671 ]
When system_supports_sme() is true but system_supports_sve() is false, restoring a specifically crafted SVE signal context can result in the task erroneously having non-streaming SVE state. Subsequent attempts to manipulate the task's FPSIMD/SVE/SME state can result in a variety of problems, including fatal EL1 UNDEFs.
In such configurations, the kernel always creates an SVE signal context when delivering a signal, and this can only be in one of two states:
(1) SVE_SIG_FLAG_SM is set, and an SVE payload is present containing streaming mode SVE state. The recorded VL is the task's live streaming VL.
(2) SVE_SIG_FLAG_SM is clear, and an SVE payload is not present. The FPSIMD context contains the non-streaming mode FPSIMD state. The recorded VL is 0.
Currently restore_sve_fpsimd_context() correctly rejects cases where SVE_SIG_FLAG_SM is set and an SVE payload is not present, but fails to reject cases where SVE_SIG_FLAG_SM is clear and an SVE payload is present. Consequently, restore_sve_fpsimd_context() can place the task in a state where it has non-streaming SVE state even when this is not supported by HW.
For example, this can cause a later EL1 UNDEF when the kernel attempts to restore the task's ZCR_EL1 value:
| # ./sme-sigcontext-to-sve | Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP | Modules linked in: | CPU: 0 UID: 0 PID: 131 Comm: sme-sigcontext- Not tainted 7.3.0-rc1 #1 PREEMPT | Hardware name: linux,dummy-virt (DT) | pstate: 61402009 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) | pc : fpsimd_restore_current_state+0x258/0x458 | lr : exit_to_user_mode_loop+0xb8/0x188 | sp : ffff80008056be40 | x29: ffff80008056be40 x28: fff00000c1670000 x27: 0000000000000000 | x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000 | x23: ffff80008056bec0 x22: 0000000000000008 x21: 0000000000000040 | x20: 0000000000000081 x19: 0000000008800010 x18: 0000000000000000 | x17: 0000fffffd412570 x16: 0000000000001000 x15: 0000fffffd4123b0 | x14: 0000fffffd412780 x13: 0000fffffd412be8 x12: 0000000047435300 | x11: 0000fffffd412570 x10: 0000000000000000 x9 : 0000000045585401 | x8 : fff00000c18a6c44 x7 : 0000000000000000 x6 : 0000000000000002 | x5 : 0000000000000002 x4 : ffff800080568000 x3 : 0000000000000001 | x2 : 0000000008800010 x1 : fff00000c1670000 x0 : 0000000008800000 | Call trace: | fpsimd_restore_current_state+0x258/0x458 (P) | exit_to_user_mode_loop+0xb8/0x188 | el0_svc+0x1cc/0x1d0 | el0t_64_sync_handler+0xa0/0xe4 | el0t_64_sync+0x198/0x19c | Code: d5384101 f9400020 53175c03 36b80de0 (d5381202) | ---[ end trace 0000000000000000 ]--- | Kernel panic - not syncing: Oops - Undefined instruction: Fatal exception in interrupt | Kernel Offset: 0x291fb1000000 from 0xffff800080000000 | PHYS_OFFSET: 0x40000000 | CPU features: 0x0,00000000,0052802f,ffb88f43,3afcf73f | Memory Limit: none
Rework restore_sve_fpsimd_context() to reject cases where SVE_SIG_FLAG_SM is clear and an SVE payload is not present. As parse_user_sigframe() rejects SVE signal frames when neither SVE nor SME are supported, it isn't necessary for restore_sve_fpsimd_context() to handle the case where neither are supported.
--- arch/arm64/kernel/signal.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
arch/arm64/kernel/signal.c +20 -5
@@ -271,22 +271,37 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)unsigned int vl, vq;struct user_fpsimd_state fpsimd;struct sve_context sve; +bool fpsimd_only;if (__copy_from_user (&sve, user->sve,sizeof (sve)))return -EFAULT ; + fpsimd_only = (sve.head.size <=sizeof (*user->sve)); +if (sve.flags &SVE_SIG_FLAG_SM ) {if (!system_supports_sme ())return -EINVAL ; +/* +* Streaming SVE state is always preserved with an SVE payload. +* Only accept streaming state which has an SVE payload. +*/ +if (fpsimd_only) +return -EINVAL ; + vl =task_get_sme_vl (current); }else {/* -* A SME only system use SVE for streaming mode so can -* have a SVE formatted context with a zero VL and no -* payload data. +* Non-streaming SVE state may be preserved without an SVE +* payload, in which case all state is saved in the FPSIMD +* context. +* +* On SME-only systems, non-streaming (FPSIMD-only) state is +* always preserved without an SVE payload, and with VL==0. On +* such systems, only accept non-streaming state without an SVE +* payload. */ -if (!system_supports_sve () && !system_supports_sme ()) +if (!system_supports_sve () && !fpsimd_only)return -EINVAL ; vl =task_get_sve_vl (current);
@@ -295,7 +310,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)if (sve.vl != vl)return -EINVAL ; -if (sve.head.size <=sizeof (*user->sve)) { +if (fpsimd_only) {clear_thread_flag (TIF_SVE ); current->thread.svcr &= ~SVCR_SM_MASK ; current->thread.fp_type =FP_STATE_FPSIMD ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 377/1887 arm64: errata: Factor out broken AMU const counter cap
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Beata Michalska <[email protected]>
[ Upstream commit 573371caf7aea8582212da81dcead2c3f48fac4b ]
Move the workaround from the erratum 2457168-specific cpucap to a generic broken AMU constant-counter one. This keeps the existing Cortex-A510 handling unchanged while allowing other errata with similar AMU constant counter issue to share the capability bit and call sites.
--- arch/arm64/Kconfig | 8 ++++++++ arch/arm64/kernel/cpu_errata.c | 20 ++++++++++++++------ arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/topology.c | 2 +- arch/arm64/tools/cpucaps | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-)
arch/arm64/Kconfig +8 -0
@@ -966,9 +966,17 @@ config ARM64_ERRATUM_1902691 If unsure, say Y. +config ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT + bool + # Targeting errata affecting AMEVCNTR01, the AMU constant counter. + # On affected CPUs the counter may not increment at the expected rate, + # making it unreliable. As a result, AMU users should treat it as + # unavailable rather than relying on misleading counter values. + config ARM64_ERRATUM_2457168 bool "Cortex-A510: 2457168: workaround for AMEVCNTR01 incrementing incorrectly" depends on ARM64_AMU_EXTN + select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT default y help This option adds the workaround for ARM Cortex-A510 erratum 2457168.
arch/arm64/kernel/cpu_errata.c +14 -6
@@ -275,6 +275,16 @@ static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = { };#endif +#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT +static const struct midr_range workaround_amu_constcnt_list[] = { +#ifdef CONFIG_ARM64_ERRATUM_2457168 +/* Cortex-A510 r0p0-r1p1 */ +MIDR_RANGE (MIDR_CORTEX_A510 ,0 ,0 ,1 ,1 ), +#endif + {} +}; +#endif /* CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT */ +#ifdef CONFIG_CAVIUM_ERRATUM_23154 static const struct midr_range cavium_erratum_23154_cpus[] = { MIDR_ALL_VERSIONS(MIDR_THUNDERX),
@@ -737,14 +747,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2) },#endif -#ifdef CONFIG_ARM64_ERRATUM_2457168 +#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT { - .desc = "ARM erratum 2457168", - .capability = ARM64_WORKAROUND_2457168, + .desc = "Broken AMU AMEVCNTR01 (const counter)", + .capability = ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT, .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE, - - /* Cortex-A510 r0p0-r1p1 */ - CAP_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1) + CAP_MIDR_RANGE_LIST(workaround_amu_constcnt_list) }, #endif #ifdef CONFIG_ARM64_ERRATUM_2038923
arch/arm64/kernel/cpufeature.c +1 -1
@@ -1907,7 +1907,7 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)cpumask_set_cpu (smp_processor_id (), &amu_cpus);/* 0 reference values signal broken/disabled counters */ -if (!this_cpu_has_cap (ARM64_WORKAROUND_2457168 )) +if (!this_cpu_has_cap (ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT ))update_freq_counters_refs (); } }
arch/arm64/kernel/topology.c +1 -1
@@ -273,7 +273,7 @@ static void cpu_read_constcnt(void *val)* the counter is disabled. A return value of 0 at counter read is * properly handled as an error case by the users of the counter. */ - *(u64 *)val =this_cpu_has_cap (ARM64_WORKAROUND_2457168 ) ? + *(u64 *)val =this_cpu_has_cap (ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT ) ?0UL :read_constcnt (); }
arch/arm64/tools/cpucaps +1 -1
@@ -69,7 +69,6 @@ WORKAROUND_1902691 WORKAROUND_2038923 WORKAROUND_2064142 WORKAROUND_2077057 -WORKAROUND_2457168 WORKAROUND_2658417 WORKAROUND_AMPERE_AC03_CPU_38 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
@@ -88,3 +87,4 @@ WORKAROUND_REPEAT_TLBI WORKAROUND_SPECULATIVE_AT WORKAROUND_SPECULATIVE_SSBS WORKAROUND_SPECULATIVE_UNPRIV_LOAD +WORKAROUND_BROKEN_AMU_CONSTCNT
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 378/1887 arm64: errata: Add Cortex-A725 erratum 3821522 workaround
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Beata Michalska <[email protected]>
[ Upstream commit 45f7304679875eb000d67e194090ee7abd05c89c ]
Cortex-A725 erratum 3821522 affects the CNT_CYCLES event, which can incur a significant increment error when a CPU enters and subsequently exits WFE or WFI, and may no longer track the system counter frequency.
The AMEVCNTR01_EL0 counter is used as the AMU constant counter for frequency invariance and CPPC FFH feedback counters. Wire the affected Cortex-A725 range into the shared broken AMU constant-counter capability so the affected counter is treated as unavailable by returning zero in the AMU counter paths. This prevents the broken counter from being used as a reference source.
The erratum can also affect PMUv3 users of the CNT_CYCLES event, but this workaround intentionally does not change PMU event handling. Hiding or rejecting the PMU event from the erratum code would change the perf-visible PMU event interface, including raw event selection, and would need a separate PMU-specific approach rather than being folded into the AMU reference-counter workaround.
--- Documentation/arm64/silicon-errata.rst | 2 ++ arch/arm64/Kconfig | 22 ++++++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 4 ++++ arch/arm64/kernel/topology.c | 9 +++++---- 4 files changed, 33 insertions(+), 4 deletions(-)
Documentation/arm64/silicon-errata.rst +2 -0
@@ -155,6 +155,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A725 | #3456106 | ARM64_ERRATUM_3194386 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A725 | #3821522 | ARM64_ERRATUM_3821522 | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X1 | #3324344 | ARM64_ERRATUM_3194386 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X1 | #4193791 | ARM64_ERRATUM_4118414 |
arch/arm64/Kconfig +22 -0
@@ -991,6 +991,28 @@ config ARM64_ERRATUM_2457168 If unsure, say Y. +config ARM64_ERRATUM_3821522 + bool "Cortex-A725: 3821522: workaround for possible CNT_CYCLES increment error due to WFE/WFI" + depends on ARM64_AMU_EXTN + select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT + default y + help + This option adds the workaround for ARM Cortex-A725 erratum 3821522. + + On affected A725 cores, the CNT_CYCLES event may incur a significant + increment error when entering and subsequently exiting WFx. + As a result, the CNT_CYCLES may diverge from the system counter + frequency at which it is expected to increment. + This renders the AMU counter AMEVCNTR01, that implements CNT_CYCLES, + being unreliable and unsuitable for use. + + Since there is no hardware workaround, reads of the affected CNT_CYCLES + counter return 0 in the relevant paths. This causes users of the counter + to treat it as unavailable and is functionally equivalent to firmware + disabling the affected counter. + + If unsure, say Y. + config ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD bool
arch/arm64/kernel/cpu_errata.c +4 -0
@@ -280,6 +280,10 @@ static const struct midr_range workaround_amu_constcnt_list[] = {#ifdef CONFIG_ARM64_ERRATUM_2457168 /* Cortex-A510 r0p0-r1p1 */ MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1), +#endif +#ifdef CONFIG_ARM64_ERRATUM_3821522 +/* Cortex-A725 r0p0 - r0p2 */ + MIDR_RANGE(MIDR_CORTEX_A725, 0, 0, 0, 2),#endif {} };
arch/arm64/kernel/topology.c +5 -4
@@ -268,10 +268,11 @@ static void cpu_read_corecnt(void *val)static void cpu_read_constcnt (void *val) {/* -* Return 0 if the current CPU is affected by erratum 2457168. A value -* of 0 is also returned if the current CPU does not support AMUs or if -* the counter is disabled. A return value of 0 at counter read is -* properly handled as an error case by the users of the counter. +* Return 0 if the current CPU is affected by a HW erratum. +* A value of 0 is also returned if the current CPU does not +* support AMUs or if the counter is disabled. A return +* value of 0 at counter read is properly handled as an error +* case by the users of the counter. */ *(u64 *)val =this_cpu_has_cap (ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT ) ?0UL :read_constcnt ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 379/1887 iio: buffer: serialize buffer teardown with mode claims
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinseob Kim <[email protected]>
commit 84bb0fc46ccf6a545b8fdf57cda83770186ed8dd upstream.
Buffer-mode claims hold mlock to guarantee that the device remains in buffer mode until the claim is released. Normal buffer updates take info_exist_lock followed by mlock in iio_update_buffers().
However, iio_device_unregister() disables and deactivates all buffers without taking mlock. This can invalidate buffer state, including active_scan_mask, while a buffer-mode claim is held.
Take mlock in iio_disable_all_buffers() so that unregister honors the mode-claim lifetime guarantee. The info_exist_lock -> mlock ordering matches iio_update_buffers().
[ Backport by Jinseob Kim to 6.1.y: mlock is still in struct iio_dev,
so use indio_dev->mlock instead of iio_dev_opaque->mlock. ]
--- drivers/iio/industrialio-buffer.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/industrialio-buffer.c +2 -0
@@ -1291,6 +1291,8 @@ EXPORT_SYMBOL_GPL(iio_update_buffers);void iio_disable_all_buffers (struct iio_dev *indio_dev) { +guard (mutex)(&indio_dev->mlock); +iio_disable_buffers (indio_dev);iio_buffer_deactivate_all (indio_dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 380/1887 KVM: arm64: Dont use the VMA to size stage-2 block mappings for VM_PFNMAP
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mostafa Saleh <[email protected]>
[ Upstream commit 71cc2c67fb8f8d5aa8154eb482e9846d2214f11b ]
get_vma_page_shift() derives the stage-2 block size for VM_PFNMAP VMAs from the VMA layout alone, which does not necessarily match what stage-1 maps for that VMA.
Upstream commit 71cc2c67fb8f ("KVM: arm64: Use stage-1 leaf size for VM_PFNMAP") drops that calculation and lets transparent_hugepage_adjust() derive the mapping size from the stage-1 leaf instead. The second part is not applicable here: in this kernel transparent_hugepage_adjust() takes a reference on the backing struct page, which is not safe for MMIO, and stage-1 has no huge PFNMAP before v6.12 anyway. Only drop the VMA-based calculation, so VM_PFNMAP VMAs are mapped at PAGE_SIZE.
--- arch/arm64/kvm/mmu.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-)
arch/arm64/kvm/mmu.c +2 -23
@@ -1077,32 +1077,11 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,return PAGE_SIZE ; } -static int get_vma_page_shift (struct vm_area_struct *vma,unsigned long hva) +static int get_vma_page_shift (struct vm_area_struct *vma) { -unsigned long pa; -if (is_vm_hugetlb_page (vma) && !(vma->vm_flags &VM_PFNMAP ))return huge_page_shift (hstate_vma (vma)); -if (!(vma->vm_flags &VM_PFNMAP )) -return PAGE_SHIFT ; - -VM_BUG_ON (is_vm_hugetlb_page (vma)); - - pa = (vma->vm_pgoff <<PAGE_SHIFT ) + (hva - vma->vm_start); - -#ifndef __PAGETABLE_PMD_FOLDED -if ((hva & (PUD_SIZE -1 )) == (pa & (PUD_SIZE -1 )) && -ALIGN_DOWN (hva,PUD_SIZE ) >= vma->vm_start && -ALIGN (hva,PUD_SIZE ) <= vma->vm_end) -return PUD_SHIFT ; -#endif - -if ((hva & (PMD_SIZE -1 )) == (pa & (PMD_SIZE -1 )) && -ALIGN_DOWN (hva,PMD_SIZE ) >= vma->vm_start && -ALIGN (hva,PMD_SIZE ) <= vma->vm_end) -return PMD_SHIFT ; -return PAGE_SHIFT ; }
@@ -1214,7 +1193,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, use_read_lock = (fault_status ==FSC_PERM && write_fault && fault_granule ==PAGE_SIZE ); }else { - vma_shift =get_vma_page_shift (vma, hva); + vma_shift =get_vma_page_shift (vma); } shared = (vma->vm_flags &VM_SHARED );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 381/1887 fsverity: add dependency on 64K or smaller pages
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit a300000233a9ff842e2fb450fb9a79f7827a586d upstream.
Currently, all filesystems that support fsverity (ext4, f2fs, and btrfs) cache the Merkle tree in the pagecache at a 64K aligned offset after the end of the file data. This offset needs to be a multiple of the page size, which is guaranteed only when the page size is 64K or smaller.
64K was chosen to be the "largest reasonable page size". But it isn't the largest *possible* page size: the hexagon and powerpc ports of Linux support 256K pages, though that configuration is rarely used.
For now, just disable support for FS_VERITY in these odd configurations to ensure it isn't used in cases where it would have incorrect behavior.
--- fs/verity/Kconfig | 3 +++ 1 file changed, 3 insertions(+)
fs/verity/Kconfig +3 -0
@@ -2,6 +2,9 @@ config FS_VERITY bool "FS Verity (read-only file-based authenticity protection)" + # Filesystems cache the Merkle tree at a 64K aligned offset in the + # pagecache. That approach assumes the page size is at most 64K. + depends on !PAGE_SIZE_256KB select CRYPTO select CRYPTO_HASH_INFO # SHA-256 is implied as it's intended to be the default hash algorithm.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 382/1887 drm/amd/display: check dc_state_create_copy() for NULL in dm_suspend
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <[email protected]>
[ Upstream commit 015e72cde567d2450e282c2790773463156b2d0a ]
dc_state_create_copy() can return NULL on allocation failure. dm_suspend() only conditionally skips dm_gpureset_toggle_interrupts() and continues execution, returning success. dm_resume() then dereferences the NULL cached_dc_state in link_enc_cfg_copy() and the following dc_state->stream_count loop, crashing during GPU reset recovery.
Return -ENOMEM immediately if the copy fails, so the caller aborts suspend instead of leaving a NULL cached state for resume.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +7 -2
@@ -2645,9 +2645,14 @@ static int dm_suspend(void *handle)dc_allow_idle_optimizations (adev->dm.dc, false); dm->cached_dc_state =dc_copy_state (dm->dc->current_state); +if (!dm->cached_dc_state) { +drm_err (adev_to_drm (adev), +"Failed to allocate cached DC state during suspend\n" ); +mutex_unlock (&dm->dc_lock); +return -ENOMEM ; + } -if (dm->cached_dc_state) -dm_gpureset_toggle_interrupts (adev, dm->cached_dc_state, false); +dm_gpureset_toggle_interrupts (adev, dm->cached_dc_state, false);amdgpu_dm_commit_zero_streams (dm->dc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 383/1887 drm/amdgpu: reset VI ASIC on MacBookPro15,1
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andre Eikmeyer <[email protected]>
[ Upstream commit a5be7ad8f5f0e067613e9197638f216f46252946 ]
After S3, reloading amdgpu on MacBookPro15,1 systems with a Radeon Pro 555X or 560X fails while loading the SMU firmware. The existing SMC register check does not request a reset because the registers do not reliably reflect the stale SMU state on these machines.
Frederick Morlock found that forcing a VI ASIC reset allows the driver to initialize again. This patch limits his workaround to the exact PCI device, Apple subsystem device and revision combinations used by these two GPUs, leaving other VI hardware unchanged.
Stable-dep-of: a22e5e4f2ebb ("drm/amdgpu: reset VI ASIC on MacBookPro14,3")
--- drivers/gpu/drm/amd/amdgpu/vi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
drivers/gpu/drm/amd/amdgpu/vi.c +20 -0
@@ -1432,10 +1432,30 @@ static uint64_t vi_get_pcie_replay_count(struct amdgpu_device *adev)return (nak_r + nak_g); } +struct vi_reset_quirk { +u16 device; +u16 subsystem_vendor; +u16 subsystem_device; +u8 revision; +}; + +static const struct vi_reset_quirk vi_reset_quirks[] = { + {0x67ef ,PCI_VENDOR_ID_APPLE ,0x0190 ,0xe3 },/* Radeon Pro 555X */ + {0x67ef ,PCI_VENDOR_ID_APPLE ,0x018f ,0xc2 },/* Radeon Pro 560X */ +}; +static bool vi_need_reset_on_init (struct amdgpu_device *adev) { +unsigned int i;u32 clock_cntl, pc; +for (i =0 ; i <ARRAY_SIZE (vi_reset_quirks); i++) +if (adev->pdev->device == vi_reset_quirks[i].device && + adev->pdev->subsystem_vendor == vi_reset_quirks[i].subsystem_vendor && + adev->pdev->subsystem_device == vi_reset_quirks[i].subsystem_device && + adev->pdev->revision == vi_reset_quirks[i].revision) +return true; +if (adev->flags &AMD_IS_APU )return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 384/1887 drm/amdgpu: reset VI ASIC on MacBookPro14,3
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Francisco Beltrán Millalén <[email protected]>
[ Upstream commit a22e5e4f2ebbdbb962cc3233094d189c4dfaa051 ]
On a MacBookPro14,3 with a Radeon Pro 555 (Polaris11), the framebuffer is at MC address 0 when amdgpu loads after a cold boot, as the firmware leaves it (MC_VM_FB_LOCATION = 0x007f0000), while the VBIOS ASIC_Init table places it at 0xF4_0000_0000 (0xf47ff400). amdgpu reads the location once, at init, so after a re-POST (S3 resume or GPU reset) the framebuffer has moved and the driver keeps programming the old
one: the SMU is handed a table that was never written and the GPU does not come back, which leaves the internal panel black.
Resetting the ASIC on load makes ASIC_Init run before the driver reads the location, so the driver uses the VBIOS placement from the start and every later re-POST puts the framebuffer back where it already is.
Add the Radeon Pro 555 used in this machine to the existing VI reset quirk table.
Tested on a MacBookPro14,3 on 6.18.49 with the quirk table backported (the kernel also carries unrelated local PCI and ACPI patches for this machine). The framebuffer is at 0x000000F400000000 after both cold and warm boot, and the GPU survived 9 S3 cycles (lid close and rtcwake, one of them with the lid closed for about 7.5 minutes and a USB-C disk attached), each followed by a few minutes of 3D load; no ring timeouts or VM faults were reported. The reset adds about 0.23 s to amdgpu init.
--- drivers/gpu/drm/amd/amdgpu/vi.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vi.c +1 -0
@@ -1442,6 +1442,7 @@ struct vi_reset_quirk {static const struct vi_reset_quirk vi_reset_quirks[] = { {0x67ef ,PCI_VENDOR_ID_APPLE ,0x0190 ,0xe3 },/* Radeon Pro 555X */ {0x67ef ,PCI_VENDOR_ID_APPLE ,0x018f ,0xc2 },/* Radeon Pro 560X */ + {0x67ef ,PCI_VENDOR_ID_APPLE ,0x017a ,0xc7 },/* Radeon Pro 555 */ };static bool vi_need_reset_on_init (struct amdgpu_device *adev)
Signature · 1 line
2.53.0