6.6.143-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 239/452 ptp: vclock: Switch from RCU to SRCU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kurt Kanzenbach <[email protected]>
[ Upstream commit 672bd0519e27c357c43b7f8c0d653fce3817d06e ]
The usage of PTP vClocks leads immediately to the following issues with ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function called from invalid context".
ptp_convert_timestamp() acquires a mutex_t within a RCU read section. This is illegal, because acquiring a mutex_t can result in voluntary scheduling request which is not allowed within a RCU read section.
Replace the RCU usage with SRCU where sleeping is allowed.
--- drivers/ptp/ptp_vclock.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/ptp/ptp_vclock.c +9 -5
@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock); static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8); +DEFINE_STATIC_SRCU (vclock_srcu); +static void ptp_vclock_hash_add (struct ptp_vclock *vclock) {spin_lock (&vclock_hash_lock);
@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock)spin_unlock (&vclock_hash_lock); -synchronize_rcu (); +synchronize_srcu (&vclock_srcu); }static int ptp_vclock_adjfine (struct ptp_clock_info *ptp,long scaled_ppm)
@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) {unsigned int hash = vclock_index %HASH_SIZE (vclock_hash);struct ptp_vclock *vclock; -u64 ns;u64 vclock_ns =0 ; +int srcu_idx; +u64 ns; ns =ktime_to_ns (*hwtstamp); -rcu_read_lock (); + srcu_idx =srcu_read_lock (&vclock_srcu); -hlist_for_each_entry_rcu (vclock, &vclock_hash[hash], vclock_hash_node) { +hlist_for_each_entry_srcu (vclock, &vclock_hash[hash], vclock_hash_node, +srcu_read_lock_held (&vclock_srcu)) {if (vclock->clock->index != vclock_index)continue ;
@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)break ; } -rcu_read_unlock (); +srcu_read_unlock (&vclock_srcu, srcu_idx);return ns_to_ktime (vclock_ns); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 240/452 net: ethernet: mtk_eth_soc: Fix use-after-free in metadata dst teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 80df409e1a483676826a6c66e693dba6ac507751 ]
mtk_free_dev() calls metadata_dst_free() which frees the metadata_dst with kfree() immediately, bypassing the RCU grace period.
In the RX path, skb_dst_set_noref() sets a non-refcounted pointer from the skb to the metadata_dst. This function requires RCU read-side protection and the dst must remain valid until all RCU readers complete. Since metadata_dst_free() calls kfree() directly, a use-after-free can occur if any skb still holds a noref pointer to the dst when the driver tears it down.
Replace metadata_dst_free() with dst_release() which properly goes through the refcount path: when the refcount drops to zero, it schedules the actual free via call_rcu_hurry(), ensuring all RCU readers have completed before the memory is freed.
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +1 -1
@@ -4246,7 +4246,7 @@ static int mtk_free_dev(struct mtk_eth *eth)for (i =0 ; i <ARRAY_SIZE (eth->dsa_meta); i++) {if (!eth->dsa_meta[i])break ; -metadata_dst_free (eth->dsa_meta[i]); +dst_release (ð->dsa_meta[i]->dst); }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 241/452 octeontx2-af: npc: Fix CPT channel mask in npc_install_flow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nithin Dabilpuram <[email protected]>
[ Upstream commit 1d31eb27e570daa04f5373345f9ac98c95863be9 ]
Use the CPT-aware NIX channel mask in the npc_install_flow path so that when the host PF installs steering rules in kernel for a VF used from userspace (e.g. DPDK), MCAM entries see the same channel mask semantics as other RX paths.
--- .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + .../ethernet/marvell/octeontx2/af/rvu_npc.c | 32 +++++++++---------- .../marvell/octeontx2/af/rvu_npc_fs.c | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu.h +1 -0
@@ -933,6 +933,7 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int lf, int slot);int rvu_cpt_ctx_flush (struct rvu *rvu,u16 pcifunc);int rvu_cpt_init (struct rvu *rvu); +u32 rvu_get_cpt_chan_mask (struct rvu *rvu);#define NDC_AF_BANK_MASK GENMASK_ULL(7, 0)#define NDC_AF_BANK_LINE_MASK GENMASK_ULL(31, 16)
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +16 -16
@@ -609,6 +609,19 @@ static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, NPC_AF_MCAMEX_BANKX_ACTION(index, bank)); } +u32 rvu_get_cpt_chan_mask (struct rvu *rvu) +{ +/* For cn10k the upper two bits of the channel number are +* cpt channel number. with masking out these bits in the +* mcam entry, same entry used for NIX will allow packets +* received from cpt for parsing. +*/ +if (!is_rvu_otx2 (rvu)) +return NIX_CHAN_CPT_X2P_MASK ; +else +return 0xFFFu ; +} +void rvu_npc_install_ucast_entry (struct rvu *rvu,u16 pcifunc,int nixlf,u64 chan,u8 *mac_addr) {
@@ -652,7 +665,7 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,eth_broadcast_addr ((u8 *)&req.mask.dmac); req.features =BIT_ULL (NPC_DMAC ); req.channel = chan; - req.chan_mask =0xFFFU ; + req.chan_mask =rvu_get_cpt_chan_mask (rvu); req.intf = pfvf->nix_rx_intf; req.op = action.op; req.hdr.pcifunc =0 ;/* AF is requester */
@@ -722,11 +735,7 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,* mcam entry, same entry used for NIX will allow packets * received from cpt for parsing. */ -if (!is_rvu_otx2 (rvu)) { - req.chan_mask =NIX_CHAN_CPT_X2P_MASK ; - }else { - req.chan_mask =0xFFFU ; - } + req.chan_mask =rvu_get_cpt_chan_mask (rvu);if (chan_cnt >1 ) {if (!is_power_of_2 (chan_cnt)) {
@@ -915,16 +924,7 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,ether_addr_copy (req.mask.dmac, mac_addr); req.features =BIT_ULL (NPC_DMAC ); -/* For cn10k the upper two bits of the channel number are -* cpt channel number. with masking out these bits in the -* mcam entry, same entry used for NIX will allow packets -* received from cpt for parsing. -*/ -if (!is_rvu_otx2 (rvu)) - req.chan_mask =NIX_CHAN_CPT_X2P_MASK ; -else - req.chan_mask =0xFFFU ; - + req.chan_mask =rvu_get_cpt_chan_mask (rvu); req.channel = chan; req.intf = pfvf->nix_rx_intf; req.entry = index;
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +1 -1
@@ -1354,7 +1354,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,/* ignore chan_mask in case pf func is not AF, revisit later */ if (!is_pffunc_af (req->hdr.pcifunc)) - req->chan_mask =0xFFF ; + req->chan_mask =rvu_get_cpt_chan_mask (rvu); err =npc_check_unsupported_flows (rvu, req->features, req->intf);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 242/452 vxlan: vnifilter: send notification on VNI add
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Roulin <[email protected]>
[ Upstream commit aa6ca1c5c338907817374b59f7551fd855a88754 ]
When a new VNI is added to a vxlan device with vnifilter enabled, no RTM_NEWTUNNEL notification is sent to userspace. This means 'bridge monitor vni' never shows VNI add events, even though VNI delete events are reported correctly.
The bug is in vxlan_vni_add(), where the notification is guarded by 'if (changed)'. The 'changed' flag is set by vxlan_vni_update_group() only when the multicast group or remote IP is modified, but for a new VNI added without a group (e.g. in L3 VxLAN interface scenarios), the function returns early without setting changed=true. Since this is a new VNI, the notification should be sent unconditionally.
The notification is not guarded by the return value of vxlan_vni_update_group() because, at this point, the VNI has already been inserted into the hash table and list with no rollback on error. The VNI will be visible in 'bridge vni show' regardless, so userspace should be informed. This is consistent with vxlan_vni_del() which also notifies unconditionally.
The 'if (changed)' guard remains correct in vxlan_vni_update(), which handles the case where a VNI already exists and is being re-added -- there, we only want to notify if the group/remote actually changed.
Reproducer:
# ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \
nolearning external vnifilter
# ip link set vxlan100 up
# bridge monitor vni &
# bridge vni add vni 1000 dev vxlan100 # no notification
# bridge vni delete vni 1000 dev vxlan100 # notification received--- drivers/net/vxlan/vxlan_vnifilter.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/vxlan/vxlan_vnifilter.c +1 -2
@@ -769,8 +769,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan, err =vxlan_vni_update_group (vxlan, vninode, group, true, &changed, extack); -if (changed) -vxlan_vnifilter_notify (vxlan, vninode,RTM_NEWTUNNEL ); +vxlan_vnifilter_notify (vxlan, vninode,RTM_NEWTUNNEL );return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 243/452 vxlan: vnifilter: fix spurious notification on VNI update
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Roulin <[email protected]>
[ Upstream commit 84683b5b60c7274e2c8f7f413d39d78d3db5540f ]
When a VNI is re-added with the same attributes (e.g. same group or no group), vxlan_vni_update() sends a spurious RTM_NEWTUNNEL notification even though nothing changed.
The bug is that 'if (changed)' tests whether the pointer is non-NULL, not the bool value it points to. Since every caller passes a valid pointer, the condition is always true and the notification fires unconditionally.
Fix by dereferencing the pointer: 'if (*changed)'.
Reproducer:
# ip link add vxlan100 type vxlan dstport 4789 local 10.0.0.1 \
nolearning external vnifilter
# ip link set vxlan100 up
# bridge monitor vni &
# bridge vni add vni 1000 dev vxlan100
# bridge vni add vni 1000 dev vxlan100 # spurious notification--- drivers/net/vxlan/vxlan_vnifilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/vxlan/vxlan_vnifilter.c +1 -1
@@ -671,7 +671,7 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan,if (ret)return ret; -if (changed) +if (*changed)vxlan_vnifilter_notify (vxlan, vninode,RTM_NEWTUNNEL );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 244/452 ieee802154: 6lowpan: only accept IPv6 packets in lowpan_xmit()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 3a5f3f7aff18bcc36a57839cf50cf0cc8de707f3 ]
The aoe driver (or similar) generates a non-IPv6 packet (e.g., ETH_P_AOE) and queues it for transmission via dev_queue_xmit() on a 6LoWPAN interface (configured by the user or test case).
Since the packet is not IPv6, the 6LoWPAN header_ops->create function (lowpan_header_create or header_create) returns early without initializing the lowpan_addr_info structure in the skb headroom.
In the transmit function (lowpan_xmit), the driver calls lowpan_header (or setup_header) which unconditionally copies and uses the lowpan_addr_info from the headroom, which contains uninitialized data.
Fix this by dropping non IPv6 packets.
A similar fix is needed in net/bluetooth/6lowpan.c bt_xmit().
--- net/ieee802154/6lowpan/tx.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ieee802154/6lowpan/tx.c +5 -0
@@ -255,6 +255,11 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)pr_debug ("package xmit\n" ); +if (skb->protocol !=htons (ETH_P_IPV6 )) { +kfree_skb (skb); +return NET_XMIT_DROP ; + } +WARN_ON_ONCE (skb->len >IPV6_MIN_MTU );/* We must take a copy of the skb before we modify/replace the ipv6
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 245/452 net/802/mrp: fix vector attribute parsing in mrp_pdu_parse_vecattr
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit 7561c7fbc694308da73300f036719e63e42bf0b4 ]
In mrp_pdu_parse_vecattr(), vector attribute events are encoded three per byte and valen tracks the number of events left to process.
The parser decrements valen after processing the first and second events from each event byte, but not after processing the third one. When valen is exactly a multiple of three, the loop continues after the last valid event and consumes the next byte as a new event byte, applying a spurious event to the MRP applicant state.
Additionally, when valen is zero the parser unconditionally consumes attrlen bytes as FirstValue and advances the offset, even though per IEEE 802.1ak a VectorAttribute with only a LeaveAllEvent has valen of zero and no FirstValue or Vector fields. This corrupts the offset for subsequent PDU parsing.
Also, when valen exceeds three the loop crosses byte boundaries but the attribute value is not incremented between the last event of one byte and the first event of the next. This causes the first event of the next byte to use the same attribute value as the third event rather than the next consecutive value.
Decrement valen after processing the third event, skip FirstValue consumption when valen is zero, and increment the attribute value at the end of each loop iteration.
--- net/802/mrp.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/802/mrp.c +9 -0
@@ -702,6 +702,12 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, valen =be16_to_cpu (get_unaligned (&mrp_cb (skb)->vah->lenflags) &MRP_VECATTR_HDR_LEN_MASK ); +/* If valen is 0, only a LeaveAllEvent is present; FirstValue and +* Vector fields are absent per IEEE 802.1ak. +*/ +if (valen ==0 ) +return 0 ; +/* The VectorAttribute structure in a PDU carries event information * about one or more attributes having consecutive values. Only the * value for the first attribute is contained in the structure. So
@@ -752,6 +758,9 @@ static int mrp_pdu_parse_vecattr(struct mrp_applicant *app, vaevents %= __MRP_VECATTR_EVENT_MAX; vaevent = vaevents;mrp_pdu_parse_vecattr_event (app, skb, vaevent); + valen--; +mrp_attrvalue_inc (mrp_cb (skb)->attrvalue, +mrp_cb (skb)->mh->attrlen); }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 246/452 sctp: purge outqueue on stale COOKIE-ECHO handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit e374b22e9b07b72a25909621464ff74096151bfb ]
sctp_stream_update() is only invoked when the association is moved into COOKIE_WAIT during association setup/reconfiguration. In this path, the outbound stream scheduler state (stream->out_curr) is expected to be clean, since no user data should have been transmitted yet unless the state machine has already partially progressed.
However, a corner case exists in sctp_sf_do_5_2_6_stale(): when a Stale Cookie ERROR is received, the association is rolled back from COOKIE_ECHOED to COOKIE_WAIT. In this scenario, user data may already have been queued and even bundled with the COOKIE-ECHO chunk.
During the rollback, sctp_stream_update() frees the old stream table and installs a new one, but it does not invalidate stream->out_curr. As a result, out_curr may still point to a freed sctp_stream_out entry from the previous stream state.
Later, SCTP scheduler dequeue paths (FCFS, RR, PRIO, etc.) rely on stream->out_curr->ext, which can lead to use-after-free once the old stream state has been released via sctp_stream_free().
This results in crashes such as (reported by Yuqi):
BUG: KASAN: slab-use-after-free in sctp_sched_fcfs_dequeue+0x13a/0x140
Read of size 8 at addr ff1100004d4d3208 by task mini_poc/9312
CPU: 1 UID: 1001 PID: 9312 Comm: mini_poc Not tainted
7.1.0-rc1-00305-gbd3a4795d574 #5 PREEMPT(full)
sctp_sched_fcfs_dequeue+0x13a/0x140
sctp_outq_flush+0x1603/0x33e0
sctp_do_sm+0x31c9/0x5d30
sctp_assoc_bh_rcv+0x392/0x6f0
sctp_inq_push+0x1db/0x270
sctp_rcv+0x138d/0x3c10Fix this by fully purging the association outqueue when handling the Stale Cookie case. This ensures all pending transmit and retransmit state is dropped, and any scheduler cached pointers are invalidated, making it safe to rebuild stream state during COOKIE_WAIT restart.
Updating only stream->out_curr would be insufficient, since queued and retransmittable data would still reference the old stream state and trigger later use-after-free in dequeue paths.
--- net/sctp/sm_statefuns.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
net/sctp/sm_statefuns.c +1 -5
@@ -2597,11 +2597,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale(*/ sctp_add_cmd_sf (commands,SCTP_CMD_DEL_NON_PRIMARY ,SCTP_NULL ()); -/* If we've sent any data bundled with COOKIE-ECHO we will need to -* resend -*/ -sctp_add_cmd_sf (commands,SCTP_CMD_T1_RETRAN , -SCTP_TRANSPORT (asoc->peer.primary_path)); +sctp_add_cmd_sf (commands,SCTP_CMD_PURGE_OUTQUEUE ,SCTP_NULL ());/* Cast away the const modifier, as we want to just * rerun it through as a sideffect.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 247/452 ipmi: Fix rcu_read_unlock to srcu_read_unlock in handle_read_event_rsp
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rui Qi <[email protected]>
Fix a bug where rcu_read_unlock() was used instead of srcu_read_unlock() in handle_read_event_rsp() when ipmi_alloc_recv_msg() fails.
This mismatch leads to an SRCU read-side critical section imbalance: the entry uses srcu_read_lock(&intf->users_srcu) but the error path incorrectly calls rcu_read_unlock(), which is a no-op for SRCU and leaves the SRCU lock held.
The offending code was restructured in mainline by commit 3be997d5a64a ("ipmi:msghandler: Remove srcu from the ipmi user structure"), which replaced the SRCU locking with a mutex in this function, effectively eliminating the mismatch. However, that commit is part of a larger SRCU removal series that is not suitable for stable backport. This minimal fix addresses the SRCU imbalance for 6.12 and earlier stable branches that still carry the original locking scheme.
--- drivers/char/ipmi/ipmi_msghandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/ipmi/ipmi_msghandler.c +1 -1
@@ -4396,7 +4396,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf, recv_msg =ipmi_alloc_recv_msg (user);if (IS_ERR (recv_msg)) { -rcu_read_unlock (); +srcu_read_unlock (&intf->users_srcu, index);list_for_each_entry_safe (recv_msg, recv_msg2, &msgs, link) {list_del (&recv_msg->link);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 248/452 signal: clear JOBCTL_PENDING_MASK for caller in zap_other_threads()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit 90918794a4e2c3b440f8fcf3847765a8b1d81b25 ]
When a multi-threaded process receives a stop signal (e.g., SIGSTOP), do_signal_stop() sets JOBCTL_STOP_PENDING and JOBCTL_STOP_CONSUME on all threads and sets signal->group_stop_count to the number of threads. If one of the threads concurrently calls execve(), de_thread() invokes zap_other_threads() to kill all other threads. zap_other_threads() aborts the pending group stop by resetting signal->group_stop_count to 0 and clears the JOBCTL_PENDING_MASK for all other threads. However, it fails to clear the job control flags for the calling thread.
When execve() completes, the calling thread returns to user mode and checks for pending signals. Seeing the stale JOBCTL_STOP_PENDING flag, it calls do_signal_stop(), which invokes task_participate_group_stop(). Since JOBCTL_STOP_CONSUME is still set, it attempts to decrement the already-zero signal->group_stop_count, triggering a warning:
sig->group_stop_count == 0
WARNING: CPU: 1 PID: 6475 at kernel/signal.c:373 task_participate_group_stop+0x215/0x2d0 Call Trace: <TASK> do_signal_stop+0x3be/0x5c0 kernel/signal.c:2619 get_signal+0xa8c/0x1330 kernel/signal.c:2884 arch_do_signal_or_restart+0xbc/0x840 arch/x86/kernel/signal.c:337 exit_to_user_mode_loop+0x8c/0x4d0 kernel/entry/common.c:98 do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
Fix this race condition by clearing the JOBCTL_PENDING_MASK for the calling thread in zap_other_threads(), ensuring it does not retain any stale job control state after the thread group is destroyed. This aligns with other functions that tear down a thread group and abort group stops, such as zap_process() and complete_signal(), which correctly clear these flags for all threads including the current one.
--- kernel/signal.c | 1 + 1 file changed, 1 insertion(+)
kernel/signal.c +1 -0
@@ -1382,6 +1382,7 @@ int zap_other_threads(struct task_struct *p)int count =0 ; p->signal->group_stop_count =0 ; +task_clear_jobctl_pending (p,JOBCTL_PENDING_MASK ); while_each_thread(p, t) {task_clear_jobctl_pending (t,JOBCTL_PENDING_MASK );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 249/452 time: Fix off-by-one in settimeofday() usec validation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naveen Kumar Chaudhary <[email protected]>
[ Upstream commit ce4abda5e12622f33450159e76c8f56d28d7f03d ]
The validation check uses '>' instead of '>=' when comparing tv_usec against USEC_PER_SEC, allowing the value 1000000 through. After conversion to nanoseconds (*= 1000), this produces tv_nsec == NSEC_PER_SEC, violating the timespec invariant that tv_nsec must be less than NSEC_PER_SEC.
Use '>=' to reject tv_usec values that are not in the valid range of 0 to 999999.
--- kernel/time/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/time.c +1 -1
@@ -207,7 +207,7 @@ SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv, get_user(new_ts.tv_nsec, &tv->tv_usec))return -EFAULT ; -if (new_ts.tv_nsec >USEC_PER_SEC || new_ts.tv_nsec <0 ) +if (new_ts.tv_nsec >=USEC_PER_SEC || new_ts.tv_nsec <0 )return -EINVAL ; new_ts.tv_nsec *=NSEC_PER_USEC ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 250/452 ALSA: PCM: Fix wait queue list corruption in snd_pcm_drain() on linked streams
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ji'an Zhou <[email protected]>
[ Upstream commit 88fe2e3658726cb21ff2dcf9770bf672f9b9d31b ]
snd_pcm_drain() uses init_waitqueue_entry which does not clear entry.prev/next, and add_wait_queue with a conditional remove_wait_queue that is skipped when to_check is no longer in the group after concurrent UNLINK. The orphaned wait entry remains on the unlinked substream sleep queue. On the next drain iteration, add_wait_queue adds the entry to a new queue while still linked on the old one, corrupting both lists. A subsequent wake_up dereferences NULL at the func pointer (mapped from the spinlock at offset 0 of the misinterpreted wait_queue_head_t), causing a kernel panic.
Replace init_waitqueue_entry/add_wait_queue/conditional remove_wait_queue with init_wait_entry/prepare_to_wait/ finish_wait. init_wait_entry clears prev/next via INIT_LIST_HEAD on each iteration and sets autoremove_wake_function which auto-removes the entry on wake-up. finish_wait safely handles both the already-removed and still-queued cases.
--- sound/core/pcm_native.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
sound/core/pcm_native.c +3 -4
@@ -2180,9 +2180,8 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, drain_no_period_wakeup = to_check->no_period_wakeup; drain_rate = to_check->rate; drain_bufsz = to_check->buffer_size; -init_waitqueue_entry (&wait, current); -set_current_state (TASK_INTERRUPTIBLE ); -add_wait_queue (&to_check->sleep, &wait); +init_wait_entry (&wait,0 ); +prepare_to_wait (&to_check->sleep, &wait,TASK_INTERRUPTIBLE );snd_pcm_stream_unlock_irq (substream);if (drain_no_period_wakeup) tout =MAX_SCHEDULE_TIMEOUT ;
@@ -2200,7 +2199,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, group =snd_pcm_stream_group_ref (substream);snd_pcm_group_for_each_entry (s, substream) {if (s->runtime == to_check) { -remove_wait_queue (&to_check->sleep, &wait); +finish_wait (&to_check->sleep, &wait);break ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 251/452 usb: gadget: f_ncm: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 ]
The network device outlived its parent gadget device during disconnection, resulting in dangling sysfs links and null pointer dereference problems.
A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1] was reverted due to power management ordering concerns and a NO-CARRIER regression.
A subsequent attempt to defer net_device allocation to bind [2] broke 1:1 mapping between function instance and network device, making it impossible for configfs to report the resolved interface name. This results in a regression where the DHCP server fails on pmOS.
Use device_move to reparent the net_device between the gadget device and /sys/devices/virtual/ across bind/unbind cycles. This preserves the network interface across USB reconnection, allowing the DHCP server to retain their binding.
Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use __free(detach_gadget) macro to undo attachment on bind failure. The bind_count ensures device_move executes only on the first bind.
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/linux-usb/[email protected]/
--- drivers/usb/gadget/function/f_ncm.c | 35 ++++++++++++++++++--------- drivers/usb/gadget/function/u_ether.c | 22 +++++++++++++++++ drivers/usb/gadget/function/u_ether.h | 26 ++++++++++++++++++++ drivers/usb/gadget/function/u_ncm.h | 2 +- 4 files changed, 73 insertions(+), 12 deletions(-)
drivers/usb/gadget/function/f_ncm.c +24 -11
@@ -1425,6 +1425,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)struct f_ncm_opts *ncm_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_ecm (cdev->gadget))
@@ -1438,16 +1439,18 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)return -ENOMEM ; } -mutex_lock (&ncm_opts->lock); -gether_set_gadget (ncm_opts->net, cdev->gadget); -if (!ncm_opts->bound) - status =gether_register_netdev (ncm_opts->net); -mutex_unlock (&ncm_opts->lock); - -if (status) -return status; - - ncm_opts->bound = true; + scoped_guard(mutex, &ncm_opts->lock) +if (ncm_opts->bind_count ==0 ) { +if (!device_is_registered (&ncm_opts->net->dev)) { +gether_set_gadget (ncm_opts->net, cdev->gadget); + status =gether_register_netdev (ncm_opts->net); + }else + status =gether_attach_gadget (ncm_opts->net, cdev->gadget); + +if (status) +return status; + net = ncm_opts->net; + } ncm_string_defs[1 ].s = ncm->ethaddr;
@@ -1547,6 +1550,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) } ncm->notify_req =no_free_ptr (request); + ncm_opts->bind_count++; +no_free_ptr (net); +DBG (cdev,"CDC Network: IN/%s OUT/%s NOTIFY/%s\n" , ncm->port.in_ep->name, ncm->port.out_ep->name, ncm->notify->name);
@@ -1593,7 +1599,7 @@ static void ncm_free_inst(struct usb_function_instance *f)struct f_ncm_opts *opts; opts = container_of(f, struct f_ncm_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -1655,9 +1661,12 @@ static void ncm_free(struct usb_function *f)static void ncm_unbind (struct usb_configuration *c,struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *ncm_opts;DBG (c->cdev,"ncm unbind\n" ); + ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); +hrtimer_cancel (&ncm->task_timer);kfree (f->os_desc_table);
@@ -1673,6 +1682,10 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)kfree (ncm->notify_req->buf);usb_ep_free_request (ncm->notify, ncm->notify_req); + + ncm_opts->bind_count--; +if (ncm_opts->bind_count ==0 ) +gether_detach_gadget (ncm_opts->net); }static struct usb_function *ncm_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_ether.c +22 -0
@@ -896,6 +896,28 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) }EXPORT_SYMBOL_GPL (gether_set_gadget); +int gether_attach_gadget (struct net_device *net,struct usb_gadget *g) +{ +int ret; + + ret =device_move (&net->dev, &g->dev,DPM_ORDER_DEV_AFTER_PARENT ); +if (ret) +return ret; + +gether_set_gadget (net, g); +return 0 ; +} +EXPORT_SYMBOL_GPL (gether_attach_gadget); + +void gether_detach_gadget (struct net_device *net) +{ +struct eth_dev *dev =netdev_priv (net); + +device_move (&net->dev,NULL ,DPM_ORDER_NONE ); + dev->gadget =NULL ; +} +EXPORT_SYMBOL_GPL (gether_detach_gadget); +int gether_set_dev_addr (struct net_device *net,const char *dev_addr) {struct eth_dev *dev;
drivers/usb/gadget/function/u_ether.h +26 -0
@@ -150,6 +150,32 @@ static inline struct net_device *gether_setup_default(void)*/ void gether_set_gadget (struct net_device *net,struct usb_gadget *g); +/** +* gether_attach_gadget - Reparent net_device to the gadget device. +* @net: The network device to reparent. +* @g: The target USB gadget device to parent to. +* +* This function moves the network device to be a child of the USB gadget +* device in the device hierarchy. This is typically done when the function +* is bound to a configuration. +* +* Returns 0 on success, or a negative error code on failure. +*/ +int gether_attach_gadget (struct net_device *net,struct usb_gadget *g); + +/** +* gether_detach_gadget - Detach net_device from its gadget parent. +* @net: The network device to detach. +* +* This function moves the network device to be a child of the virtual +* devices parent, effectively detaching it from the USB gadget device +* hierarchy. This is typically done when the function is unbound +* from a configuration but the instance is not yet freed. +*/ +void gether_detach_gadget (struct net_device *net); + +DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T)) +/** * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address * @net: device representing this link
drivers/usb/gadget/function/u_ncm.h +1 -1
@@ -18,7 +18,7 @@struct f_ncm_opts {struct usb_function_instance func_inst;struct net_device *net; -bool bound; +int bind_count;struct config_group *ncm_interf_group;struct usb_os_desc ncm_os_desc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 252/452 usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit e002e92e88e12457373ed096b18716d97e7bbb20 ]
Commit ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move") reparents the gadget device to /sys/devices/virtual during unbind, clearing the gadget pointer. If the userspace tool queries on the surviving interface during this detached window, this leads to a NULL pointer dereference.
Unable to handle kernel NULL pointer dereference Call trace: eth_get_drvinfo+0x50/0x90 ethtool_get_drvinfo+0x5c/0x1f0 __dev_ethtool+0xaec/0x1fe0 dev_ethtool+0x134/0x2e0 dev_ioctl+0x338/0x560
Add a NULL check for dev->gadget in eth_get_drvinfo(). When detached, skip copying the fw_version and bus_info strings, which is natively handled by ethtool_get_drvinfo for empty strings.
--- drivers/usb/gadget/function/u_ether.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/usb/gadget/function/u_ether.c +4 -2
@@ -112,8 +112,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)strscpy (p->driver,"g_ether" ,sizeof (p->driver));strscpy (p->version,UETH__VERSION ,sizeof (p->version)); -strscpy (p->fw_version, dev->gadget->name,sizeof (p->fw_version)); -strscpy (p->bus_info,dev_name (&dev->gadget->dev),sizeof (p->bus_info)); +if (dev->gadget) { +strscpy (p->fw_version, dev->gadget->name,sizeof (p->fw_version)); +strscpy (p->bus_info,dev_name (&dev->gadget->dev),sizeof (p->bus_info)); + } }/* REVISIT can also support:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 253/452 tools/rv: Fix cleanup after failed trace setup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriele Monaco <[email protected]>
[ Upstream commit 33ec2269a4155cad7e9e42c92327dcaa9aee59a7 ]
Currently if ikm_setup_trace_instance() fails, the tool returns without any cleanup, if rv was called with both -t and -r, this means the reactor is not going to be cleared.
Jump to the cleanup label to restore the reactor if necessary.
--- tools/verification/rv/src/in_kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/verification/rv/src/in_kernel.c +1 -1
@@ -655,7 +655,7 @@ int ikm_run_monitor(char *monitor_name, int argc, char **argv)if (config_trace) { inst =ikm_setup_trace_instance (monitor_name);if (!inst) -return -1 ; + goto out_free_instance; } retval =ikm_enable (monitor_name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 254/452 net: skbuff: fix missing zerocopy reference in pskb_carve helpers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Minh Nguyen <[email protected]>
commit 98d0912e9f841e5529a5b89a972805f34cb1c69d upstream.
pskb_carve_inside_header() and pskb_carve_inside_nonlinear() both copy the old skb_shared_info header into a new buffer via memcpy(), which includes the destructor_arg pointer (uarg) for MSG_ZEROCOPY skbs. Neither function calls net_zcopy_get() for the new shinfo, creating an unaccounted holder: every skb_shared_info with destructor_arg set will call skb_zcopy_clear() once when freed, but the corresponding net_zcopy_get() was never called for the new copy. Repeated calls drive uarg->refcnt to zero prematurely, freeing ubuf_info_msgzc while TX skbs still hold live destructor_arg pointers.
KASAN reports use-after-free on a freed ubuf_info_msgzc:
BUG: KASAN: slab-use-after-free in skb_release_data+0x77b/0x810 Read of size 8 at addr ffff88801574d3e8 by task poc/220 Call Trace: skb_release_data+0x77b/0x810 kfree_skb_list_reason+0x13e/0x610 skb_release_data+0x4cd/0x810 sk_skb_reason_drop+0xf3/0x340 skb_queue_purge_reason+0x282/0x440 rds_tcp_inc_free+0x1e/0x30 rds_recvmsg+0x354/0x1780 __sys_recvmsg+0xdf/0x180 Allocated by task 219: msg_zerocopy_realloc+0x157/0x7b0 tcp_sendmsg_locked+0x2892/0x3ba0 Freed by task 219: ip_recv_error+0x74a/0xb10 tcp_recvmsg+0x475/0x530
The skb consuming the late access still referenced the same uarg via shinfo->destructor_arg copied by pskb_carve_inside_nonlinear() without a refcount bump. This has been verified to be reliably exploitable: a working proof-of-concept achieves full root privilege escalation from an unprivileged local user on a default kernel configuration.
The fix follows the pattern of pskb_expand_head() which has the same memcpy/cloned structure. For pskb_carve_inside_header(), net_zcopy_get() is placed after skb_orphan_frags() succeeds, so the orphan error path needs no cleanup. For pskb_carve_inside_nonlinear(), net_zcopy_get() is placed after all failure points and just before skb_release_data(), so no error path needs cleanup at all -- matching pskb_expand_head() more closely and avoiding the need for a balancing net_zcopy_put().
--- net/core/skbuff.c | 4 ++++ 1 file changed, 4 insertions(+)
net/core/skbuff.c +4 -0
@@ -6412,6 +6412,8 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,skb_kfree_head (data, size);return -ENOMEM ; } +if (skb_zcopy (skb)) +net_zcopy_get (skb_zcopy (skb));for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++)skb_frag_ref (skb, i);if (skb_has_frag_list (skb))
@@ -6561,6 +6563,8 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,skb_kfree_head (data, size);return -ENOMEM ; } +if (skb_zcopy (skb)) +net_zcopy_get (skb_zcopy (skb));skb_release_data (skb,SKB_CONSUMED , false); skb->head = data;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 255/452 tap: free page on error paths in tap_get_user_xdp()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 3bcf7aec6a9d16438f2cec29f5d7c8d5b8edf9b2 ]
tap_get_user_xdp() rejects a frame shorter than ETH_HLEN with -EINVAL, and returns -ENOMEM when build_skb() fails. Both paths jump to the err label without freeing the page that vhost_net_build_xdp() allocated for the frame. tap_sendmsg() discards the per-buffer return value and always returns 0, so vhost_tx_batch() takes the success path and never frees the page; each rejected frame in a batch leaks one page-frag chunk.
Free the page on both error paths, before the skb is built. This is the tap counterpart of the same leak in tun_xdp_one().
--- drivers/net/tap.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/tap.c +2 -0
@@ -1178,6 +1178,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)int err, depth;if (unlikely (xdp->data_end - xdp->data <ETH_HLEN )) { +put_page (virt_to_head_page (xdp->data)); err = -EINVAL ; goto err; }
@@ -1187,6 +1188,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) skb =build_skb (xdp->data_hard_start, buflen);if (!skb) { +put_page (virt_to_head_page (xdp->data)); err = -ENOMEM ; goto err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 256/452 KVM: arm64: Remove VPIPT I-cache handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit ced242ba9d7cb3571f6e0f165f643cb832d52148 upstream.
We have some special handling for VPIPT I-cache in critical parts of the cache and TLB maintenance. Remove it.
--- arch/arm64/include/asm/kvm_mmu.h | 5 ++- arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +- arch/arm64/kvm/hyp/nvhe/tlb.c | 61 -------------------------------- arch/arm64/kvm/hyp/vhe/tlb.c | 13 ------- 4 files changed, 3 insertions(+), 78 deletions(-)
arch/arm64/include/asm/kvm_mmu.h +2 -3
@@ -229,9 +229,8 @@ static inline void __invalidate_icache_guest_page(void *va, size_t size)if (icache_is_aliasing ()) {/* any kind of VIPT cache */ icache_inval_all_pou (); - }else if (read_sysreg (CurrentEL) != CurrentEL_EL1 || - !icache_is_vpipt ()) { -/* PIPT or VPIPT at EL2 (see comment in __kvm_tlb_flush_vmid_ipa) */ + }else { +/* PIPT */ icache_inval_pou ((unsigned long )va, (unsigned long )va + size); } }
arch/arm64/kvm/hyp/nvhe/pkvm.c +1 -1
@@ -12,7 +12,7 @@#include <nvhe/pkvm.h> #include <nvhe/trap_handler.h> -/* Used by icache_is_vpipt(). */ +/* Used by icache_is_aliasing(). */ unsigned long __icache_flags;/* Used by kvm_get_vttbr(). */
arch/arm64/kvm/hyp/nvhe/tlb.c +0 -61
84 lines not on this page · raw message
arch/arm64/kvm/hyp/vhe/tlb.c +0 -13
@@ -206,18 +206,5 @@ void __kvm_flush_vm_context(void) {dsb (ishst);__tlbi (alle1is); - -/* -* VIPT and PIPT caches are not affected by VMID, so no maintenance -* is necessary across a VMID rollover. -* -* VPIPT caches constrain lookup and maintenance to the active VMID, -* so we need to invalidate lines with a stale VMID to avoid an ABA -* race after multiple rollovers. -* -*/ -if (icache_is_vpipt ()) - asmvolatile ("ic ialluis" ); -dsb (ish); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 257/452 arm64: tlb: Allow XZR argument to TLBI ops
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit bfd9c931d19aa59fb8371d557774fa169b15db9a upstream.
The TLBI instruction accepts XZR as a register argument, and for TLBI operations with a register argument, there is no functional difference between using XZR or another GPR which contains zeroes. Operations without a register argument are encoded as if XZR were used.
Allow the __TLBI_1() macro to use XZR when a register argument is all zeroes.
Today this only results in a trivial code saving in __do_compat_cache_op()'s workaround for Neoverse-N1 erratum #1542419. In subsequent patches this pattern will be used more generally.
There should be no functional change as a result of this patch.
--- arch/arm64/include/asm/tlbflush.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm64/include/asm/tlbflush.h +3 -3
@@ -38,12 +38,12 @@ : : )#define __TLBI_1 (op, arg) asm (ARM64_ASM_PREAMBLE \ - "tlbi " #op ", %0\n" \ + "tlbi " #op ", %x0\n" \ ALTERNATIVE("nop\n nop", \ - "dsb ish\n tlbi " #op ", %0", \ + "dsb ish\n tlbi " #op ", %x0", \ ARM64_WORKAROUND_REPEAT_TLBI, \ CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ - : : "r" (arg)) + : : "rZ" (arg))#define __TLBI_N (op, arg, n, ...) __TLBI_##n(op, arg)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 258/452 arm64: tlb: Optimize ARM64_WORKAROUND_REPEAT_TLBI
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit a8f78680ee6bf795086384e8aea159a52814f827 upstream.
The ARM64_WORKAROUND_REPEAT_TLBI workaround is used to mitigate several errata where broadcast TLBI;DSB sequences don't provide all the architecturally required synchronization. The workaround performs more work than necessary, and can have significant overhead. This patch optimizes the workaround, as explained below.
The workaround was originally added for Qualcomm Falkor erratum 1009 in commit:
d9ff80f83ecb ("arm64: Work around Falkor erratum 1009")
As noted in the message for that commit, the workaround is applied even in cases where it is not strictly necessary.
The workaround was later reused without changes for:
* Arm Cortex-A76 erratum #1286807
SDEN v33: https://developer.arm.com/documentation/SDEN-885749/33-0/
* Arm Cortex-A55 erratum #2441007
SDEN v16: https://developer.arm.com/documentation/SDEN-859338/1600/
* Arm Cortex-A510 erratum #2441009
SDEN v19: https://developer.arm.com/documentation/SDEN-1873351/1900/
The important details to note are as follows:
1. All relevant errata only affect the ordering and/or completion of memory accesses which have been translated by an invalidated TLB entry. The actual invalidation of TLB entries is unaffected.
2. The existing workaround is applied to both broadcast and local TLB invalidation, whereas for all relevant errata it is only necessary to apply a workaround for broadcast invalidation.
3. The existing workaround replaces every TLBI with a TLBI;DSB;TLBI sequence, whereas for all relevant errata it is only necessary to execute a single additional TLBI;DSB sequence after any number of TLBIs are completed by a DSB.
For example, for a sequence of batched TLBIs:
TLBI <op1>[, <arg1>]
TLBI <op2>[, <arg2>]
TLBI <op3>[, <arg3>]
DSB ISH... the existing workaround will expand this to:
TLBI <op1>[, <arg1>]
DSB ISH // additional
TLBI <op1>[, <arg1>] // additional
TLBI <op2>[, <arg2>]
DSB ISH // additional
TLBI <op2>[, <arg2>] // additional
TLBI <op3>[, <arg3>]
DSB ISH // additional
TLBI <op3>[, <arg3>] // additional
DSB ISH... whereas it is sufficient to have:
TLBI <op1>[, <arg1>]
TLBI <op2>[, <arg2>]
TLBI <op3>[, <arg3>]
DSB ISH
TLBI <opX>[, <argX>] // additional
DSB ISH // additionalUsing a single additional TBLI and DSB at the end of the sequence can have significantly lower overhead as each DSB which completes a TLBI must synchronize with other PEs in the system, with potential performance effects both locally and system-wide.
4. The existing workaround repeats each specific TLBI operation, whereas for all relevant errata it is sufficient for the additional TLBI to use *any* operation which will be broadcast, regardless of which translation regime or stage of translation the operation applies to.
For example, for a single TLBI:
TLBI ALLE2IS
DSB ISH
... the existing workaround will expand this to:
TLBI ALLE2IS
DSB ISH
TLBI ALLE2IS // additional
DSB ISH // additional
... whereas it is sufficient to have:
TLBI ALLE2IS
DSB ISH
TLBI VALE1IS, XZR // additional
DSB ISH // additional
As the additional TLBI doesn't have to match a specific earlier TLBI, the additional TLBI can be implemented in separate code, with no memory of the earlier TLBIs. The additional TLBI can also use a cheaper TLBI operation.
5. The existing workaround is applied to both Stage-1 and Stage-2 TLB invalidation, whereas for all relevant errata it is only necessary to apply a workaround for Stage-1 invalidation.
Architecturally, TLBI operations which invalidate only Stage-2 information (e.g. IPAS2E1IS) are not required to invalidate TLB entries which combine information from Stage-1 and Stage-2 translation table entries, and consequently may not complete memory accesses translated by those combined entries. In these cases, completion of memory accesses is only guaranteed after subsequent invalidation of Stage-1 information (e.g. VMALLE1IS).
Taking the above points into account, this patch reworks the workaround logic to reduce overhead:
* New __tlbi_sync_s1ish() and __tlbi_sync_s1ish_hyp() functions are added and used in place of any dsb(ish) which is used to complete broadcast Stage-1 TLB maintenance. When the ARM64_WORKAROUND_REPEAT_TLBI workaround is enabled, these helpers will execute an additional TLBI;DSB sequence.
For consistency, it might make sense to add __tlbi_sync_*() helpers for local and stage 2 maintenance. For now I've left those with open-coded dsb() to keep the diff small.
* The duplication of TLBIs in __TLBI_0() and __TLBI_1() is removed. This is no longer needed as the necessary synchronization will happen in __tlbi_sync_s1ish() or __tlbi_sync_s1ish_hyp().
* The additional TLBI operation is chosen to have minimal impact:
- __tlbi_sync_s1ish() uses "TLBI VALE1IS, XZR". This is only used at EL1 or at EL2 with {E2H,TGE}=={1,1}, where it will target an unused entry for the reserved ASID in the kernel's own translation regime, and have no adverse affect.
- __tlbi_sync_s1ish_hyp() uses "TLBI VALE2IS, XZR". This is only used in hyp code, where it will target an unused entry in the hyp code's TTBR0 mapping, and should have no adverse effect.
* As __TLBI_0() and __TLBI_1() no longer replace each TLBI with a TLBI;DSB;TLBI sequence, batching TLBIs is worthwhile, and there's no need for arch_tlbbatch_should_defer() to consider ARM64_WORKAROUND_REPEAT_TLBI.
When building defconfig with GCC 15.1.0, compared to v6.19-rc1, this patch saves ~1KiB of text, makes the vmlinux ~42KiB smaller, and makes the resulting Image 64KiB smaller:
| [mark@lakrids:~/src/linux]% size vmlinux-* | text data bss dec hex filename | 21179831 19660919 708216 41548966 279fca6 vmlinux-after | 21181075 19660903 708216 41550194 27a0172 vmlinux-before | [mark@lakrids:~/src/linux]% ls -l vmlinux-* | -rwxr-xr-x 1 mark mark 157771472 Feb 4 12:05 vmlinux-after | -rwxr-xr-x 1 mark mark 157815432 Feb 4 12:05 vmlinux-before | [mark@lakrids:~/src/linux]% ls -l Image-* | -rw-r--r-- 1 mark mark 41007616 Feb 4 12:05 Image-after | -rw-r--r-- 1 mark mark 41073152 Feb 4 12:05 Image-before
--- arch/arm64/include/asm/tlbflush.h | 60 ++++++++++++++++++------------- arch/arm64/kernel/sys_compat.c | 2 +- arch/arm64/kvm/hyp/nvhe/mm.c | 2 +- arch/arm64/kvm/hyp/nvhe/tlb.c | 8 ++--- arch/arm64/kvm/hyp/pgtable.c | 2 +- arch/arm64/kvm/hyp/vhe/tlb.c | 8 ++--- 6 files changed, 46 insertions(+), 36 deletions(-)
arch/arm64/include/asm/tlbflush.h +35 -25
@@ -31,18 +31,10 @@*/ #define __TLBI_0 (op, arg) asm (ARM64_ASM_PREAMBLE \ "tlbi " #op "\n" \ - ALTERNATIVE("nop\n nop", \ - "dsb ish\n tlbi " #op, \ - ARM64_WORKAROUND_REPEAT_TLBI, \ - CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ : : )#define __TLBI_1 (op, arg) asm (ARM64_ASM_PREAMBLE \ "tlbi " #op ", %x0\n" \ - ALTERNATIVE("nop\n nop", \ - "dsb ish\n tlbi " #op ", %x0", \ - ARM64_WORKAROUND_REPEAT_TLBI, \ - CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ : : "rZ" (arg))#define __TLBI_N (op, arg, n, ...) __TLBI_##n(op, arg)
@@ -165,6 +157,34 @@ static inline unsigned long get_trans_granule(void) (__pages >> (5 * (scale) +1 )) -1 ; \ }) +#define __repeat_tlbi_sync(op, arg...) \ +do { \ + if (!alternative_has_cap_unlikely(ARM64_WORKAROUND_REPEAT_TLBI)) \ + break; \ + __tlbi(op, ##arg); \ + dsb(ish); \ +} while (0) + +/* +* Complete broadcast TLB maintenance issued by the host which invalidates +* stage 1 information in the host's own translation regime. +*/ +static inline void __tlbi_sync_s1ish (void ) +{ +dsb (ish); +__repeat_tlbi_sync (vale1is,0 ); +} + +/* +* Complete broadcast TLB maintenance issued by hyp code which invalidates +* stage 1 translation information in any translation regime. +*/ +static inline void __tlbi_sync_s1ish_hyp (void ) +{ +dsb (ish); +__repeat_tlbi_sync (vale2is,0 ); +} +/* * TLB Invalidation * ================
@@ -246,7 +266,7 @@ static inline void flush_tlb_all(void) {dsb (ishst);__tlbi (vmalle1is); -dsb (ish); +__tlbi_sync_s1ish ();isb (); }
@@ -258,7 +278,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm) asid =__TLBI_VADDR (0 ,ASID (mm));__tlbi (aside1is, asid);__tlbi_user (aside1is, asid); -dsb (ish); +__tlbi_sync_s1ish ();mmu_notifier_arch_invalidate_secondary_tlbs (mm,0 ,-1UL ); }
@@ -285,21 +305,11 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) {flush_tlb_page_nosync (vma, uaddr); -dsb (ish); +__tlbi_sync_s1ish (); }static inline bool arch_tlbbatch_should_defer (struct mm_struct *mm) { -#ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI -/* -* TLB flush deferral is not required on systems which are affected by -* ARM64_WORKAROUND_REPEAT_TLBI, as __tlbi()/__tlbi_user() implementation -* will have two consecutive TLBI instructions with a dsb(ish) in between -* defeating the purpose (i.e save overall 'dsb ish' cost). -*/ -if (unlikely (cpus_have_const_cap (ARM64_WORKAROUND_REPEAT_TLBI ))) -return false; -#endif return true; }
@@ -333,7 +343,7 @@ static inline void arch_flush_tlb_batched_pending(struct mm_struct *mm)*/ static inline void arch_tlbbatch_flush (struct arch_tlbflush_unmap_batch *batch) { -dsb (ish); +__tlbi_sync_s1ish (); }/*
@@ -437,7 +447,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,else __flush_tlb_range_op (vae1is, start, pages, stride, asid, tlb_level, true); -dsb (ish); +__tlbi_sync_s1ish ();mmu_notifier_arch_invalidate_secondary_tlbs (vma->vm_mm, start, end); }
@@ -467,7 +477,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long enddsb (ishst);for (addr = start; addr < end; addr +=1 << (PAGE_SHIFT -12 ))__tlbi (vaale1is, addr); -dsb (ish); +__tlbi_sync_s1ish ();isb (); }
@@ -481,7 +491,7 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)dsb (ishst);__tlbi (vaae1is, addr); -dsb (ish); +__tlbi_sync_s1ish (); isb(); }#endif
arch/arm64/kernel/sys_compat.c +1 -1
@@ -37,7 +37,7 @@ __do_compat_cache_op(unsigned long start, unsigned long end)* We pick the reserved-ASID to minimise the impact. */ __tlbi (aside1is,__TLBI_VADDR (0 ,0 )); -dsb (ish); +__tlbi_sync_s1ish (); } ret =caches_clean_inval_user_pou (start, start + chunk);
arch/arm64/kvm/hyp/nvhe/mm.c +1 -1
@@ -261,7 +261,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)*/ dsb (ishst);__tlbi_level (vale2is,__TLBI_VADDR (addr,0 ), (KVM_PGTABLE_MAX_LEVELS -1 )); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb (); }
arch/arm64/kvm/hyp/nvhe/tlb.c +4 -4
@@ -102,7 +102,7 @@ void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,*/ dsb (ish);__tlbi (vmalle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -158,7 +158,7 @@ void __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,dsb (ish);__tlbi (vmalle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -172,7 +172,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)__tlb_switch_to_guest (mmu, &cxt, false);__tlbi (vmalls12e1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -198,5 +198,5 @@ void __kvm_flush_vm_context(void)/* Same remark as in __tlb_switch_to_guest() */ dsb (ish);__tlbi (alle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp (); }
arch/arm64/kvm/hyp/pgtable.c +1 -1
@@ -534,7 +534,7 @@ static int hyp_unmap_walker(const struct kvm_pgtable_visit_ctx *ctx, *unmapped += granule; } -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb (); mm_ops->put_page (ctx->ptep);
arch/arm64/kvm/hyp/vhe/tlb.c +4 -4
@@ -105,7 +105,7 @@ void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,*/ dsb (ish);__tlbi (vmalle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -165,7 +165,7 @@ void __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,dsb (ish);__tlbi (vmalle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -181,7 +181,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)__tlb_switch_to_guest (mmu, &cxt);__tlbi (vmalls12e1is); -dsb (ish); +__tlbi_sync_s1ish_hyp ();isb ();__tlb_switch_to_host (&cxt);
@@ -206,5 +206,5 @@ void __kvm_flush_vm_context(void) {dsb (ishst);__tlbi (alle1is); -dsb (ish); +__tlbi_sync_s1ish_hyp (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 259/452 iomap: dont revert iov_iter on partially completed buffered writes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Foster <[email protected]>
Gregg reports that the iomap retry behavior for nonblocking (nowait) append writes is broken. The problem occurs when an append write is first submitted in non-blocking mode (i.e. via io_uring), partially completes before hitting -EAGAIN, and then is resubmitted from blocking context.
The specific problem is that at least one iteration of the loop in iomap_write_iter() completes in non-blocking context and thus has bumped i_size. The next iteration hits -EAGAIN, reverts the iov_iter and returns. io_uring retries the entire append write from blocking context, but since i_size has already been increased, the data that was partially written on the first attempt is rewritten at the new i_size. This is essentially an intra-write data corruption since the data written to the file does not reflect the write from userspace.
This problem is already fixed on master as of commit 1a1a3b574b97 ("iomap: advance the iter directly on buffered writes"). That commit was primarily intended to clean up iomap iter state tracking, but it also happened to remove the iov_iter revert and thus accidentally fix this problem as well. Without the revert, iomap will commit partial progress internally and loop once more before it more than likely hits -EAGAIN and returns partial progress consistent with the inode updates. This means the blocking retry from io_uring will pick up where the first attempt left off at the current i_size and perform the remainder of the write correctly.
--- fs/iomap/buffered-io.c | 4 ---- 1 file changed, 4 deletions(-)
fs/iomap/buffered-io.c +0 -4
@@ -974,10 +974,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) } }while (iov_iter_count (i) && length); -if (status == -EAGAIN ) { -iov_iter_revert (i, written); -return -EAGAIN ; - }return written ? written : status; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 260/452 xfrm: policy: fix use-after-free on inexact bin in xfrm_policy_bysel_ctx()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanghyun Park <[email protected]>
[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ]
Fix the race by pruning the bin while still holding xfrm_policy_lock, before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() becomes unused and is removed.
Race:
CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO)
========================== ==========================
xfrm_policy_bysel_ctx():
spin_lock_bh(xfrm_policy_lock)
bin = xfrm_policy_inexact_lookup()
__xfrm_policy_unlink(pol)
spin_unlock_bh(xfrm_policy_lock)
xfrm_policy_kill(ret)
// wide window, lock not held
xfrm_hash_rebuild():
spin_lock_bh(xfrm_policy_lock)
__xfrm_policy_inexact_flush():
kfree_rcu(bin) // bin freed
spin_unlock_bh(xfrm_policy_lock)
xfrm_policy_inexact_prune_bin(bin)
// UAF: bin is freed--- net/xfrm/xfrm_policy.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
net/xfrm/xfrm_policy.c +2 -11
@@ -1127,15 +1127,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool } } -static void xfrm_policy_inexact_prune_bin (struct xfrm_pol_inexact_bin *b) -{ -struct net *net =read_pnet (&b->k.net); - -spin_lock_bh (&net->xfrm.xfrm_policy_lock); -__xfrm_policy_inexact_prune_bin (b, false); -spin_unlock_bh (&net->xfrm.xfrm_policy_lock); -} -static void __xfrm_policy_inexact_flush (struct net *net) {struct xfrm_pol_inexact_bin *bin, *t;
@@ -1729,12 +1720,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, } ret = pol; } +if (bin && delete) +__xfrm_policy_inexact_prune_bin (bin, false);spin_unlock_bh (&net->xfrm.xfrm_policy_lock);if (ret && delete)xfrm_policy_kill (ret); -if (bin && delete) -xfrm_policy_inexact_prune_bin (bin);return ret; }EXPORT_SYMBOL (xfrm_policy_bysel_ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 261/452 netlabel: validate unlabeled address and mask attribute lengths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ]
netlbl_unlabel_addrinfo_get() used the address attribute length to determine whether the attribute data could be read as an IPv4 or IPv6 address, but did not independently validate the corresponding mask attribute length. A crafted Generic Netlink request could therefore provide a valid IPv4/IPv6 address attribute with a shorter mask attribute, which would later be read as a full struct in_addr or struct in6_addr.
NLA_BINARY policy lengths are maximum lengths by default, so use NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask attributes. This rejects short attributes during policy validation and also exposes the exact length requirements through policy introspection.
--- net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-)
net/netlabel/netlabel_unlabeled.c +10 -20
@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family;/* NetLabel Netlink attribute policy */ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX +1 ] = { [NLBL_UNLABEL_A_ACPTFLG ] = { .type =NLA_U8 }, - [NLBL_UNLABEL_A_IPV6ADDR ] = { .type =NLA_BINARY , - .len =sizeof (struct in6_addr ) }, - [NLBL_UNLABEL_A_IPV6MASK ] = { .type =NLA_BINARY , - .len =sizeof (struct in6_addr ) }, - [NLBL_UNLABEL_A_IPV4ADDR ] = { .type =NLA_BINARY , - .len =sizeof (struct in_addr ) }, - [NLBL_UNLABEL_A_IPV4MASK ] = { .type =NLA_BINARY , - .len =sizeof (struct in_addr ) }, + [NLBL_UNLABEL_A_IPV6ADDR ] = +NLA_POLICY_EXACT_LEN (sizeof (struct in6_addr )), + [NLBL_UNLABEL_A_IPV6MASK ] = +NLA_POLICY_EXACT_LEN (sizeof (struct in6_addr )), + [NLBL_UNLABEL_A_IPV4ADDR ] = +NLA_POLICY_EXACT_LEN (sizeof (struct in_addr )), + [NLBL_UNLABEL_A_IPV4MASK ] = +NLA_POLICY_EXACT_LEN (sizeof (struct in_addr )), [NLBL_UNLABEL_A_IFACE ] = { .type =NLA_NUL_STRING , .len =IFNAMSIZ -1 }, [NLBL_UNLABEL_A_SECCTX ] = { .type =NLA_BINARY }
@@ -764,24 +764,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, void **mask, u32 *len) { - u32 addr_len; -if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR ] && info->attrs[NLBL_UNLABEL_A_IPV4MASK ]) { - addr_len =nla_len (info->attrs[NLBL_UNLABEL_A_IPV4ADDR ]); -if (addr_len !=sizeof (struct in_addr ) && - addr_len !=nla_len (info->attrs[NLBL_UNLABEL_A_IPV4MASK ])) -return -EINVAL ; - *len = addr_len; + *len =sizeof (struct in_addr ); *addr =nla_data (info->attrs[NLBL_UNLABEL_A_IPV4ADDR ]); *mask =nla_data (info->attrs[NLBL_UNLABEL_A_IPV4MASK ]);return 0 ; }else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR ]) { - addr_len =nla_len (info->attrs[NLBL_UNLABEL_A_IPV6ADDR ]); -if (addr_len !=sizeof (struct in6_addr ) && - addr_len !=nla_len (info->attrs[NLBL_UNLABEL_A_IPV6MASK ])) -return -EINVAL ; - *len = addr_len; + *len =sizeof (struct in6_addr ); *addr =nla_data (info->attrs[NLBL_UNLABEL_A_IPV6ADDR ]); *mask =nla_data (info->attrs[NLBL_UNLABEL_A_IPV6MASK ]);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 262/452 gpio: mvebu: fix NULL pointer dereference in suspend/resume
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ]
mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO banks during suspend/resume, but not all banks have PWM functionality. GPIO banks without PWM have mvchip->mvpwm set to NULL.
Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer dereference when it tries to access mvpwm->blink_select.
Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write [00000020] *pgd=00000000 Internal error: Oops: 815 [#1] PREEMPT ARM Modules linked in: CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 Hardware name: Marvell Armada 370/XP (Device Tree) PC is at regmap_mmio_read+0x38/0x54 LR is at regmap_mmio_read+0x38/0x54 pc : [<c05fd2ac>] lr : [<c05fd2ac>] psr: 200f0013 sp : f0c11d10 ip : 00000000 fp : c100d2f0 r10: c14fb854 r9 : 00000000 r8 : 00000000 r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 135ec059 DAC: 00000051 Call trace: regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac _regmap_bus_reg_read from _regmap_read+0x60/0x154 _regmap_read from regmap_read+0x3c/0x60 regmap_read from mvebu_gpio_suspend+0xa4/0x14c mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 dpm_run_callback from device_suspend+0x124/0x630 device_suspend from dpm_suspend+0x124/0x270 dpm_suspend from dpm_suspend_start+0x64/0x6c dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 suspend_devices_and_enter from pm_suspend+0x2fc/0x308 pm_suspend from state_store+0x6c/0xc8 state_store from kernfs_fop_write_iter+0x10c/0x1f8 kernfs_fop_write_iter from vfs_write+0x270/0x468 vfs_write from ksys_write+0x70/0xf0 ksys_write from ret_fast_syscall+0x0/0x54
Add a NULL check for mvchip->mvpwm before calling the PWM suspend/resume functions.
--- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpio/gpio-mvebu.c +2 -2
@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)BUG (); } -if (IS_REACHABLE (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ) && mvchip->mvpwm)mvebu_pwm_suspend (mvchip);return 0 ;
@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)BUG (); } -if (IS_REACHABLE (CONFIG_PWM )) +if (IS_REACHABLE (CONFIG_PWM ) && mvchip->mvpwm)mvebu_pwm_resume (mvchip);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 263/452 ASoC: wm_adsp: Fix NULL dereference when removing firmware controls
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ]
In wm_adsp_control_remove() check that the priv pointer is not NULL before attempting to cleanup what it points to.
When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that wm_adsp can create its own private control data. There are two cases where private data is not created:
1. The control is a SYSTEM control, so an ALSA control is not created.
2. The codec driver has registered a control_add() callback that hides the control, so wm_adsp_control_add() is not called.
When cs_dsp_remove destroys its control list it calls wm_adsp_control_remove() for each control. But wm_adsp_control_remove() was attempting to cleanup the private data pointed to by cs_ctl->priv without checking the pointer for NULL.
--- sound/soc/codecs/wm_adsp.c | 3 +++ 1 file changed, 3 insertions(+)
sound/soc/codecs/wm_adsp.c +3 -0
@@ -674,6 +674,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) {struct wm_coeff_ctl *ctl = cs_ctl->priv; +if (!ctl) +return ; +cancel_work_sync (&ctl->work);kfree (ctl->name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 264/452 tcp: restrict SO_ATTACH_FILTER to priv users
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ]
This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets to users with CAP_NET_ADMIN capability.
This blocks potential side-channel attack where an unprivileged application attaches a filter to leak TCP sequence/acknowledgment numbers.
--- net/core/sock.c | 5 +++++ 1 file changed, 5 insertions(+)
net/core/sock.c +5 -0
@@ -1311,6 +1311,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname,case SO_ATTACH_FILTER : {struct sock_fprog fprog; +if (sk_is_tcp (sk) && + !sockopt_ns_capable (sock_net (sk)->user_ns,CAP_NET_ADMIN )) { + ret = -EPERM ; +break ; + } ret =copy_bpf_fprog_from_user (&fprog, optval, optlen);if (!ret) ret =sk_attach_filter (&fprog, sk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 265/452 net/mlx4: avoid GCC 10 __bad_copy_from() false positive
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yao Sang <[email protected]>
[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ]
mlx4_init_user_cqes() fills a scratch buffer with the CQE initialization pattern and then copies from that buffer to userspace.
In the single-copy path, the copy length is array_size(entries, cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 does not carry the branch invariant strongly enough through the object size checks and falsely triggers __bad_copy_from().
Size the scratch buffer to the actual copy length for the active path, keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() guard for the PAGE_SIZE invariant before allocating the buffer.
--- drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx4/cq.c +8 -1
@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)static int mlx4_init_user_cqes (void *buf,int entries,int cqe_size) {int entries_per_copy =PAGE_SIZE / cqe_size; +size_t copy_bytes;void *init_ents;int err =0 ;int i;
@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) buf +=PAGE_SIZE ; } }else { + copy_bytes =array_size (entries, cqe_size); +if (WARN_ON_ONCE (copy_bytes >PAGE_SIZE )) { + err = -EINVAL ; + goto out; + } + err =copy_to_user ((void __user *)buf, init_ents, -array_size (entries, cqe_size)) ? + copy_bytes) ? -EFAULT :0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 266/452 net: phy: clean the sfp upstream if phy probing fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Chevallier <[email protected]>
[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ]
Sashiko reported that we don't call sfp_bus_del_upstream() in the probe failure path, so let's add it, otherwise the sfp-bus is left with a dangling 'upstream' field, that may be used later on during SFP events.
This issue existed before the generic phylib sfp support, back when drivers were calling phy_sfp_probe themselves.
--- drivers/net/phy/phy_device.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/phy/phy_device.c +6 -0
@@ -1432,6 +1432,9 @@ int phy_sfp_probe(struct phy_device *phydev, ret =sfp_bus_add_upstream (bus, phydev, ops);sfp_bus_put (bus); + +if (ret) + phydev->sfp_bus =NULL ; }return ret; }
@@ -3414,6 +3417,9 @@ static int phy_probe(struct device *dev)return 0 ; out: +sfp_bus_del_upstream (phydev->sfp_bus); + phydev->sfp_bus =NULL ; +if (!phydev->is_on_sfp_module)phy_led_triggers_unregister (phydev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 267/452 net: qrtr: fix refcount saturation and potential UAF in qrtr_port_remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ]
In qrtr_port_remove(), the socket reference count is decremented via __sock_put() before the port is removed from the qrtr_ports XArray and before the RCU grace period elapses.
This breaks the fundamental RCU update paradigm. It exposes a race window where a concurrent RCU reader (such as qrtr_reset_ports() or qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, and attempt to call sock_hold() on a socket whose reference count has already dropped to zero.
This exact race condition was hit during syzkaller fuzzing, leading to the following refcount saturation warning and a potential Use-After-Free:
refcount_t: saturated; leaking memory.
WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 Modules linked in: qrtr(+) bochs drm_shmem_helper ... Call Trace: <TASK> qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] kernel_bind+0xe4/0x120 net/socket.c:3592 qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] do_one_initcall+0xf5/0x5e0 init/main.c:1283 ... </TASK>
Fix this by deferring the reference count decrement until after the xa_erase() and the synchronize_rcu() complete.
(Note: The v1 of this patch incorrectly replaced __sock_put() with sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() still hold a reference to the socket, so freeing the socket memory here would lead to a subsequent UAF in the caller. Thus, the __sock_put() is kept, but only repositioned to close the RCU race.)
--- net/qrtr/af_qrtr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/qrtr/af_qrtr.c +2 -2
@@ -707,13 +707,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)if (port ==QRTR_PORT_CTRL ) port =0 ; -__sock_put (&ipc->sk); -xa_erase (&qrtr_ports, port);/* Ensure that if qrtr_port_lookup() did enter the RCU read section we * wait for it to up increment the refcount */ synchronize_rcu (); + +__sock_put (&ipc->sk); }/* Assign port number to socket.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 268/452 net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <[email protected]>
[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ]
mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using the PF's log_max_current_uc/mc_list capabilities. When querying a VF vport with a larger configured max (via devlink), the firmware response can overflow this buffer:
BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] Call Trace: <TASK> dump_stack_lvl+0x69/0xa0 print_report+0x176/0x4e4 kasan_report+0xc8/0x100 mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] esw_vport_change_handler+0x6a/0x90 [mlx5_core] process_one_work+0x87f/0x15e0 worker_thread+0x62b/0x1020 kthread+0x375/0x490 ret_from_fork+0x4dc/0x810 ret_from_fork_asm+0x11/0x20 </TASK>
Fix by querying the vport's own HCA caps to size the buffer correctly. Refactor the function to allocate and return the MAC list internally, removing the caller's dependency on knowing the correct max.
--- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- include/linux/mlx5/vport.h | 4 +- 3 files changed, 59 insertions(+), 30 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +3 -10
@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, struct mlx5_vport *vport, int list_type) { bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; -u8 (*mac_list)[ETH_ALEN ]; +u8 (*mac_list)[ETH_ALEN ] =NULL ;struct l2addr_node *node;struct vport_addr *addr;struct hlist_head *hash;struct hlist_node *tmp; -int size; +int size =0 ;int err;int hi;int i; - size = is_uc ?MLX5_MAX_UC_PER_VPORT (esw->dev) : -MLX5_MAX_MC_PER_VPORT (esw->dev); - - mac_list =kcalloc (size,ETH_ALEN ,GFP_KERNEL ); -if (!mac_list) -return ; - hash = is_uc ? vport->uc_list : vport->mc_list;for_each_l2hash_node (node, tmp, hash, hi) {
@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, goto out; err =mlx5_query_nic_vport_mac_list (esw->dev, vport->vport, list_type, - mac_list, &size); + &mac_list, &size);if (err) goto out; esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
drivers/net/ethernet/mellanox/mlx5/core/vport.c +54 -18
105 lines not on this page · raw message
include/linux/mlx5/vport.h +2 -2
@@ -94,8 +94,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev,int mlx5_query_nic_vport_mac_list (struct mlx5_core_dev *dev,u16 vport,enum mlx5_list_type list_type, -u8 addr_list[][ETH_ALEN ], -int *list_size); +u8 (**mac_list)[ETH_ALEN ], +int *mac_list_size); int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, enum mlx5_list_type list_type, u8 addr_list[][ETH_ALEN],
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 269/452 ipv6: sit: reload inner IPv6 header after GSO offloads
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ]
ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function entry and continues using it after iptunnel_handle_offloads().
For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). When the skb header is cloned, skb_header_unclone() can call pskb_expand_head(), which may move the skb head. The pskb_expand_head() contract requires pointers into the skb header to be reloaded after the call.
If the later skb_realloc_headroom() branch is not taken, SIT uses the stale iph6 pointer to read the inner hop limit and DS field. That can read from a freed skb head after the old head's remaining clone is released.
Reload iph6 after the offload helper succeeds and before subsequent reads from the inner IPv6 header. Keep the existing reload after skb_realloc_headroom(), since that branch can also replace the skb.
--- net/ipv6/sit.c | 1 + 1 file changed, 1 insertion(+)
net/ipv6/sit.c +1 -0
@@ -965,6 +965,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,ip_rt_put (rt); goto tx_error; } + iph6 =ipv6_hdr (skb);if (df) { mtu =dst_mtu (&rt->dst) - t_hlen;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 270/452 net: openvswitch: fix possible kfree_skb of ERR_PTR
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Moreno <[email protected]>
[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ]
After the patch in the "Fixes" tag, the allocation of the "reply" skb can happen either before or after locking the ovs_mutex.
However, error cleanups still follow the classical reversed order, assuming "reply" is allocated before locking: it is freed after unlocking.
If "reply" allocation happens after locking the mutex and it fails, "reply" is left with an ERR_PTR, and execution jumps to the correspondent cleanup stage which will try to free an invalid pointer.
Fix this by setting the pointer to NULL after having saved its error value.
--- net/openvswitch/datapath.c | 1 + 1 file changed, 1 insertion(+)
net/openvswitch/datapath.c +1 -0
@@ -1287,6 +1287,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)if (IS_ERR (reply)) { error =PTR_ERR (reply); + reply =NULL ; goto err_unlock_ovs; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 271/452 r8152: handle the return value of usb_reset_device()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chih Kai Hsu <[email protected]>
[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ]
If usb_reset_device() returns a negative error code, stop the process of probing.
--- drivers/net/usb/r8152.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/usb/r8152.c +6 -1
@@ -9757,7 +9757,12 @@ static int rtl8152_probe_once(struct usb_interface *intf,struct net_device *netdev;int ret; -usb_reset_device (udev); + ret =usb_reset_device (udev); +if (ret <0 ) { +dev_err (&intf->dev,"USB reset failed, errno=%d\n" , ret); +return ret; + } + netdev =alloc_etherdev (sizeof (struct r8152 ));if (!netdev) {dev_err (&intf->dev,"Out of memory\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 272/452 sctp: fix uninit-value in __sctp_rcv_asconf_lookup()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ]
__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF chunk can hold the ADDIP header and a parameter header, then calls af->from_addr_param(), which reads the full address (16 bytes for IPv6) trusting the parameter's declared length.
An unauthenticated peer can send a truncated trailing ASCONF chunk that declares an IPv6 address parameter but stops after the 4-byte parameter header; reached from the no-association lookup path, from_addr_param() then reads uninitialized bytes past the parameter.
Impact: an unauthenticated SCTP peer makes the receive path read up to 16 bytes of uninitialized memory past a truncated ASCONF address parameter.
The sibling __sctp_rcv_init_lookup() bounds parameters with sctp_walk_params(); this path open-codes the fetch and omits the bound. Verify the whole address parameter lies within the chunk before from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 ("net: sctp: fix KMSAN uninit-value in sctp_inq_pop").
--- net/sctp/input.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/sctp/input.c +8 -0
@@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(/* Skip over the ADDIP header and find the Address parameter */ param = (union sctp_addr_param *)(asconf +1 ); +/* The whole address parameter must lie within the chunk before +* af->from_addr_param() reads the variable-length address; otherwise a +* truncated trailing ASCONF chunk lets it read uninitialized bytes past +* the parameter. +*/ +if (sizeof (*asconf) +ntohs (param->p.length) >ntohs (ch->length)) +return NULL ; + af =sctp_get_af_specific (param_type2af (param->p.type));if (unlikely (!af))return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 273/452 net: guard timestamp cmsgs to real error queue skbs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ]
skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb from sk_error_queue. That assumption is not true for AF_PACKET sockets:
outgoing packet taps are also delivered to packet sockets with skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET instead of struct sock_exterr_skb.
If such an skb is received with timestamping enabled, the generic timestamp cmsg path can read AF_PACKET control-buffer state as sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop counter overlaps opt_stats. An odd drop count makes the path emit SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear skbs this copies past the linear head and can trigger hardened usercopy or disclose adjacent heap contents.
Keep skb_is_err_queue() local to net/socket.c, but make it verify that the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal receive ownership and no longer pass as error-queue skbs, while legitimate sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free ownership.
--- include/net/sock.h | 1 + net/core/skbuff.c | 6 +++--- net/socket.c | 11 ++++++----- 3 files changed, 10 insertions(+), 8 deletions(-)
include/net/sock.h +1 -0
@@ -1921,6 +1921,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, gfp_t priority);void skb_orphan_partial (struct sk_buff *skb);void sock_rfree (struct sk_buff *skb); +void sock_rmem_free (struct sk_buff *skb);void sock_efree (struct sk_buff *skb);#ifdef CONFIG_INET void sock_edemux (struct sk_buff *skb);
net/core/skbuff.c +3 -3
@@ -5120,7 +5120,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) }EXPORT_SYMBOL_GPL (skb_cow_data); -static void sock_rmem_free (struct sk_buff *skb) +void sock_rmem_free (struct sk_buff *skb) {struct sock *sk = skb->sk;
@@ -5129,8 +5129,8 @@ static void sock_rmem_free(struct sk_buff *skb)static void skb_set_err_queue (struct sk_buff *skb) { -/* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. -* So, it is safe to (mis)use it to mark skbs on the error queue. +/* The error-queue test in skb_is_err_queue() matches this marker +* with the sock_rmem_free destructor installed by sock_queue_err_skb(). */ skb->pkt_type =PACKET_OUTGOING ;BUILD_BUG_ON (PACKET_OUTGOING ==0 );
net/socket.c +6 -5
@@ -823,12 +823,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked);static bool skb_is_err_queue (const struct sk_buff *skb) { -/* pkt_type of skbs enqueued on the error queue are set to -* PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do -* in recvmsg, since skbs received on a local socket will never -* have a pkt_type of PACKET_OUTGOING. +/* Error-queue skbs are marked as PACKET_OUTGOING in +* skb_set_err_queue() and use the destructor installed by +* sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: +* AF_PACKET outgoing taps use the same pkt_type. */ -return skb->pkt_type ==PACKET_OUTGOING ; +return skb->pkt_type ==PACKET_OUTGOING && + skb->destructor == sock_rmem_free; }/* On transmit, software and hardware timestamps are returned independently.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 274/452 net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic completion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ]
rds_ib_xmit_atomic() always programs a masked atomic opcode (IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) for every RDS atomic cmsg. But the completion-side switch in rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked atomic completion falls through to default and returns rm == NULL while send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection triggers it; on hardware that natively accepts masked atomics (mlx4, mlx5) no extra setup is needed.
RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR!
Oops: general protection fault [#1] SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) Call Trace: <IRQ> rds_ib_send_cqe_handler (net/rds/ib_send.c:282) poll_scq (net/rds/ib_cm.c:274) rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) tasklet_action_common (kernel/softirq.c:943) handle_softirqs (kernel/softirq.c:573) run_ksoftirqd (kernel/softirq.c:479) </IRQ> Kernel panic - not syncing: Fatal exception in interrupt
Handle the masked atomic opcodes in the same case as the non-masked
ones: they map to the same struct rds_message.atomic union member, so the existing container_of()/rds_ib_send_unmap_atomic() body is correct for them.
--- net/rds/ib_send.c | 2 ++ 1 file changed, 2 insertions(+)
net/rds/ib_send.c +2 -0
@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic,break ;case IB_WR_ATOMIC_FETCH_AND_ADD :case IB_WR_ATOMIC_CMP_AND_SWP : +case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD : +case IB_WR_MASKED_ATOMIC_CMP_AND_SWP :if (send->s_op) { rm = container_of(send->s_op, struct rds_message, atomic);rds_ib_send_unmap_atomic (ic, send->s_op, wc_status);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 275/452 ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ]
In vti6_tnl_lookup(), when an exact match for a tunnel fails, the code falls back to searching for wildcard tunnels:
- Tunnels matching the packet's local address, with any remote address wildcard remote).
- Tunnels matching the packet's remote address, with any local address (wildcard local).
However, vti6 stores all these different types of tunnels in the same hash table (ip6n->tnls_r_l) prone to hash collisions.
The bug is that the fallback search loops in vti6_tnl_lookup() were missing checks to ensure that the candidate tunnel actually has a wildcard address.
--- net/ipv6/ip6_vti.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/ip6_vti.c +2 -0
@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, hash =HASH (&any, local);for_each_vti6_tunnel_rcu (ip6n->tnls_r_l[hash]) {if (ipv6_addr_equal (local, &t->parms.laddr) && +ipv6_addr_any (&t->parms.raddr) && (t->dev->flags &IFF_UP ))return t; }
@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, hash =HASH (remote, &any);for_each_vti6_tunnel_rcu (ip6n->tnls_r_l[hash]) {if (ipv6_addr_equal (remote, &t->parms.raddr) && +ipv6_addr_any (&t->parms.laddr) && (t->dev->flags &IFF_UP ))return t; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 276/452 rds: mark snapshot pages dirty in rds_info_getsockopt()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ]
rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and the RDS_INFO_* producers memcpy the snapshot into them through kmap_atomic(). Because that copy goes through the kernel direct map, the dirty bit on the user PTE is never set, so unpin_user_pages() releases the pages without marking them dirty. A file-backed destination page can then be reclaimed without writeback, silently discarding the copied data.
Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified pages are marked dirty before they are unpinned.
--- net/rds/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/rds/info.c +1 -1
@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, out:if (pages) -unpin_user_pages (pages, nr_pages); +unpin_user_pages_dirty_lock (pages, nr_pages, true);kfree (pages);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 277/452 netfilter: nf_conntrack: destroy stale expectfn expectations on unregister
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ]
NAT helpers such as nf_nat_h323 store a raw pointer to module text in exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() only unlinks the callback descriptor and never walks the expectation table, so an expectation pending at module removal survives with a dangling exp->expectfn into freed module text.
When the expected connection arrives, init_conntrack() invokes exp->expectfn(), now a stale pointer into the unloaded module. Reproduced on a KASAN build by loading the H.323 helpers, creating a Q.931 expectation, unloading nf_nat_h323, then connecting to the expected port:
Oops: int3: 0000 [#1] SMP KASAN NOPTI RIP: 0010:0xffffffffa06102d1 init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) nf_hook_slow (net/netfilter/core.c:619) __ip_local_out (net/ipv4/ip_output.c:120) __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) tcp_connect (net/ipv4/tcp_output.c:4374) tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) __sys_connect (net/socket.c:2167) Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323]
Reaching the dangling state requires CAP_SYS_MODULE in the initial user namespace to remove a NAT helper that still has live expectations, so this is a robustness fix; leaving an expectation pointing at freed text is wrong regardless.
Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and drops every expectation whose ->expectfn matches the descriptor being torn down. Call it from each NAT helper's exit path after the existing RCU grace period, so no expectation outlives the code it points at and no extra synchronize_rcu() is introduced. With the fix, the same reproducer runs to completion without the Oops.
--- include/net/netfilter/nf_conntrack_helper.h | 1 + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ net/netfilter/nf_nat_core.c | 2 ++ net/netfilter/nf_nat_sip.c | 1 + 5 files changed, 25 insertions(+)
include/net/netfilter/nf_conntrack_helper.h +1 -0
@@ -155,6 +155,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,void nf_ct_helper_expectfn_register (struct nf_ct_helper_expectfn *n);void nf_ct_helper_expectfn_unregister (struct nf_ct_helper_expectfn *n); +void nf_ct_helper_expectfn_destroy (const struct nf_ct_helper_expectfn *n);struct nf_ct_helper_expectfn *nf_ct_helper_expectfn_find_by_name (const char *name); struct nf_ct_helper_expectfn *
net/ipv4/netfilter/nf_nat_h323.c +2 -0
@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void)nf_ct_helper_expectfn_unregister (&q931_nat);nf_ct_helper_expectfn_unregister (&callforwarding_nat);synchronize_rcu (); +nf_ct_helper_expectfn_destroy (&q931_nat); +nf_ct_helper_expectfn_destroy (&callforwarding_nat); }/****************************************************************************/
net/netfilter/nf_conntrack_helper.c +19 -0
@@ -288,6 +288,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) }EXPORT_SYMBOL_GPL (nf_ct_helper_expectfn_unregister); +static bool expect_iter_expectfn (struct nf_conntrack_expect *exp,void *data) +{ +const struct nf_ct_helper_expectfn *n = data; + +/* Relies on registered expectfn descriptors having unique ->expectfn +* pointers, which holds for the in-tree NAT helpers. +*/ +return exp->expectfn == n->expectfn; +} + +/* Destroy expectations still pointing at @n->expectfn; call after the +* caller's RCU grace period so none outlives the (often modular) callback. +*/ +void nf_ct_helper_expectfn_destroy (const struct nf_ct_helper_expectfn *n) +{ +nf_ct_expect_iterate_destroy (expect_iter_expectfn, (void *)n); +} +EXPORT_SYMBOL_GPL (nf_ct_helper_expectfn_destroy); +/* Caller should hold the rcu lock */ struct nf_ct_helper_expectfn *nf_ct_helper_expectfn_find_by_name (const char *name)
net/netfilter/nf_nat_core.c +2 -0
@@ -1363,6 +1363,7 @@ static int __init nf_nat_init(void)RCU_INIT_POINTER (nf_nat_hook,NULL );nf_ct_helper_expectfn_unregister (&follow_master_nat);synchronize_net (); +nf_ct_helper_expectfn_destroy (&follow_master_nat);unregister_pernet_subsys (&nat_net_ops);kvfree (nf_nat_bysource); }
@@ -1380,6 +1381,7 @@ static void __exit nf_nat_cleanup(void)RCU_INIT_POINTER (nf_nat_hook,NULL );synchronize_net (); +nf_ct_helper_expectfn_destroy (&follow_master_nat);kvfree (nf_nat_bysource);unregister_pernet_subsys (&nat_net_ops); }
net/netfilter/nf_nat_sip.c +1 -0
@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void)RCU_INIT_POINTER (nf_nat_sip_hooks,NULL );nf_ct_helper_expectfn_unregister (&sip_nat);synchronize_rcu (); +nf_ct_helper_expectfn_destroy (&sip_nat); }static const struct nf_nat_sip_hooks sip_hooks = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 278/452 netfilter: x_tables: avoid leaking percpu counter pointers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ]
The native and compat get-entries paths copy the fixed rule entry header from the kernelized rule blob to userspace before overwriting the entry's counter fields with a sanitized counter snapshot.
On SMP kernels, entry->counters.pcnt contains the percpu allocation address used by x_tables rule counters. A caller can provide a userspace buffer that faults during the initial fixed-header copy after pcnt has been copied but before the later sanitized counter copy runs. The syscall then returns -EFAULT while leaving the raw percpu pointer in userspace.
Copy only the fixed entry prefix before counters from the kernelized rule blob, then copy the sanitized counter snapshot into the counter field. Apply this ordering to the IPv4, IPv6, and ARP native and compat get-entries implementations so a fault cannot expose the internal percpu counter pointer.
--- net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- 3 files changed, 18 insertions(+), 27 deletions(-)
net/ipv4/netfilter/arp_tables.c +6 -9
@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size,const struct xt_entry_target *t; e = loc_cpu_entry + off; -if (copy_to_user (userptr + off, e,sizeof (*e))) { - ret = -EFAULT ; - goto free_counters; - } -if (copy_to_user (userptr + off +if (copy_to_user (userptr + off, e, + offsetof(struct arpt_entry , counters)) || +copy_to_user (userptr + off + offsetof(struct arpt_entry , counters), &counters[num], -sizeof (counters[num])) !=0 ) { +sizeof (counters[num]))) { ret = -EFAULT ; goto free_counters; }
@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, origsize = *size; ce = *dstptr; -if (copy_to_user (ce, e,sizeof (struct arpt_entry )) !=0 || -copy_to_user (&ce->counters, &counters[i], -sizeof (counters[i])) !=0 ) +if (copy_to_user (ce, e, offsetof(struct compat_arpt_entry , counters)) || +copy_to_user (&ce->counters, &counters[i],sizeof (counters[i])))return -EFAULT ; *dstptr +=sizeof (struct compat_arpt_entry );
net/ipv4/netfilter/ip_tables.c +6 -9
@@ -832,14 +832,12 @@ copy_entries_to_user(unsigned int total_size,const struct xt_entry_target *t; e = loc_cpu_entry + off; -if (copy_to_user (userptr + off, e,sizeof (*e))) { - ret = -EFAULT ; - goto free_counters; - } -if (copy_to_user (userptr + off +if (copy_to_user (userptr + off, e, + offsetof(struct ipt_entry , counters)) || +copy_to_user (userptr + off + offsetof(struct ipt_entry , counters), &counters[num], -sizeof (counters[num])) !=0 ) { +sizeof (counters[num]))) { ret = -EFAULT ; goto free_counters; }
@@ -1228,9 +1226,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, origsize = *size; ce = *dstptr; -if (copy_to_user (ce, e,sizeof (struct ipt_entry )) !=0 || -copy_to_user (&ce->counters, &counters[i], -sizeof (counters[i])) !=0 ) +if (copy_to_user (ce, e, offsetof(struct compat_ipt_entry , counters)) || +copy_to_user (&ce->counters, &counters[i],sizeof (counters[i])))return -EFAULT ; *dstptr +=sizeof (struct compat_ipt_entry );
net/ipv6/netfilter/ip6_tables.c +6 -9
@@ -848,14 +848,12 @@ copy_entries_to_user(unsigned int total_size,const struct xt_entry_target *t; e = loc_cpu_entry + off; -if (copy_to_user (userptr + off, e,sizeof (*e))) { - ret = -EFAULT ; - goto free_counters; - } -if (copy_to_user (userptr + off +if (copy_to_user (userptr + off, e, + offsetof(struct ip6t_entry , counters)) || +copy_to_user (userptr + off + offsetof(struct ip6t_entry , counters), &counters[num], -sizeof (counters[num])) !=0 ) { +sizeof (counters[num]))) { ret = -EFAULT ; goto free_counters; }
@@ -1244,9 +1242,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, origsize = *size; ce = *dstptr; -if (copy_to_user (ce, e,sizeof (struct ip6t_entry )) !=0 || -copy_to_user (&ce->counters, &counters[i], -sizeof (counters[i])) !=0 ) +if (copy_to_user (ce, e, offsetof(struct compat_ip6t_entry , counters)) || +copy_to_user (&ce->counters, &counters[i],sizeof (counters[i])))return -EFAULT ; *dstptr +=sizeof (struct compat_ip6t_entry );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 279/452 netfilter: nf_log: validate MAC header was set before dumping it
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ]
The fallback path of dump_mac_header() guards the MAC header access only with "skb->mac_header != skb->network_header", without checking skb_mac_header_was_set(). When the MAC header is unset, mac_header is 0xffff, so the test passes and skb_mac_header(skb) returns skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads dev->hard_header_len bytes out of bounds into the kernel log.
This is reachable via the netdev logger: nf_log_unknown_packet() calls dump_mac_header() unconditionally, and an skb sent through AF_PACKET with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still unset (__dev_queue_xmit(), which would reset it, is bypassed).
Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already uses, and replace the open-coded MAC header length test with skb_mac_header_len(). Only skbs with an unset MAC header are affected; valid ones are dumped as before.
BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) Read of size 1 at addr ffff88800ea49d3f by task exploit/148 Call Trace: kasan_report (mm/kasan/report.c:595) dump_mac_header (net/netfilter/nf_log_syslog.c:831) nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) nf_log_packet (net/netfilter/nf_log.c:260) nft_log_eval (net/netfilter/nft_log.c:60) nft_do_chain (net/netfilter/nf_tables_core.c:285) nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) nf_hook_slow (net/netfilter/core.c:619) nf_hook_direct_egress (net/packet/af_packet.c:257) packet_xmit (net/packet/af_packet.c:280) packet_sendmsg (net/packet/af_packet.c:3114) __sys_sendto (net/socket.c:2265)
--- net/netfilter/nf_log_syslog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/nf_log_syslog.c +2 -2
@@ -799,8 +799,8 @@ static void dump_mac_header(struct nf_log_buf *m, fallback:nf_log_buf_add (m,"MAC=" ); -if (dev->hard_header_len && - skb->mac_header != skb->network_header) { +if (dev->hard_header_len &&skb_mac_header_was_set (skb) && +skb_mac_header_len (skb) !=0 ) {const unsigned char *p =skb_mac_header (skb);unsigned int i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 280/452 netfilter: nft_exthdr: fix register tracking for F_PRESENT flag
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ]
nft_exthdr_init() passes user-controlled priv->len to nft_parse_register_store(), which marks that many bytes in the register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT is set, the eval paths write only 1 byte (nft_reg_store8) or 4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, registers beyond the first are never written, retaining uninitialized stack data from nft_regs.
Bail out if userspace requests too much data when F_PRESENT is set.
--- net/netfilter/nft_exthdr.c | 3 +++ 1 file changed, 3 insertions(+)
net/netfilter/nft_exthdr.c +3 -0
@@ -530,6 +530,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,return err; } +if ((flags &NFT_EXTHDR_F_PRESENT ) && len !=1 ) +return -EINVAL ; + priv->type =nla_get_u8 (tb[NFTA_EXTHDR_TYPE ]); priv->offset = offset; priv->len = len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 281/452 net: mvpp2: sync RX data at the hardware packet offset
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Til Kaiser <[email protected]>
[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ]
mvpp2 programs the RX queue packet offset, so hardware writes received data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the unused headroom and misses the same number of bytes at the packet tail.
On non-coherent DMA systems this can leave the CPU reading stale cache contents for the end of the received frame.
Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range offset so the sync covers the Marvell header and packet data actually written by hardware.
--- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +4 -3
@@ -3948,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, dma_dir =DMA_FROM_DEVICE ; } -dma_sync_single_for_cpu (dev->dev.parent, dma_addr, - rx_bytes +MVPP2_MH_SIZE , - dma_dir); +dma_sync_single_range_for_cpu (dev->dev.parent, dma_addr, +MVPP2_SKB_HEADROOM , + rx_bytes +MVPP2_MH_SIZE , + dma_dir);/* Buffer header not supported */ if (rx_status &MVPP2_RXD_BUF_HDR )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 282/452 net: mvpp2: limit XDP frame size to the RX buffer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Til Kaiser <[email protected]>
[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ]
mvpp2 has short and long BM pools, and short pool buffers can be smaller than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with PAGE_SIZE as frame size.
XDP helpers use frame_sz to validate tail growth and to derive the hard end of the data area. Advertising PAGE_SIZE for short buffers can let bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting memory or later tripping skb tailroom checks.
Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches the actual buffer backing the packet.
--- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +1 -1
@@ -3981,7 +3981,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,else xdp_rxq = &rxq->xdp_rxq_long; -xdp_init_buff (&xdp,PAGE_SIZE , xdp_rxq); +xdp_init_buff (&xdp, bm_pool->frag_size, xdp_rxq);xdp_prepare_buff (&xdp, data,MVPP2_MH_SIZE +MVPP2_SKB_HEADROOM , rx_bytes, false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 283/452 net: mvpp2: Add metadata support for xdp mode
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 9a45e193c88a55a536d7fd0ebfa29823d588c2cf ]
Set metadata size building the skb from xdp_buff in mvpp2 driver mvpp2 driver sets xdp headroom to:
MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM
where
MVPP2_MH_SIZE 2MVPP2_SKB_HEADROOM min(max(XDP_PACKET_HEADROOM, NET_SKB_PAD), 224)
so the headroom is large enough to contain xdp_frame and xdp metadata. Please note this patch is just compiled tested.
Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS")
--- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +6 -2
@@ -3915,13 +3915,13 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,while (rx_done < rx_todo) {struct mvpp2_rx_desc *rx_desc =mvpp2_rxq_next_desc_get (rxq); +u32 rx_status, timestamp, metasize =0 ;struct mvpp2_bm_pool *bm_pool;struct page_pool *pp =NULL ;struct sk_buff *skb;unsigned int frag_size;dma_addr_t dma_addr;phys_addr_t phys_addr; -u32 rx_status, timestamp;int pool, rx_bytes, err, ret;struct page *page;void *data;
@@ -3984,7 +3984,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,xdp_init_buff (&xdp, bm_pool->frag_size, xdp_rxq);xdp_prepare_buff (&xdp, data,MVPP2_MH_SIZE +MVPP2_SKB_HEADROOM , - rx_bytes, false); + rx_bytes, true); ret =mvpp2_run_xdp (port, xdp_prog, &xdp, pp, &ps);
@@ -4000,6 +4000,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, ps.rx_bytes += rx_bytes;continue ; } + + metasize = xdp.data - xdp.data_meta; }if (frag_size)
@@ -4039,6 +4041,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,skb_reserve (skb,MVPP2_MH_SIZE +MVPP2_SKB_HEADROOM );skb_put (skb, rx_bytes); +if (metasize) +skb_metadata_set (skb, metasize); skb->ip_summed =mvpp2_rx_csum (port, rx_status); skb->protocol =eth_type_trans (skb, dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 284/452 net: mvpp2: refill RX buffers before XDP or skb use
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Til Kaiser <[email protected]>
[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ]
The RX error path returns the current descriptor buffer to the hardware BM pool. That is only valid while the driver still owns the buffer.
mvpp2_rx_refill() can fail after the current buffer has been handed to XDP or attached to an skb. In those cases mvpp2_run_xdp() may have recycled, redirected, or queued the page for XDP_TX, and an skb free also retires the data buffer. Returning such a buffer to BM lets hardware DMA into memory that is no longer owned by the RX ring.
Refill the BM pool before handing the current buffer to XDP or to the skb. If the allocation fails there, drop the packet and return the still-owned current buffer to BM, preserving the pool depth. Once the refill succeeds, later local drops retire/free the current buffer instead of returning it to BM.
Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS")
--- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +24 -19
@@ -3973,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,else frag_size = bm_pool->frag_size; + err =mvpp2_rx_refill (port, bm_pool, pp, pool); +if (err) { +netdev_err (port->dev,"failed to refill BM pools\n" ); + goto err_drop_frame; + } +if (xdp_prog) {struct xdp_rxq_info *xdp_rxq;
@@ -3990,12 +3996,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,if (ret) { xdp_ret |= ret; - err =mvpp2_rx_refill (port, bm_pool, pp, pool); -if (err) { -netdev_err (port->dev,"failed to refill BM pools\n" ); - goto err_drop_frame; - } - ps.rx_packets++; ps.rx_bytes += rx_bytes;continue ;
@@ -4010,8 +4010,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, skb =slab_build_skb (data);if (!skb) {netdev_warn (port->dev,"skb build failed\n" ); - goto err_drop_frame; +if (pp) { +page_pool_put_page (pp,virt_to_head_page (data), + rx_bytes +MVPP2_MH_SIZE , + true); + }else { +dma_unmap_single_attrs (dev->dev.parent, dma_addr, + bm_pool->buf_size, +DMA_FROM_DEVICE , +DMA_ATTR_SKIP_CPU_SYNC ); +mvpp2_frag_free (bm_pool, pp, data); + } + goto err_drop_frame_retired; } +if (pp) +skb_mark_for_recycle (skb);/* If we have RX hardware timestamping enabled, grab the * timestamp from the queue and convert.
@@ -4022,16 +4035,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, skb_hwtstamps(skb)); } - err =mvpp2_rx_refill (port, bm_pool, pp, pool); -if (err) { -netdev_err (port->dev,"failed to refill BM pools\n" ); -dev_kfree_skb_any (skb); - goto err_drop_frame; - } - -if (pp) -skb_mark_for_recycle (skb); -else +if (!pp)dma_unmap_single_attrs (dev->dev.parent, dma_addr, bm_pool->buf_size,DMA_FROM_DEVICE ,DMA_ATTR_SKIP_CPU_SYNC );
@@ -4050,13 +4054,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,continue ; err_drop_frame: - dev->stats.rx_errors++; -mvpp2_rx_error (port, rx_desc);/* Return the buffer to the pool */ if (rx_status &MVPP2_RXD_BUF_HDR )mvpp2_buff_hdr_pool_put (port, rx_desc, pool, rx_status);else mvpp2_bm_pool_put (port, pool, dma_addr, phys_addr); +err_drop_frame_retired: + dev->stats.rx_errors++; +mvpp2_rx_error (port, rx_desc); }if (xdp_ret &MVPP2_XDP_REDIR )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 285/452 net: mvpp2: build skb from XDP-adjusted data on XDP_PASS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Til Kaiser <[email protected]>
[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ]
When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets derived from the original RX descriptor. Packet geometry changes made by the XDP program are therefore discarded before the skb reaches the stack.
Update rx_offset and rx_bytes from xdp.data and xdp.data_end for XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen by XDP, and makes RX byte accounting for XDP_PASS follow the length of the skb passed to the network stack.
Keep a separate rx_sync_size for page-pool recycling on skb allocation failure, which must stay tied to the received buffer range.
Non-PASS verdicts continue to account the descriptor length because no skb is passed up in those cases.
--- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +15 -6
@@ -3919,10 +3919,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,struct mvpp2_bm_pool *bm_pool;struct page_pool *pp =NULL ;struct sk_buff *skb; -unsigned int frag_size; +unsigned int frag_size, rx_sync_size;dma_addr_t dma_addr;phys_addr_t phys_addr; -int pool, rx_bytes, err, ret; +int pool, rx_bytes, rx_offset, err, ret;struct page *page;void *data;
@@ -3935,6 +3935,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, rx_status =mvpp2_rxdesc_status_get (port, rx_desc); rx_bytes =mvpp2_rxdesc_size_get (port, rx_desc); rx_bytes -=MVPP2_MH_SIZE ; + rx_sync_size = rx_bytes +MVPP2_MH_SIZE ; + rx_offset =MVPP2_MH_SIZE +MVPP2_SKB_HEADROOM ; dma_addr =mvpp2_rxdesc_dma_addr_get (port, rx_desc); pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >>
@@ -3950,7 +3952,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,dma_sync_single_range_for_cpu (dev->dev.parent, dma_addr,MVPP2_SKB_HEADROOM , - rx_bytes +MVPP2_MH_SIZE , + rx_sync_size, dma_dir);/* Buffer header not supported */
@@ -4001,6 +4003,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,continue ; } + rx_sync_size = max_t(unsigned int, rx_sync_size, + xdp.data_end - xdp.data_hard_start - +MVPP2_SKB_HEADROOM ); + +/* Update offset and length to reflect any XDP adjustments. */ + rx_offset = xdp.data - data; + rx_bytes = xdp.data_end - xdp.data; + metasize = xdp.data - xdp.data_meta; }
@@ -4012,8 +4022,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,netdev_warn (port->dev,"skb build failed\n" );if (pp) {page_pool_put_page (pp,virt_to_head_page (data), - rx_bytes +MVPP2_MH_SIZE , - true); + rx_sync_size, true); }else { dma_unmap_single_attrs(dev->dev.parent, dma_addr, bm_pool->buf_size,
@@ -4043,7 +4052,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, ps.rx_packets++; ps.rx_bytes += rx_bytes; -skb_reserve (skb,MVPP2_MH_SIZE +MVPP2_SKB_HEADROOM ); +skb_reserve (skb, rx_offset);skb_put (skb, rx_bytes);if (metasize)skb_metadata_set (skb, metasize);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 286/452 ipv6: Fix a potential NPD in cleanup_prefix_route()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit b70c687b7cf267fb08586667a3946c8851cad672 ]
addrconf_get_prefix_route() can return the fib6_null_entry sentinel entry which has a NULL fib6_table pointer. Therefore, before setting the route's expiration time, check that we are not working with this entry, as otherwise a NPD will be triggered [1].
Note that the other callers of addrconf_get_prefix_route() are not susceptible to this bug:
1. addrconf_prefix_rcv(): Requests a route with the 'RTF_ADDRCONF | RTF_PREFIX_RT' flags which are not set on fib6_null_entry.
2. modify_prefix_route(): Fixed by commit a747e02430df ("ipv6: avoid possible NULL deref in modify_prefix_route()").
3. __ipv6_ifa_notify(): Calls ip6_del_rt() which specifically checks for fib6_null_entry and returns an error.
[1]
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037] [...] Call Trace: <TASK> __kasan_check_byte (mm/kasan/common.c:573) lock_acquire.part.0 (kernel/locking/lockdep.c:5842 (discriminator 1)) _raw_spin_lock_bh (kernel/locking/spinlock.c:182 (discriminator 1))
cleanup_prefix_route (net/ipv6/addrconf.c:1280)ipv6_del_addr (net/ipv6/addrconf.c:1342)
inet6_addr_del.isra.0 (net/ipv6/addrconf.c:3119) inet6_rtm_deladdr (net/ipv6/addrconf.c:4812)rtnetlink_rcv_msg (net/core/rtnetlink.c:6997)netlink_rcv_skb (net/netlink/af_netlink.c:2555)netlink_unicast (net/netlink/af_netlink.c:1344)netlink_sendmsg (net/netlink/af_netlink.c:1899)__sock_sendmsg (net/socket.c:802 (discriminator 4)) ____sys_sendmsg (net/socket.c:2698)___sys_sendmsg (net/socket.c:2752)__sys_sendmsg (net/socket.c:2784)do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
--- net/ipv6/addrconf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/ipv6/addrconf.c +4 -2
@@ -1268,6 +1268,7 @@ static void cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt, bool del_peer) { + struct net *net = dev_net(ifp->idev->dev);struct fib6_table *table;struct fib6_info *f6i;
@@ -1276,9 +1277,10 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, ifp->idev->dev, 0, RTF_DEFAULT, true);if (f6i) {if (del_rt) -ip6_del_rt (dev_net (ifp->idev->dev), f6i, false); +ip6_del_rt (net, f6i, false);else { -if (!(f6i->fib6_flags &RTF_EXPIRES )) { +if (f6i != net->ipv6.fib6_null_entry && + !(f6i->fib6_flags &RTF_EXPIRES )) { table = f6i->fib6_table;spin_lock_bh (&table->tb6_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 287/452 netfilter: ctnetlink: ensure safe access to master conntrack
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit bffcaad9afdfe45d7fc777397d3b83c1e3ebffe5 ]
Holding reference on the expectation is not sufficient, the master conntrack object can just go away, making exp->master invalid.
To access exp->master safely:
- Grab the nf_conntrack_expect_lock, this gets serialized with clean_from_lists() which also holds this lock when the master conntrack goes away.
- Hold reference on master conntrack via nf_conntrack_find_get(). Not so easy since the master tuple to look up for the master conntrack is not available in the existing problematic paths.
This patch goes for extending the nf_conntrack_expect_lock section to address this issue for simplicity, in the cases that are described below this is just slightly extending the lock section.
The add expectation command already holds a reference to the master conntrack from ctnetlink_create_expect().
However, the delete expectation command needs to grab the spinlock before looking up for the expectation. Expand the existing spinlock section to address this to cover the expectation lookup. Note that, the nf_ct_expect_iterate_net() calls already grabs the spinlock while iterating over the expectation table, which is correct.
The get expectation command needs to grab the spinlock to ensure master conntrack does not go away. This also expands the existing spinlock section to cover the expectation lookup too. I needed to move the netlink skb allocation out of the spinlock to keep it GFP_KERNEL.
For the expectation events, the IPEXP_DESTROY event is already delivered under the spinlock, just move the delivery of IPEXP_NEW under the spinlock too because the master conntrack event cache is reached through exp->master.
While at it, add lockdep notations to help identify what codepaths need to grab the spinlock.
[ fix timer_delete -> del_timer in diff context lines since 8fa7292 ("treewide: Switch/rename to timer_delete[_sync]()") landed in 6.15 ]
--- include/net/netfilter/nf_conntrack_core.h | 5 ++++ net/netfilter/nf_conntrack_ecache.c | 2 ++ net/netfilter/nf_conntrack_expect.c | 10 +++++++- net/netfilter/nf_conntrack_netlink.c | 28 +++++++++++++++-------- 4 files changed, 35 insertions(+), 10 deletions(-)
include/net/netfilter/nf_conntrack_core.h +5 -0
@@ -83,6 +83,11 @@ void nf_conntrack_lock(spinlock_t *lock);extern spinlock_t nf_conntrack_expect_lock; +static inline void lockdep_nfct_expect_lock_held (void ) +{ +lockdep_assert_held (&nf_conntrack_expect_lock); +} +/* ctnetlink code shared by both ctnetlink and nf_conntrack_bpf */ static inline void __nf_ct_set_timeout (struct nf_conn *ct,u64 timeout)
net/netfilter/nf_conntrack_ecache.c +2 -0
@@ -237,6 +237,8 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,struct nf_ct_event_notifier *notify;struct nf_conntrack_ecache *e; +lockdep_nfct_expect_lock_held (); +rcu_read_lock (); notify =rcu_dereference (net->ct.nf_conntrack_event_cb);if (!notify)
net/netfilter/nf_conntrack_expect.c +9 -1
@@ -51,6 +51,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,struct net *net =nf_ct_exp_net (exp);struct nf_conntrack_net *cnet; +lockdep_nfct_expect_lock_held ();WARN_ON (!master_help);WARN_ON (timer_pending (&exp->timeout));
@@ -118,6 +119,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,bool nf_ct_remove_expect (struct nf_conntrack_expect *exp) { +lockdep_nfct_expect_lock_held (); +if (del_timer (&exp->timeout)) {nf_ct_unlink_expect (exp);nf_ct_expect_put (exp);
@@ -177,6 +180,8 @@ nf_ct_find_expectation(struct net *net,struct nf_conntrack_expect *i, *exp =NULL ;unsigned int h; +lockdep_nfct_expect_lock_held (); +if (!cnet->expect_count)return NULL ;
@@ -459,6 +464,8 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,unsigned int h;int ret =0 ; +lockdep_nfct_expect_lock_held (); +if (!master_help) { ret = -ESHUTDOWN ; goto out;
@@ -515,8 +522,9 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,nf_ct_expect_insert (expect); -spin_unlock_bh (&nf_conntrack_expect_lock);nf_ct_expect_event_report (IPEXP_NEW , expect, portid, report); +spin_unlock_bh (&nf_conntrack_expect_lock); +return 0 ; out:spin_unlock_bh (&nf_conntrack_expect_lock);
net/netfilter/nf_conntrack_netlink.c +19 -9
@@ -3326,31 +3326,37 @@ static int ctnetlink_get_expect(struct sk_buff *skb,if (err <0 )return err; + skb2 =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); +if (!skb2) +return -ENOMEM ; + +spin_lock_bh (&nf_conntrack_expect_lock); exp =nf_ct_expect_find_get (info->net, &zone, &tuple); -if (!exp) +if (!exp) { +spin_unlock_bh (&nf_conntrack_expect_lock); +kfree_skb (skb2);return -ENOENT ; + }if (cda[CTA_EXPECT_ID ]) {__be32 id =nla_get_be32 (cda[CTA_EXPECT_ID ]);if (id !=nf_expect_get_id (exp)) {nf_ct_expect_put (exp); +spin_unlock_bh (&nf_conntrack_expect_lock); +kfree_skb (skb2);return -ENOENT ; } } - skb2 =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); -if (!skb2) { -nf_ct_expect_put (exp); -return -ENOMEM ; - } -rcu_read_lock (); err =ctnetlink_exp_fill_info (skb2,NETLINK_CB (skb).portid, info->nlh->nlmsg_seq,IPCTNL_MSG_EXP_NEW , exp);rcu_read_unlock ();nf_ct_expect_put (exp); +spin_unlock_bh (&nf_conntrack_expect_lock); +if (err <=0 ) {kfree_skb (skb2);return -ENOMEM ;
@@ -3397,22 +3403,26 @@ static int ctnetlink_del_expect(struct sk_buff *skb,if (err <0 )return err; +spin_lock_bh (&nf_conntrack_expect_lock); +/* bump usage count to 2 */ exp =nf_ct_expect_find_get (info->net, &zone, &tuple); -if (!exp) +if (!exp) { +spin_unlock_bh (&nf_conntrack_expect_lock);return -ENOENT ; + }if (cda[CTA_EXPECT_ID ]) {__be32 id =nla_get_be32 (cda[CTA_EXPECT_ID ]);if (id !=nf_expect_get_id (exp)) {nf_ct_expect_put (exp); +spin_unlock_bh (&nf_conntrack_expect_lock);return -ENOENT ; } }/* after list removal, usage count == 1 */ -spin_lock_bh (&nf_conntrack_expect_lock);if (del_timer (&exp->timeout)) {nf_ct_unlink_expect_report (exp,NETLINK_CB (skb).portid,nlmsg_report (info->nlh));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 288/452 clk: qcom: dispcc-sc8280xp: Dont park mdp_clk_src at registration time
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengyu Luo <[email protected]>
[ Upstream commit 5285b046757844435d1db96c1b5c3a6621b2979a ]
Parking disp{0,1}_cc_mdss_mdp_clk_src clk broke simplefb on HUAWEI Gaokun3, the image will stuck at grey for seconds until msm takes over framebuffer. Use clk_rcg2_shared_no_init_park_ops to skip it.
--- drivers/clk/qcom/dispcc-sc8280xp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/qcom/dispcc-sc8280xp.c +2 -2
@@ -978,7 +978,7 @@ static struct clk_rcg2 disp0_cc_mdss_mdp_clk_src = { .name = "disp0_cc_mdss_mdp_clk_src", .parent_data = disp0_cc_parent_data_5, .num_parents = ARRAY_SIZE(disp0_cc_parent_data_5), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, }, };
@@ -992,7 +992,7 @@ static struct clk_rcg2 disp1_cc_mdss_mdp_clk_src = { .name = "disp1_cc_mdss_mdp_clk_src", .parent_data = disp1_cc_parent_data_5, .num_parents = ARRAY_SIZE(disp1_cc_parent_data_5), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 289/452 drm/virtio: Fix driver removal with disabled KMS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Osipenko <[email protected]>
[ Upstream commit f329e8325e054bd6d84d10904f8dd51137281b92 ]
DRM atomic and modesetting aren't initialized if virtio-gpu driver built with disabled KMS, leading to access of uninitialized data on driver removal/unbinding and crashing kernel. Fix it by skipping shutting down atomic core with unavailable KMS.
--- drivers/gpu/drm/virtio/virtgpu_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_drv.c +4 -1
@@ -118,7 +118,10 @@ static void virtio_gpu_remove(struct virtio_device *vdev)struct drm_device *dev = vdev->priv;drm_dev_unplug (dev); -drm_atomic_helper_shutdown (dev); + +if (drm_core_check_feature (dev,DRIVER_ATOMIC )) +drm_atomic_helper_shutdown (dev); +virtio_gpu_deinit (dev);drm_dev_put (dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 290/452 drm/vc4: fix krealloc() memory leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander A. Klimov <[email protected]>
[ Upstream commit 5d563a5da8717629ae72f9eadf1e0e340bd1658b ]
Don't just overwrite the original pointer passed to krealloc() with its return value without checking latter:
MEM = krealloc(MEM, SZ, GFP);
If krealloc() returns NULL, that erases the pointer to the still allocated memory, hence leaks this memory. Instead, use a temporary variable, check it's not NULL and only then assign it to the original pointer:
TMP = krealloc(MEM, SZ, GFP);
if (!TMP) return;
MEM = TMP;While on it, use krealloc_array().
--- drivers/gpu/drm/vc4/vc4_validate_shaders.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/gpu/drm/vc4/vc4_validate_shaders.c +7 -6
@@ -288,15 +288,16 @@ static bool require_uniform_address_uniform(struct vc4_validated_shader_info *va {uint32_t o = validated_shader->num_uniform_addr_offsets;uint32_t num_uniforms = validated_shader->uniforms_size /4 ; +u32 *offsets; - validated_shader->uniform_addr_offsets = -krealloc (validated_shader->uniform_addr_offsets, - (o +1 ) * -sizeof (*validated_shader->uniform_addr_offsets), -GFP_KERNEL ); -if (!validated_shader->uniform_addr_offsets) + offsets =krealloc_array (validated_shader->uniform_addr_offsets, + o +1 , +sizeof (*validated_shader->uniform_addr_offsets), +GFP_KERNEL ); +if (!offsets)return false; + validated_shader->uniform_addr_offsets = offsets; validated_shader->uniform_addr_offsets[o] = num_uniforms; validated_shader->num_uniform_addr_offsets++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 291/452 netfilter: nft_tunnel: fix use-after-free on object destroy
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit c32b26aaa2f9216520a38b3f4bfeec846eb3eb8a upstream.
nft_tunnel_obj_destroy() calls metadata_dst_free() which directly kfree()s the metadata_dst, ignoring the dst_entry refcount. Packets that took a reference via dst_hold() in nft_tunnel_obj_eval() and are still queued (e.g. in a netem qdisc) are left with a dangling pointer. When these packets are eventually dequeued, dst_release() operates on freed memory.
Replace metadata_dst_free() with dst_release() so the metadata_dst is freed only after all references are dropped. The dst subsystem already handles metadata_dst cleanup in dst_destroy() when DST_METADATA is set.
--- net/netfilter/nft_tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nft_tunnel.c +1 -1
@@ -699,7 +699,7 @@ static void nft_tunnel_obj_destroy(const {struct nft_tunnel_obj *priv =nft_obj_data (obj); -metadata_dst_free (priv->md); +dst_release (&priv->md->dst); }static struct nft_object_type nft_tunnel_obj_type;
Greg Kroah-Hartman
maintainerPATCH 292/452 Bluetooth: hci_sync: reject oversized Broadcast Announcement prepend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 5c65b96b549ea2dcfde497436bf9e048deb87758 upstream.
Existing advertising instances can already hold the maximum extended advertising payload. When hci_adv_bcast_annoucement() prepends the Broadcast Announcement service data to that payload, the combined data may no longer fit in the temporary buffer used to rebuild the advertising data.
Reject that case before copying the existing payload and report the failure through the device log. This keeps the existing advertising data intact and avoids overrunning the temporary buffer.
--- net/bluetooth/hci_sync.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/hci_sync.c +5 -0
@@ -1759,6 +1759,11 @@ static int hci_adv_bcast_annoucement(str/* Generate Broadcast ID */ get_random_bytes (bid,sizeof (bid)); len =eir_append_service_data (ad,0 ,0x1852 , bid,sizeof (bid)); +if (adv->adv_data_len >sizeof (ad) - len) { +bt_dev_err (hdev,"No room for Broadcast Announcement" ); +return -EINVAL ; + } +memcpy (ad + len, adv->adv_data, adv->adv_data_len);hci_set_adv_instance_data (hdev, adv->instance, len + adv->adv_data_len, ad,0 ,NULL );
Greg Kroah-Hartman
maintainerPATCH 293/452 Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit dd214733544427587a95f66dbf3adff072568990 upstream.
net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR signaling packets up to the channel MTU and dispatches each command without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer within radio range can send a fixed-channel CID 0x0001 packet that is larger than MTUsig and contains many L2CAP_ECHO_REQ commands before pairing. In a real-radio stock-kernel run, one 681-byte signaling packet containing 168 zero-length ECHO_REQ commands made the target transmit 168 ECHO_RSP frames over about 220 ms.
Impact: a Bluetooth BR/EDR peer within radio range, before pairing, can force 168 ECHO_RSP frames from one 681-byte fixed-channel signaling packet containing packed ECHO_REQ commands.
Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and reject any larger signaling packet with one L2CAP_COMMAND_REJECT_RSP carrying L2CAP_REJ_MTU_EXCEEDED before any command is dispatched.
The Bluetooth Core spec wording for MTUExceeded says the reject identifier shall match the first request command in the packet, and that packets containing only responses shall be silently discarded. Linux intentionally deviates from that prescription: silently discarding desynchronizes the peer because the remote stack never learns its responses were dropped, and locating the first request command requires walking command headers past MTUsig, i.e. processing bytes from a packet we have already decided is too large to process. We therefore always emit one reject and use the identifier from the first command header, a single fixed-offset byte read.
The unrestricted BR/EDR signaling parser and ECHO_REQ response path both trace to the initial git import; no later introducing commit is available for a Fixes tag.
--- include/net/bluetooth/l2cap.h | 1 net/bluetooth/l2cap_core.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
include/net/bluetooth/l2cap.h +1 -0
@@ -33,6 +33,7 @@/* L2CAP defaults */ #define L2CAP_DEFAULT_MTU 672#define L2CAP_DEFAULT_MIN_MTU 48 +#define L2CAP_SIG_MTU 48/* BR/EDR signaling MTU */ #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF#define L2CAP_EFS_DEFAULT_FLUSH_TO 0xFFFFFFFF#define L2CAP_DEFAULT_TX_WINDOW 63
net/bluetooth/l2cap_core.c +46 -0
58 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 294/452 tracing/probes: Point the error offset correctly for eprobe argument error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 85e0f27dd1396307913ffc5745b0c05137e9beac upstream.
Fix to point the error offset correctly for eprobe argument error. In the cleanup commit 1b8b0cd754cd ("tracing/probes: Move event parameter fetching code to common parser"), due to incorrect backward compatibility aimed at conforming to the test specifications, the error location was set to 0 when a non-existent formal parameter was specified for Eprobe. However, this should be corrected in both the test and the implementation to point correct error position.
--- kernel/trace/trace_probe.c | 2 -- tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-)
kernel/trace/trace_probe.c +0 -2
@@ -933,8 +933,6 @@ static int parse_probe_vars(char *orig_a code->op =FETCH_OP_COMM ;return 0 ; } -/* backward compatibility */ - ctx->offset =0 ; goto inval; }
tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc +1 -1
@@ -20,7 +20,7 @@ check_error 'e:foo/^12345678901234567890 check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME check_error 'e:foo/bar syscalls/sys_enter_openat arg=^dfd' # BAD_FETCH_ARG -check_error 'e:foo/bar syscalls/sys_enter_openat ^arg=$foo' # BAD_ATTACH_ARG +check_error 'e:foo/bar syscalls/sys_enter_openat arg=^$foo' # BAD_ATTACH_ARG if grep -q '<attached-group>\.<attached-event>.*\[if <filter>\]' README; then check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER
Greg Kroah-Hartman
maintainerPATCH 295/452 mmc: litex_mmc: Use DIV_ROUND_UP for more accurate clock calculation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Inochi Amaoto <[email protected]>
commit b837e38c255dd9f8b53511d52e87f1fda32b3dfe upstream.
The previous clock uses roundup_pow_of_two() to calculate the core clock frequency. It does not meet the actual hardware meaning. The actual frequency is calculated by "ref_clk / ((div >> 1) << 1)".
Fix the clock divider calculation.
--- drivers/mmc/host/litex_mmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/mmc/host/litex_mmc.c +3 -3
@@ -16,6 +16,7 @@#include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/litex.h> +#include <linux/math.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h>
@@ -436,11 +437,10 @@ static void litex_mmc_setclk(struct litestruct device *dev =mmc_dev (host->mmc);u32 div; - div = freq ? host->ref_clk / freq :256U ; - div =roundup_pow_of_two (div); + div = freq ?DIV_ROUND_UP (host->ref_clk, freq) :256U ; div =clamp (div,2U ,256U );dev_dbg (dev,"sd_clk_freq=%d: set to %d via div=%d\n" , - freq, host->ref_clk / div, div); + freq, host->ref_clk / ((div +1 ) & ~1U ), div);litex_write16 (host->sdphy +LITEX_PHY_CLOCKERDIV , div); host->sd_clk = freq; }
Greg Kroah-Hartman
maintainerPATCH 296/452 KVM: Dont WARN if memory is dirtied without a vCPU when the VM is dying
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 8618004d3e897c0f1b71d9a9ab860461289bb89a upstream.
When marking a page dirty, complain about not having a running/loaded vCPU if and only if the VM is still alive, i.e. its refcount is non-zero. This will allow fixing a memory leak for x86 SEV-ES guests without hitting what is effectively a false positive on the WARN.
For some SEV-ES VM-Exits, KVM keeps a writable mapping of a guest page across an exit to userspace, and typically unmaps the page on the next KVM_RUN. But if userspace never calls KVM_RUN after such an exit, then KVM needs to unmap the page when the vCPU is destroyed, which in turn triggers the WARN about not having a running vCPU.
Alternatively, SEV-ES could temporarily load the vCPU to suppress the WARN, as is done in nested_vmx_free_vcpu() (but for completely unrelated reasons; suppressing WARN from nested_put_vmcs12_pages() is pure happenstance). But loading a vCPU during destruction is gross (ideally nVMX code would be cleaned up), risks complicating the SEV-ES code (KVM would need to ensure the temporarily load()+put() only runs when the vCPU isn't already loaded), and is ultimately pointless.
The motivation for the WARN is to guard against KVM dirtying guest memory without pushing the corresponding GFN to the active vCPU's dirty ring, e.g. to ensure userspace doesn't miss a dirty page. But for the VM's refcount to reach zero, there can't be _any_ userspace mappings to the dirty ring, as mapping the dirty ring requires doing mmap() on the vCPU FD. I.e. if userspace had a valid mapping for the dirty ring, then the vCPU file and thus the owning VM would still be alive. And so since userspace can't possibly reach the dirty ring, whether or not KVM technically "misses" a push to the dirty ring is irrelevant.
Message-ID: <[email protected]>
Message-ID: <[email protected]>
--- virt/kvm/kvm_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/kvm_main.c +2 -1
@@ -3357,7 +3357,8 @@ void mark_page_dirty_in_slot(struct kvmif (WARN_ON_ONCE (vcpu && vcpu->kvm != kvm))return ; -WARN_ON_ONCE (!vcpu && !kvm_arch_allow_write_without_running_vcpu (kvm)); +WARN_ON_ONCE (!vcpu &&refcount_read (&kvm->users_count) && + !kvm_arch_allow_write_without_running_vcpu (kvm));#endif if (memslot &&kvm_slot_dirty_track_enabled (memslot)) {
Greg Kroah-Hartman
maintainerPATCH 297/452 drm/i915/gem: Fix phys BO pread/pwrite with offset
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit d21ad938398bca695a511307de38a65889e3b354 upstream.
sg_page() returns struct page pointer not (void *) so the scaling of pread/pwrite is wrong for phys BO and wrong parts of BO would be accessed if non-zero offset is used.
Last impacted platform with overlay or cursor planes using phys mapping was Gen3/945G/Lakeport.
--- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/gem/i915_gem_phys.c +15 -4
@@ -17,6 +17,17 @@#include "i915_gem_tiling.h" #include "i915_scatterlist.h" +/* Abuse scatterlist to store pointer instead of struct page. */ +static inline void __set_phys_vaddr (struct scatterlist *sg,void *vaddr) +{ +sg_assign_page (sg, (struct page *)vaddr); +} + +static inline void *__get_phys_vaddr (struct scatterlist *sg) +{ +return (void *)sg_page (sg); +} +static int i915_gem_object_get_pages_phys (struct drm_i915_gem_object *obj) {struct address_space *mapping = obj->base.filp->f_mapping;
@@ -57,7 +68,7 @@ static int i915_gem_object_get_pages_phy sg->offset =0 ; sg->length = obj->base.size; -sg_assign_page (sg, (struct page *)vaddr); +__set_phys_vaddr (sg, vaddr);sg_dma_address (sg) = dma;sg_dma_len (sg) = obj->base.size;
@@ -101,7 +112,7 @@ i915_gem_object_put_pages_phys(struct dr struct sg_table *pages) {dma_addr_t dma =sg_dma_address (pages->sgl); -void *vaddr =sg_page (pages->sgl); +void *vaddr =__get_phys_vaddr (pages->sgl);__i915_gem_object_release_shmem (obj, pages, false);
@@ -144,7 +155,7 @@ i915_gem_object_put_pages_phys(struct drint i915_gem_object_pwrite_phys (struct drm_i915_gem_object *obj,const struct drm_i915_gem_pwrite *args) { -void *vaddr =sg_page (obj->mm.pages->sgl) + args->offset; +void *vaddr =__get_phys_vaddr (obj->mm.pages->sgl) + args->offset;char __user *user_data =u64_to_user_ptr (args->data_ptr);struct drm_i915_private *i915 =to_i915 (obj->base.dev);int err;
@@ -175,7 +186,7 @@ int i915_gem_object_pwrite_phys(struct dint i915_gem_object_pread_phys (struct drm_i915_gem_object *obj,const struct drm_i915_gem_pread *args) { -void *vaddr =sg_page (obj->mm.pages->sgl) + args->offset; +void *vaddr =__get_phys_vaddr (obj->mm.pages->sgl) + args->offset;char __user *user_data =u64_to_user_ptr (args->data_ptr);int err;
Greg Kroah-Hartman
maintainerPATCH 298/452 ksmbd: fix use-after-free of a deferred file_lock on double SMB2_CANCEL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gil Portnoy <[email protected]>
commit f580d27e8928828693df44ba2db0fffdbe11dfea upstream.
A deferred byte-range lock (an SMB2_LOCK that blocks) registers an async work on conn->async_requests via setup_async_work(), with cancel_fn = smb2_remove_blocked_lock and cancel_argv[0] pointing at the struct file_lock.
When the request is cancelled, the worker frees the file_lock with locks_free_lock() and takes the cancelled early-exit, which "goto out"s and never reaches release_async_work() -- the only site that unlinks the work from conn->async_requests and clears cancel_fn/cancel_argv. The work therefore stays matchable on async_requests with a live cancel_fn pointing at the freed file_lock, until connection teardown finally runs release_async_work().
smb2_cancel() fires cancel_fn unconditionally with no state guard, so a second SMB2_CANCEL for the same AsyncId, arriving in that window, re-runs smb2_remove_blocked_lock() on the freed file_lock -- a slab use-after-free:
BUG: KASAN: slab-use-after-free in __locks_delete_block
__locks_delete_block
locks_delete_block
ksmbd_vfs_posix_lock_unblock
smb2_remove_blocked_lock
smb2_cancel <- 2nd SMB2_CANCEL fires cancel_fn
handle_ksmbd_work
Allocated by ...: locks_alloc_lock <- smb2_lock
Freed by ...: locks_free_lock <- smb2_lock (cancelled branch)
... cache file_lock_cache of size 192Reproduced on mainline with KASAN by an authenticated SMB client.
Skip a work whose state is already KSMBD_WORK_CANCELLED so its cancel callback cannot be fired a second time.
--- fs/smb/server/smb2pdu.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/smb/server/smb2pdu.c +11 -0
@@ -7191,6 +7191,17 @@ int smb2_cancel(struct ksmbd_work *work) le64_to_cpu(hdr->Id.AsyncId))continue ; +/* +* A cancelled deferred byte-range lock frees its +* file_lock and takes the smb2_lock() early-exit that +* skips release_async_work(), so the work stays on +* conn->async_requests with a live cancel_fn pointing +* at the freed file_lock. Re-firing it on a second +* SMB2_CANCEL is a use-after-free. +*/ +if (iter->state ==KSMBD_WORK_CANCELLED ) +break ; + ksmbd_debug(SMB, "smb2 with AsyncId %llu cancelled command = 0x%x\n", le64_to_cpu(hdr->Id.AsyncId),
Greg Kroah-Hartman
maintainerPATCH 299/452 xfrm: espintcp: do not reuse an in-progress partial send
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
commit c381039ade2e161ab08c0eda73c4f8b9a7115928 upstream.
espintcp keeps a single in-flight transmit in ctx->partial. Before building a new sk_msg, espintcp_sendmsg() first tries to flush that state through espintcp_push_msgs().
For blocking callers, espintcp_push_msgs() may return success even when the previous partial send is still pending. espintcp_sendmsg() would then reinitialize emsg->skmsg and reuse ctx->partial while the old transfer still owns that state.
Do not rebuild the send message when ctx->partial is still in progress. If espintcp_push_msgs() returns with emsg->len still set, fail the new send instead of overwriting the live partial state.
This is a memory-safety fix: reusing the live partial-send state can leave a stale offset attached to a new sk_msg and lead to an out-of- bounds read in the send path.
tcp_sendmsg_locked() already handles waiting for send buffer memory, so the fix here is just to preserve espintcp's one-message-at-a-time transmit state.
--- net/xfrm/espintcp.c | 4 ++++ 1 file changed, 4 insertions(+)
net/xfrm/espintcp.c +4 -0
@@ -347,6 +347,10 @@ static int espintcp_sendmsg(struct sock err = -ENOBUFS ; goto unlock; } +if (emsg->len) { + err = -ENOBUFS ; + goto unlock; + }sk_msg_init (&emsg->skmsg);while (1 ) {
Greg Kroah-Hartman
maintainerPATCH 300/452 USB: serial: io_ti: fix heap overflow in get_manuf_info()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Korwel <[email protected]>
commit 183c1076eca43bbb3e7bdf597456f91d81c73e74 upstream.
get_manuf_info() reads le16_to_cpu(rom_desc->Size) bytes from the device I2C EEPROM into a buffer allocated with kmalloc_obj(), which is sizeof(struct edge_ti_manuf_descriptor) = 10 bytes.
The Size field comes from the device and is only validated (in check_i2c_image()) to make sure the descriptor fits within TI_MAX_I2C_SIZE (16384 bytes), not against the destination buffer size. A malicious USB device can therefore set Size to any value up to 16377, causing a heap overflow of up to 16367 bytes when plugged into a host running this driver.
valid_csum() is called after read_rom() and also iterates buffer[0..Size-1], compounding the out-of-bounds access.
Fix by rejecting descriptors with unexpected length before calling read_rom().
--- drivers/usb/serial/io_ti.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/usb/serial/io_ti.c +6 -0
@@ -773,6 +773,12 @@ static int get_manuf_info(struct edgepor }/* Read the descriptor data */ +if (le16_to_cpu (rom_desc->Size) !=sizeof (struct edge_ti_manuf_descriptor )) { +dev_err (dev,"unexpected Edge descriptor length: %u\n" , +le16_to_cpu (rom_desc->Size)); + status = -EINVAL ; + goto exit; + } status =read_rom (serial, start_address+sizeof (struct ti_i2c_desc ),le16_to_cpu (rom_desc->Size), buffer);if (status)
Greg Kroah-Hartman
maintainerPATCH 301/452 USB: serial: io_ti: fix heap overflow in build_i2c_fw_hdr()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Korwel <[email protected]>
commit 0fd2b00b2d3d05e3eaa13342b3dfb0fa85c226ae upstream.
build_i2c_fw_hdr() allocates a fixed-size buffer of (16*1024 - 512) + sizeof(struct ti_i2c_firmware_rec) bytes, then copies le16_to_cpu(img_header->Length) bytes into it without validating that Length fits within the available space after the firmware record header.
img_header->Length is a __le16 from the firmware file and can be up to 65535. check_fw_sanity() validates the total firmware size but not img_header->Length specifically.
Fix by rejecting images where img_header->Length exceeds the available destination space.
--- drivers/usb/serial/io_ti.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/usb/serial/io_ti.c +5 -0
@@ -844,6 +844,11 @@ static int build_i2c_fw_hdr(u8 *header,/* Pointer to fw_down memory image */ img_header = (struct ti_i2c_image_header *)&fw->data[4 ]; +if (le16_to_cpu (img_header->Length) > + buffer_size -sizeof (struct ti_i2c_firmware_rec )) { +kfree (buffer); +return -EINVAL ; + }memcpy (buffer +sizeof (struct ti_i2c_firmware_rec ), &fw->data[4 +sizeof (struct ti_i2c_image_header )],le16_to_cpu (img_header->Length));
Greg Kroah-Hartman
maintainerPATCH 302/452 USB: serial: option: add usb-id for Dell Wireless DW5826e-m
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jack Wu <[email protected]>
commit 1938fb9fe38c4f04a3f30bea44f8071c80a63be4 upstream.
Add support for Dell DW5826e-m with USB-id 0x413c:0x81ea
T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#= 8 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=413c ProdID=81ea Rev= 5.04 S: Manufacturer=DELL S: Product=DW5826e-m Qualcomm Snapdragon X12 Global LTE-A S: SerialNumber=358988870177734 C:* #Ifs= 7 Cfg#= 1 Atr=a0 MxPwr=500mA A: FirstIf#=12 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00 I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=87(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I:* If#=12 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=88(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#=13 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim I:* If#=13 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0f(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/option.c +3 -0
@@ -202,6 +202,7 @@ static void option_instat_callback(struc#define DELL_PRODUCT_5821E_ESIM 0x81e0#define DELL_PRODUCT_5829E_ESIM 0x81e4#define DELL_PRODUCT_5829E 0x81e6 +#define DELL_PRODUCT_5826E_ESIM 0x81ea#define DELL_PRODUCT_FM101R_ESIM 0x8213#define DELL_PRODUCT_FM101R 0x8215
@@ -1123,6 +1124,8 @@ static const struct usb_device_id option .driver_info = RSVD(0) | RSVD(6) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E_ESIM), .driver_info = RSVD(0) | RSVD(6) }, + { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_5826E_ESIM, 0xff), + .driver_info = RSVD(1) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R_ESIM, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
Greg Kroah-Hartman
maintainerPATCH 303/452 USB: serial: kl5kusb105: fix bulk-out buffer overflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit 96d47e40bf9db4a9efd5c8fb53287a508d165f14 upstream.
klsi_105_prepare_write_buffer() is called by the generic write path with the bulk-out buffer and its size (bulk_out_size, 64 bytes). It stores a two-byte length header at the start of the buffer and copies the payload from the write fifo starting at buf + KLSI_HDR_LEN, but passes the full buffer size as the number of bytes to copy:
count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN,
size, &port->lock);
When the fifo holds at least size bytes, size bytes are copied starting two bytes into the size-byte buffer, writing KLSI_HDR_LEN bytes past its end. Copy at most size - KLSI_HDR_LEN bytes instead, leaving room for the header as safe_serial already does.
Writing bulk_out_size or more bytes to the tty triggers a slab out-of-bounds write, observed with KASAN by emulating the device with dummy_hcd and raw-gadget:
BUG: KASAN: slab-out-of-bounds in kfifo_copy_out+0x83/0xc0 Write of size 64 at addr ffff888112c62202 by task python3 kfifo_copy_out klsi_105_prepare_write_buffer [kl5kusb105] usb_serial_generic_write_start [usbserial] Allocated by task 139: usb_serial_probe [usbserial] The buggy address is located 2 bytes inside of allocated 64-byte region
The out-of-bounds write no longer occurs with this change applied.
--- drivers/usb/serial/kl5kusb105.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/serial/kl5kusb105.c +2 -2
@@ -331,8 +331,8 @@ static int klsi_105_prepare_write_bufferunsigned char *buf = dest;int count; - count =kfifo_out_locked (&port->write_fifo, buf +KLSI_HDR_LEN , size, - &port->lock); + count =kfifo_out_locked (&port->write_fifo, buf +KLSI_HDR_LEN , + size -KLSI_HDR_LEN , &port->lock);put_unaligned_le16 (count, buf);return count +KLSI_HDR_LEN ;
Greg Kroah-Hartman
maintainerPATCH 304/452 ALSA: timer: Fix UAF at snd_timer_user_params()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 053a401b592be424fea9d57c789f66cd5d8cec11 upstream.
At releasing a timer object, e.g. when a userspace timer (CONFIG_SND_UTIMER) gets closed and snd_timer_free() is called, it tries to detach the timer instances and release the resources. However, it's still possible that other in-flight tasks are holding the timer instance where the to-be-deleted timer object is associated, and this may lead to racy accesses.
Fortunately, most of ioctls dealing with the timer instance list already have the protection with register_mutex, and this also avoids such races. But, SNDRV_TIMER_IOCTL_PARAMS isn't protected, hence the concurrent ioctl may lead to use-after-free.
This patch just adds the guard with register_mutex to protect snd_timer_user_params() for covering the code path as a quick workaround. It's no hot-path but rather a rarely issued ioctl, so the performance penalty doesn't matter.
--- sound/core/timer.c | 1 + 1 file changed, 1 insertion(+)
sound/core/timer.c +1 -0
@@ -1850,6 +1850,7 @@ static int snd_timer_user_params(structstruct snd_timer *t;int err; +guard (mutex)(®ister_mutex); tu = file->private_data;if (!tu->timeri)return -EBADFD ;
Greg Kroah-Hartman
maintainerPATCH 305/452 drm/virtio: fix dma_fence refcount leak on error in virtio_gpu_dma_fence_wait()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 3f26bb732cc136ab20176697c92f32c9c84cb125 upstream.
dma_fence_unwrap_for_each() internally calls dma_fence_unwrap_first() which does cursor->chain = dma_fence_get(head), taking an extra reference. On normal loop completion, dma_fence_unwrap_next() releases this via dma_fence_chain_walk() -> dma_fence_put().
When virtio_gpu_do_fence_wait() fails and the function returns early from inside the loop, the cursor->chain reference is never released. This is the only caller in the entire kernel that does an early return inside dma_fence_unwrap_for_each.
Add dma_fence_put(itr.chain) before the early return.
--- drivers/gpu/drm/virtio/virtgpu_submit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_submit.c +3 -1
@@ -65,8 +65,10 @@ static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit,dma_fence_unwrap_for_each (f, &itr, fence) { err =virtio_gpu_do_fence_wait (submit, f); -if (err) +if (err) { +dma_fence_put (itr.chain);return err; + } }return 0 ;
Signature · 1 line
2.54.0
Greg Kroah-Hartman
maintainerPATCH 306/452 drm/amd/display: Reject gpio_bitshift >= 32 in bios_parser_get_gpio_pin_info()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit 49c3da65961fe9857c831d47fa1989084e87514a upstream.
[Why & How]gpio_bitshift is a uint8_t read directly from the VBIOS GPIO pin table. If the value is >= 32, the expression "1 << gpio_bitshift" triggers undefined behaviour in C (shift count exceeds type width). On x86 the shift is silently masked to 5 bits, producing an incorrect GPIO mask that may cause wrong MMIO register bits to be toggled.
Validate gpio_bitshift before use and return BP_RESULT_BADBIOSTABLE for out-of-range values.
--- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +4 -2
@@ -697,8 +697,10 @@ static enum bp_result bios_parser_get_gp info->offset_en = info->offset +1 ; info->offset_mask = info->offset -1 ; - info->mask = (uint32_t ) (1 << - header->gpio_pin[i].gpio_bitshift); +if (header->gpio_pin[i].gpio_bitshift >=32 ) +return BP_RESULT_BADBIOSTABLE ; + + info->mask =1u << header->gpio_pin[i].gpio_bitshift; info->mask_y = info->mask +2 ; info->mask_en = info->mask +1 ; info->mask_mask = info->mask -1 ;
Greg Kroah-Hartman
maintainerPATCH 307/452 mm/damon/ops-common: call folio_test_lru() after folio_get()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <[email protected]>
commit d6b8b02a27b3dd09ec12144322b3dac46d9bc9ef upstream.
damon_get_folio() speculatively calls folio_test_lru() before folio_try_get(). The folio can get freed and reallocated to a tail page. In the case, VM_BUG_ON_PGFLAGS() in const_folio_flags() can be triggered. Remove the speculative call.
Also mark folio_test_lru() check right after folio_try_get() success as no more unlikely.
The race should be rare. Also the problem can happen only if the kernel has enabled CONFIG_DEBUG_VM_PGFLAGS. No real world report of this issue has been made so far. This fix is based on only theoretical analysis. That said, a bug is a bug. A similar issue was also fixed via commit 3203b3ab0fcf ("mm/filemap: don't call folio_test_locked() without a reference in next_uptodate_folio()"). I don't expect this change will make a meaningful impact to DAMON performance in the real world, though I will be happy to be corrected from the real world reports.
The issue was discovered [1] by Sashiko.
--- mm/damon/ops-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
mm/damon/ops-common.c +2 -2
@@ -28,9 +28,9 @@ struct folio *damon_get_folio(unsigned lreturn NULL ; folio =page_folio (page); -if (!folio_test_lru (folio) || !folio_try_get (folio)) +if (!folio_try_get (folio))return NULL ; -if (unlikely (page_folio (page) != folio || !folio_test_lru (folio))) { +if (unlikely (page_folio (page) != folio) || !folio_test_lru (folio)) {folio_put (folio); folio =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 308/452 RDMA/srp: bound SRP_RSP sense copy by the received length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 13e91fd076306f5d0cdfa14f53d69e37274723c4 upstream.
srp_process_rsp() copies sense data from rsp->data + resp_data_len, where resp_data_len is the full 32-bit value supplied by the SRP target and is never checked against the number of bytes actually received (wc->byte_len). The copy length is bounded to SCSI_SENSE_BUFFERSIZE, so at most 96 bytes are copied, but the source offset is not bounded.
A malicious or compromised SRP target on the InfiniBand/RoCE fabric that the initiator has logged into can return an SRP_RSP with SRP_RSP_FLAG_SNSVALID set and a large resp_data_len. The receive buffer is allocated at the target-chosen max_ti_iu_len, so the source of the sense copy lands past the bytes actually received; with resp_data_len near 0xFFFFFFFF it is gigabytes past the buffer and the read faults.
Copy the sense data only if it has not been truncated, that is, only if the response header, the response data, and the sense region fit within the bytes actually received; otherwise drop the sense and log. The in-tree iSER and NVMe-RDMA receive paths already bound their parse by wc->byte_len; this brings ib_srp into line with them.
--- drivers/infiniband/ulp/srp/ib_srp.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +24 -6
@@ -1930,7 +1930,8 @@ static int srp_post_recv(struct srp_rdmareturn ib_post_recv (ch->qp, &wr,NULL ); } -static void srp_process_rsp (struct srp_rdma_ch *ch,struct srp_rsp *rsp) +static void srp_process_rsp (struct srp_rdma_ch *ch,struct srp_rsp *rsp, +u32 byte_len) {struct srp_target_port *target = ch->target;struct srp_request *req;
@@ -1971,10 +1972,27 @@ static void srp_process_rsp(struct srp_r scmnd->result = rsp->status;if (rsp->flags &SRP_RSP_FLAG_SNSVALID ) { -memcpy (scmnd->sense_buffer, rsp->data + -be32_to_cpu (rsp->resp_data_len), -min_t (int,be32_to_cpu (rsp->sense_data_len), -SCSI_SENSE_BUFFERSIZE )); +u32 resp_len =be32_to_cpu (rsp->resp_data_len); +u32 sense_len =be32_to_cpu (rsp->sense_data_len); + +/* +* The sense data starts resp_data_len bytes past the +* response data area; both lengths come from the +* target-controlled response. Copy the sense data +* only if it has not been truncated, that is, only if +* the full sense region fits within the bytes actually +* received. Otherwise the copy source would run past +* the receive buffer (sized to the target-chosen +* max_ti_iu_len), reading out of bounds. +*/ +if (sizeof (*rsp) + (u64 )resp_len + sense_len <= byte_len) +memcpy (scmnd->sense_buffer, + rsp->data + resp_len, +min (sense_len,SCSI_SENSE_BUFFERSIZE )); +else +shost_printk (KERN_ERR , target->scsi_host, +"dropping truncated sense data (resp_data_len %u sense_data_len %u, %u bytes received)\n" , + resp_len, sense_len, byte_len); }if (unlikely (rsp->flags &SRP_RSP_FLAG_DIUNDER ))
@@ -2084,7 +2102,7 @@ static void srp_recv_done(struct ib_cq *switch (opcode) {case SRP_RSP : -srp_process_rsp (ch, iu->buf); +srp_process_rsp (ch, iu->buf, wc->byte_len);break ;case SRP_CRED_REQ :
Greg Kroah-Hartman
maintainerPATCH 309/452 zram: fix use-after-free in zram_bvec_write_partial()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cunlong Li <[email protected]>
commit 732fd9f0b9c1cdc6dfd77162ded60df005182cc0 upstream.
zram_read_page() picks the sync or async backing device read path based on whether the parent bio is NULL. zram_bvec_write_partial() passes its parent bio down, so for ZRAM_WB slots the read is dispatched asynchronously and zram_read_page() returns 0 while the bio is still in flight. The caller then runs memcpy_from_bvec(), zram_write_page() and __free_page() on the buffer, leaving the async read to write into a freed page.
zram_bvec_read_partial() was switched to NULL in commit 4e3c87b9421d ("zram: fix synchronous reads") for the same reason; the write_partial counterpart was missed.
--- drivers/block/zram/zram_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/zram/zram_drv.c +1 -1
@@ -1569,7 +1569,7 @@ static int zram_bvec_write_partial(strucif (!page)return -ENOMEM ; - ret =zram_read_page (zram, page, index, bio); + ret =zram_read_page (zram, page, index,NULL );if (!ret) {memcpy_from_bvec (page_address (page) + offset, bvec); ret =zram_write_page (zram, page, index);
Greg Kroah-Hartman
maintainerPATCH 310/452 udp: clear skb->dev before running a sockmap verdict
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
commit 3c94f241f776562c489876ff506f366224565c21 upstream.
On the UDP receive path skb->dev is repurposed as dev_scratch (the truesize/state cache set by udp_set_dev_scratch()), through the union { struct net_device *dev; unsigned long dev_scratch; } in sk_buff.
When a UDP socket is in a sockmap, sk_data_ready is sk_psock_verdict_data_ready(), which calls udp_read_skb() -> recv_actor() (sk_psock_verdict_recv) to run the attached SK_SKB verdict program in softirq. If that program calls a socket-lookup helper (bpf_sk_lookup_tcp/udp, bpf_skc_lookup_tcp), bpf_skc_lookup() does:
if (skb->dev) caller_net = dev_net(skb->dev);
skb->dev still holds the dev_scratch value (a non-NULL integer), so dev_net() dereferences it as a struct net_device * and the kernel takes a general protection fault on a non-canonical address in softirq:
Oops: general protection fault, probably for non-canonical address 0x1010000800004a0 CPU: 1 UID: 0 PID: 1406 Comm: syz.2.19 Not tainted 7.1.0-rc6 #1 PREEMPT(full) RIP: 0010:bpf_skc_lookup net/core/filter.c:7033 [inline] RIP: 0010:bpf_sk_lookup+0x45/0x160 net/core/filter.c:7047 Call Trace: <IRQ> bpf_prog_4675cb904b7071f8+0x12e/0x14e bpf_prog_run_pin_on_cpu+0xc6/0x1f0 sk_psock_verdict_recv+0x1ba/0x350 udp_read_skb+0x31a/0x370 sk_psock_verdict_data_ready+0x2e3/0x600 __udp_enqueue_schedule_skb+0x4c8/0x650 udpv6_queue_rcv_one_skb+0x3ec/0x740 udp6_unicast_rcv_skb+0x11d/0x140 ip6_protocol_deliver_rcu+0x61e/0x950 ip6_input_finish+0xa9/0x150 NF_HOOK+0x286/0x2f0 ip6_input+0x117/0x220 NF_HOOK+0x286/0x2f0 __netif_receive_skb+0x85/0x200 process_backlog+0x374/0x9a0 __napi_poll+0x4f/0x1c0 net_rx_action+0x3b0/0x770 handle_softirqs+0x15a/0x460 do_softirq+0x57/0x80 </IRQ>
The rmem charge that dev_scratch accounted for is released by skb_recv_udp() on dequeue, just above, so the scratch is dead by the time recv_actor() runs. Clear skb->dev so bpf_skc_lookup() falls back to sock_net(skb->sk), which skb_set_owner_sk_safe() set just above.
--- net/ipv4/udp.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/ipv4/udp.c +8 -0
@@ -1801,6 +1801,14 @@ try_again: }WARN_ON_ONCE (!skb_set_owner_sk_safe (skb, sk)); + +/* +* skb->dev still aliases the UDP rx dev_scratch (its charge was freed +* on dequeue above); a sockmap verdict program may deref it via +* bpf_sk_lookup_*(), so clear it -> bpf_skc_lookup() uses skb->sk +*/ + skb->dev =NULL ; +return recv_actor (sk, skb); }EXPORT_SYMBOL (udp_read_skb);
Greg Kroah-Hartman
maintainerPATCH 311/452 ARM: socfpga: Fix OF node refcount leak in SMP setup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
commit 63838c323924fe4a78b2323bd45aa1030f72ca60 upstream.
socfpga_smp_prepare_cpus() looks up the Cortex-A9 SCU node with of_find_compatible_node(), which returns a node reference that must be released with of_node_put().
The function maps the SCU registers and then returns without dropping that reference, leaking the node on both the success path and the of_iomap() failure path.
Drop the reference once the mapping attempt is complete. The returned MMIO mapping does not depend on keeping the device node reference held.
--- arch/arm/mach-socfpga/platsmp.c | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-socfpga/platsmp.c +1 -0
@@ -78,6 +78,7 @@ static void __init socfpga_smp_prepare_c } socfpga_scu_base_addr =of_iomap (np,0 ); +of_node_put (np);if (!socfpga_scu_base_addr)return ;scu_enable (socfpga_scu_base_addr);
Greg Kroah-Hartman
maintainerPATCH 312/452 ARM: 9474/1: io: avoid KASAN instrumentation of raw halfword I/O
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit d59ed803715a71fb9582e139d648ece8d66dc743 upstream.
For CPUs before ARMv6, __raw_readw() and __raw_writew() are implemented as C volatile halfword accesses so the compiler can generate an access sequence that is safe for those machines. With KASAN enabled, those C accesses are instrumented as normal memory accesses.
That is not valid for MMIO. On ARM926/VersatilePB with KASAN enabled, PL011 probing traps in __asan_store2() while registering the UART, because the instrumented writew() tries to check KASAN shadow for an MMIO address.
Keep the existing volatile halfword access, but move the ARMv5 definitions into __no_kasan_or_inline functions so raw MMIO halfword accesses are not instrumented by KASAN. The ARMv6-and-newer inline assembly path is unchanged.
--- arch/arm/include/asm/io.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
arch/arm/include/asm/io.h +13 -2
@@ -56,8 +56,19 @@ void __raw_readsl(const volatile void __* the bus. Rather than special-case the machine, just let the compiler * generate the access for CPUs prior to ARMv6. */ -#define __raw_readw (a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a)) -#define __raw_writew (v,a) ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))) +#define __raw_writew __raw_writew +static __no_kasan_or_inline void __raw_writew(u16 val, volatile void __iomem *addr) +{ +__chk_io_ptr (addr); + *(volatile unsigned short __force *)addr = val; +} + +#define __raw_readw __raw_readw +static __no_kasan_or_inline u16 __raw_readw(const volatile void __iomem *addr) +{ +__chk_io_ptr (addr); +return *(const volatile unsigned short __force *)addr; +}#else /* * When running under a hypervisor, we want to avoid I/O accesses with
Greg Kroah-Hartman
maintainerPATCH 313/452 ARM: 9475/1: entry: use byte load for KASAN VMAP stack shadow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 77a1f6883dc6e837bb2cb30b9b02e2f94338e2c6 upstream.
Commit 44e9a3bb76e5 ("ARM: 9430/1: entry: Do a dummy read from VMAP shadow") added a dummy read from the KASAN VMAP stack shadow in __switch_to(). The read uses ldr, but the KASAN shadow address is byte-granular and is not guaranteed to be word aligned.
ARMv5 faults unaligned word loads. With CONFIG_KASAN_VMALLOC and CONFIG_VMAP_STACK enabled, ARM926/VersatilePB crashes in __switch_to() with an alignment exception before reaching init.
Use ldrb for the dummy shadow access. The code only needs to fault in the shadow mapping if the stack shadow is missing, so a byte load is sufficient and matches the granularity of KASAN shadow memory.
--- arch/arm/kernel/entry-armv.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/kernel/entry-armv.S +1 -1
@@ -561,7 +561,7 @@ ENTRY(__switch_to) @ are using KASAN mov_l r2, KASAN_SHADOW_OFFSET add r2, r2, ip, lsr #KASAN_SHADOW_SCALE_SHIFT - ldr r2, [r2] + ldrb r2, [r2] #endif #endif
Greg Kroah-Hartman
maintainerPATCH 314/452 mptcp: fix retransmission loop when csum is enabled
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
commit d1918b36edcaed0ec4ef6888b2358c6b1ddcff47 upstream.
Sashiko noted that retransmission with csum enabled can actually transmit new data, but currently the relevant code does not update accordingly snd_nxt.
The may cause incoming ack drop and an endless retransmission loop.
Address the issue incrementing snd_nxt as needed.
--- net/mptcp/protocol.c | 4 ++++ 1 file changed, 4 insertions(+)
net/mptcp/protocol.c +4 -0
@@ -2751,6 +2751,10 @@ static void __mptcp_retrans(struct sock msk->bytes_retrans += len; dfrag->already_sent =max (dfrag->already_sent, len); +/* With csum enabled retransmission can send new data. */ +if (after64 (dfrag->already_sent + dfrag->data_seq, msk->snd_nxt)) +WRITE_ONCE (msk->snd_nxt, dfrag->already_sent + dfrag->data_seq); + reset_timer:mptcp_check_and_set_pending (sk);
Greg Kroah-Hartman
maintainerPATCH 315/452 mptcp: close TOCTOU race while computing rcv_wnd
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
commit 8ab24fdebc369c0dfb90f82c1650b1e66662bb45 upstream.
The MPTCP output path access locklessly the MPTCP-level ack_seq in multiple times, using possibly different values for the data_ack in the DSS option and to compute the announced rcv wnd for the same packet.
Refactor the cote to avoid inconsistencies which may confuse the peer. Also ensure that the MPTCP level rcv wnd is updated only when the egress packet actually contains a DSS ack.
--- net/mptcp/options.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
net/mptcp/options.c +18 -18
@@ -571,7 +571,6 @@ static bool mptcp_established_options_dsstruct mptcp_ext *mpext;unsigned int ack_size;bool ret = false; -u64 ack_seq; opts->csum_reqd =READ_ONCE (msk->csum_enabled); mpext = skb ?mptcp_get_ext (skb) :NULL ;
@@ -602,14 +601,11 @@ static bool mptcp_established_options_dsreturn ret; } - ack_seq =READ_ONCE (msk->ack_seq);if (READ_ONCE (msk->use_64bit_ack)) { ack_size =TCPOLEN_MPTCP_DSS_ACK64 ; - opts->ext_copy.data_ack = ack_seq; opts->ext_copy.ack64 =1 ; }else { ack_size =TCPOLEN_MPTCP_DSS_ACK32 ; - opts->ext_copy.data_ack32 = (uint32_t )ack_seq; opts->ext_copy.ack64 =0 ; } opts->ext_copy.use_ack =1 ;
@@ -1295,19 +1291,14 @@ bool mptcp_incoming_options(struct sockreturn true; } -static void mptcp_set_rwin (struct tcp_sock *tp,struct tcphdr *th) +static u64 mptcp_set_rwin (struct mptcp_sock *msk,struct tcp_sock *tp, +struct tcphdr *th,u64 ack_seq) {const struct sock *ssk = (const struct sock *)tp; -struct mptcp_subflow_context *subflow; -u64 ack_seq, rcv_wnd_old, rcv_wnd_new; -struct mptcp_sock *msk; +u64 rcv_wnd_old, rcv_wnd_new;u32 new_win;u64 win; - subflow =mptcp_subflow_ctx (ssk); - msk =mptcp_sk (subflow->conn); - - ack_seq =READ_ONCE (msk->ack_seq); rcv_wnd_new = ack_seq + tp->rcv_wnd; rcv_wnd_old =atomic64_read (&msk->rcv_wnd_sent);
@@ -1359,7 +1350,7 @@ raise_win: update_wspace:WRITE_ONCE (msk->old_wspace, tp->rcv_wnd); - subflow->rcv_wnd_sent = rcv_wnd_new; +return rcv_wnd_new; }static void mptcp_track_rwin (struct tcp_sock *tp)
@@ -1471,13 +1462,25 @@ void mptcp_write_options(struct tcphdr * *ptr++ =mptcp_option (MPTCPOPT_DSS , len,0 , flags);if (mpext->use_ack) { +struct mptcp_sock *msk; +u64 ack_seq; + +/* DSS option is set only by mptcp_established_options, +* the caller is __tcp_transmit_skb() and ssk is always +* not NULL. +*/ + subflow =mptcp_subflow_ctx (ssk); + msk =mptcp_sk (subflow->conn); + ack_seq =READ_ONCE (msk->ack_seq);if (mpext->ack64) { -put_unaligned_be64 (mpext->data_ack, ptr); +put_unaligned_be64 (ack_seq, ptr); ptr +=2 ; }else { -put_unaligned_be32 (mpext->data_ack32, ptr); +put_unaligned_be32 (ack_seq, ptr); ptr +=1 ; } + subflow->rcv_wnd_sent =mptcp_set_rwin (msk, tp, th, + ack_seq); }if (mpext->use_map) {
@@ -1705,9 +1708,6 @@ mp_capable_done: i +=4 ; } } - -if (tp) -mptcp_set_rwin (tp, th); }__be32 mptcp_get_reset_option (const struct sk_buff *skb)
Greg Kroah-Hartman
maintainerPATCH 316/452 mptcp: allow subflow rcv wnd to shrink
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
commit da23be77e1292cd611e736c3aa17da633d7ddce7 upstream.
In MPTCP connection, the window field in the TCP header refers to the MPTCP-level rcv_nxt and it's right edge should not move backward. Such constraint is enforced at DSS option generation time.
At the same time, the TCP stack ensures independently that the TCP-level rcv wnd right's edge does not move backward. That in turn causes artificial inflating of the MPTCP rcv window when the incoming data is acked at the TCP level and is OoO in the MPTCP sequence space (or lands in the backlog).
As a consequence, the incoming traffic can exceed the receiver rcvbuf size even when the sender is not misbehaving.
Prevent such scenario forcibly allowing the TCP subflow to shrink the TCP-level rcv wnd regardless of the current netns setting.
--- net/mptcp/options.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/mptcp/options.c +7 -0
@@ -567,6 +567,7 @@ static bool mptcp_established_options_ds {struct mptcp_subflow_context *subflow =mptcp_subflow_ctx (sk);struct mptcp_sock *msk =mptcp_sk (subflow->conn); +struct tcp_sock *tp =tcp_sk (sk);unsigned int dss_size =0 ;struct mptcp_ext *mpext;unsigned int ack_size;
@@ -615,6 +616,12 @@ static bool mptcp_established_options_dsif (dss_size ==0 ) ack_size +=TCPOLEN_MPTCP_DSS_BASE ; +/* The caller is __tcp_transmit_skb(), and will compute the new rcv +* wnd soon: ensure that the window can shrink. +*/ +if (skb) + tp->rcv_wnd = tp->rcv_nxt - tp->rcv_wup; + dss_size += ack_size; *size =ALIGN (dss_size,4 );
Greg Kroah-Hartman
maintainerPATCH 317/452 mptcp: sockopt: check timestamping ret value
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
commit 57132affbc89c02e1bf73fdf5724311bdc9a29da upstream.
sock_set_timestamping() can fail for different reasons. The returned value should then be checked.
If sock_set_timestamping() fails for at least one subflow, the first error is now reported to the userspace, similar to what is done with other socket options.
--- net/mptcp/sockopt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/mptcp/sockopt.c +6 -2
@@ -235,15 +235,19 @@ static int mptcp_setsockopt_sol_socket_tmptcp_for_each_subflow (msk, subflow) {struct sock *ssk =mptcp_subflow_tcp_sock (subflow); +int err;lock_sock (ssk); -sock_set_timestamping (ssk, optname, timestamping); + err =sock_set_timestamping (ssk, optname, timestamping);release_sock (ssk); + +if (err <0 && ret ==0 ) + ret = err; }release_sock (sk); -return 0 ; +return ret; } static int mptcp_setsockopt_sol_socket_linger(struct mptcp_sock *msk, sockptr_t optval,
Greg Kroah-Hartman
maintainerPATCH 318/452 selftests: mptcp: add test for extra_subflows underflow on userspace PM
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
commit 06fd2bec7aebf393288e4b78924482fe170caabc upstream.
Add a test to verify that when userspace PM fails to create a subflow (e.g. using an unreachable address), the extra_subflows counter is not decremented below zero.
--- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 ++++ 1 file changed, 4 insertions(+)
tools/testing/selftests/net/mptcp/mptcp_join.sh +4 -0
@@ -3774,6 +3774,10 @@ userspace_tests() chk_rm_nr 0 1 chk_mptcp_info subflows 0 subflows 0 chk_subflows_total 1 1 + # check counters are not affected by errors at creation time + userspace_pm_add_sf $ns2 10.0.12.2 10 2>/dev/null + chk_mptcp_info subflows 0 subflows 0 + chk_subflows_total 1 1 kill_events_pids mptcp_lib_kill_group_wait $tests_pid fi
Greg Kroah-Hartman
maintainerPATCH 319/452 wifi: nl80211: reject oversized EMA RNR lists
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 4cd92957e8f8cc4ebfe8a5d4203c14c592fde6b1 upstream.
nl80211_parse_rnr_elems() stores the parsed element count in a u8-backed cfg80211_rnr_elems::cnt field and uses that count to size the flexible array allocation.
Reject nested NL80211_ATTR_EMA_RNR_ELEMS input once the count reaches 255, before incrementing it again. This keeps the parser aligned with the data structure it fills and matches the existing bound check used by nl80211_parse_mbssid_elems().
--- net/wireless/nl80211.c | 3 +++ 1 file changed, 3 insertions(+)
net/wireless/nl80211.c +3 -0
@@ -5498,6 +5498,9 @@ nl80211_parse_rnr_elems(struct wiphy *wiif (ret)return ERR_PTR (ret); +if (num_elems >=255 ) +return ERR_PTR (-EINVAL ); + num_elems++; }
Greg Kroah-Hartman
maintainerPATCH 320/452 vsock/vmci: fix sk_ack_backlog leak on failed handshake
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raf Dickson <[email protected]>
commit c05fa14db43ebef3bd862ca9d073981c0358b3f0 upstream.
When vmci_transport_recv_connecting_server() returns an error, vmci_transport_recv_listen() calls vsock_remove_pending() but never calls sk_acceptq_removed(). This leaves sk_ack_backlog incremented permanently.
Repeated handshake failures (malformed packets, queue pair alloc failure, event subscribe failure) cause sk_ack_backlog to climb toward sk_max_ack_backlog. Once it reaches the limit the listener permanently refuses all new connections with -ECONNREFUSED, a silent denial of service requiring a process restart to recover.
The two existing sk_acceptq_removed() calls in af_vsock.c do not cover this path: line 764 checks vsock_is_pending() which returns false after vsock_remove_pending(), and line 1889 is only reached on successful accept().
Fix by balancing sk_acceptq_added() with sk_acceptq_removed() on the error path.
--- net/vmw_vsock/vmci_transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/vmw_vsock/vmci_transport.c +3 -1
@@ -972,8 +972,10 @@ static int vmci_transport_recv_listen(st err = -EINVAL ; } -if (err <0 ) +if (err <0 ) {vsock_remove_pending (sk, pending); +sk_acceptq_removed (sk); + }release_sock (pending);vmci_transport_release_pending (pending);
Greg Kroah-Hartman
maintainerPATCH 321/452 ASoC: fsl_sai: Fix 32 slots TDM broken by integer shift UB in xMR write
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chancel Liu <[email protected]>
commit 4790af1cc2e8871fb31f28c66e42b9a949a23992 upstream.
When configuring 32 slots TDM (channels == slots == 32), the xMR (Mask Register) write used:
~0UL - ((1 << min(channels, slots)) - 1)
The literal "1" is a signed 32-bit int. Shifting it by 32 positions is undefined behaviour which may set this register to 0xFFFFFFFF, masking all 32 slots.
Use GENMASK_U32() macro instead. For 32 slots this produces a zero mask:
~GENMASK_U32(31, 0) = ~0xFFFFFFFF = 0x00000000
Behaviour for fewer than 32 slots is unchanged.
--- sound/soc/fsl/fsl_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_sai.c +1 -1
@@ -705,7 +705,7 @@ static int fsl_sai_hw_params(struct snd_ FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);regmap_write (sai->regmap,FSL_SAI_xMR (tx), - ~0UL - ((1 <<min (channels, slots)) -1 )); + ~GENMASK_U32 (min (channels, slots) -1 ,0 ));return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 322/452 bnxt_en: Fix NULL pointer dereference
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Meyer <[email protected]>
commit d930276f2cddd0b7294cac7a8fe7b877f6d9e08d upstream.
PCIe errors detected by a Root Port or Downstream Port cause error recovery services to run on all subordinate devices regardless of administrative state.
The .error_detected() callback, bnxt_io_error_detected(), disables and synchronizes IRQs via bnxt_disable_int_sync(), which calls bnxt_cp_num_to_irq_num() to map completion rings to IRQs using bp->bnapi.
Since bp->bnapi is allocated on NIC open and freed on NIC close, PCIe error recovery on a closed NIC can dereference a NULL pointer.
Check if bp->bnapi is NULL before disabling and synchronizing IRQs.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +1 -1
@@ -4698,7 +4698,7 @@ static void bnxt_disable_int_sync(struct {int i; -if (!bp->irq_tbl) +if (!bp->irq_tbl || !bp->bnapi)return ;atomic_inc (&bp->intr_sem);
Greg Kroah-Hartman
maintainerPATCH 323/452 IB/isert: Reject login PDUs shorter than ISER_HEADERS_LEN
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 29e7b925ae6df64894e82ab6419994dc25580a8a upstream.
In drivers/infiniband/ulp/isert/ib_isert.c, isert_login_recv_done() computes the login request payload length as wc->byte_len minus ISER_HEADERS_LEN with no lower bound, and login_req_len is a signed int. A remote iSER initiator can post a login Send work request carrying fewer than ISER_HEADERS_LEN (76) bytes, so the subtraction underflows and login_req_len becomes negative.
isert_rx_login_req() then reads that negative length back into a signed int, takes size = min(rx_buflen, MAX_KEY_VALUE_PAIRS), and because the min() is signed it keeps the negative value; the value is then passed as the memcpy() length and sign-extended to a multi-gigabyte size_t. The copy into the 8192-byte login->req_buf runs far out of bounds and faults, crashing the target node. The login phase precedes iSCSI authentication, so no credentials are required to reach this path.
Reject any login PDU shorter than ISER_HEADERS_LEN before the subtraction, mirroring the existing early return on a failed work completion, so login_req_len can never go negative. The upper bound was already safe: a posted login buffer cannot deliver more than ISER_RX_PAYLOAD_SIZE, so the difference stays at or below MAX_KEY_VALUE_PAIRS and the existing min() clamps it; only the missing lower bound needs to be added.
--- drivers/infiniband/ulp/isert/ib_isert.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/infiniband/ulp/isert/ib_isert.c +6 -0
@@ -1388,6 +1388,12 @@ isert_login_recv_done(struct ib_cq *cq,ib_dma_sync_single_for_cpu (ib_dev, isert_conn->login_desc->dma_addr,ISER_RX_SIZE ,DMA_FROM_DEVICE ); +if (unlikely (wc->byte_len <ISER_HEADERS_LEN )) { +isert_dbg ("login request length %u is too short\n" , + wc->byte_len); +return ; + } + isert_conn->login_req_len = wc->byte_len -ISER_HEADERS_LEN ;if (isert_conn->conn) {
Greg Kroah-Hartman
maintainerPATCH 324/452 inet: frags: fix use-after-free caused by the fqdir_pre_exit() flush
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit 32594b09854970d7ba83eb2dc8c69a2edd158c8e upstream.
On netns teardown, fqdir_pre_exit() walks the fqdir rhashtable and flushes every fragment queue that is not yet complete using inet_frag_queue_flush(). That helper frees all the skbs queued on the fragment queue but does not set INET_FRAG_COMPLETE, and leaves q->fragments_tail and q->last_run_head pointing at the freed skbs. The queue itself stays in the rhashtable.
fqdir_pre_exit() first lowers high_thresh to 0 to stop new queue lookups, but it cannot stop a fragment that already obtained the queue through inet_frag_find() earlier and stalled just before taking the queue lock. Once that fragment resumes after the flush and takes the queue lock, it passes the INET_FRAG_COMPLETE check and then dereferences the freed fragments_tail. inet_frag_queue_insert() reads FRAG_CB() and ->len of that pointer and, on the append path, writes ->next_frag, causing a slab use-after-free. IPv6, nf_conntrack_reasm6 and 6lowpan reassembly share the same flush path and are affected as well.
Reset rb_fragments, fragments_tail and last_run_head in inet_frag_queue_flush() so a flushed queue no longer points at the freed skbs. A fragment that resumes after the flush and takes the queue lock then finds an empty queue and starts a new run instead of dereferencing the freed fragments_tail. ip_frag_reinit() already performed this reset after its own flush, so drop the now duplicate code there.
--- net/ipv4/inet_fragment.c | 3 +++ net/ipv4/ip_fragment.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-)
net/ipv4/inet_fragment.c +3 -0
@@ -329,6 +329,9 @@ void inet_frag_queue_flush(struct inet_f reason = reason ?:SKB_DROP_REASON_FRAG_REASM_TIMEOUT ; sum =inet_frag_rbtree_purge (&q->rb_fragments, reason);sub_frag_mem_limit (q->fqdir, sum); + q->rb_fragments =RB_ROOT ; + q->fragments_tail =NULL ; + q->last_run_head =NULL ; }EXPORT_SYMBOL (inet_frag_queue_flush);
net/ipv4/ip_fragment.c +0 -3
@@ -265,9 +265,6 @@ static int ip_frag_reinit(struct ipq *qp qp->q.flags =0 ; qp->q.len =0 ; qp->q.meat =0 ; - qp->q.rb_fragments =RB_ROOT ; - qp->q.fragments_tail =NULL ; - qp->q.last_run_head =NULL ; qp->iif =0 ; qp->ecn =0 ;
Greg Kroah-Hartman
maintainerPATCH 325/452 pidfd: refuse access to tasks that have started exiting harder
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 62c4d31d78294bd61cf3403626b789e854357177 upstream.
The recent ptrace fix closed a hole where someone could rely on task->mm becoming NULL during do_exit() to bypass dumpability checks. This api here leans on on the very same check and so inherits the fix.
But there is no good reason to let it succeed at all once the target has entered do_exit(). PF_EXITING is set by exit_signals() at the very top of do_exit(), before exit_mm() and exit_files() run. Once we observe it, the task is committed to dying and exit_files() will release the fdtable shortly.
--- kernel/pid.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
kernel/pid.c +5 -3
@@ -675,10 +675,12 @@ static struct file *__pidfd_fget(structif (ret)return ERR_PTR (ret); -if (ptrace_may_access (task,PTRACE_MODE_ATTACH_REALCREDS )) - file =fget_task (task, fd); -else +if (!ptrace_may_access (task,PTRACE_MODE_ATTACH_REALCREDS )) file =ERR_PTR (-EPERM ); +else if (task->flags &PF_EXITING ) + file =ERR_PTR (-ESRCH ); +else + file =fget_task (task, fd);up_read (&task->signal->exec_update_lock);
Greg Kroah-Hartman
maintainerPATCH 326/452 fuse: reject fuse_notify() pagecache ops on directories
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 9c954499d43aefac01c5dfb57a82b13d2dcf4b94 upstream.
The operations FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE allow the FUSE daemon to actively write/read pagecache contents.
For directories with FOPEN_CACHE_DIR, the pagecache is used as kernel-internal cache storage, and userspace is not supposed to have direct access to this cache - in particular, fuse_parse_cache() will hit WARN_ON() if the cache contains bogus data.
Reject FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE on anything other than regular files with -EINVAL.
--- fs/fuse/dev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/fuse/dev.c +8 -1
@@ -1597,6 +1597,10 @@ static int fuse_notify_store(struct fuse inode =fuse_ilookup (fc, nodeid,NULL );if (!inode) goto out_up_killsb; +if (!S_ISREG (inode->i_mode)) { + err = -EINVAL ; + goto out_iput; + } mapping = inode->i_mapping; index = outarg.offset >>PAGE_SHIFT ;
@@ -1768,7 +1772,10 @@ static int fuse_notify_retrieve(struct f inode =fuse_ilookup (fc, nodeid, &fm);if (inode) { - err =fuse_retrieve (fm, inode, &outarg); +if (!S_ISREG (inode->i_mode)) + err = -EINVAL ; +else + err =fuse_retrieve (fm, inode, &outarg);iput (inode); }up_read (&fc->killsb);
Greg Kroah-Hartman
maintainerPATCH 327/452 i2c: qcom-cci: Fix NULL pointer dereference in cci_remove()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
commit 729ac5a4b966aac42e08a94dea966f4429008548 upstream.
On all modern platforms Qualcomm CCI controller provides two I2C masters, and on particular boards only one I2C master may be initialized, and in such cases the device unbinding or driver removal causes a NULL pointer dereference, because cci_halt() is called for all two I2C masters, but a completion is initialized only for the single enabled master:
% rmmod i2c-qcom-cci
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
<snip>
Call trace:
__wait_for_common+0x194/0x1a8 (P)
wait_for_completion_timeout+0x20/0x2c
cci_remove+0xc4/0x138 [i2c_qcom_cci]
platform_remove+0x20/0x30
device_remove+0x4c/0x80
device_release_driver_internal+0x1c8/0x224
driver_detach+0x50/0x98
bus_remove_driver+0x6c/0xbc
driver_unregister+0x30/0x60
platform_driver_unregister+0x14/0x20
qcom_cci_driver_exit+0x18/0x1008 [i2c_qcom_cci]
....--- drivers/i2c/busses/i2c-qcom-cci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-qcom-cci.c +1 -1
@@ -683,8 +683,8 @@ static void cci_remove(struct platform_dif (cci->master[i].cci) {i2c_del_adapter (&cci->master[i].adap);of_node_put (cci->master[i].adap.dev.of_node); +cci_halt (cci, i); } -cci_halt (cci, i); }disable_irq (cci->irq);
Greg Kroah-Hartman
maintainerPATCH 328/452 i2c: stm32f7: fix timing computation ignoring i2c-analog-filter
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillermo Rodríguez <[email protected]>
commit a124579c0763da7bc408f4cd7e8f606cadc94855 upstream.
stm32f7_i2c_compute_timing() uses i2c_dev->analog_filter to pick the analog filter delay, but i2c_dev->analog_filter is parsed from the "i2c-analog-filter" DT property only after the compute_timing loop in stm32f7_i2c_setup_timing(), so in practice the timing calculations always ignore the analog filter. On an STM32MP1 board with clock-frequency = <400000> and i2c-analog-filter set, measured SCL frequency was ~382 kHz.
This also affects (widens) the computed SDADEL range. At high bus clock speeds, this can select an SDADEL value that violates tVD;DAT (data valid time).
Fix by parsing "i2c-analog-filter" before the compute_timing loop.
--- drivers/i2c/busses/i2c-stm32f7.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/i2c/busses/i2c-stm32f7.c +3 -3
@@ -680,6 +680,9 @@ static int stm32f7_i2c_setup_timing(struif (!of_property_read_bool (i2c_dev->dev->of_node,"i2c-digital-filter" )) i2c_dev->dnf_dt =STM32F7_I2C_DNF_DEFAULT ; + i2c_dev->analog_filter =of_property_read_bool (i2c_dev->dev->of_node, +"i2c-analog-filter" ); + do { ret = stm32f7_i2c_compute_timing(i2c_dev, setup, &i2c_dev->timing);
@@ -701,9 +704,6 @@ static int stm32f7_i2c_setup_timing(strureturn ret; } - i2c_dev->analog_filter =of_property_read_bool (i2c_dev->dev->of_node, -"i2c-analog-filter" ); -dev_dbg (i2c_dev->dev,"I2C Speed(%i), Clk Source(%i)\n" , setup->speed_freq, setup->clock_src); dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
Greg Kroah-Hartman
maintainerPATCH 329/452 i2c: tegra: Fix NOIRQ suspend/resume
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akhil R <[email protected]>
commit 656646b3847ac6a21b074a813223feef2aadd6e2 upstream.
The Tegra I2C driver relies on runtime PM to wake up the controller before each transfer. However, runtime PM is disabled between the system suspend and NOIRQ suspend. If an I2C device initiates a transfer during this window, the I2C controller fails to wake up and the transfer fails. To handle this, the controller must be kept available for this period to allow transfers.
Rework the I2C controller's system PM callbacks such that the controller is resumed from runtime suspend during system suspend and it stays RPM_ACTIVE throughout the suspend-resume cycle until it is runtime suspended back in the system resume. The clocks are disabled in NOIRQ suspend and enabled back in NOIRQ resume by calling the controller's runtime PM functions directly.
--- drivers/i2c/busses/i2c-tegra.c | 53 +++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 23 deletions(-)
drivers/i2c/busses/i2c-tegra.c +30 -23
@@ -1889,28 +1889,37 @@ static int __maybe_unused tegra_i2c_runtstatic int __maybe_unused tegra_i2c_suspend (struct device *dev) { +/* +* Bring the controller up and hold a usage count so it stays +* available until the noirq phase. +*/ +return pm_runtime_resume_and_get (dev); +} + +static int __maybe_unused tegra_i2c_suspend_noirq (struct device *dev) +{struct tegra_i2c_dev *i2c_dev =dev_get_drvdata (dev); -int err;i2c_mark_adapter_suspended (&i2c_dev->adapter); -if (!pm_runtime_status_suspended (dev)) { - err =tegra_i2c_runtime_suspend (dev); -if (err) -return err; - } - -return 0 ; +/* +* Runtime PM is already disabled at this point, so invoke the +* runtime_suspend callback directly to put the controller down. +*/ +return tegra_i2c_runtime_suspend (dev); } -static int __maybe_unused tegra_i2c_resume (struct device *dev) +static int __maybe_unused tegra_i2c_resume_noirq (struct device *dev) {struct tegra_i2c_dev *i2c_dev =dev_get_drvdata (dev);int err;/* -* We need to ensure that clocks are enabled so that registers can be -* restored in tegra_i2c_init(). +* Runtime PM is still disabled at this point, so invoke the +* runtime_resume callback directly to bring the controller back up +* before re-initializing the hardware. The adapter is then marked +* resumed so that consumers can issue transfers from their own +* resume_noirq() handlers and onwards. */ err =tegra_i2c_runtime_resume (dev);if (err)
@@ -1920,24 +1929,22 @@ static int __maybe_unused tegra_i2c_resuif (err)return err; -/* -* In case we are runtime suspended, disable clocks again so that we -* don't unbalance the clock reference counts during the next runtime -* resume transition. -*/ -if (pm_runtime_status_suspended (dev)) { - err =tegra_i2c_runtime_suspend (dev); -if (err) -return err; - } -i2c_mark_adapter_resumed (&i2c_dev->adapter);return 0 ; } +static int __maybe_unused tegra_i2c_resume (struct device *dev) +{ +pm_runtime_put (dev); + +return 0 ; +} +static const struct dev_pm_ops tegra_i2c_pm = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) + SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend_noirq, + tegra_i2c_resume_noirq)SET_RUNTIME_PM_OPS (tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,NULL ) };
Greg Kroah-Hartman
maintainerPATCH 330/452 Input: atkbd - add DMI quirk for Lenovo Yoga Air 14 (83QK)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zeyu WANG <[email protected]>
commit ad0979fe053e9f2db82da82188256ef6eb41095a upstream.
The Lenovo Yoga Air 14 (83QK) laptop keyboard becomes unresponsive after the standard atkbd init sequence. Controlled testing on the actual hardware shows the F5 (ATKBD_CMD_RESET_DIS / deactivate) command specifically corrupts the EC state, causing zero IRQ1 interrupts after init.
Skipping only the deactivate command (while keeping F4 ENABLE) resolves the issue completely: both keystroke input and CapsLock LED toggle work correctly. The reverse test - skipping only F4 while keeping F5 - makes the problem worse (zero keystroke interrupts), confirming F5 is the sole culprit.
Add a DMI quirk entry for LENOVO/83QK using the existing atkbd_deactivate_fixup callback, consistent with the existing entries for LG Electronics and HONOR FMB-P that address the same EC F5 deactivate issue.
--- drivers/input/keyboard/atkbd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/input/keyboard/atkbd.c +8 -0
@@ -1944,6 +1944,14 @@ static const struct dmi_system_id atkbd_ }, .callback = atkbd_deactivate_fixup, }, + { + /* Lenovo Yoga Air 14 (83QK) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83QK"), + }, + .callback = atkbd_deactivate_fixup, + }, { } };
Greg Kroah-Hartman
maintainerPATCH 331/452 Input: atkbd - skip deactivate for HONOR BCC-Ns internal keyboard
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cryolitia PukNgae <[email protected]>
commit fb402386af4cdce108ff991a796386de55439735 upstream.
After commit 9cf6e24c9fbf17e52de9fff07f12be7565ea6d61 ("Input: atkbd - do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID"), HONOR BCC-N, aka HONOR MagicBook 14 2026's internal keyboard stops working. Adding the atkbd_deactivate_fixup quirk fixes it.
DMI: HONOR BCC-N/BCC-N-PCB, BIOS 1.04 04/07/2026
--- drivers/input/keyboard/atkbd.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/input/keyboard/atkbd.c +7 -0
@@ -1952,6 +1952,13 @@ static const struct dmi_system_id atkbd_ }, .callback = atkbd_deactivate_fixup, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"), + }, + .callback = atkbd_deactivate_fixup, + }, { } };
Greg Kroah-Hartman
maintainerPATCH 332/452 ipc/shm: serialize orphan cleanup with shm_nattch updates
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yilin Zhu <[email protected]>
commit 2e5c6f4fd4001562781e99bbfc7f1f0127187542 upstream.
shm_destroy_orphaned() walks the shm idr under shm_ids(ns).rwsem, but that does not serialize all fields tested by shm_may_destroy(). In particular, shm_nattch is updated while holding shm_perm.lock, and attach paths can do that without holding the rwsem.
Do not decide that an orphaned segment is unused before taking the object lock. Move the shm_may_destroy() check under shm_perm.lock, matching the other destroy paths, and unlock the segment when it no longer qualifies for removal.
--- ipc/shm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
ipc/shm.c +6 -4
@@ -415,15 +415,17 @@ static int shm_try_destroy_orphaned(int* We want to destroy segments without users and with already * exit'ed originating process. * -* As shp->* are changed under rwsem, it's safe to skip shp locking. +* shm_nattch can be changed under shm_perm.lock without holding the +* rwsem, so take the object lock before checking shm_may_destroy(). */ if (!list_empty (&shp->shm_clist))return 0 ; -if (shm_may_destroy (shp)) { -shm_lock_by_ptr (shp); +shm_lock_by_ptr (shp); +if (shm_may_destroy (shp))shm_destroy (ns, shp); - } +else +shm_unlock (shp);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 333/452 misc: fastrpc: fix use-after-free of fastrpc_user in workqueue context
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anandu Krishnan E <[email protected]>
commit e85eb5feca8e254905ffa6c57a3c99c89a674a0f upstream.
There is a race between fastrpc_device_release() and the workqueue that processes DSP responses. When the user closes the file descriptor, fastrpc_device_release() frees the fastrpc_user structure. Concurrently, an in-flight DSP invocation can complete and fastrpc_rpmsg_callback() schedules context cleanup via schedule_work(&ctx->put_work). If the workqueue runs fastrpc_context_free() in parallel with or after fastrpc_device_release() has freed the user structure, it dereferences the freed fastrpc_user. Depending on the state of the context at the time of the race, any one of the following accesses can be hit:
1. fastrpc_buf_free() calls fastrpc_ipa_to_dma_addr(buf->fl->cctx, ...) to strip the SID bits from the stored IOVA before passing the physical address to dma_free_coherent().
2. fastrpc_free_map() reads map->fl->cctx->vmperms[0].vmid to reconstruct the source permission bitmask needed for the qcom_scm_assign_mem() call that returns memory from the DSP VM back to HLOS.
3. fastrpc_free_map() acquires map->fl->lock to safely remove the
map node from the fl->maps list.
The resulting use-after-free manifests as:
pc : fastrpc_buf_free+0x38/0x80 [fastrpc] lr : fastrpc_context_free+0xa8/0x1b0 [fastrpc] fastrpc_context_free+0xa8/0x1b0 [fastrpc] fastrpc_context_put_wq+0x78/0xa0 [fastrpc] process_one_work+0x180/0x450 worker_thread+0x26c/0x388
Add kref-based reference counting to fastrpc_user. Have each invoke context take a reference on the user at allocation time and release it when the context is freed. Release the initial reference in fastrpc_device_release() at file close. Move the teardown of the user structure — freeing pending contexts, maps, mmaps, and the channel context reference — into the kref release callback fastrpc_user_free(), so that it runs only when the last reference is dropped, regardless of whether that happens at device close or after the final in-flight context completes.
--- drivers/misc/fastrpc.c | 75 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 23 deletions(-)
drivers/misc/fastrpc.c +52 -23
@@ -305,6 +305,8 @@ struct fastrpc_user {spinlock_t lock;/* lock for allocations */ struct mutex mutex; +/* Reference count */ +struct kref refcount; };static void fastrpc_free_map (struct kref *ref)
@@ -473,15 +475,57 @@ static void fastrpc_channel_ctx_put(strukref_put (&cctx->refcount, fastrpc_channel_ctx_free); } +static void fastrpc_context_put (struct fastrpc_invoke_ctx *ctx); + +static void fastrpc_user_free (struct kref *ref) +{ + struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount); +struct fastrpc_invoke_ctx *ctx, *n; +struct fastrpc_map *map, *m; +struct fastrpc_buf *buf, *b; + +if (fl->init_mem) +fastrpc_buf_free (fl->init_mem); + +list_for_each_entry_safe (ctx, n, &fl->pending, node) { +list_del (&ctx->node); +fastrpc_context_put (ctx); + } + +list_for_each_entry_safe (map, m, &fl->maps, node) +fastrpc_map_put (map); + +list_for_each_entry_safe (buf, b, &fl->mmaps, node) { +list_del (&buf->node); +fastrpc_buf_free (buf); + } + +fastrpc_channel_ctx_put (fl->cctx); +mutex_destroy (&fl->mutex); +kfree (fl); +} + +static void fastrpc_user_get (struct fastrpc_user *fl) +{ +kref_get (&fl->refcount); +} + +static void fastrpc_user_put (struct fastrpc_user *fl) +{ +kref_put (&fl->refcount, fastrpc_user_free); +} +static void fastrpc_context_free (struct kref *ref) {struct fastrpc_invoke_ctx *ctx;struct fastrpc_channel_ctx *cctx; +struct fastrpc_user *fl;unsigned long flags;int i; ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount); cctx = ctx->cctx; + fl = ctx->fl;for (i =0 ; i < ctx->nbufs; i++)fastrpc_map_put (ctx->maps[i]);
@@ -497,6 +541,8 @@ static void fastrpc_context_free(structkfree (ctx->olaps);kfree (ctx); +/* Release the reference taken in fastrpc_context_alloc() */ +fastrpc_user_put (fl);fastrpc_channel_ctx_put (cctx); }
@@ -606,6 +652,8 @@ static struct fastrpc_invoke_ctx *fastrp/* Released in fastrpc_context_put() */ fastrpc_channel_ctx_get (cctx); +/* Take a reference to user, released in fastrpc_context_free() */ +fastrpc_user_get (user); ctx->sc = sc; ctx->retval =-1 ;
@@ -636,6 +684,7 @@ err_idr:spin_lock (&user->lock);list_del (&ctx->node);spin_unlock (&user->lock); +fastrpc_user_put (user);fastrpc_channel_ctx_put (cctx);kfree (ctx->maps);kfree (ctx->olaps);
@@ -1549,9 +1598,6 @@ static int fastrpc_device_release(struct {struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;struct fastrpc_channel_ctx *cctx = fl->cctx; -struct fastrpc_invoke_ctx *ctx, *n; -struct fastrpc_map *map, *m; -struct fastrpc_buf *buf, *b;unsigned long flags;fastrpc_release_current_dsp_process (fl);
@@ -1560,28 +1606,10 @@ static int fastrpc_device_release(structlist_del (&fl->user);spin_unlock_irqrestore (&cctx->lock, flags); -if (fl->init_mem) -fastrpc_buf_free (fl->init_mem); - -list_for_each_entry_safe (ctx, n, &fl->pending, node) { -list_del (&ctx->node); -fastrpc_context_put (ctx); - } - -list_for_each_entry_safe (map, m, &fl->maps, node) -fastrpc_map_put (map); - -list_for_each_entry_safe (buf, b, &fl->mmaps, node) { -list_del (&buf->node); -fastrpc_buf_free (buf); - } -fastrpc_session_free (cctx, fl->sctx); -fastrpc_channel_ctx_put (cctx); - -mutex_destroy (&fl->mutex); -kfree (fl); file->private_data =NULL ; +/* Release the reference taken in fastrpc_device_open */ +fastrpc_user_put (fl);return 0 ; }
@@ -1626,6 +1654,7 @@ static int fastrpc_device_open(struct inspin_lock_irqsave (&cctx->lock, flags);list_add_tail (&fl->user, &cctx->users);spin_unlock_irqrestore (&cctx->lock, flags); +kref_init (&fl->refcount);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 334/452 misc: fastrpc: fix use-after-free race in fastrpc_map_create
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenghang Xiao <[email protected]>
commit 07ebe87915d8accdaba20c4f88c5ae430fe62fbb upstream.
fastrpc_map_lookup returns a raw pointer after releasing fl->lock. The caller fastrpc_map_create then calls fastrpc_map_get (kref_get_unless_zero) on this unprotected pointer. A concurrent MEM_UNMAP can free the map between the lock release and the kref operation, resulting in a use-after-free on the freed slab object.
Restore the take_ref parameter to fastrpc_map_lookup so the reference is acquired atomically under fl->lock before the pointer is exposed to the caller.
--- drivers/misc/fastrpc.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
drivers/misc/fastrpc.c +11 -14
@@ -364,7 +364,7 @@ static int fastrpc_map_get(struct fastrpstatic int fastrpc_map_lookup (struct fastrpc_user *fl,int fd, -struct fastrpc_map **ppmap) +struct fastrpc_map **ppmap,bool take_ref) {struct fastrpc_map *map =NULL ;struct dma_buf *buf;
@@ -379,6 +379,12 @@ static int fastrpc_map_lookup(struct fasif (map->fd != fd || map->buf != buf)continue ; +if (take_ref) { + ret =fastrpc_map_get (map); +if (ret) +break ; + } + *ppmap = map; ret =0 ;break ;
@@ -893,19 +899,10 @@ get_err:static int fastrpc_map_create (struct fastrpc_user *fl,int fd,u64 len,u32 attr,struct fastrpc_map **ppmap) { -struct fastrpc_session_ctx *sess = fl->sctx; -int err =0 ; +if (!fastrpc_map_lookup (fl, fd, ppmap, true)) +return 0 ; -if (!fastrpc_map_lookup (fl, fd, ppmap)) { -if (!fastrpc_map_get (*ppmap)) -return 0 ; -dev_dbg (sess->dev,"%s: Failed to get map fd=%d\n" , - __func__, fd); - } - - err =fastrpc_map_attach (fl, fd, len, attr, ppmap); - -return err; +return fastrpc_map_attach (fl, fd, len, attr, ppmap); }/*
@@ -1172,7 +1169,7 @@ cleanup_fdlist:for (i =0 ; i <FASTRPC_MAX_FDLIST ; i++) {if (!fdlist[i])break ; -if (!fastrpc_map_lookup (fl, (int )fdlist[i], &mmap)) +if (!fastrpc_map_lookup (fl, (int )fdlist[i], &mmap, false))fastrpc_map_put (mmap); }
Greg Kroah-Hartman
maintainerPATCH 335/452 misc: fastrpc: fix DMA address corruption due to find_vma misuse
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit 464c6ad2aa16e1e1df9d559289199356493d1e00 upstream.
fastrpc_get_args() uses find_vma() to look up the VMA for a user-provided pointer and compute a DMA address offset. When the address falls in a gap before the returned VMA, (ptr & PAGE_MASK) - vma->vm_start underflows, corrupting the DMA address sent to the DSP.
Replace find_vma() with vma_lookup(), which returns NULL when the address is not contained within any VMA.
--- drivers/misc/fastrpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/fastrpc.c +1 -1
@@ -1057,7 +1057,7 @@ static int fastrpc_get_args(u32 kernel, pages[i].addr = ctx->maps[i]->phys;mmap_read_lock (current->mm); - vma =find_vma (current->mm, ctx->args[i].ptr); + vma =vma_lookup (current->mm, ctx->args[i].ptr);if (vma) pages[i].addr += (ctx->args[i].ptr &PAGE_MASK ) - vma->vm_start;
Greg Kroah-Hartman
maintainerPATCH 336/452 misc: fastrpc: Fix NULL pointer dereference in rpmsg callback
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
commit 5401fb4fe10fac6134c308495df18ed74aebb9c4 upstream.
A NULL pointer dereference was observed on Hawi at boot when the DSP sends a glink message before fastrpc_rpmsg_probe() has completed initialization:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000178 pc : _raw_spin_lock_irqsave+0x34/0x8c lr : fastrpc_rpmsg_callback+0x3c/0xcc [fastrpc] ... Call trace: _raw_spin_lock_irqsave+0x34/0x8c (P) fastrpc_rpmsg_callback+0x3c/0xcc [fastrpc] qcom_glink_native_rx+0x538/0x6a4 qcom_glink_smem_intr+0x14/0x24 [qcom_glink_smem]
The faulting address 0x178 corresponds to the lock variable inside struct fastrpc_channel_ctx, confirming that cctx is NULL when fastrpc_rpmsg_callback() attempts to take the spinlock.
There are two issues here. First, dev_set_drvdata() is called before spin_lock_init() and idr_init(), leaving a window where the callback can retrieve a valid cctx pointer but operate on an uninitialized spinlock. Second, the rpmsg channel becomes live as soon as the driver is bound, so fastrpc_rpmsg_callback() can fire before dev_set_drvdata() is called at all, resulting in dev_get_drvdata() returning NULL.
Fix both issues by moving all cctx initialization ahead of dev_set_drvdata() so the structure is fully initialized before it becomes visible to the callback, and add a NULL check in fastrpc_rpmsg_callback() as a guard against any remaining window.
--- drivers/misc/fastrpc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/misc/fastrpc.c +4 -1
@@ -2392,7 +2392,6 @@ static int fastrpc_rpmsg_probe(struct rpkref_init (&data->refcount); -dev_set_drvdata (&rpdev->dev, data); rdev->dma_mask = &data->dma_mask;dma_set_mask_and_coherent (rdev,DMA_BIT_MASK (32 ));INIT_LIST_HEAD (&data->users);
@@ -2401,6 +2400,7 @@ static int fastrpc_rpmsg_probe(struct rpidr_init (&data->ctx_idr); data->domain_id = domain_id; data->rpdev = rpdev; +dev_set_drvdata (&rpdev->dev, data); err =of_platform_populate (rdev->of_node,NULL ,NULL , rdev);if (err)
@@ -2474,6 +2474,9 @@ static int fastrpc_rpmsg_callback(structif (len <sizeof (*rsp))return -EINVAL ; +if (!cctx) +return -ENODEV ; + ctxid = ((rsp->ctx &FASTRPC_CTXID_MASK ) >>4 );spin_lock_irqsave (&cctx->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 337/452 net/mlx5: Reorder completion before putting command entry in cmd_work_handler
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Kuratov <[email protected]>
commit 02896a7fa4cd3ec61d60ba30136841e4f04bdeac upstream.
Assuming callback != NULL && !page_queue, cmd_work_handler takes command entry with refcnt == 1 from mlx5_cmd_invoke. If either semaphore timeout or index allocation error happens, it does final cmd_ent_put(ent). To avoid access to freed memory, notify slotted completion before cmd_ent_put.
This is theoretical issue found by Svace static analyser.
--- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +4 -2
@@ -989,12 +989,13 @@ static void cmd_work_handler(struct work ent->callback (-EBUSY , ent->context);mlx5_free_cmd_msg (dev, ent->out);free_msg (dev, ent->in); +complete (&ent->slotted);cmd_ent_put (ent); }else { ent->ret = -EBUSY ;complete (&ent->done); +complete (&ent->slotted); } -complete (&ent->slotted);return ; } alloc_ret =cmd_alloc_index (cmd, ent);
@@ -1004,13 +1005,14 @@ static void cmd_work_handler(struct work ent->callback (-EAGAIN , ent->context);mlx5_free_cmd_msg (dev, ent->out);free_msg (dev, ent->in); +complete (&ent->slotted);cmd_ent_put (ent); }else { ent->ret = -EAGAIN ;complete (&ent->done); +complete (&ent->slotted); }up (&cmd->vars.sem); -complete (&ent->slotted);return ; } }else {
Greg Kroah-Hartman
maintainerPATCH 338/452 net: bonding: fix NULL pointer dereference in bond_do_ioctl()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhaoJinming <[email protected]>
commit a764b0e8317a863006e05732e1aefe821b9d8c2d upstream.
In bond_do_ioctl(), slave_dev is obtained via __dev_get_by_name() which can return NULL if the requested interface name does not exist. However, the subsequent slave_dbg() call is placed before the NULL check:
slave_dev = __dev_get_by_name(net, ifr->ifr_slave);
slave_dbg(bond_dev, slave_dev, "slave_dev=%p:\n", slave_dev); //here
if (!slave_dev)
return -ENODEV;The slave_dbg() macro expands to netdev_dbg(bond_dev, "(slave %s): " fmt, (slave_dev)->name, ...) which unconditionally dereferences slave_dev->name before the NULL check is performed. This results in a NULL pointer dereference kernel oops when a user calls bonding ioctl (e.g. SIOCBONDENSLAVE, SIOCBONDRELEASE, etc.) with a non-existent slave interface name.
This is reachable from userspace via the bonding ioctl interface with CAP_NET_ADMIN capability, making it a potential local denial-of-service vector.
Fix by moving the slave_dbg() call after the NULL check.
--- drivers/net/bonding/bond_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/bonding/bond_main.c +2 -2
@@ -4640,11 +4640,11 @@ static int bond_do_ioctl(struct net_devi slave_dev =__dev_get_by_name (net, ifr->ifr_slave); -slave_dbg (bond_dev, slave_dev,"slave_dev=%p:\n" , slave_dev); -if (!slave_dev)return -ENODEV ; +slave_dbg (bond_dev, slave_dev,"slave_dev=%p:\n" , slave_dev); +switch (cmd) {case SIOCBONDENSLAVE : res =bond_enslave (bond_dev, slave_dev,NULL );
Greg Kroah-Hartman
maintainerPATCH 339/452 net: mv643xx: fix OF node refcount
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit 4aacf509e537a711fa71bca9f234e5eb6968850e upstream.
Platform devices created with platform_device_alloc() call platform_device_release() when the last reference to the device's kobject is dropped. This function calls of_node_put() unconditionally. This works fine for devices created with platform_device_register_full() but users of the split approach (platform_device_alloc() + platform_device_add()) must bump the reference of the of_node they assign manually. Add the missing call to of_node_get().
--- drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/mv643xx_eth.c +1 -1
@@ -2784,7 +2784,7 @@ static int mv643xx_eth_shared_of_add_por goto put_err; } ppdev->dev.coherent_dma_mask =DMA_BIT_MASK (32 ); - ppdev->dev.of_node = pnp; + ppdev->dev.of_node =of_node_get (pnp); ret =platform_device_add_resources (ppdev, &res,1 );if (ret)
Greg Kroah-Hartman
maintainerPATCH 340/452 net: rds: clear i_sends on setup unwind
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 20cf0fb715c41111469577e85e35d15f099473e0 upstream.
The RDS IB connection teardown path is written so it can run during partial startup and on repeated shutdown attempts. It uses NULL pointers to distinguish resources that are still owned from resources that have already been released.
When rds_ib_setup_qp() fails after allocating i_sends but before allocating i_recvs, the sends_out path frees i_sends without clearing the pointer. A later shutdown pass can still treat that stale pointer as a live send ring allocation.
Clear i_sends after vfree() in the error unwind path so the existing shutdown logic continues to use the correct ownership state.
--- net/rds/ib_cm.c | 1 + 1 file changed, 1 insertion(+)
net/rds/ib_cm.c +1 -0
@@ -656,6 +656,7 @@ static int rds_ib_setup_qp(struct rds_co sends_out:vfree (ic->i_sends); + ic->i_sends =NULL ; ack_dma_out: rds_dma_hdr_free(rds_ibdev->dev, ic->i_ack, ic->i_ack_dma,
Greg Kroah-Hartman
maintainerPATCH 341/452 nvmem: layouts: onie-tlv: fix hang on unknown types
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andre Heider <[email protected]>
commit ea41020b9018e31c2ea7e9d89021e3e6d7470883 upstream.
The EEPROM on my board has a vendor specific entry of type 0x41. When stumbling upon that, this driver hangs in an endless loop.
Fix it by keep incrementing the offset on unknown entries, so the loop will eventually stop.
--- drivers/nvmem/layouts/onie-tlv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/nvmem/layouts/onie-tlv.c +2 -1
@@ -119,7 +119,7 @@ static int onie_tlv_add_cells(struct dev cell.name =onie_tlv_cell_name (tlv.type);if (!cell.name) -continue ; + goto next; cell.offset = hdr_len + offset +sizeof (tlv.type) +sizeof (tlv.len); cell.bytes = tlv.len;
@@ -132,6 +132,7 @@ static int onie_tlv_add_cells(struct devreturn ret; } +next: offset +=sizeof (tlv) + tlv.len; }
Greg Kroah-Hartman
maintainerPATCH 342/452 octeontx2-af: fix memory leak in rvu_setup_hw_resources()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 09a5bf856aa759513afc4afd233d15bcc711b84e upstream.
If rvu_npc_exact_init() fails in rvu_setup_hw_resources(), the function returns directly instead of jumping to the error handling path. This causes a resource leak for the previously initialized CGX, NPC, fwdata, and MSI-X states.
Fix this by replacing the direct return with goto cgx_err to ensure proper cleanup.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1-rc6.
An x86_64 allyesconfig build showed no new warnings. As we do not have access to Marvell OcteonTX2 RVU AF hardware to test with, no runtime testing was able to be performed.
--- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu.c +1 -1
@@ -1130,7 +1130,7 @@ cpt: err =rvu_npc_exact_init (rvu);if (err) {dev_err (rvu->dev,"failed to initialize exact match table\n" ); -return err; + goto cgx_err; }/* Assign MACs for CGX mapped functions */
Greg Kroah-Hartman
maintainerPATCH 343/452 bpf: Track equal scalars history on per-instruction level
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit 4bf79f9be434e000c8e12fe83b2f4402480f1460 ]
Use bpf_verifier_state->jmp_history to track which registers were updated by find_equal_scalars() (renamed to collect_linked_regs()) when conditional jump was verified. Use recorded information in backtrack_insn() to propagate precision.
E.g. for the following program:
while verifying instructions
1: r1 = r0 | 2: if r1 < 8 goto ... | push r0,r1 as linked registers in jmp_history 3: if r0 > 16 goto ... | push r0,r1 as linked registers in jmp_history 4: r2 = r10 | 5: r2 += r0 v mark_chain_precision(r0)
while doing mark_chain_precision(r0)
5: r2 += r0 | mark r0 precise 4: r2 = r10 | 3: if r0 > 16 goto ... | mark r0,r1 as precise 2: if r1 < 8 goto ... | mark r0,r1 as precise 1: r1 = r0 v
Technically, do this as follows:
- Use 10 bits to identify each register that gains range because of sync_linked_regs():
- 3 bits for frame number;
- 6 bits for register or stack slot number;
- 1 bit to indicate if register is spilled.
- Use u64 as a vector of 6 such records + 4 bits for vector length.
- Augment struct bpf_jmp_history_entry with a field 'linked_regs' representing such vector.
- When doing check_cond_jmp_op() remember up to 6 registers that gain range because of sync_linked_regs() in such a vector.
- Don't propagate range information and reset IDs for registers that don't fit in 6-value vector.
- Push a pair {instruction index, linked registers vector} to bpf_verifier_state->jmp_history.
- When doing backtrack_insn() check if any of recorded linked registers is currently marked precise, if so mark all linked registers as precise.
This also requires fixes for two test_verifier tests:
- precise: test 1
- precise: test 2
Both tests contain the following instruction sequence:
19: (bf) r2 = r9 ; R2=scalar(id=3) R9=scalar(id=3)
20: (a5) if r2 < 0x8 goto pc+1 ; R2=scalar(id=3,umin=8)
21: (95) exit
22: (07) r2 += 1 ; R2_w=scalar(id=3+1,...) 23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0 24: (07) r1 += -8 ; R1_w=fp-8 25: (b7) r3 = 0 ; R3_w=0
26: (85) call bpf_probe_read_kernel#113
The call to bpf_probe_read_kernel() at (26) forces r2 to be precise. Previously, this forced all registers with same id to become precise immediately when mark_chain_precision() is called.
After this change, the precision is propagated to registers sharing same id only when 'if' instruction is backtracked.
Hence verification log for both tests is changed:
regs=r2,r9 -> regs=r2 for instructions 25..20.
[ zhenzhong: backport to 6.6.y verifier layout and adapt
sync_linked_regs() to the pre-BPF_ADD_CONST scalar-id code. ]
--- include/linux/bpf_verifier.h | 4 + kernel/bpf/verifier.c | 256 ++++++++++++++++-- .../bpf/progs/verifier_subprog_precision.c | 2 +- 3 files changed, 239 insertions(+), 23 deletions(-)
include/linux/bpf_verifier.h +4 -0
@@ -345,6 +345,10 @@ struct bpf_jmp_history_entry { u32 prev_idx : 22;/* special flags, e.g., whether insn is doing register stack spill/load */ u32 flags : 10; +/* additional registers that need precision tracking when this +* jump is backtracked, vector of six 10-bit records +*/ +u64 linked_regs; };/* Maximum number of register states that can exist at once */
kernel/bpf/verifier.c +234 -22
403 lines not on this page · raw message
tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +1 -1
@@ -141,7 +141,7 @@ __msg("mark_precise: frame0: last_idx 14 first_idx 9") __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") -__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") +__msg("mark_precise: frame0: regs=r0,r6 stack= before 10: (bf) r6 = r0")__msg ("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop" ) /* State entering callback body popped from states stack */__msg ("from 9 to 17: frame1:" )
Signature · 1 line
2.53.0
Re: [PATCH 6.6 343/452] bpf: Track equal scalars history on per-instruction level
Quoted 1 line · Greg Kroah-Hartman
6.6-stable review patch. If anyone has any objections, please let me know.
As discussed in [1] and its reply, this patch is currently breaking the BPF selftests on 6.6.y. I think it would be best to drop this series and wait for a v4 of the backport.
1: https://lore.kernel.org/stable/[email protected]/
Quoted 550 lines
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit
4bf79f9be434e000c8e12fe83b2f4402480f1460]Use
bpf_verifier_state->jmp_historyto track which registers were updated byfind_equal_scalars()(renamed tocollect_linked_regs()) when conditional jump was verified. Use recorded information inbacktrack_insn()to propagate precision.E.g. for the following program:
while verifying instructions
1: r1 = r0 | 2: if r1 < 8 goto ... | push r0,r1 as linked registers in jmp_history 3: if r0 > 16 goto ... | push r0,r1 as linked registers in jmp_history 4: r2 = r10 | 5: r2 += r0 v mark_chain_precision(r0)while doing
mark_chain_precision(r0)5: r2 += r0 | mark r0 precise 4: r2 = r10 | 3: if r0 > 16 goto ... | mark r0,r1 as precise 2: if r1 < 8 goto ... | mark r0,r1 as precise 1: r1 = r0 vTechnically, do this as follows:
- Use 10 bits to identify each register that gains range because ofsync_linked_regs():
- 3 bits for frame number;
- 6 bits for register or stack slot number;
- 1 bit to indicate if register is spilled.
- Use u64 as a vector of 6 such records + 4 bits for vector length.
- Augment structbpf_jmp_history_entrywith a field 'linked_regs' representing such vector.
- When doingcheck_cond_jmp_op()remember up to 6 registers that gain range because ofsync_linked_regs()in such a vector.
- Don't propagate range information and reset IDs for registers that don't fit in 6-value vector.
- Push a pair {instruction index, linked registers vector} tobpf_verifier_state->jmp_history.
- When doingbacktrack_insn()check if any of recorded linked registers is currently marked precise, if so mark all linked registers as precise.This also requires fixes for two
test_verifiertests:
- precise: test 1
- precise: test 2Both tests contain the following instruction sequence:
19: (bf) r2 = r9 ; R2=scalar(id=3) R9=scalar(id=3)
20: (a5) if r2 <0x8goto pc+1 ; R2=scalar(id=3,umin=8)
21: (95) exit22: (07) r2 += 1 ; R2_w=scalar(id=3+1,...) 23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0 24: (07) r1 += -8 ; R1_w=fp-8 25: (b7) r3 = 0 ; R3_w=026: (85) call bpf_probe_read_kernel#113
The call to
bpf_probe_read_kernel()at (26) forces r2 to be precise. Previously, this forced all registers with same id to become precise immediately whenmark_chain_precision()is called.
After this change, the precision is propagated to registers sharing same id only when 'if' instruction is backtracked.
Hence verification log for both tests is changed:
regs=r2,r9 -> regs=r2 for instructions 25..20.Fixes 904e6ddf4133 ("bpf: Use scalar ids in mark_chain_precision()")Reported-by Hao Sun <[email protected]>Suggested-by Andrii Nakryiko <[email protected]>Signed-off-by Eduard Zingerman <[email protected]>Signed-off-by Andrii Nakryiko <[email protected]>[ zhenzhong: backport to 6.6.y verifier layout and adapt
sync_linked_regs()to the pre-BPF_ADD_CONST scalar-id code. ]Signed-off-by Zhenzhong Wu <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- include/linux/bpf_verifier.h | 4 + kernel/bpf/verifier.c | 256 ++++++++++++++++-- .../bpf/progs/verifier_subprog_precision.c | 2 +- 3 files changed, 239 insertions(+), 23 deletions(-)include/linux/bpf_verifier.h +4
-0@@ -345,6 +345,10 @@ struct bpf_jmp_history_entry { u32 prev_idx : 22;/* special flags, e.g., whether insn is doing register stack spill/load */ u32 flags : 10; +/* additional registers that need precision tracking when this +* jump is backtracked, vector of six 10-bit records +*/ +u64 linked_regs; };/* Maximum number of register states that can exist at once */ kernel/bpf/verifier.c +234
-22@@ -3461,9 +3461,87 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx)return env->insn_aux_data[insn_idx].jmp_point; } +#define LR_FRAMENO_BITS 3 +#define LR_SPI_BITS 6 +#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1) +#define LR_SIZE_BITS 4 +#define LR_FRAMENO_MASK ((1ull << LR_FRAMENO_BITS) - 1) +#define LR_SPI_MASK ((1ull << LR_SPI_BITS) - 1) +#define LR_SIZE_MASK ((1ull << LR_SIZE_BITS) - 1) +#define LR_SPI_OFF LR_FRAMENO_BITS +#define LR_IS_REG_OFF (LR_SPI_BITS + LR_FRAMENO_BITS) +#define LINKED_REGS_MAX 6 + +struct linked_reg { +u8 frameno; +union { +u8 spi; +u8 regno; + }; +bool is_reg; +}; + +struct linked_regs { +int cnt; +struct linked_reg entries[LINKED_REGS_MAX ]; +}; + +static struct linked_reg *linked_regs_push (struct linked_regs *s) +{ +if (s->cnt <LINKED_REGS_MAX ) +return &s->entries[s->cnt++]; + +return NULL ; +} + +/* Use u64 as a vector of 6 10-bit values, use first 4-bits to track +* number of elements currently in stack. +* Pack one history entry for linked registers as 10 bits in the following format: +* - 3-bits frameno +* - 6-bits spi_or_reg +* - 1-bit is_reg +*/ +static u64 linked_regs_pack (struct linked_regs *s) +{ +u64 val =0 ; +int i; + +for (i =0 ; i < s->cnt; ++i) { +struct linked_reg *e = &s->entries[i]; +u64 tmp =0 ; + + tmp |= e->frameno; + tmp |= e->spi <<LR_SPI_OFF ; + tmp |= (e->is_reg ?1 :0 ) <<LR_IS_REG_OFF ; + + val <<=LR_ENTRY_BITS ; + val |= tmp; + } + val <<=LR_SIZE_BITS ; + val |= s->cnt; +return val; +} + +static void linked_regs_unpack (u64 val,struct linked_regs *s) +{ +int i; + + s->cnt = val &LR_SIZE_MASK ; + val >>=LR_SIZE_BITS ; + +for (i =0 ; i < s->cnt; ++i) { +struct linked_reg *e = &s->entries[i]; + + e->frameno = val &LR_FRAMENO_MASK ; + e->spi = (val >>LR_SPI_OFF ) &LR_SPI_MASK ; + e->is_reg = (val >>LR_IS_REG_OFF ) &0x1 ; + val >>=LR_ENTRY_BITS ; + } +} +/* for any branch, call, exit record the history of jmps in the given state */ static int push_jmp_history (struct bpf_verifier_env *env,struct bpf_verifier_state *cur, -int insn_flags) +int insn_flags,u64 linked_regs) {u32 cnt = cur->jmp_history_cnt;struct bpf_jmp_history_entry *p;@@ -3479,6 +3557,10 @@ static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_st"verifier insn history bug: insn_idx %d cur flags %x new flags %x\n" , env->insn_idx, env->cur_hist_ent->flags, insn_flags); env->cur_hist_ent->flags |= insn_flags; +WARN_ONCE (env->cur_hist_ent->linked_regs !=0 , +"verifier insn history bug: insn_idx %d linked_regs != 0: %#llx\n" , + env->insn_idx, env->cur_hist_ent->linked_regs); + env->cur_hist_ent->linked_regs = linked_regs;return 0 ; }@@ -3493,6 +3575,7 @@ static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_st p->idx = env->insn_idx; p->prev_idx = env->prev_insn_idx; p->flags = insn_flags; + p->linked_regs = linked_regs; cur->jmp_history_cnt = cnt; env->cur_hist_ent = p;@@ -3668,6 +3751,11 @@ static inline bool bt_is_reg_set(struct backtrack_state *bt, u32 reg)return bt->reg_masks[bt->frame] & (1 << reg); } +static inline bool bt_is_frame_reg_set (struct backtrack_state *bt,u32 frame,u32 reg) +{ +return bt->reg_masks[frame] & (1 << reg); +} +static inline bool bt_is_frame_slot_set (struct backtrack_state *bt,u32 frame,u32 slot) {return bt->stack_masks[frame] & (1ull << slot);@@ -3717,6 +3805,42 @@ static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) } } +/* If any register R in hist->linked_regs is marked as precise in bt, +* do bt_set_frame_{reg,slot}(bt, R) for all registers in hist->linked_regs. +*/ +static void bt_sync_linked_regs (struct backtrack_state *bt,struct bpf_jmp_history_entry *hist) +{ +struct linked_regs linked_regs; +bool some_precise = false; +int i; + +if (!hist || hist->linked_regs ==0 ) +return ; + +linked_regs_unpack (hist->linked_regs, &linked_regs); +for (i =0 ; i < linked_regs.cnt; ++i) { +struct linked_reg *e = &linked_regs.entries[i]; + +if ((e->is_reg &&bt_is_frame_reg_set (bt, e->frameno, e->regno)) || + (!e->is_reg &&bt_is_frame_slot_set (bt, e->frameno, e->spi))) { + some_precise = true; +break ; + } + } + +if (!some_precise) +return ; + +for (i =0 ; i < linked_regs.cnt; ++i) { +struct linked_reg *e = &linked_regs.entries[i]; + +if (e->is_reg) +bt_set_frame_reg (bt, e->frameno, e->regno); +else +bt_set_frame_slot (bt, e->frameno, e->spi); + } +} +static bool calls_callback (struct bpf_verifier_env *env,int insn_idx);/* For given verifier state backtrack_insn() is called from the last insn to @@ -3756,6 +3880,12 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,print_bpf_insn (&cbs, insn, env->allow_ptr_leaks); } +/* If there is a history record that some registers gained range at this insn, +* propagate precision marks to those registers, so that bt_is_reg_set() +* accounts for these registers. +*/ +bt_sync_linked_regs (bt, hist); +if (class ==BPF_ALU || class ==BPF_ALU64 ) {if (!bt_is_reg_set (bt, dreg))return 0 ;@@ -3985,7 +4115,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,*/ bt_set_reg (bt, dreg);bt_set_reg (bt, sreg); -/* else dreg <cond> K + }else if (BPF_SRC (insn->code) ==BPF_K ) { +/* dreg <cond> K * Only dreg still needs precision before * this insn, so for the K-based conditional * there is nothing new to be marked. @@ -4003,6 +4134,10 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,/* to be analyzed */ return -ENOTSUPP ; } +/* Propagate precision marks to linked registers, to account for +* registers marked as precise in this function. +*/ +bt_sync_linked_regs (bt, hist);return 0 ; }@@ -4354,7 +4489,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)/* If some register with scalar ID is marked as precise, * make sure that all registers sharing this ID are also precise. -* This is needed to estimate effect of find_equal_scalars(). +* This is needed to estimate effect of sync_linked_regs(). * Do this at the last instruction of each state, * bpf_reg_state::id fields are valid for these instructions. * @@ -4368,7 +4503,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)* ... * --- state #1 {r1.id = A, r2.id = A} --- * ... -* if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 +* if (r2 > 10) goto exit; // sync_linked_regs() assigns range to r1 * ... * --- state #2 {r1.id = A, r2.id = A} --- * r3 = r10 @@ -4736,7 +4871,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, }if (insn_flags) -return push_jmp_history (env, env->cur_state, insn_flags); +return push_jmp_history (env, env->cur_state, insn_flags,0 );return 0 ; }@@ -5032,7 +5167,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, insn_flags =0 ;/* we are not restoring spilled register */ }if (insn_flags) -return push_jmp_history (env, env->cur_state, insn_flags); +return push_jmp_history (env, env->cur_state, insn_flags,0 );return 0 ; }@@ -13540,7 +13675,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, ptr_reg = dst_reg; else/* Make sure ID is cleared otherwise dst_reg min/max could be -* incorrectly propagated into other registers by find_equal_scalars() +* incorrectly propagated into other registers by sync_linked_regs() */ dst_reg->id = 0;if (BPF_SRC (insn->code) ==BPF_X ) {@@ -13700,7 +13835,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)*/ if (need_id)/* Assign src and dst registers the same ID -* that will be used by find_equal_scalars() +* that will be used by sync_linked_regs() * to propagate min/max range. */ src_reg->id = ++env->id_gen;@@ -13746,7 +13881,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)copy_register_state (dst_reg, src_reg);/* Make sure ID is cleared if src_reg is not in u32 * range otherwise dst_reg min/max could be incorrectly -* propagated into src_reg by find_equal_scalars() +* propagated into src_reg by sync_linked_regs() */ if (!is_src_reg_u32) dst_reg->id =0 ;@@ -14564,19 +14699,78 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,return true; } -static void find_equal_scalars (struct bpf_verifier_state *vstate, -struct bpf_reg_state *known_reg) +static void __collect_linked_regs (struct linked_regs *reg_set,struct bpf_reg_state *reg, +u32 id,u32 frameno,u32 spi_or_reg,bool is_reg) { -struct bpf_func_state *state; +struct linked_reg *e; + +if (reg->type !=SCALAR_VALUE || reg->id != id) +return ; + + e =linked_regs_push (reg_set); +if (e) { + e->frameno = frameno; + e->is_reg = is_reg; + e->regno = spi_or_reg; + }else { + reg->id =0 ; + } +} + +/* For all R being scalar registers or spilled scalar registers +* in verifier state, save R in linked_regs if R->id == id. +* If there are too many Rs sharing same id, reset id for leftover Rs. +*/ +static void collect_linked_regs (struct bpf_verifier_state *vstate,u32 id, +struct linked_regs *linked_regs) +{ +struct bpf_func_state *func;struct bpf_reg_state *reg; +int i, j; -bpf_for_each_reg_in_vstate (vstate, state, reg, ({ -if (reg->type ==SCALAR_VALUE && reg->id == known_reg->id) { +for (i = vstate->curframe; i >=0 ; i--) { + func = vstate->frame[i]; +for (j =0 ; j <BPF_REG_FP ; j++) { + reg = &func->regs[j]; +__collect_linked_regs (linked_regs, reg, id, i, j, true); + } +for (j =0 ; j < func->allocated_stack /BPF_REG_SIZE ; j++) { +if (!is_spilled_reg (&func->stack[j])) +continue ; + reg = &func->stack[j].spilled_ptr; +__collect_linked_regs (linked_regs, reg, id, i, j, false); + } + } + +if (linked_regs->cnt ==1 ) + linked_regs->cnt =0 ; +} + +/* For all R in linked_regs, copy known_reg range into R +* if R->id == known_reg->id. +*/ +static void sync_linked_regs (struct bpf_verifier_state *vstate,struct bpf_reg_state *known_reg, +struct linked_regs *linked_regs) +{ +struct bpf_reg_state *reg; +struct linked_reg *e; +int i; + +for (i =0 ; i < linked_regs->cnt; ++i) { + e = &linked_regs->entries[i]; + reg = e->is_reg ? &vstate->frame[e->frameno]->regs[e->regno] + : &vstate->frame[e->frameno]->stack[e->spi].spilled_ptr; +if (reg->type !=SCALAR_VALUE || reg == known_reg) +continue ; +if (reg->id != known_reg->id) +continue ; + {s32 saved_subreg_def = reg->subreg_def; +copy_register_state (reg, known_reg); reg->subreg_def = saved_subreg_def; } - })); + } } static int check_cond_jmp_op(struct bpf_verifier_env *env,@@ -14587,6 +14781,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs;struct bpf_reg_state *dst_reg, *other_branch_regs, *src_reg =NULL ;struct bpf_reg_state *eq_branch_regs; +struct linked_regs linked_regs = {};u8 opcode =BPF_OP (insn->code);bool is_jmp32;int pred =-1 ;@@ -14704,6 +14899,21 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,return 0 ; } +/* Push scalar registers sharing same ID to jump history, +* do this before creating 'other_branch', so that both +* 'this_branch' and 'other_branch' share this history +* if parent state is created. +*/ +if (BPF_SRC (insn->code) ==BPF_X && src_reg->type ==SCALAR_VALUE && src_reg->id) +collect_linked_regs (this_branch, src_reg->id, &linked_regs); +if (dst_reg->type ==SCALAR_VALUE && dst_reg->id) +collect_linked_regs (this_branch, dst_reg->id, &linked_regs); +if (linked_regs.cnt >0 ) { + err =push_jmp_history (env, this_branch,0 ,linked_regs_pack (&linked_regs)); +if (err) +return err; + } + other_branch =push_stack (env, *insn_idx + insn->off +1 , *insn_idx, false);if (!other_branch)@@ -14746,8 +14956,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, src_reg, dst_reg, opcode);if (src_reg->id && !WARN_ON_ONCE (src_reg->id != other_branch_regs[insn->src_reg].id)) { -find_equal_scalars (this_branch, src_reg); -find_equal_scalars (other_branch, &other_branch_regs[insn->src_reg]); +sync_linked_regs (this_branch, src_reg, &linked_regs); +sync_linked_regs (other_branch, &other_branch_regs[insn->src_reg], + &linked_regs); } }@@ -14759,8 +14970,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,if (dst_reg->type ==SCALAR_VALUE && dst_reg->id && !WARN_ON_ONCE (dst_reg->id != other_branch_regs[insn->dst_reg].id)) { -find_equal_scalars (this_branch, dst_reg); -find_equal_scalars (other_branch, &other_branch_regs[insn->dst_reg]); +sync_linked_regs (this_branch, dst_reg, &linked_regs); +sync_linked_regs (other_branch, &other_branch_regs[insn->dst_reg], + &linked_regs); }/* if one pointer register is compared to another pointer @@ -16182,7 +16394,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,* * First verification path is [1-6]: * - at (4) same bpf_reg_state::id (b) would be assigned to r6 and r7; -* - at (5) r6 would be marked <= X, find_equal_scalars() would also mark +* - at (5) r6 would be marked <= X, sync_linked_regs() would also mark * r7 <= X, because r6 and r7 share same id. * Next verification path is [1-4, 6]. * @@ -16915,7 +17127,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)* the current state. */ if (is_jmp_point (env, env->insn_idx)) - err = err ? :push_jmp_history (env, cur,0 ); + err = err ? :push_jmp_history (env, cur,0 ,0 ); err = err ? :propagate_precision (env, &sl->state);if (err)return err;@@ -17181,7 +17393,7 @@ static int do_check(struct bpf_verifier_env *env) }if (is_jmp_point (env, env->insn_idx)) { - err =push_jmp_history (env, state,0 ); + err =push_jmp_history (env, state,0 ,0 );if (err)return err; }tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +1
-1@@ -141,7 +141,7 @@ __msg("mark_precise: frame0: last_idx 14 first_idx 9") __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") -__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") +__msg("mark_precise: frame0: regs=r0,r6 stack= before 10: (bf) r6 = r0")__msg ("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop" ) /* State entering callback body popped from states stack */__msg ("from 9 to 17: frame1:" )Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerRe: [PATCH 6.6 343/452] bpf: Track equal scalars history on per-instruction level
Quoted 8 lines · Paul Chaignon
Quoted 1 line · Greg Kroah-Hartman
6.6-stable review patch. If anyone has any objections, please let me know.
As discussed in [1] and its reply, this patch is currently breaking the BPF selftests on 6.6.y. I think it would be best to drop this series and wait for a v4 of the backport.
Now dropped, thanks.
greg k-h
Greg Kroah-Hartman
maintainerPATCH 344/452 bpf: Remove mark_precise_scalar_ids()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit 842edb5507a1038e009d27e69d13b94b6f085763 ]
Function mark_precise_scalar_ids() is superseded by bt_sync_linked_regs() and equal scalars tracking in jump history. mark_precise_scalar_ids() propagates precision over registers sharing same ID on parent/child state boundaries, while jump history records allow bt_sync_linked_regs() to propagate same information with instruction level granularity, which is strictly more precise.
This commit removes mark_precise_scalar_ids() and updates test cases in progs/verifier_scalar_ids to reflect new verifier behavior.
The tests are updated in the following manner:
- mark_precise_scalar_ids() propagated precision regardless of presence of conditional jumps, while new jump history based logic only kicks in when conditional jumps are present.
Hence test cases are augmented with conditional jumps to still trigger precision propagation.
- As equal scalars tracking no longer relies on parent/child state boundaries some test cases are no longer interesting, such test cases are removed, namely:
- precision_same_state and precision_cross_state are superseded by
linked_regs_bpf_k;
- precision_same_state_broken_link and equal_scalars_broken_link are superseded by linked_regs_broken_link.
[ zhenzhong: backport to 6.6.y after adapting the first linked-regs
history commit to the older scalar-id verifier layout. ]
--- kernel/bpf/verifier.c | 115 ------------ .../selftests/bpf/progs/verifier_scalar_ids.c | 171 ++++++------------ .../testing/selftests/bpf/verifier/precise.c | 2 +- 3 files changed, 56 insertions(+), 232 deletions(-)
kernel/bpf/verifier.c +0 -115
@@ -4265,96 +4265,6 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ } } -static bool idset_contains (struct bpf_idset *s,u32 id) -{ -u32 i; - -for (i =0 ; i < s->count; ++i) -if (s->ids[i] == id) -return true; - -return false; -} - -static int idset_push (struct bpf_idset *s,u32 id) -{ -if (WARN_ON_ONCE (s->count >=ARRAY_SIZE (s->ids))) -return -EFAULT ; - s->ids[s->count++] = id; -return 0 ; -} - -static void idset_reset (struct bpf_idset *s) -{ - s->count =0 ; -} - -/* Collect a set of IDs for all registers currently marked as precise in env->bt. -* Mark all registers with these IDs as precise. -*/ -static int mark_precise_scalar_ids (struct bpf_verifier_env *env,struct bpf_verifier_state *st) -{ -struct bpf_idset *precise_ids = &env->idset_scratch; -struct backtrack_state *bt = &env->bt; -struct bpf_func_state *func; -struct bpf_reg_state *reg; -DECLARE_BITMAP (mask,64 ); -int i, fr; - -idset_reset (precise_ids); - -for (fr = bt->frame; fr >=0 ; fr--) { - func = st->frame[fr]; - -bitmap_from_u64 (mask,bt_frame_reg_mask (bt, fr)); -for_each_set_bit (i, mask,32 ) { - reg = &func->regs[i]; -if (!reg->id || reg->type !=SCALAR_VALUE ) -continue ; -if (idset_push (precise_ids, reg->id)) -return -EFAULT ; - } - -bitmap_from_u64 (mask,bt_frame_stack_mask (bt, fr)); -for_each_set_bit (i, mask,64 ) { -if (i >= func->allocated_stack /BPF_REG_SIZE ) -break ; -if (!is_spilled_scalar_reg (&func->stack[i])) -continue ; - reg = &func->stack[i].spilled_ptr; -if (!reg->id) -continue ; -if (idset_push (precise_ids, reg->id)) -return -EFAULT ; - } - } - -for (fr =0 ; fr <= st->curframe; ++fr) { - func = st->frame[fr]; - -for (i =BPF_REG_0 ; i <BPF_REG_10 ; ++i) { - reg = &func->regs[i]; -if (!reg->id) -continue ; -if (!idset_contains (precise_ids, reg->id)) -continue ; -bt_set_frame_reg (bt, fr, i); - } -for (i =0 ; i < func->allocated_stack /BPF_REG_SIZE ; ++i) { -if (!is_spilled_scalar_reg (&func->stack[i])) -continue ; - reg = &func->stack[i].spilled_ptr; -if (!reg->id) -continue ; -if (!idset_contains (precise_ids, reg->id)) -continue ; -bt_set_frame_slot (bt, fr, i); - } - } - -return 0 ; -} -/* * __mark_chain_precision() backtracks BPF program instruction sequence and * chain of verifier states making sure that register *regno* (if regno >= 0)
@@ -4487,31 +4397,6 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) bt->frame, last_idx, first_idx, subseq_idx); } -/* If some register with scalar ID is marked as precise, -* make sure that all registers sharing this ID are also precise. -* This is needed to estimate effect of sync_linked_regs(). -* Do this at the last instruction of each state, -* bpf_reg_state::id fields are valid for these instructions. -* -* Allows to track precision in situation like below: -* -* r2 = unknown value -* ... -* --- state #0 --- -* ... -* r1 = r2 // r1 and r2 now share the same ID -* ... -* --- state #1 {r1.id = A, r2.id = A} --- -* ... -* if (r2 > 10) goto exit; // sync_linked_regs() assigns range to r1 -* ... -* --- state #2 {r1.id = A, r2.id = A} --- -* r3 = r10 -* r3 += r1 // need to mark both r1 and r2 -*/ -if (mark_precise_scalar_ids (env, st)) -return -EFAULT ; -if (last_idx <0 ) {/* we are at the entry into subprog, which * is expected for global funcs, but only if
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +55 -116
263 lines not on this page · raw message
tools/testing/selftests/bpf/verifier/precise.c +1 -1
@@ -106,7 +106,7 @@ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ - mark_precise: frame0: regs=r2,r9 stack= before 20\ + mark_precise: frame0: regs=r2 stack= before 20\ mark_precise: frame0: parent state regs=r2,r9 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ mark_precise: frame0: regs=r2,r9 stack= before 19\
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 345/452 selftests/bpf: Tests for per-insn sync_linked_regs() precision tracking
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit bebc17b1c03b224a0b4aec6a171815e39f8ba9bc ]
Add a few test cases to verify precision tracking for scalars gaining range because of sync_linked_regs():
- check what happens when more than 6 registers might gain range in sync_linked_regs();
- check if precision is propagated correctly when operand of conditional jump gained range in sync_linked_regs() and one of linked registers is marked precise;
- check if precision is propagated correctly when operand of conditional jump gained range in sync_linked_regs() and a other-linked operand of the conditional jump is marked precise;
- add a minimized reproducer for precision tracking bug reported in [0];
- Check that mark_chain_precision() for one of the conditional jump operands does not trigger equal scalars precision propagation.
[0] https://lore.kernel.org/bpf/CAEf4BzZ0xidVCqB47XnkXcNhkPWF6_nTV7yt+_Lf0kcFEut2Mg@mail.gmail.com/
[ zhenzhong: keep the linked_regs_broken_link_2 reject check, but
drop the mark_precise log expectations because 6.6.y does not derive the scalar-vs-scalar range for that non-constant JMP_X comparison. ]
--- .../selftests/bpf/progs/verifier_scalar_ids.c | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+)
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +162 -0
@@ -47,6 +47,72 @@ __naked void linked_regs_bpf_k(void) : __clobber_all); } +/* Registers r{0,1,2} share same ID when 'if r1 > ...' insn is processed, +* check that verifier marks r{1,2} as precise while backtracking +* 'if r1 > ...' with r0 already marked. +*/ +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("frame0: regs=r0 stack= before 5: (2d) if r1 > r3 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") +__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") +__naked void linked_regs_bpf_x_src (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id == r2.id */ +"r1 = r0;" +"r2 = r0;" +"r3 = 7;" +"if r1 > r3 goto +0;" +/* force r0 to be precise, this eventually marks r1 and r2 as +* precise as well because of shared IDs +*/ +"r4 = r10;" +"r4 += r0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Registers r{0,1,2} share same ID when 'if r1 > r3' insn is processed, +* check that verifier marks r{0,1,2} as precise while backtracking +* 'if r1 > r3' with r3 already marked. +*/ +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("frame0: regs=r3 stack= before 5: (2d) if r1 > r3 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") +__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") +__naked void linked_regs_bpf_x_dst (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id == r2.id */ +"r1 = r0;" +"r2 = r0;" +"r3 = 7;" +"if r1 > r3 goto +0;" +/* force r0 to be precise, this eventually marks r1 and r2 as +* precise as well because of shared IDs +*/ +"r4 = r10;" +"r4 += r3;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} +/* Same as linked_regs_bpf_k, but break one of the * links, note that r1 is absent from regs=... in __msg below. */
@@ -280,6 +346,102 @@ __naked void precision_two_ids(void) : __clobber_all); } +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +/* check thar r0 and r6 have different IDs after 'if', + * collect_linked_regs() can't tie more than 6 registers for a single insn. + */ +__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1") +__msg ("9: (bf) r6 = r6 ; R6_w=scalar(id=2" ) +/* check that r{0-5} are marked precise after 'if' */ +__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:") +__naked void linked_regs_too_many_regs (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r{0-6} IDs */ +"r1 = r0;" +"r2 = r0;" +"r3 = r0;" +"r4 = r0;" +"r5 = r0;" +"r6 = r0;" +/* propagate range for r{0-6} */ +"if r0 > 7 goto +0;" +/* make r6 appear in the log */ +"r6 = r6;" +/* force r0 to be precise, +* this would cause r{0-4} to be precise because of shared IDs +*/ +"r7 = r10;" +"r7 += r0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +SEC("socket") +__failure __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("div by zero") +__naked void linked_regs_broken_link_2 (void ) +{ + asmvolatile ( +"call %[bpf_get_prandom_u32];" +"r7 = r0;" +"r8 = r0;" +"call %[bpf_get_prandom_u32];" +"if r0 > 1 goto +0;" +/* r7.id == r8.id, +* thus r7 precision implies r8 precision, +* which implies r0 precision because of the conditional below. +*/ +"if r8 >= r0 goto 1f;" +/* break id relation between r7 and r8 */ +"r8 += r8;" +/* make r7 precise */ +"if r7 == 0 goto 1f;" +"r0 /= 0;" +"1:" +"r0 = 42;" +"exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* Check that mark_chain_precision() for one of the conditional jump +* operands does not trigger equal scalars precision propagation. +*/ +SEC("socket") +__success __log_level(2) +__msg("3: (25) if r1 > 0x100 goto pc+0") +__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0") +__naked void cjmp_no_linked_regs_trigger (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id */ +"r1 = r0;" +/* the jump below would be predicted, thus r1 would be marked precise, +* this should not imply precision mark for r0 +*/ +"if r1 > 256 goto +0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} +/* Verify that check_ids() is used by regsafe() for scalars. * * r9 = ... some pointer with range X ...
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 346/452 selftests/bpf: Update comments find_equal_scalars->sync_linked_regs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit cfbf25481d6dec0089c99c9d33a2ea634fe8f008 ]
find_equal_scalars() is renamed to sync_linked_regs(), this commit updates existing references in the selftests comments.
--- tools/testing/selftests/bpf/progs/verifier_spill_fill.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/bpf/progs/verifier_spill_fill.c +2 -2
@@ -392,7 +392,7 @@ __naked void spill_32bit_of_64bit_fail(void) *(u32 *)(r10 -8 ) = r1; \/* 32-bit fill r2 from stack. */ \ r2 = *(u32 *)(r10 -8 ); \ -/* Compare r2 with another register to trigger find_equal_scalars.\ +/* Compare r2 with another register to trigger sync_linked_regs.\ * Having one random bit is important here, otherwise the verifier cuts\ * the corners. If the ID was mistakenly preserved on spill, this would\ * cause the verifier to think that r1 is also equal to zero in one of\
@@ -431,7 +431,7 @@ __naked void spill_16bit_of_32bit_fail(void) *(u16 *)(r10 -8 ) = r1; \/* 16-bit fill r2 from stack. */ \ r2 = *(u16 *)(r10 -8 ); \ -/* Compare r2 with another register to trigger find_equal_scalars.\ +/* Compare r2 with another register to trigger sync_linked_regs.\ * Having one random bit is important here, otherwise the verifier cuts\ * the corners. If the ID was mistakenly preserved on spill, this would\ * cause the verifier to think that r1 is also equal to zero in one of\
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 347/452 mm/hugetlb: restore reservation on error in hugetlb folio copy paths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 40c81856e622a9dc59294a90d169ac07ea25b0b0 upstream.
Two sites in mm/hugetlb.c allocate a hugetlb folio via alloc_hugetlb_folio() (consuming a VMA reservation) and then call copy_user_large_folio(), which became int-returning in commit 1cb9dc4b475c ("mm: hwpoison: support recovery from HugePage copy-on-write faults") and can now fail (e.g. -EHWPOISON on a hwpoisoned source page). On the failure path, folio_put() restores the global hugetlb pool count through free_huge_folio(), but the per-VMA reservation map entry is left marked consumed:
- hugetlb_mfill_atomic_pte() resubmission path (UFFDIO_COPY)
- copy_hugetlb_page_range() fork-time CoW path when hugetlb_try_dup_anon_rmap() fails (rare: pinned hugetlb anon folio under fork)
User-visible effect: on UFFDIO_COPY into a private hugetlb VMA where the resubmission copy fails, the reservation for that address is leaked from the VMA's reserve map. A subsequent fault at the same address takes the no-reservation path, and under hugetlb pool pressure the task is SIGBUSed at an address it had previously reserved. The fork-time CoW path leaks the same way in the child VMA's reserve map, though it requires the much rarer combination of pinned hugetlb anon page + hwpoisoned source.
Add the missing restore_reserve_on_error() call before folio_put() on both error paths.
--- mm/hugetlb.c | 2 ++ 1 file changed, 2 insertions(+)
mm/hugetlb.c +2 -0
@@ -5174,6 +5174,7 @@ again: addr, dst_vma);folio_put (pte_folio);if (ret) { +restore_reserve_on_error (h, dst_vma, addr, new_folio);folio_put (new_folio);break ; }
@@ -6383,6 +6384,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_folio_put (*foliop); *foliop =NULL ;if (ret) { +restore_reserve_on_error (h, dst_vma, dst_addr, folio);folio_put (folio); goto out; }
Greg Kroah-Hartman
maintainerPATCH 348/452 mmc: core: Fix host controller programming for fixed driver type
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kamal Dasu <[email protected]>
commit 5a52c5701a67d5176eb1afbf1bdaf7d6dfeec597 upstream.
When using the fixed-emmc-driver-type device tree property, the MMC core correctly selects the driver strength for the card but fails to program the host controller accordingly. This causes a mismatch where the card uses the specified driver type while the host controller defaults to Type B (since ios->drv_type remains zero).
Split the driver type programming logic to handle both fixed and dynamic driver type selection paths. For fixed driver types, program the host controller with the selected drive_strength value. For dynamic selection, use the existing drv_type as before.
This ensures both the eMMC device and host controller use matching driver strengths, preventing potential signal integrity issues.
--- drivers/mmc/core/mmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/core/mmc.c +3 -1
@@ -1354,7 +1354,9 @@ static void mmc_select_driver_type(struc card->drive_strength = drive_strength; -if (drv_type) +if (fixed_drv_type >=0 && drive_strength) +mmc_set_driver_type (card->host, drive_strength); +else if (drv_type)mmc_set_driver_type (card->host, drv_type); }
Greg Kroah-Hartman
maintainerPATCH 349/452 mmc: litex_mmc: Set mandatory idle clocks before CMD0
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Inochi Amaoto <[email protected]>
commit 99982b743e5ba72bd1f5de0e03e3b96ae70b1e51 upstream.
The litex_mmc driver assumes the card is already probed in the BIOS and skip the phy initialization. This will cause the command fail like the following when the old card is unplugged and then insert a new card:
[ 62.923593] litex-mmc f0004000.mmc: Command (cmd 8) error, status -110 [ 62.949717] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 [ 62.976606] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 [ 63.002516] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110 [ 63.028442] litex-mmc f0004000.mmc: Command (cmd 55) error, status -110
Add required clock settings and initialization for the CMD 0, so it can probe the new card.
--- drivers/mmc/host/litex_mmc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/mmc/host/litex_mmc.c +14 -0
@@ -69,6 +69,9 @@#define SD_SLEEP_US 5#define SD_TIMEOUT_US 20000 +#define SD_INIT_DELAY_US 1000 +#define SD_INIT_CLK_HZ 400000 +#define SDIRQ_CARD_DETECT 1#define SDIRQ_SD_TO_MEM_DONE 2#define SDIRQ_MEM_TO_SD_DONE 4
@@ -450,6 +453,17 @@ static void litex_mmc_set_ios(struct mmcstruct litex_mmc_host *host =mmc_priv (mmc);/* +* The SD specification requires at least 74 idle clocks before CMD0. +* These dummy cycles is generated by writing LITEX_PHY_INITIALIZE. +*/ +if (ios->chip_select ==MMC_CS_HIGH ) { +litex_mmc_setclk (host,SD_INIT_CLK_HZ ); +litex_write8 (host->sdphy +LITEX_PHY_INITIALIZE ,1 ); +fsleep (SD_INIT_DELAY_US ); +return ; + } + +/* * NOTE: Ignore any ios->bus_width updates; they occur right after * the mmc core sends its own acmd6 bus-width change notification, * which is redundant since we snoop on the command flow and inject
Greg Kroah-Hartman
maintainerPATCH 350/452 mmc: renesas_sdhi: Add OF entry for RZ/G2H SoC
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lad Prabhakar <[email protected]>
commit f48ee49726ee4ab545fd2dc644f169c0809b19b3 upstream.
The RZ/G2H (R8A774E1) SoC was previously handled via the generic "renesas,rcar-gen3-sdhi" fallback compatible string. However, because the SDHI IP on RZ/G2H is identical with the R-Car H3-N (R8A77951), it requires the specific quirks and configuration defined in of_r8a7795_compatible rather than the generic Gen3 data.
Add the explicit "renesas,sdhi-r8a774e1" match entry to map it correctly. Note that the DT binding file renesas,sdhi.yaml does not need an update as the entry for this SoC is already present.
--- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/renesas_sdhi_internal_dmac.c +1 -0
@@ -277,6 +277,7 @@ static const struct renesas_sdhi_of_datastatic const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible ="renesas,sdhi-r7s9210" , .data = &of_rza2_compatible, }, { .compatible ="renesas,sdhi-mmc-r8a77470" , .data = &of_rcar_gen3_compatible, }, + { .compatible ="renesas,sdhi-r8a774e1" , .data = &of_r8a7795_compatible, }, { .compatible ="renesas,sdhi-r8a7795" , .data = &of_r8a7795_compatible, }, { .compatible ="renesas,sdhi-r8a77961" , .data = &of_r8a77961_compatible, }, { .compatible ="renesas,sdhi-r8a77965" , .data = &of_r8a77965_compatible, },
Greg Kroah-Hartman
maintainerPATCH 351/452 mmc: sdhci: add signal voltage switch in sdhci_resume_host
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jisheng Zhang <[email protected]>
commit f595e8e77a51eee35e331f69321766593a845ef2 upstream.
I met one suspend/resume issue with sdr104 capable sdio wifi card (with "keep-power-in-suspend" set in DT property):
After resuming from suspend to ram, the sdio wifi card stops working. Further debug shows that although ios shows the sdio card is at sdr104 mode, the voltage is still at 3V3. This is due to missing the calling of ->start_signal_voltage_switch() in sdhci_resume_host().
Fix this issue by adding ->start_signal_voltage_switch() in sdhci_resume_host(). This also matches what we do for sdhci_runtime_resume_host().
Then the question is: why this issue hasn't reported and fixed for so long time. IMHO, several reasons: Some host controllers just kick off the runtime resume for system resume, so they benefit from the well supported runtime pm code; Some platforms just use the old sdio wifi card which doesn't need signal voltage switch at all, the default voltage is 3v3 after resuming.
--- drivers/mmc/host/sdhci.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/sdhci.c +1 -0
@@ -3800,6 +3800,7 @@ int sdhci_resume_host(struct sdhci_host host->pwr =0 ; host->clock =0 ; host->reinit_uhs = true; + mmc->ops->start_signal_voltage_switch (mmc, &mmc->ios); mmc->ops->set_ios (mmc, &mmc->ios); }else {sdhci_init (host, (mmc->pm_flags &MMC_PM_KEEP_POWER ));
Greg Kroah-Hartman
maintainerPATCH 352/452 sctp: diag: reject stale associations in dump_one path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Zhang <[email protected]>
commit 5eba3e48d78edd7551b992cb7ba687019b3a78da upstream.
The SCTP exact sock_diag lookup can hold a transport reference, block on lock_sock(sk), and then resume after sctp_association_free() has marked the association dead and freed its bind address list.
When that happens, inet_assoc_attr_size() and inet_diag_msg_sctpasoc_fill() can still dereference association state that is no longer valid for reporting. In particular, inet_diag_msg_sctpasoc_fill() may read an empty bind-address list as a real sctp_sockaddr_entry and trigger an out-of-bounds read from unrelated association memory.
Reject the association after taking the socket lock if it has been reaped or detached from the endpoint, and report the lookup as stale. This keeps the exact dump-one path from formatting torn association state.
--- net/sctp/diag.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
net/sctp/diag.c +9 -8
@@ -266,15 +266,15 @@ static int sctp_sock_dump_one(struct sctlock_sock (sk); - rep =nlmsg_new (inet_assoc_attr_size (sk, assoc),GFP_KERNEL ); -if (!rep) { -release_sock (sk); -return -ENOMEM ; +if (ep != assoc->ep || assoc->base.dead) { + err = -ESTALE ; + goto out_unlock; } -if (ep != assoc->ep) { - err = -EAGAIN ; - goto out; + rep =nlmsg_new (inet_assoc_attr_size (sk, assoc),GFP_KERNEL ); +if (!rep) { + err = -ENOMEM ; + goto out_unlock; } err = inet_sctp_diag_fill(sk, assoc, rep, req, sk_user_ns(NETLINK_CB(skb).sk),
@@ -289,8 +289,9 @@ static int sctp_sock_dump_one(struct sctreturn nlmsg_unicast (sock_net (skb->sk)->diag_nlsk, rep,NETLINK_CB (skb).portid); out: -release_sock (sk);kfree_skb (rep); +out_unlock: +release_sock (sk);return err; }
Greg Kroah-Hartman
maintainerPATCH 353/452 sctp: stream: fully roll back denied add-stream state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
commit a5f8a90ac9f77c678a9781c0a464b635e0d63e49 upstream.
When ADD_OUT_STREAMS is denied, SCTP only shrinks the queued chunks and then lowers outcnt. That leaves removed stream metadata behind, so a later re-add can reuse a stale ext and hit a null-pointer dereference in the scheduler get path.
Fix the rollback by tearing down the removed stream state the same way other stream resizes do. Unschedule the current scheduler state, drop the removed stream ext state with sctp_stream_outq_migrate(), and then reschedule the remaining streams.
This keeps scheduler-private RR/FC/PRIO lists consistent while fully rolling back denied outgoing stream additions.
--- net/sctp/stream.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/sctp/stream.c +5 -1
@@ -1038,6 +1038,7 @@ struct sctp_chunk *sctp_process_strreset stsn, rtsn, GFP_ATOMIC); }else if (req->type ==SCTP_PARAM_RESET_ADD_OUT_STREAMS ) {struct sctp_strreset_addstrm *addstrm; +const struct sctp_sched_ops *sched;__u16 number; addstrm = (struct sctp_strreset_addstrm *)req;
@@ -1048,7 +1049,10 @@ struct sctp_chunk *sctp_process_strresetfor (i = number; i < stream->outcnt; i++)SCTP_SO (stream, i)->state =SCTP_STREAM_OPEN ; }else { -sctp_stream_shrink_out (stream, number); + sched =sctp_sched_ops_from_stream (stream); + sched->unsched_all (stream); +sctp_stream_outq_migrate (stream,NULL , number); + sched->sched_all (stream); stream->outcnt = number; }
Greg Kroah-Hartman
maintainerPATCH 354/452 thunderbolt: Reject zero-length property entries in validator
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit cff8eb65d1eafe7793e54b4d0cf6bf831644630b upstream.
tb_property_entry_valid() accepts entries with length == 0 for DIRECTORY, DATA, and TEXT types. A zero-length TEXT entry passes validation but causes an underflow in the null-termination logic:
property->value.text[property->length * 4 - 1] = '\0';
When property->length is 0 this writes to offset -1 relative to the allocation.
Reject zero-length entries early in the validator since they have no valid representation in the XDomain property protocol.
--- drivers/thunderbolt/property.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/thunderbolt/property.c +2 -0
@@ -59,6 +59,8 @@ static bool tb_property_entry_valid(conscase TB_PROPERTY_TYPE_DIRECTORY :case TB_PROPERTY_TYPE_DATA :case TB_PROPERTY_TYPE_TEXT : +if (!entry->length) +return false;if (entry->length > block_len)return false; if (check_add_overflow(entry->value, entry->length, &end) ||
Greg Kroah-Hartman
maintainerPATCH 355/452 thunderbolt: Bound root directory content to block size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 65423079c7420e3dbf9a7aa345c243a3f5752e5d upstream.
__tb_property_parse_dir() does not check that content_offset + content_len fits within block_len for the root directory case. When rootdir->length equals or exceeds block_len - 2, the entry loop reads past the allocated property block.
Add a bounds check after computing content_offset and content_len to reject directories whose content extends past the block.
--- drivers/thunderbolt/property.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/thunderbolt/property.c +4 -0
@@ -181,6 +181,10 @@ static struct tb_property_dir *__tb_propif (is_root) { content_offset = dir_offset +2 ; content_len = dir_len; +if (content_offset + content_len > block_len) { +tb_property_free_dir (dir); +return NULL ; + } }else {if (dir_len <4 ) {tb_property_free_dir (dir);
Greg Kroah-Hartman
maintainerPATCH 356/452 thunderbolt: Clamp XDomain response data copy to allocation size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 322e93448d908434ae5545660fcbe8f5a7a8e141 upstream.
tb_xdp_properties_request() derives the per-packet copy length from the response header without checking that it fits in the previously allocated data buffer. A malicious peer can set its length field larger than the declared data_length, causing memcpy to write past the kcalloc allocation.
Clamp the per-packet copy length so that the cumulative offset never exceeds data_len.
--- drivers/thunderbolt/xdomain.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/thunderbolt/xdomain.c +2 -0
@@ -393,6 +393,8 @@ static int tb_xdp_properties_request(str } } +if (req.offset + len > data_len) + len = data_len - req.offset;memcpy (data + req.offset, res->data, len *4 ); req.offset += len; }while (!data_len || req.offset < data_len);
Greg Kroah-Hartman
maintainerPATCH 357/452 thunderbolt: Validate XDomain request packet size before type cast
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit a504b9f2797b739e0304d537e8aa4ce883ecce39 upstream.
tb_xdp_handle_request() casts the received packet buffer to protocol-specific structs without verifying that the allocation is large enough for the target type. A peer can send a minimal XDomain packet that passes the generic header length check but is shorter than the struct accessed after the cast, causing out-of- bounds reads from the kmemdup allocation.
Plumb the packet length through xdomain_request_work and validate it against the expected struct size before each cast.
--- drivers/thunderbolt/xdomain.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/thunderbolt/xdomain.c +6 -2
@@ -55,6 +55,7 @@ static const char * const state_names[]struct xdomain_request_work {struct work_struct work;struct tb_xdp_header *pkg; +size_t pkg_len;struct tb *tb; };
@@ -731,6 +732,7 @@ static void tb_xdp_handle_request(structstruct xdomain_request_work *xw =container_of (work,typeof (*xw), work);const struct tb_xdp_header *pkg = xw->pkg;const struct tb_xdomain_header *xhdr = &pkg->xd_hdr; +size_t pkg_len = xw->pkg_len;struct tb *tb = xw->tb;struct tb_ctl *ctl = tb->ctl;struct tb_xdomain *xd;
@@ -762,7 +764,7 @@ static void tb_xdp_handle_request(structswitch (pkg->type) {case PROPERTIES_REQUEST :tb_dbg (tb,"%llx: received XDomain properties request\n" , route); -if (xd) { +if (xd && pkg_len >=sizeof (struct tb_xdp_properties )) { ret =tb_xdp_properties_response (tb, ctl, xd, sequence, (const struct tb_xdp_properties *)pkg); }
@@ -816,7 +818,8 @@ static void tb_xdp_handle_request(structtb_dbg (tb,"%llx: received XDomain link state change request\n" , route); -if (xd && xd->state ==XDOMAIN_STATE_BONDING_UUID_HIGH ) { +if (xd && xd->state ==XDOMAIN_STATE_BONDING_UUID_HIGH && + pkg_len >=sizeof (struct tb_xdp_link_state_change )) {const struct tb_xdp_link_state_change *lsc = (const struct tb_xdp_link_state_change *)pkg;
@@ -868,6 +871,7 @@ tb_xdp_schedule_request(struct tb *tb, ckfree (xw);return false; } + xw->pkg_len = size; xw->tb =tb_domain_get (tb);schedule_work (&xw->work);
Greg Kroah-Hartman
maintainerPATCH 358/452 thunderbolt: Limit XDomain response copy to actual frame size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 4db2bd2ed4785dbadaeeab9f4e346b21ac5fb8eb upstream.
tb_xdomain_copy() copies req->response_size bytes from the received packet buffer regardless of the actual frame size. When a short response arrives, this reads past the valid frame data in the DMA pool buffer into stale contents from previous transactions.
Use the minimum of frame size and expected response size for the copy length.
--- drivers/thunderbolt/xdomain.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/thunderbolt/xdomain.c +3 -1
@@ -123,7 +123,9 @@ static bool tb_xdomain_match(const strucstatic bool tb_xdomain_copy (struct tb_cfg_request *req,const struct ctl_pkg *pkg) { -memcpy (req->response, pkg->buffer, req->response_size); +size_t len =min_t (size_t, pkg->frame.size, req->response_size); + +memcpy (req->response, pkg->buffer, len); req->result.err =0 ;return true; }
Greg Kroah-Hartman
maintainerPATCH 359/452 slimbus: qcom-ngd-ctrl: fix OF node refcount
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit 120134fe75c6b0ae38f14eb8b548ad1e5761f912 upstream.
Platform devices created with platform_device_alloc() call platform_device_release() when the last reference to the device's kobject is dropped. This function calls of_node_put() unconditionally. This works fine for devices created with platform_device_register_full() but users of the split approach (platform_device_alloc() + platform_device_add()) must bump the reference of the of_node they assign manually. Add the missing call to of_node_get().
--- drivers/slimbus/qcom-ngd-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/slimbus/qcom-ngd-ctrl.c +1 -1
@@ -1545,7 +1545,7 @@ static int of_qcom_slim_ngd_register(strof_node_put (node);return ret; } - ngd->pdev->dev.of_node = node; + ngd->pdev->dev.of_node =of_node_get (node); ctrl->ngd = ngd; ret =platform_device_add (ngd->pdev);
Greg Kroah-Hartman
maintainerPATCH 360/452 slimbus: qcom-ngd-ctrl: Avoid ABBA on tx_lock/ctrl->lock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
commit 55f2ea9ff83cc27a85526b14bc9b32f96a08d6ec upstream.
During the SSR/PDR down notification the tx_lock is taken with the intent to provide synchronization with active DMA transfers.
But during this period qcom_slim_ngd_down() is invoked, which ends up in slim_report_absent(), which takes the slim_controller lock. In multiple other codepaths these two locks are taken in the opposite order (i.e. slim_controller then tx_lock).
The result is a lockdep splat, and a possible deadlock:
rprocctl/449 is trying to acquire lock:
ffff00009793e620 (&ctrl->lock){+.+.}-{4:4}, at: slim_report_absent (drivers/slimbus/core.c:322) slimbus
but task is already holding lock:
ffff00009793fb50 (&ctrl->tx_lock){+.+.}-{4:4}, at: qcom_slim_ngd_ssr_pdr_notify (drivers/slimbus/qcom-ngd-ctrl.c:1475) slim_qcom_ngd_ctrl
which lock already depends on the new lock.
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&ctrl->tx_lock);
lock(&ctrl->lock);
lock(&ctrl->tx_lock); lock(&ctrl->lock);
The assumption is that the comment refers to the desire to not call qcom_slim_ngd_exit_dma() while we have an ongoing DMA TX transaction. But any such transaction is initiated and completed within a single qcom_slim_ngd_xfer_msg().
Prior to calling qcom_slim_ngd_exit_dma() the slim_controller is torn down, all child devices are notified that the slimbus is gone and the child devices are removed.
Stop taking the tx_lock in qcom_slim_ngd_ssr_pdr_notify() to avoid the deadlock.
--- drivers/slimbus/qcom-ngd-ctrl.c | 3 --- 1 file changed, 3 deletions(-)
drivers/slimbus/qcom-ngd-ctrl.c +0 -3
@@ -1469,15 +1469,12 @@ static int qcom_slim_ngd_ssr_pdr_notify(switch (action) {case QCOM_SSR_BEFORE_SHUTDOWN :case SERVREG_SERVICE_STATE_DOWN : -/* Make sure the last dma xfer is finished */ -mutex_lock (&ctrl->tx_lock);if (ctrl->state !=QCOM_SLIM_NGD_CTRL_DOWN ) {pm_runtime_get_noresume (ctrl->ctrl.dev); ctrl->state =QCOM_SLIM_NGD_CTRL_DOWN ;qcom_slim_ngd_down (ctrl);qcom_slim_ngd_exit_dma (ctrl); } -mutex_unlock (&ctrl->tx_lock);break ;case QCOM_SSR_AFTER_POWERUP :case SERVREG_SERVICE_STATE_UP :
Greg Kroah-Hartman
maintainerPATCH 361/452 drm/amdkfd: fix NULL dereference in get_queue_ids()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit 2bd550b547deabef98bd3b017ff743b7c34d3a6d upstream.
When usr_queue_id_array is NULL and num_queues is non-zero, get_queue_ids() returns NULL. The callers check only IS_ERR() on the return value; since IS_ERR(NULL) == false the check passes, and suspend_queues() calls q_array_invalidate() which immediately dereferences NULL while iterating num_queues times.
Userspace can trigger this via kfd_ioctl_set_debug_trap() by supplying num_queues > 0 with a zero queue_array_ptr, causing a kernel panic.
A NULL usr_queue_id_array with num_queues == 0 is a legitimate no-op (q_array_invalidate never executes, and resume_queues already guards all queue_ids dereferences behind a NULL check). Return ERR_PTR(-EINVAL) only when num_queues is non-zero and the pointer is absent; both callers already propagate IS_ERR() returns correctly to userspace.
--- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +1 -1
@@ -2787,7 +2787,7 @@ static void copy_context_work_handler (sstatic uint32_t *get_queue_ids (uint32_t num_queues,uint32_t *usr_queue_id_array) {if (!usr_queue_id_array) -return NULL ; +return num_queues ?ERR_PTR (-EINVAL ) :NULL ;if (num_queues >KFD_MAX_NUM_OF_QUEUES_PER_PROCESS )return ERR_PTR (-EINVAL );
Greg Kroah-Hartman
maintainerPATCH 362/452 drm/amdkfd: Fix buffer overflow in SDMA queue checkpoint/restore on GFX11
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Martin <[email protected]>
commit 352ea59028ea48a6fff77f19ae28f98f71946a80 upstream.
The v11 MQD manager incorrectly assigned the CP-compute variants of checkpoint_mqd/restore_mqd for KFD_MQD_TYPE_SDMA queues. These functions use sizeof(struct v11_compute_mqd) (2048 bytes) instead of sizeof(struct v11_sdma_mqd) (512 bytes), causing a 1536-byte overflow.
During CRIU checkpoint of an SDMA queue on Navi3x:
- checkpoint_mqd() reads 2048 bytes from a 512-byte SDMA MQD buffer, leaking 1536 bytes of adjacent GTT memory to userspace
During CRIU restore:
- restore_mqd() writes 2048 bytes into a 512-byte SDMA MQD buffer, corrupting 1536 bytes of adjacent GTT memory (often the ring buffer or neighboring MQDs)
This is a copy-paste regression unique to v11. All other ASIC backends (cik, vi, v9, v10, v12) correctly use the SDMA-specific variants.
Add checkpoint_mqd_sdma() and restore_mqd_sdma() functions that properly handle the smaller v11_sdma_mqd structure, matching the pattern used in other MQD managers.
--- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c | 49 +++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +41 -8
@@ -333,8 +333,7 @@ static void checkpoint_mqd(struct mqd_mastatic void restore_mqd (struct mqd_manager *mm,void **mqd,struct kfd_mem_obj *mqd_mem_obj,uint64_t *gart_addr, -struct queue_properties *qp, -const void *mqd_src, +struct queue_properties *qp,const void *mqd_src,const void *ctl_stack_src,const u32 ctl_stack_size) {uint64_t addr;
@@ -350,14 +349,48 @@ static void restore_mqd(struct mqd_manag *gart_addr = addr; m->cp_hqd_pq_doorbell_control = - qp->doorbell_off << -CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT ; -pr_debug ("cp_hqd_pq_doorbell_control 0x%x\n" , - m->cp_hqd_pq_doorbell_control); + qp->doorbell_off <<CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT ; +pr_debug ("cp_hqd_pq_doorbell_control 0x%x\n" , m->cp_hqd_pq_doorbell_control); qp->is_active =0 ; } +static void checkpoint_mqd_sdma (struct mqd_manager *mm, +void *mqd, +void *mqd_dst, +void *ctl_stack_dst) +{ +struct v11_sdma_mqd *m; + + m =get_sdma_mqd (mqd); + +memcpy (mqd_dst, m,sizeof (struct v11_sdma_mqd )); +} + +static void restore_mqd_sdma (struct mqd_manager *mm,void **mqd, +struct kfd_mem_obj *mqd_mem_obj,uint64_t *gart_addr, +struct queue_properties *qp, +const void *mqd_src, +const void *ctl_stack_src, +const u32 ctl_stack_size) +{ +uint64_t addr; +struct v11_sdma_mqd *m; + + m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr; + addr = mqd_mem_obj->gpu_addr; + +memcpy (m, mqd_src,sizeof (*m)); + + m->sdmax_rlcx_doorbell_offset = + qp->doorbell_off <<SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT ; + + *mqd = m; +if (gart_addr) + *gart_addr = addr; + + qp->is_active =0 ; +} static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
@@ -542,8 +575,8 @@ struct mqd_manager *mqd_manager_init_v11 mqd->update_mqd = update_mqd_sdma; mqd->destroy_mqd = kfd_destroy_mqd_sdma; mqd->is_occupied = kfd_is_occupied_sdma; - mqd->checkpoint_mqd = checkpoint_mqd; - mqd->restore_mqd = restore_mqd; + mqd->checkpoint_mqd = checkpoint_mqd_sdma; + mqd->restore_mqd = restore_mqd_sdma; mqd->mqd_size =sizeof (struct v11_sdma_mqd ); mqd->mqd_stride = kfd_mqd_stride;#if defined(CONFIG_DEBUG_FS )
Greg Kroah-Hartman
maintainerPATCH 363/452 drm/amdgpu: restart the CS if some parts of the VM are still invalidated
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
commit 40396ffdf6120e2380706c59e1a84d7e765a37b6 upstream.
Make sure that we only submit work with full up to date VM page tables.
Backport to 7.1 and older.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +3 -1
@@ -1272,6 +1272,7 @@ static int amdgpu_cs_submit(struct amdgp {struct amdgpu_fpriv *fpriv = p->filp->driver_priv;struct amdgpu_job *leader = p->gang_leader; +struct amdgpu_vm *vm = &fpriv->vm;struct amdgpu_bo_list_entry *e;struct drm_gem_object *gobj;unsigned long index;
@@ -1317,7 +1318,8 @@ static int amdgpu_cs_submit(struct amdgp e->range); e->range =NULL ; } -if (r) { + +if (r || !list_empty (&vm->invalidated)) { r = -EAGAIN ;mutex_unlock (&p->adev->notifier_lock);return r;
Greg Kroah-Hartman
maintainerPATCH 364/452 drm/amd/display: Clamp HDMI HDCP2 rx_id_list read to buffer size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit f0f3981c43b32cadfe373d636d9e9ca522bb3702 upstream.
[Why & How]
During HDCP 2.x repeater authentication over HDMI, the driver reads the sink's RxStatus register and extracts a 10-bit message size field (max value 1023). This value is used as the read length for the ReceiverID list without being clamped to the size of the destination buffer rx_id_list[177]. A malicious HDMI repeater could advertise a message size larger than the buffer, causing an out-of-bounds write during the I2C read.
Clamp the read length in mod_hdcp_read_rx_id_list() to the size of the rx_id_list buffer, matching the approach already used in the DP branch.
--- drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c +2 -1
@@ -533,7 +533,8 @@ enum mod_hdcp_status mod_hdcp_read_rx_id }else { status =read (hdcp,MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST , hdcp->auth.msg.hdcp2.rx_id_list, - hdcp->auth.msg.hdcp2.rx_id_list_size); +MIN (hdcp->auth.msg.hdcp2.rx_id_list_size, +sizeof (hdcp->auth.msg.hdcp2.rx_id_list))); }return status; }
Greg Kroah-Hartman
maintainerPATCH 365/452 drm/amd/display: Clamp VBIOS HDMI retimer register count to array size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit fb0707ce00eef4e2d60c3020e1c0432739703e4a upstream.
[Why & How]
The VBIOS integrated info tables (v1_11 and v2_1) contain HdmiRegNum and Hdmi6GRegNum fields that are used as loop bounds when copying retimer I2C register settings into fixed-size arrays (dp*_ext_hdmi_reg_settings[9] and dp*_ext_hdmi_6g_reg_settings[3]). These u8 fields are not validated before use, so a malformed VBIOS can specify values up to 255, causing an out-of-bounds heap write during driver probe.
Clamp each register count to the destination array size using min_t() before the copy loops, in both get_integrated_info_v11() and get_integrated_info_v2_1().
--- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 48 ++++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-)
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +32 -16
@@ -2516,14 +2516,16 @@ static enum bp_result get_integrated_inf info_v11->extdispconninfo.checksum; info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr; - info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum; + info->dp0_ext_hdmi_reg_num =min_t (u8, info_v11->dp0_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp0_ext_hdmi_reg_settings));for (i =0 ; i < info->dp0_ext_hdmi_reg_num; i++) { info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index = info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val = info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum; + info->dp0_ext_hdmi_6g_reg_num =min_t (u8, info_v11->dp0_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp0_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp0_ext_hdmi_6g_reg_num; i++) { info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2532,14 +2534,16 @@ static enum bp_result get_integrated_inf } info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr; - info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum; + info->dp1_ext_hdmi_reg_num =min_t (u8, info_v11->dp1_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp1_ext_hdmi_reg_settings));for (i =0 ; i < info->dp1_ext_hdmi_reg_num; i++) { info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index = info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val = info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum; + info->dp1_ext_hdmi_6g_reg_num =min_t (u8, info_v11->dp1_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp1_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp1_ext_hdmi_6g_reg_num; i++) { info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2548,14 +2552,16 @@ static enum bp_result get_integrated_inf } info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr; - info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum; + info->dp2_ext_hdmi_reg_num =min_t (u8, info_v11->dp2_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp2_ext_hdmi_reg_settings));for (i =0 ; i < info->dp2_ext_hdmi_reg_num; i++) { info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index = info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val = info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum; + info->dp2_ext_hdmi_6g_reg_num =min_t (u8, info_v11->dp2_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp2_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp2_ext_hdmi_6g_reg_num; i++) { info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2564,14 +2570,16 @@ static enum bp_result get_integrated_inf } info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr; - info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum; + info->dp3_ext_hdmi_reg_num =min_t (u8, info_v11->dp3_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp3_ext_hdmi_reg_settings));for (i =0 ; i < info->dp3_ext_hdmi_reg_num; i++) { info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index = info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val = info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum; + info->dp3_ext_hdmi_6g_reg_num =min_t (u8, info_v11->dp3_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp3_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp3_ext_hdmi_6g_reg_num; i++) { info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2721,14 +2729,16 @@ static enum bp_result get_integrated_inf info->ext_disp_conn_info.checksum = info_v2_1->extdispconninfo.checksum; info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr; - info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum; + info->dp0_ext_hdmi_reg_num =min_t (u8, info_v2_1->dp0_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp0_ext_hdmi_reg_settings));for (i =0 ; i < info->dp0_ext_hdmi_reg_num; i++) { info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index = info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val = info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum; + info->dp0_ext_hdmi_6g_reg_num =min_t (u8, info_v2_1->dp0_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp0_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp0_ext_hdmi_6g_reg_num; i++) { info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2736,14 +2746,16 @@ static enum bp_result get_integrated_inf info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal; } info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr; - info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum; + info->dp1_ext_hdmi_reg_num =min_t (u8, info_v2_1->dp1_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp1_ext_hdmi_reg_settings));for (i =0 ; i < info->dp1_ext_hdmi_reg_num; i++) { info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index = info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val = info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum; + info->dp1_ext_hdmi_6g_reg_num =min_t (u8, info_v2_1->dp1_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp1_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp1_ext_hdmi_6g_reg_num; i++) { info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2751,14 +2763,16 @@ static enum bp_result get_integrated_inf info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal; } info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr; - info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum; + info->dp2_ext_hdmi_reg_num =min_t (u8, info_v2_1->dp2_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp2_ext_hdmi_reg_settings));for (i =0 ; i < info->dp2_ext_hdmi_reg_num; i++) { info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index = info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val = info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum; + info->dp2_ext_hdmi_6g_reg_num =min_t (u8, info_v2_1->dp2_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp2_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp2_ext_hdmi_6g_reg_num; i++) { info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2766,14 +2780,16 @@ static enum bp_result get_integrated_inf info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal; } info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr; - info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum; + info->dp3_ext_hdmi_reg_num =min_t (u8, info_v2_1->dp3_retimer_set.HdmiRegNum, +ARRAY_SIZE (info->dp3_ext_hdmi_reg_settings));for (i =0 ; i < info->dp3_ext_hdmi_reg_num; i++) { info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index = info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex; info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val = info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal; } - info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum; + info->dp3_ext_hdmi_6g_reg_num =min_t (u8, info_v2_1->dp3_retimer_set.Hdmi6GRegNum, +ARRAY_SIZE (info->dp3_ext_hdmi_6g_reg_settings));for (i =0 ; i < info->dp3_ext_hdmi_6g_reg_num; i++) { info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index = info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
Greg Kroah-Hartman
maintainerPATCH 366/452 drm/amd/display: Fix NULL deref and buffer over-read in SDP debugfs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit adf67034b1f61f7119295208085bfd43f85f56af upstream.
[Why & How]dp_sdp_message_debugfs_write() dereferences connector->base.state->crtc without checking for NULL. A connector can be connected but not bound to any CRTC (e.g. after hot-plug before the next atomic commit), causing a kernel crash when writing to the sdp_message debugfs node.
The function also ignores the user-provided size argument and always passes 36 bytes to copy_from_user(), reading past the user buffer when size < 36.
Fix both issues by:
- Returning -ENODEV when connector->base.state or state->crtc is NULL
- Clamping write_size to min(size, sizeof(data))
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +5 -0
@@ -1230,8 +1230,13 @@ static ssize_t dp_sdp_message_debugfs_wrif (size ==0 )return 0 ; +if (!connector->base.state || !connector->base.state->crtc) +return -ENODEV ; + acrtc_state =to_dm_crtc_state (connector->base.state->crtc->state); + write_size =min_t (size_t, size,sizeof (data)); + r =copy_from_user (data, buf, write_size); write_size -= r;
Greg Kroah-Hartman
maintainerPATCH 367/452 drm/amd/display: Use krealloc_array() in dal_vector_reserve()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit da48bc4461b8a5ebfb9264c9b191a701d8e99009 upstream.
[Why & How]dal_vector_reserve() computes the allocation size as "capacity * vector->struct_size" using uint32_t arithmetic, which can silently wrap to a small value on overflow. This would cause krealloc to return a smaller buffer than expected, leading to heap overflows on subsequent vector appends.
Replace krealloc() with krealloc_array() which performs an internal overflow check and returns NULL on wrap, preventing the issue.
--- drivers/gpu/drm/amd/display/dc/basics/vector.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/basics/vector.c +2 -2
@@ -288,8 +288,8 @@ bool dal_vector_reserve(struct vector *vif (capacity <= vector->capacity)return true; - new_container =krealloc (vector->container, - capacity * vector->struct_size,GFP_KERNEL ); + new_container =krealloc_array (vector->container, + capacity, vector->struct_size,GFP_KERNEL );if (new_container) { vector->container = new_container;
Greg Kroah-Hartman
maintainerPATCH 368/452 fs/fcntl: fix SOFTIRQ-unsafe lock order in fasync signaling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
commit 00633c4683828acd5256fa8d5163f440d74bbe71 upstream.
A SOFTIRQ-safe to SOFTIRQ-unsafe lock order deadlock can occur in send_sigio() and send_sigurg() when a process group receives a signal.
When FASYNC is configured for a process group (PIDTYPE_PGID), both functions use read_lock(&tasklist_lock) to traverse the task list. However, they are frequently called from softirq context:
- send_sigio() via input_inject_event -> kill_fasync
- send_sigurg() via tcp_check_urg -> sk_send_sigurg (NET_RX_SOFTIRQ)
The deadlock is caused by the rwlock writer fairness mechanism:
1. CPU 0 (process context) holds read_lock(&tasklist_lock) in do_wait().
2. CPU 1 (process context) attempts write_lock(&tasklist_lock) in fork() or exit() and spins, which blocks all new readers.
3. CPU 0 is interrupted by a softirq (e.g., TCP URG packet reception).
4. The softirq calls send_sigurg() and attempts to acquire read_lock(&tasklist_lock), deadlocking because CPU 1 is waiting.
Since PID hashing and do_each_pid_task() traversals are already RCU-protected, the read_lock on tasklist_lock is no longer strictly required for safe traversal. Fix this by replacing tasklist_lock with rcu_read_lock(), aligning the process group signaling path with the single-PID path. This also mitigates a potential remote denial of service vector via TCP URG packets.
Lockdep splat:
=====================================================
WARNING: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected [...]
Chain exists of: &dev->event_lock --> &f_owner->lock --> tasklist_lock
Possible interrupt unsafe locking scenario:
CPU0 CPU1
---- ----
lock(tasklist_lock);
local_irq_disable();
lock(&dev->event_lock);
lock(&f_owner->lock);
<Interrupt>
lock(&dev->event_lock);*** DEADLOCK ***
--- fs/fcntl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/fcntl.c +4 -4
@@ -783,11 +783,11 @@ void send_sigio(struct fown_struct *fownsend_sigio_to_task (p, fown, fd, band, type);rcu_read_unlock (); }else { -read_lock (&tasklist_lock); +rcu_read_lock (); do_each_pid_task(pid, type, p) {send_sigio_to_task (p, fown, fd, band, type); }while_each_pid_task (pid, type, p); -read_unlock (&tasklist_lock); +rcu_read_unlock (); } out_unlock_fown:read_unlock_irqrestore (&fown->lock, flags);
@@ -824,11 +824,11 @@ int send_sigurg(struct fown_struct *fownsend_sigurg_to_task (p, fown, type);rcu_read_unlock (); }else { -read_lock (&tasklist_lock); +rcu_read_lock (); do_each_pid_task(pid, type, p) {send_sigurg_to_task (p, fown, type); }while_each_pid_task (pid, type, p); -read_unlock (&tasklist_lock); +rcu_read_unlock (); } out_unlock_fown:read_unlock_irqrestore (&fown->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 369/452 driver core: reject devices with unregistered buses
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 36f35b8df6972167102a1c3d4361e0afb6a84534 upstream.
Trying to register a device on a bus which has not yet been registered used to trigger a NULL-pointer dereference, but since the const bus structure rework registration instead succeeds without the device being added to the bus.
This specifically means that the device will never bind to a driver and that the bus sysfs attributes are not created (i.e. as if the device had no bus).
Reject devices with unregistered buses to catch any callers that get the ordering wrong and to handle bus registration failures more gracefully.
--- drivers/base/bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/base/bus.c +9 -2
@@ -503,10 +503,10 @@ static const struct attribute_group driv*/ int bus_add_device (struct device *dev) { -struct subsys_private *sp =bus_to_subsys (dev->bus); +struct subsys_private *sp;int error; -if (!sp) { +if (!dev->bus) {/* * This is a normal operation for many devices that do not * have a bus assigned to them, just say that all went
@@ -515,6 +515,13 @@ int bus_add_device(struct device *dev)return 0 ; } + sp =bus_to_subsys (dev->bus); +if (!sp) { +pr_err ("%s: cannot add device '%s' to unregistered bus '%s'\n" , + __func__,dev_name (dev), dev->bus->name); +return -EINVAL ; + } +/* * Reference in sp is now incremented and will be dropped when * the device is removed from the bus
Greg Kroah-Hartman
maintainerPATCH 370/452 mm/hugetlb: avoid false positive lockdep assertion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes <[email protected]>
[ Upstream commit b4aea43cd37afad714b5684fe9fdfcb0e78dba26 ]
Commit 081056dc00a2 ("mm/hugetlb: unshare page tables during VMA split, not before") changed the locking model around hugetlbfs PMD unsharing on VMA split, but did not update the function which asserts the locks, hugetlb_vma_assert_locked().
This function asserts that either the hugetlb VMA lock is held (if a shared mapping) or that the reservation map lock is held (if private).
If you get an unfortunate race between something which results in one of these locks being released and a hugetlb VMA split and you have CONFIG_LOCKDEP enabled, you can therefore see a false positive assertion arise when there is in fact no issue.
Since this change introduced a new take_locks parameter to hugetlb_unshare_pmds(), which, when set to false, indicates that locking is sufficient, simply pass this to the unsharing logic and predicate the lock assertions on this.
This is safe, as we already asserted the file rmap lock and the VMA write lock prior to this (implying exclusive mmap write lock), so we cannot be raced by either rmap or page fault page table walkers which the asserted locks are intended to protect against (we don't mind GUP-fast).
Separate out huge_pmd_unshare() into __huge_pmd_unshare() to add a check_locks parameter, and update hugetlb_unshare_pmds() to pass this parameter to it.
This leaves all other callers of huge_pmd_unshare() still correctly asserting the locks.
The below reproducer will trigger the assert in a kernel with CONFIG_LOCKDEP enabled by racing process teardown (which will release the hugetlb lock) against a hugetlb split.
void execute_one(void)
{
void *ptr;
pid_t pid;
/*
* Create a hugetlb mapping spanning a PUD entry.
*
* We force the hugetlb page allocation with populate and
* noreserve.
*
* |---------------------|
* | |
* |---------------------|
* 0 PUD boundary
*/
ptr = mmap(0, PUD_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED | MAP_ANON |
MAP_NORESERVE | MAP_HUGETLB | MAP_POPULATE,
-1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
/*
* Fork but with a bogus stack pointer so we try to execute code in
* a non-VM_EXEC VMA, causing segfault + teardown via exit_mmap().
*
* The clone will cause PMD page table sharing between the
* processes first via:
* copy_process() -> ... -> huge_pte_alloc() -> huge_pmd_share()
*
* Then tear down and release the hugetlb 'VMA' lock via:
* exit_mmap() -> ... -> vma_close() -> hugetlb_vma_lock_free()
*/
pid = syscall(__NR_clone, 0, 2 * PMD_SIZE, 0, 0, 0);
if (pid < 0) {
perror("clone");
exit(EXIT_FAILURE);
} if (pid == 0) {
/* Pop stack... */
return;
}
/*
* We are the parent process.
*
* Race the child process's teardown with a PMD unshare.
*
* We do this by triggering:
*
* __split_vma() -> hugetlb_split() -> hugetlb_unshare_pmds()
*
* Which, importantly, doesn't hold the hugetlb VMA lock (nor can
* it), meaning we assert in hugetlb_vma_assert_locked().
*
* .
* |----------.----------|
* | . |
* |----------.----------|
* 0 . PUD boundary
*/
mmap(0, PUD_SIZE / 2, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
}int main(void)
{
int i;
/* Kick off fork children. */
for (i = 0; i < NUM_FORKS; i++) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
/* Fork children do their work and exit. */
if (!pid) {
int j;
for (j = 0; j < NUM_ITERS; j++)
execute_one();
return EXIT_SUCCESS;
}
}
/* If we succeeded, wait on children. */
for (i = 0; i < NUM_FORKS; i++)
wait(NULL);
return EXIT_SUCCESS;
}--- mm/hugetlb.c | 57 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 20 deletions(-)
mm/hugetlb.c +37 -20
@@ -95,6 +95,9 @@ static int hugetlb_acct_memory(struct hstate *h, long delta);static void hugetlb_vma_lock_free (struct vm_area_struct *vma);static void hugetlb_vma_lock_alloc (struct vm_area_struct *vma);static void __hugetlb_vma_unlock_write_free (struct vm_area_struct *vma); +static int __huge_pmd_unshare (struct mmu_gather *tlb, +struct vm_area_struct *vma,unsigned long addr,pte_t *ptep, +bool check_locks);static void hugetlb_unshare_pmds (struct vm_area_struct *vma,unsigned long start,unsigned long end,bool take_locks);static struct resv_map *vma_resv_map (struct vm_area_struct *vma);
@@ -7032,6 +7035,31 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,return pte; } +static int __huge_pmd_unshare (struct mmu_gather *tlb, +struct vm_area_struct *vma,unsigned long addr,pte_t *ptep, +bool check_locks) +{ +unsigned long sz =huge_page_size (hstate_vma (vma)); +struct mm_struct *mm = vma->vm_mm; +pgd_t *pgd =pgd_offset (mm, addr); +p4d_t *p4d =p4d_offset (pgd, addr); +pud_t *pud =pud_offset (p4d, addr); + +if (sz !=PMD_SIZE ) +return 0 ; +if (!ptdesc_pmd_is_shared (virt_to_ptdesc (ptep))) +return 0 ; +i_mmap_assert_write_locked (vma->vm_file->f_mapping); +if (check_locks) +hugetlb_vma_assert_locked (vma); +pud_clear (pud); + +tlb_unshare_pmd_ptdesc (tlb,virt_to_ptdesc (ptep), addr); + +mm_dec_nr_pmds (mm); +return 1 ; +} +/** * huge_pmd_unshare - Unmap a pmd table if it is shared by multiple users * @tlb: the current mmu_gather.
@@ -7051,25 +7079,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,int huge_pmd_unshare (struct mmu_gather *tlb,struct vm_area_struct *vma,unsigned long addr,pte_t *ptep) { -unsigned long sz =huge_page_size (hstate_vma (vma)); -struct mm_struct *mm = vma->vm_mm; -pgd_t *pgd =pgd_offset (mm, addr); -p4d_t *p4d =p4d_offset (pgd, addr); -pud_t *pud =pud_offset (p4d, addr); - -i_mmap_assert_write_locked (vma->vm_file->f_mapping); -hugetlb_vma_assert_locked (vma); -if (sz !=PMD_SIZE ) -return 0 ; -if (!ptdesc_pmd_is_shared (virt_to_ptdesc (ptep))) -return 0 ; - -pud_clear (pud); - -tlb_unshare_pmd_ptdesc (tlb,virt_to_ptdesc (ptep), addr); - -mm_dec_nr_pmds (mm); -return 1 ; +return __huge_pmd_unshare (tlb, vma, addr, ptep,/*check_locks=*/ true); }/*
@@ -7103,6 +7113,13 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,return NULL ; } +static int __huge_pmd_unshare (struct mmu_gather *tlb, +struct vm_area_struct *vma,unsigned long addr,pte_t *ptep, +bool check_locks) +{ +return 0 ; +} +int huge_pmd_unshare (struct mmu_gather *tlb,struct vm_area_struct *vma,unsigned long addr,pte_t *ptep) {
@@ -7377,7 +7394,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,if (!ptep)continue ; ptl =huge_pte_lock (h, mm, ptep); -huge_pmd_unshare (&tlb, vma, address, ptep); +__huge_pmd_unshare (&tlb, vma, address, ptep, take_locks);spin_unlock (ptl); }huge_pmd_unshare_flush (&tlb, vma);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 371/452 soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit d922113ef91e6e7e8065e9070f349365341ba32e ]
The current platform driver design causes probe ordering races with consumers (UFS, eMMC) due to ICE's dependency on SCM firmware calls. If ICE probe fails (missing ICE SCM or DT registers), devm_of_qcom_ice_get() loops with -EPROBE_DEFER, leaving consumers non-functional even when ICE should be gracefully disabled. devm_of_qcom_ice_get() doesn't know if the ICE driver probe has failed due to above reasons or it is waiting for the SCM driver.
Moreover, there is no devlink dependency between ICE and consumer drivers as 'qcom,ice' is not considered as a DT 'supplier'. So the consumer drivers have no idea of when the ICE driver is going to probe.
To address these issues, store the error pointer in a global xarray with ice node phandle as a key during probe in addition to the valid ice pointer and synchronize both qcom_ice_probe() and of_qcom_ice_get() using a mutex.
If the xarray entry is NULL, then it implies that the driver is not probed yet, so return -EPROBE_DEFER. If it has any error pointer, return that error pointer directly. Otherwise, add the devlink as usual and return the valid pointer to the consumer.
Xarray is used instead of platform drvdata, since driver core frees the drvdata during probe failure. So it cannot be used to pass the error pointer to the consumers.
Note that this change only fixes the standalone ICE DT node bindings and not the ones with 'ice' range embedded in the consumer nodes, where there is no issue.
--- drivers/soc/qcom/ice.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-)
drivers/soc/qcom/ice.c +29 -7
@@ -15,6 +15,7 @@#include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/xarray.h> #include <linux/firmware/qcom/qcom_scm.h>
@@ -49,6 +50,9 @@ struct qcom_ice {struct clk *core_clk; }; +static DEFINE_XARRAY (ice_handles); +static DEFINE_MUTEX (ice_mutex); +static bool qcom_ice_check_supported (struct qcom_ice *ice) {u32 regval =qcom_ice_readl (ice,QCOM_ICE_REG_VERSION );
@@ -288,6 +292,8 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev)return qcom_ice_create (&pdev->dev, base); } +guard (mutex)(&ice_mutex); +/* * If the consumer node does not provider an 'ice' reg range * (legacy DT binding), then it must at least provide a phandle
@@ -304,12 +310,11 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) goto out; } - ice =platform_get_drvdata (pdev); -if (!ice) { -dev_err (dev,"Cannot get ice instance from %s\n" , -dev_name (&pdev->dev)); + ice =xa_load (&ice_handles, pdev->dev.of_node->phandle); +if (IS_ERR_OR_NULL (ice)) {platform_device_put (pdev); - ice =ERR_PTR (-EPROBE_DEFER ); +if (!ice) + ice =ERR_PTR (-EPROBE_DEFER ); goto out; }
@@ -378,24 +383,40 @@ EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);static int qcom_ice_probe (struct platform_device *pdev) { +unsigned long phandle = pdev->dev.of_node->phandle;struct qcom_ice *engine;void __iomem *base; +guard (mutex)(&ice_mutex); + base =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (base)) {dev_warn (&pdev->dev,"ICE registers not found\n" ); +/* Store the error pointer for devm_of_qcom_ice_get() */ +xa_store (&ice_handles, phandle, (__force void *)base,GFP_KERNEL );return PTR_ERR (base); } engine =qcom_ice_create (&pdev->dev, base); -if (IS_ERR (engine)) +if (IS_ERR (engine)) { +/* Store the error pointer for devm_of_qcom_ice_get() */ +xa_store (&ice_handles, phandle, engine,GFP_KERNEL );return PTR_ERR (engine); + } -platform_set_drvdata (pdev, engine); +xa_store (&ice_handles, phandle, engine,GFP_KERNEL );return 0 ; } +static void qcom_ice_remove (struct platform_device *pdev) +{ +unsigned long phandle = pdev->dev.of_node->phandle; + +guard (mutex)(&ice_mutex); +xa_store (&ice_handles, phandle,NULL ,GFP_KERNEL ); +} +static const struct of_device_id qcom_ice_of_match_table[] = { { .compatible ="qcom,inline-crypto-engine" }, { },
@@ -404,6 +425,7 @@ MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);static struct platform_driver qcom_ice_driver = { .probe = qcom_ice_probe, + .remove_new = qcom_ice_remove, .driver = { .name ="qcom-ice" , .of_match_table = qcom_ice_of_match_table,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 372/452 mm/huge_memory: update file PMD counter before folio_put()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yin Tirui <[email protected]>
[ Upstream commit 8d878059924f12c1bc24556a92ec56add74de3c8 ]
__split_huge_pmd_locked() updates the file/shmem RSS counter after dropping the PMD mapping's folio reference. If folio_put() drops the last reference, mm_counter_file() can later read freed folio state via folio_test_swapbacked().
Move the counter update before folio_put().
--- mm/huge_memory.c | 2 ++ 1 file changed, 2 insertions(+)
mm/huge_memory.c +2 -0
@@ -2095,7 +2095,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,if (!PageReferenced (page) &&pmd_young (old_pmd))SetPageReferenced (page);page_remove_rmap (page, vma, true); +add_mm_counter (mm,mm_counter_file (page), -HPAGE_PMD_NR );put_page (page); +return ; }add_mm_counter (mm,mm_counter_file (page), -HPAGE_PMD_NR );return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 373/452 ipmi:ssif: Remove unnecessary indention
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit 91eb7ec7261254b6875909df767185838598e21e upstream.
A section was in {} that didn't need to be, move the variable definition to the top and set th eindentino properly.
--- drivers/char/ipmi/ipmi_ssif.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-)
drivers/char/ipmi/ipmi_ssif.c +12 -16
@@ -1667,6 +1667,7 @@ static int ssif_probe(struct i2c_clientint len =0 ;int i;u8 slave_addr =0 ; +unsigned int thread_num;struct ssif_addr_info *addr_info =NULL ;mutex_lock (&ssif_infos_mutex);
@@ -1875,22 +1876,17 @@ static int ssif_probe(struct i2c_client ssif_info->handlers.request_events = request_events; ssif_info->handlers.set_need_watch = ssif_set_need_watch; - { -unsigned int thread_num; - - thread_num = ((i2c_adapter_id (ssif_info->client->adapter) - <<8 ) | - ssif_info->client->addr); -init_completion (&ssif_info->wake_thread); - ssif_info->thread =kthread_run (ipmi_ssif_thread, ssif_info, -"kssif%4.4x" , thread_num); -if (IS_ERR (ssif_info->thread)) { - rv =PTR_ERR (ssif_info->thread); -dev_notice (&ssif_info->client->dev, -"Could not start kernel thread: error %d\n" , - rv); - goto out; - } + thread_num = ((i2c_adapter_id (ssif_info->client->adapter) <<8 ) | + ssif_info->client->addr); +init_completion (&ssif_info->wake_thread); + ssif_info->thread =kthread_run (ipmi_ssif_thread, ssif_info, +"kssif%4.4x" , thread_num); +if (IS_ERR (ssif_info->thread)) { + rv =PTR_ERR (ssif_info->thread); +dev_notice (&ssif_info->client->dev, +"Could not start kernel thread: error %d\n" , + rv); + goto out; }dev_set_drvdata (&ssif_info->client->dev, ssif_info);
Greg Kroah-Hartman
maintainerPATCH 374/452 ipmi:ssif: NULL thread on error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit a8aebe93a4938c0ca1941eeaae821738f869be3d upstream.
Cleanup code was checking the thread for NULL, but it was possibly a PTR_ERR() in one spot.
Spotted with static analysis.
--- drivers/char/ipmi/ipmi_ssif.c | 1 + 1 file changed, 1 insertion(+)
drivers/char/ipmi/ipmi_ssif.c +1 -0
@@ -1883,6 +1883,7 @@ static int ssif_probe(struct i2c_client "kssif%4.4x", thread_num);if (IS_ERR (ssif_info->thread)) { rv =PTR_ERR (ssif_info->thread); + ssif_info->thread =NULL ;dev_notice (&ssif_info->client->dev,"Could not start kernel thread: error %d\n" , rv);
Greg Kroah-Hartman
maintainerPATCH 375/452 fbdev/vt8500lcdfb: Initialize fb_ops with fbdev macros
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 63a11adaceb8b77d70bcce0890197fa9462ce160 upstream.
Initialize the instance of struct fb_ops with fbdev initializer macros for framebuffers in DMA-able virtual address space. Set the read/write, draw and mmap callbacks to the correct implementation and avoid implicit defaults. Also select the necessary helpers in Kconfig.
Fbdev drivers sometimes rely on the callbacks being NULL for a default I/O-memory-based implementation to be invoked; hence requiring the I/O helpers to be built in any case. Setting all callbacks in all drivers explicitly will allow to make the I/O helpers optional. This benefits systems that do not use these functions.
--- drivers/video/fbdev/Kconfig | 1 + drivers/video/fbdev/vt8500lcdfb.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/video/fbdev/Kconfig +1 -0
@@ -1464,6 +1464,7 @@ config FB_VT8500 select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS select FB_MODE_HELPERS select VIDEOMODE_HELPERS help
drivers/video/fbdev/vt8500lcdfb.c +3 -1
@@ -241,6 +241,7 @@ static int vt8500lcd_blank(int blank, ststatic const struct fb_ops vt8500lcd_ops = { .owner =THIS_MODULE , + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_set_par = vt8500lcd_set_par, .fb_setcolreg = vt8500lcd_setcolreg, .fb_fillrect = wmt_ge_fillrect,
@@ -250,6 +251,7 @@ static const struct fb_ops vt8500lcd_ops .fb_ioctl = vt8500lcd_ioctl, .fb_pan_display = vt8500lcd_pan_display, .fb_blank = vt8500lcd_blank, +// .fb_mmap needs DMA mmap };static irqreturn_t vt8500lcd_handle_irq (int irq,void *dev_id)
@@ -357,7 +359,7 @@ static int vt8500lcd_probe(struct platfo fbi->fb.fix.smem_start = fb_mem_phys; fbi->fb.fix.smem_len = fb_mem_len; - fbi->fb.screen_base = fb_mem_virt; + fbi->fb.screen_buffer = fb_mem_virt; fbi->palette_size =PAGE_ALIGN (512 ); fbi->palette_cpu = dma_alloc_coherent(&pdev->dev,
Greg Kroah-Hartman
maintainerPATCH 376/452 ksmbd: fix OOB write in QUERY_INFO for compound requests
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit fda9522ed6afaec45cabc198d8492270c394c7bc upstream.
When a compound request such as READ + QUERY_INFO(Security) is received, and the first command (READ) consumes most of the response buffer, ksmbd could write beyond the allocated buffer while building a security descriptor.
The root cause was that smb2_get_info_sec() checked buffer space using ppntsd_size from xattr, while build_sec_desc() often synthesized a significantly larger descriptor from POSIX ACLs.
This patch introduces smb_acl_sec_desc_scratch_len() to accurately compute the final descriptor size beforehand, performs proper buffer checking with smb2_calc_max_out_buf_len(), and uses exact-sized allocation + iov pinning.
[ In v6.6, replace KSMBD_DEFAULT_GFP with GFP_KERNEL per commit 0066f623bce8 ("ksmbd: use __GFP_RETRY_MAYFAIL"). ]
--- fs/smb/server/smb2pdu.c | 121 +++++++++++++++++++++++++++++++++++------------- fs/smb/server/smbacl.c | 43 +++++++++++++++++ fs/smb/server/smbacl.h | 2 3 files changed, 134 insertions(+), 32 deletions(-)
fs/smb/server/smb2pdu.c +89 -32
@@ -3385,20 +3385,24 @@ int smb2_open(struct ksmbd_work *work) KSMBD_SHARE_FLAG_ACL_XATTR)) {struct smb_fattr fattr;struct smb_ntsd *pntsd; -int pntsd_size, ace_num =0 ; +int pntsd_size; +size_t scratch_len;ksmbd_acls_fattr (&fattr, idmap, inode); -if (fattr.cf_acls) - ace_num = fattr.cf_acls->a_count; -if (fattr.cf_dacls) - ace_num += fattr.cf_dacls->a_count; - - pntsd =kmalloc (sizeof (struct smb_ntsd ) + -sizeof (struct smb_sid ) *3 + -sizeof (struct smb_acl ) + -sizeof (struct smb_ace ) * ace_num *2 , -GFP_KERNEL ); + scratch_len =smb_acl_sec_desc_scratch_len (&fattr, +NULL ,0 , +OWNER_SECINFO |GROUP_SECINFO | +DACL_SECINFO ); +if (!scratch_len || scratch_len ==SIZE_MAX ) { + rc = -EFBIG ; +posix_acl_release (fattr.cf_acls); +posix_acl_release (fattr.cf_dacls); + goto err_out; + } + + pntsd =kvzalloc (scratch_len,GFP_KERNEL );if (!pntsd) { + rc = -ENOMEM ;posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls); goto err_out;
@@ -3413,7 +3417,7 @@ int smb2_open(struct ksmbd_work *work)posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls);if (rc) { -kfree (pntsd); +kvfree (pntsd); goto err_out; }
@@ -3423,7 +3427,7 @@ int smb2_open(struct ksmbd_work *work) pntsd, pntsd_size, false); -kfree (pntsd); +kvfree (pntsd);if (rc)pr_err ("failed to store ntacl in xattr : %d\n" , rc);
@@ -5345,8 +5349,9 @@ static int smb2_get_info_file(struct ksmif (test_share_config_flag (work->tcon->share_conf,KSMBD_SHARE_FLAG_PIPE )) {/* smb2 info file called for pipe */ -return smb2_get_info_file_pipe (work->sess, req, rsp, + rc =smb2_get_info_file_pipe (work->sess, req, rsp, work->response_buf); + goto iov_pin_out; }if (work->next_smb2_rcv_hdr_off) {
@@ -5446,6 +5451,12 @@ static int smb2_get_info_file(struct ksm rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), rsp, work->response_buf);ksmbd_fd_put (work, fp); + +iov_pin_out: +if (!rc) + rc =ksmbd_iov_pin_rsp (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer) + +le32_to_cpu (rsp->OutputBufferLength));return rc; }
@@ -5665,6 +5676,11 @@ static int smb2_get_info_filesystem(stru rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), rsp, work->response_buf);path_put (&path); + +if (!rc) + rc =ksmbd_iov_pin_rsp (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer) + +le32_to_cpu (rsp->OutputBufferLength));return rc; }
@@ -5674,13 +5690,14 @@ static int smb2_get_info_sec(struct ksmb {struct ksmbd_file *fp;struct mnt_idmap *idmap; -struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd =NULL ; +struct smb_ntsd *pntsd =NULL , *ppntsd =NULL ;struct smb_fattr fattr = {{0 }};struct inode *inode;__u32 secdesclen =0 ;unsigned int id =KSMBD_NO_FID , pid =KSMBD_NO_FID ;int addition_info =le32_to_cpu (req->AdditionalInformation); -int rc =0 , ppntsd_size =0 ; +int rc =0 , ppntsd_size =0 , max_len; +size_t scratch_len =0 ; if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | PROTECTED_DACL_SECINFO |
@@ -5688,6 +5705,11 @@ static int smb2_get_info_sec(struct ksmbksmbd_debug (SMB ,"Unsupported addition info: 0x%x)\n" , addition_info); + pntsd =kzalloc (ALIGN (sizeof (struct smb_ntsd ),8 ), +GFP_KERNEL ); +if (!pntsd) +return -ENOMEM ; + pntsd->revision =cpu_to_le16 (1 ); pntsd->type =cpu_to_le16 (SELF_RELATIVE |DACL_PROTECTED ); pntsd->osidoffset =0 ;
@@ -5696,9 +5718,7 @@ static int smb2_get_info_sec(struct ksmb pntsd->dacloffset =0 ; secdesclen =sizeof (struct smb_ntsd ); - rsp->OutputBufferLength =cpu_to_le32 (secdesclen); - -return 0 ; + goto iov_pin; }if (work->next_smb2_rcv_hdr_off) {
@@ -5730,18 +5750,58 @@ static int smb2_get_info_sec(struct ksmb &ppntsd);/* Check if sd buffer size exceeds response buffer size */ -if (smb2_resp_buf_len (work,8 ) > ppntsd_size) - rc =build_sec_desc (idmap, pntsd, ppntsd, ppntsd_size, - addition_info, &secdesclen, &fattr); + max_len =smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_info_rsp , Buffer), +le32_to_cpu (req->OutputBufferLength)); +if (max_len <0 ) { + rc = -EINVAL ; + goto release_acl; + } + + scratch_len =smb_acl_sec_desc_scratch_len (&fattr, ppntsd, + ppntsd_size, addition_info); +if (!scratch_len || scratch_len ==SIZE_MAX ) { + rc = -EFBIG ; + goto release_acl; + } + + pntsd =kvzalloc (scratch_len,GFP_KERNEL ); +if (!pntsd) { + rc = -ENOMEM ; + goto release_acl; + } + + rc =build_sec_desc (idmap, pntsd, ppntsd, ppntsd_size, + addition_info, &secdesclen, &fattr); + +release_acl:posix_acl_release (fattr.cf_acls);posix_acl_release (fattr.cf_dacls);kfree (ppntsd);ksmbd_fd_put (work, fp); + +if (!rc &&ALIGN (secdesclen,8 ) > scratch_len) + rc = -EFBIG ;if (rc) -return rc; + goto err_out; +iov_pin: rsp->OutputBufferLength =cpu_to_le32 (secdesclen); -return 0 ; + rc =buffer_check_err (le32_to_cpu (req->OutputBufferLength), + rsp, work->response_buf); +if (rc) + goto err_out; + + rc =ksmbd_iov_pin_rsp_read (work, (void *)rsp, + offsetof(struct smb2_query_info_rsp , Buffer), + pntsd, secdesclen); +err_out: +if (rc) { + rsp->OutputBufferLength =0 ; +kvfree (pntsd); + } + +return rc; }/**
@@ -5765,6 +5825,9 @@ int smb2_query_info(struct ksmbd_work *w goto err_out; } + rsp->StructureSize =cpu_to_le16 (9 ); + rsp->OutputBufferOffset =cpu_to_le16 (72 ); +switch (req->InfoType) {case SMB2_O_INFO_FILE :ksmbd_debug (SMB ,"GOT SMB2_O_INFO_FILE\n" );
@@ -5785,14 +5848,6 @@ int smb2_query_info(struct ksmbd_work *w }ksmbd_revert_fsids (work); -if (!rc) { - rsp->StructureSize =cpu_to_le16 (9 ); - rsp->OutputBufferOffset =cpu_to_le16 (72 ); - rc =ksmbd_iov_pin_rsp (work, (void *)rsp, - offsetof(struct smb2_query_info_rsp , Buffer) + -le32_to_cpu (rsp->OutputBufferLength)); - } - err_out:if (rc <0 ) {if (rc == -EACCES )
@@ -5803,6 +5858,8 @@ err_out: rsp->hdr.Status =STATUS_UNEXPECTED_IO_ERROR ; else if (rc == -ENOMEM) rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; + else if (rc == -EINVAL && rsp->hdr.Status == 0) + rsp->hdr.Status =STATUS_INVALID_PARAMETER ; else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) rsp->hdr.Status =STATUS_INVALID_INFO_CLASS ;smb2_set_err_rsp (work);
fs/smb/server/smbacl.c +43 -0
49 lines not on this page · raw message
fs/smb/server/smbacl.h +2 -0
@@ -101,6 +101,8 @@ int set_info_sec(struct ksmbd_conn *conn bool type_check, bool get_write);void id_to_sid (unsigned int cid,uint sidtype,struct smb_sid *ssid);void ksmbd_init_domain (u32 *sub_auth); +size_t smb_acl_sec_desc_scratch_len (struct smb_fattr *fattr, +struct smb_ntsd *ppntsd,int ppntsd_size,int addition_info);static inline uid_t posix_acl_uid_translate (struct mnt_idmap *idmap,struct posix_acl_entry *pace)