6.12.105-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 137/220 eventpoll: pin files while checking reverse paths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guidong Han <[email protected]>
[ Upstream commit 8b7e8245e2293078f657521236ac92c045552e5a ]
Commit 319c15174757 ("epoll: take epitem list out of struct file") intentionally removed temporary file references from the reverse path check list. At the time, both epitems and their files were freed after an RCU grace period, so unlist_file() could obtain file->f_lock through an epitem while clear_tfile_check_list() held rcu_read_lock().
Commit 0ede61d8589c ("file: convert to SLAB_TYPESAFE_BY_RCU") made struct file SLAB_TYPESAFE_BY_RCU and removed its RCU-delayed freeing. RCU still protects the epitem, but no longer keeps the referenced file from being freed and reused. A concurrent close can therefore make unlist_file() lock or unlock f_lock in a recycled file object.
This violates the documented SLAB_TYPESAFE_BY_RCU rule requiring a reference before acquiring an object's lock. The race was reproduced, causing a wild unlock of f_lock in a recycled file and breaking its mutual exclusion.
Add ->file to epitems_head to remember the pinned file independently of ->epitems. A concurrent EPOLL_CTL_DEL can empty ->epitems before the head is unlisted, leaving no epi->ffd.file from which to drop the reference.
In list_file(), acquire the reference before adding the head to the check list. The caller either owns a reference or holds the ep->mtx for the epitem leading to the file. In the latter case, file_ref_get() can fail after the last reference is dropped, but eventpoll_release_file() must acquire the same mutex before the file can be freed. The dying leaf can be skipped because removing links cannot increase the reverse path count.
In unlist_file(), epnested_mutex excludes another list_file() or unlist_file(), while head->next prevents a concurrent EPOLL_CTL_DEL from freeing the head. Save head->file locally, clear it with head->next under f_lock, and drop the reference after the RCU-protected operation.
Christian Brauner <[email protected]> quotes:
Quoted 57 lines
SLAB_TYPESAFE_BY_RCUallows a slab slot to be reused while an RCU reader still holds its old address. Once that address contains a new live struct file, KASAN sees valid, unpoisoned memory and cannot distinguish the stale object identity.CONFIG_DEBUG_SPINLOCKexposes the failure instead.The failing interleaving is:
CPU0: nested
EPOLL_CTL_ADDCPU1: close/open churn
------------------------------------ ---------------------------------
p =hlist_first_rcu(&head->epitems)
epi =container_of(p, ...)close(victim) __fput() eventpoll_release_file() file_free(victim) // the slot is free; f_lock remains
spin_lock(&epi->ffd.file->f_lock)
open()reuses the slot asnew_file
spin_lock_init(&new_file->f_lock)spin_unlock(&epi->ffd.file->f_lock)// wild unlock of new_file's lock
CONFIG_DEBUG_SPINLOCKreports:BUG: spinlock already unlocked on CPU#0, poc_unlist/150 lock: 0xffff8880067fb200, .magic: dead4ead, .owner: <none>/-1, .owner_cpu: -1 CPU: 0 UID: 1000 PID: 150 Comm: poc_unlist Not tainted 7.2.0-rc3-dirty #22 PREEMPTLAZY Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x64/0x80 do_raw_spin_unlock+0x75/0xb0 _raw_spin_unlock+0xe/0x30 clear_tfile_check_list+0x88/0xe0 do_epoll_ctl_file+0x519/0xcf0 ? __pfx_ep_ptable_queue_proc+0x10/0x10 do_epoll_ctl+0x8f/0x100 __x64_sys_epoll_ctl+0x6f/0xa0 do_syscall_64+0xdc/0x520 ? srso_alias_return_thunk+0x5/0xfbef5 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x42034e Code: 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 e9 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007a657ff3c198 EFLAGS: 00000202 ORIG_RAX: 00000000000000e9 RAX: ffffffffffffffda RBX: 00007a657ff3ccdc RCX: 000000000042034e RDX: 0000000000000003 RSI: 0000000000000001 RDI: 0000000000000004 RBP: 00007a657ff3c2f0 R08: 0000000000000000 R09: 00007a657ff3c6c0 R10: 00007a657ff3c1a4 R11: 0000000000000202 R12: 00007a657ff3c6c0 R13: ffffffffffffffb8 R14: 000000000000000d R15: 00007fffb7de0210 </TASK> ------------[ cut here ]------------
unlist_file()does not appear as a separate frame because it was inlined intoclear_tfile_check_list(). This report was obtained withmdelay()instrumentation immediately beforespin_lock()andspin_unlock()inunlist_file()to widen the two race windows.
Quoted 5 lines
More importantly, this is a wild unlock. The stale unlock can target
f_lockof a different live file and invalidate mutual exclusion for state protected by that lock. Turning this into a reliable exploit would require precise scheduling and same-slot reuse and is likely difficult, but the primitive is potentially exploitable.
--- fs/eventpoll.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
fs/eventpoll.c +16 -1
@@ -404,11 +404,13 @@ static struct kmem_cache *pwq_cache __ro/* * List of files with newly added links, where we may need to limit the number -* of emanating paths. Protected by the epnested_mutex. +* of emanating paths. Protected by the epnested_mutex. The ->file field holds +* a reference to the associated file while the head is on the list. */ struct epitems_head {struct hlist_head epitems;struct epitems_head *next; +struct file *file; };static struct epitems_head *tfile_check_list =EP_UNACTIVE_PTR ;
@@ -426,6 +428,16 @@ static void list_file(struct file *file) head = container_of(file->f_ep, struct epitems_head, epitems);if (!head->next) { +/* +* The caller owns a reference to @file or holds the ep->mtx for the +* epitem that led here. The latter blocks eventpoll_release_file() +* before the file allocation can be freed and reused. A dying leaf +* can be skipped since removing links cannot increase the reverse +* path count. +*/ +if (!atomic_long_inc_not_zero (&file->f_count)) +return ; + head->file = file; head->next = tfile_check_list; tfile_check_list = head; }
@@ -435,15 +447,18 @@ static void unlist_file(struct epitems_h {struct epitems_head *to_free = head;struct hlist_node *p =rcu_dereference (hlist_first_rcu (&head->epitems)); +struct file *file = head->file;if (p) { struct epitem *epi= container_of(p, struct epitem, fllink);spin_lock (&epi->ffd.file->f_lock);if (!hlist_empty (&head->epitems)) to_free =NULL ; head->next =NULL ; + head->file =NULL ;spin_unlock (&epi->ffd.file->f_lock); }free_ephead (to_free); +fput (file); }#ifdef CONFIG_SYSCTL
Greg Kroah-Hartman
maintainerPATCH 138/220 tcp: Pass flags to __tcp_send_ack
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit 9866884ce8ef25338c5b33cbb97c2b5d92088528 ]
Accurate ECN needs to send custom flags to handle IP-ECN field reflection during handshake.
Stable-dep-of: a28c4fcbf774 ("tcp: challenge ACK for non-exact RST in SYN-RECEIVED")
--- include/net/tcp.h | 2 +- net/ipv4/bpf_tcp_ca.c | 2 +- net/ipv4/tcp_dctcp.h | 2 +- net/ipv4/tcp_output.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-)
include/net/tcp.h +1 -1
@@ -668,7 +668,7 @@ void tcp_send_active_reset(struct sock * enum sk_rst_reason reason);int tcp_send_synack (struct sock *);void tcp_push_one (struct sock *,unsigned int mss_now); -void __tcp_send_ack (struct sock *sk,u32 rcv_nxt); +void __tcp_send_ack (struct sock *sk,u32 rcv_nxt,u16 flags);void tcp_send_ack (struct sock *sk);void tcp_send_delayed_ack (struct sock *sk);void tcp_send_loss_probe (struct sock *sk);
net/ipv4/bpf_tcp_ca.c +1 -1
@@ -121,7 +121,7 @@ static int bpf_tcp_ca_btf_struct_access( BPF_CALL_2(bpf_tcp_send_ack, struct tcp_sock *, tp, u32, rcv_nxt) {/* bpf_tcp_ca prog cannot have NULL tp */ -__tcp_send_ack ((struct sock *)tp, rcv_nxt); +__tcp_send_ack ((struct sock *)tp, rcv_nxt,0 );return 0 ; }
net/ipv4/tcp_dctcp.h +1 -1
@@ -28,7 +28,7 @@ static inline void dctcp_ece_ack_update(*/ if (inet_csk (sk)->icsk_ack.pending &ICSK_ACK_TIMER ) {dctcp_ece_ack_cwr (sk, *ce_state); -__tcp_send_ack (sk, *prior_rcv_nxt); +__tcp_send_ack (sk, *prior_rcv_nxt,0 ); }inet_csk (sk)->icsk_ack.pending |=ICSK_ACK_NOW ; }
net/ipv4/tcp_output.c +3 -3
@@ -4250,7 +4250,7 @@ void tcp_send_delayed_ack(struct sock *s }/* This routine sends an ack and also updates the window. */ -void __tcp_send_ack (struct sock *sk,u32 rcv_nxt) +void __tcp_send_ack (struct sock *sk,u32 rcv_nxt,u16 flags) {struct sk_buff *buff;
@@ -4279,7 +4279,7 @@ void __tcp_send_ack(struct sock *sk, u32/* Reserve space for headers and prepare control bits. */ skb_reserve (buff,MAX_TCP_HEADER ); -tcp_init_nondata_skb (buff,tcp_acceptable_seq (sk),TCPHDR_ACK ); +tcp_init_nondata_skb (buff,tcp_acceptable_seq (sk),TCPHDR_ACK | flags);/* We do not want pure acks influencing TCP Small Queues or fq/pacing * too much.
@@ -4294,7 +4294,7 @@ EXPORT_SYMBOL_GPL(__tcp_send_ack);void tcp_send_ack (struct sock *sk) { -__tcp_send_ack (sk,tcp_sk (sk)->rcv_nxt); +__tcp_send_ack (sk,tcp_sk (sk)->rcv_nxt,0 ); }/* This routine sends a packet with an out of date sequence
Greg Kroah-Hartman
maintainerPATCH 139/220 tcp: fast path functions later
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit 61b2f7baa9779b12a7bf1b9800a3f2a2549a1315 ]
The following patch will use tcp_ecn_mode_accecn(), TCP_ACCECN_CEP_INIT_OFFSET, TCP_ACCECN_CEP_ACE_MASK in __tcp_fast_path_on() to make new flag for AccECN.
No functional changes.
Stable-dep-of: a28c4fcbf774 ("tcp: challenge ACK for non-exact RST in SYN-RECEIVED")
--- include/net/tcp.h | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-)
include/net/tcp.h +27 -27
@@ -768,33 +768,6 @@ static inline u32 __tcp_set_rto(const streturn usecs_to_jiffies ((tp->srtt_us >>3 ) + tp->rttvar_us); } -static inline void __tcp_fast_path_on (struct tcp_sock *tp,u32 snd_wnd) -{ -/* mptcp hooks are only on the slow path */ -if (sk_is_mptcp ((struct sock *)tp)) -return ; - - tp->pred_flags =htonl ((tp->tcp_header_len <<26 ) | -ntohl (TCP_FLAG_ACK ) | - snd_wnd); -} - -static inline void tcp_fast_path_on (struct tcp_sock *tp) -{ -__tcp_fast_path_on (tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); -} - -static inline void tcp_fast_path_check (struct sock *sk) -{ -struct tcp_sock *tp =tcp_sk (sk); - -if (RB_EMPTY_ROOT (&tp->out_of_order_queue) && - tp->rcv_wnd && -atomic_read (&sk->sk_rmem_alloc) < sk->sk_rcvbuf && - !tp->urg_data) -tcp_fast_path_on (tp); -} -u32 tcp_delack_max (const struct sock *sk);/* Compute the actual rto_min value */
@@ -1743,6 +1716,33 @@ static inline bool tcp_paws_reject(constreturn true; } +static inline void __tcp_fast_path_on (struct tcp_sock *tp,u32 snd_wnd) +{ +/* mptcp hooks are only on the slow path */ +if (sk_is_mptcp ((struct sock *)tp)) +return ; + + tp->pred_flags =htonl ((tp->tcp_header_len <<26 ) | +ntohl (TCP_FLAG_ACK ) | + snd_wnd); +} + +static inline void tcp_fast_path_on (struct tcp_sock *tp) +{ +__tcp_fast_path_on (tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); +} + +static inline void tcp_fast_path_check (struct sock *sk) +{ +struct tcp_sock *tp =tcp_sk (sk); + +if (RB_EMPTY_ROOT (&tp->out_of_order_queue) && + tp->rcv_wnd && +atomic_read (&sk->sk_rmem_alloc) < sk->sk_rcvbuf && + !tp->urg_data) +tcp_fast_path_on (tp); +} +bool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time);
Greg Kroah-Hartman
maintainerPATCH 140/220 tcp: reorganize tcp_sock_write_txrx group for variables later
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chia-Yu Chang <[email protected]>
[ Upstream commit c3426ba2ed6942fe33c75bf17fc7513ba2c6ac64 ]
Use the first 3-byte hole at the beginning of the tcp_sock_write_txrx group for 'noneagle'/'rate_app_limited' to fill in the existing hole in later patches. Therefore, the group size of tcp_sock_write_txrx is reduced from 92 + 4 to 91 + 4. In addition, the group size of tcp_sock_write_rx is changed to 96 to fit in the pahole outcome. Below are the trimmed pahole outcomes before and after this patch:
[BEFORE THIS PATCH]
struct tcp_sock {
[...]
__cacheline_group_begin__tcp_sock_write_txrx[0]; /* 2521 0 */
/* XXX 3 bytes hole, try to pack */
[...]
struct tcp_options_received rx_opt; /* 2588 24 */
u8 nonagle:4; /* 2612: 0 1 */
u8 rate_app_limited:1; /* 2612: 4 1 */
/* XXX 3 bits hole, try to pack */
__cacheline_group_end__tcp_sock_write_txrx[0]; /* 2613 0 */
/* XXX 3 bytes hole, try to pack */
__cacheline_group_begin__tcp_sock_write_rx[0] __attribute__((__aligned__(8))); /* 2616 0 */
[...]
__cacheline_group_end__tcp_sock_write_rx[0]; /* 2712 0 */
[...]
/* size: 3200, cachelines: 50, members: 161 */
}[AFTER THIS PATCH]
struct tcp_sock {
[...]
__cacheline_group_begin__tcp_sock_write_txrx[0]; /* 2521 0 */
u8 nonagle:4; /* 2521: 0 1 */
u8 rate_app_limited:1; /* 2521: 4 1 */
/* XXX 3 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
[...]
struct tcp_options_received rx_opt; /* 2588 24 */
__cacheline_group_end__tcp_sock_write_txrx[0]; /* 2612 0 */
/* XXX 4 bytes hole, try to pack */
__cacheline_group_begin__tcp_sock_write_rx[0] __attribute__((__aligned__(8))); /* 2616 0 */
[...]
__cacheline_group_end__tcp_sock_write_rx[0]; /* 2712 0 */
[...]
/* size: 3200, cachelines: 50, members: 161 */
}Stable-dep-of: a28c4fcbf774 ("tcp: challenge ACK for non-exact RST in SYN-RECEIVED")
--- include/linux/tcp.h | 4 ++-- net/ipv4/tcp.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
include/linux/tcp.h +2 -2
@@ -282,6 +282,8 @@ struct tcp_sock {* Header prediction flags * 0x5?10 << 16 + snd_wnd in net byte order */ + u8 nonagle : 4,/* Disable Nagle algorithm? */ + rate_app_limited:1; /* rate_{delivered,interval_us} limited? */__be32 pred_flags;u64 tcp_clock_cache;/* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ u64 tcp_mstamp;/* most recent packet received/sent */
@@ -300,8 +302,6 @@ struct tcp_sock {* Options received (usually on last packet, some only on SYN packets). */ struct tcp_options_received rx_opt; - u8 nonagle : 4,/* Disable Nagle algorithm? */ - rate_app_limited:1; /* rate_{delivered,interval_us} limited? */__cacheline_group_end (tcp_sock_write_txrx);/* RX read-write hotpath cache lines */
net/ipv4/tcp.c +2 -2
@@ -5061,7 +5061,7 @@ static void __init tcp_struct_check(void/* 32bit arches with 8byte alignment on u64 fields might need padding * before tcp_clock_cache. */ - CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_txrx, 92 + 4); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_txrx, 91 + 4);/* RX read-write hotpath cache lines */ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_received);
@@ -5078,7 +5078,7 @@ static void __init tcp_struct_check(void CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_acked); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_rtt_est); CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcvq_space); - CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_rx, 99); + CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_rx, 96); }void __init tcp_init (void )
Greg Kroah-Hartman
maintainerPATCH 141/220 tcp: challenge ACK for non-exact RST in SYN-RECEIVED
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
[ Upstream commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 ]
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response.
--- include/net/tcp.h | 2 + net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++++++++----------- net/ipv4/tcp_minisocks.c | 12 +++++++++- 3 files changed, 56 insertions(+), 14 deletions(-)
include/net/tcp.h +2 -0
@@ -1745,6 +1745,8 @@ static inline void tcp_fast_path_check(sbool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack (struct sock *sk,struct sk_buff *skb, +struct request_sock *req);static inline void tcp_mib_init (struct net *net) {
net/ipv4/tcp_input.c +43 -13
79 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +11 -1
@@ -775,7 +775,7 @@ struct sock *tcp_check_req(struct sock ** elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ -if ((flg &TCP_FLAG_ACK ) && !fastopen && +if ((flg &TCP_FLAG_ACK ) && !(flg &TCP_FLAG_RST ) && !fastopen && (TCP_SKB_CB (skb)->ack_seq !=tcp_rsk (req)->snt_isn +1 ))return sk;
@@ -811,6 +811,16 @@ struct sock *tcp_check_req(struct sock * flg &= ~TCP_FLAG_SYN ; } +/* RFC 5961 section 3.2, as clarified by RFC 9293 section +* 3.10.7.4, requires a challenge ACK for a non-exact +* in-window RST in SYN-RECEIVED. +*/ +if ((flg &TCP_FLAG_RST ) && +TCP_SKB_CB (skb)->seq !=tcp_rsk (req)->rcv_nxt) { +tcp_reqsk_send_challenge_ack (sk, skb, req); +return NULL ; + } +/* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */
Greg Kroah-Hartman
maintainerPATCH 142/220 iommufd: Fix wrong hwpt passed to iommufd_auto_response_faults on replace
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
[ Upstream commit ba5c0f28a26e7d9be1e0997f8920dd638e2782fd ]
iommufd_hwpt_replace_device() calls:
iommufd_auto_response_faults(hwpt, old_handle);
passing the *new* hwpt together with the handle of the device's *old* domain. This should be a parameter mismatch:
1. Semantically, iommufd_auto_response_faults(x, handle) scans x->fault's deliver list and response xarray for groups matching "handle". A group is queued under the hwpt that was attached at fault-delivery time. old_handle is fetched *before* the domain switch, so its group lives on old->fault, not on the new hwpt->fault.
2. Historically, the first argument was "old". The routine was introduced by commit b7d8833677ba ("iommufd: Fault-capable hwpt attach/detach/replace") as __fault_domain_replace_dev() in fault.c, correctly calling iommufd_auto_response_faults(old, curr). Commit fb21b1568ada ("iommufd: Make attach_handle generic than fault specific") moved this into iommufd_hwpt_replace_device() in device.c and swapped it to "hwpt". This should be a refactor regression, not an intentional change.
Fix this by passing "old" instead.
--- drivers/iommu/iommufd/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/device.c +1 -1
@@ -453,7 +453,7 @@ static int iommufd_hwpt_replace_device(s goto out_disable_iopf;if (old->fault) { -iommufd_auto_response_faults (hwpt, old_handle); +iommufd_auto_response_faults (old, old_handle);if (!hwpt->fault)iommufd_fault_iopf_disable (idev); }
Greg Kroah-Hartman
maintainerPATCH 143/220 btrfs: add debug build only WARN
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba <[email protected]>
[ Upstream commit 3db15c6ca6feb2c5000a1cbb39c33866e0349abd ]
Add conditional WARN() wrapper that's enabled only in debug build. It should be used for unexpected conditions that should be noisy. Use it instead of ASSERT(0). As it will not lead to BUG() make sure that continuing is still possible, e.g. the error is handled anyway.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/messages.h | 7 +++++++ 1 file changed, 7 insertions(+)
fs/btrfs/messages.h +7 -0
@@ -181,6 +181,13 @@ do { \#define ASSERT (expr) (void)(expr)#endif +#ifdef CONFIG_BTRFS_DEBUG +/* Verbose warning only under debug build. */ +#define DEBUG_WARN(args...) WARN(1, KERN_ERR args) +#else +#define DEBUG_WARN (...) do {} while(0) +#endif + __printf(5, 6)__cold void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
Greg Kroah-Hartman
maintainerPATCH 144/220 btrfs: add space_info argument to btrfs_chunk_alloc()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naohiro Aota <[email protected]>
[ Upstream commit 098a442d5b6d440602604dc1a88706a2a91bce4e ]
Take a btrfs_space_info argument in btrfs_chunk_alloc(). New block group will belong to that space_info.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/block-group.c | 27 +++++++++++++++++---------- fs/btrfs/block-group.h | 3 ++- fs/btrfs/extent-tree.c | 6 ++++-- fs/btrfs/space-info.c | 2 +- fs/btrfs/transaction.c | 5 +++-- 5 files changed, 27 insertions(+), 16 deletions(-)
fs/btrfs/block-group.c +17 -10
@@ -3003,6 +3003,7 @@ int btrfs_inc_block_group_ro(struct btrf bool do_chunk_alloc) {struct btrfs_fs_info *fs_info = cache->fs_info; +struct btrfs_space_info *space_info = cache->space_info;struct btrfs_trans_handle *trans;struct btrfs_root *root =btrfs_block_group_root (fs_info);u64 alloc_flags;
@@ -3055,7 +3056,7 @@ int btrfs_inc_block_group_ro(struct btrf*/ alloc_flags =btrfs_get_alloc_profile (fs_info, cache->flags);if (alloc_flags != cache->flags) { - ret =btrfs_chunk_alloc (trans, alloc_flags, + ret =btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE );/* * ENOSPC is allowed here, we may have enough space
@@ -3083,15 +3084,15 @@ int btrfs_inc_block_group_ro(struct btrf (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM)) goto unlock_out; - alloc_flags =btrfs_get_alloc_profile (fs_info, cache->space_info->flags); - ret =btrfs_chunk_alloc (trans, alloc_flags,CHUNK_ALLOC_FORCE ); + alloc_flags =btrfs_get_alloc_profile (fs_info, space_info->flags); + ret =btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE );if (ret <0 ) goto out;/* * We have allocated a new chunk. We also need to activate that chunk to * grant metadata tickets for zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (fs_info, cache->space_info, true); + ret =btrfs_zoned_activate_one_bg (fs_info, space_info, true);if (ret <0 ) goto out;
@@ -3941,8 +3942,15 @@ static int should_alloc_chunk(const struint btrfs_force_chunk_alloc (struct btrfs_trans_handle *trans,u64 type) {u64 alloc_flags =btrfs_get_alloc_profile (trans->fs_info, type); +struct btrfs_space_info *space_info; + + space_info =btrfs_find_space_info (trans->fs_info, type); +if (!space_info) { +DEBUG_WARN (); +return -EINVAL ; + } -return btrfs_chunk_alloc (trans, alloc_flags,CHUNK_ALLOC_FORCE ); +return btrfs_chunk_alloc (trans, space_info, alloc_flags,CHUNK_ALLOC_FORCE ); }static struct btrfs_block_group *do_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags)
@@ -4138,6 +4146,8 @@ out:* * This function, btrfs_chunk_alloc(), belongs to phase 1. * +* @space_info: specify which space_info the new chunk should belong to. +* * If @force is CHUNK_ALLOC_FORCE: * - return 1 if it successfully allocates a chunk, * - return errors including -ENOSPC otherwise.
@@ -4146,11 +4156,11 @@ out:* - return 1 if it successfully allocates a chunk, * - return errors including -ENOSPC otherwise. */ -int btrfs_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags, +int btrfs_chunk_alloc (struct btrfs_trans_handle *trans, +struct btrfs_space_info *space_info,u64 flags,enum btrfs_chunk_alloc_enum force) {struct btrfs_fs_info *fs_info = trans->fs_info; -struct btrfs_space_info *space_info;struct btrfs_block_group *ret_bg;bool wait_for_alloc = false;bool should_alloc = false;
@@ -4189,9 +4199,6 @@ int btrfs_chunk_alloc(struct btrfs_transif (flags &BTRFS_BLOCK_GROUP_SYSTEM )return -ENOSPC ; - space_info =btrfs_find_space_info (fs_info, flags); -ASSERT (space_info); - do { spin_lock(&space_info->lock); if (force < space_info->force_alloc)
fs/btrfs/block-group.h +2 -1
@@ -342,7 +342,8 @@ int btrfs_add_reserved_bytes(struct btrf bool force_wrong_size_class);void btrfs_free_reserved_bytes (struct btrfs_block_group *cache,u64 num_bytes,int delalloc); -int btrfs_chunk_alloc (struct btrfs_trans_handle *trans,u64 flags, +int btrfs_chunk_alloc (struct btrfs_trans_handle *trans, +struct btrfs_space_info *space_info,u64 flags,enum btrfs_chunk_alloc_enum force);int btrfs_force_chunk_alloc (struct btrfs_trans_handle *trans,u64 type);void check_system_chunk (struct btrfs_trans_handle *trans,const u64 type);
fs/btrfs/extent-tree.c +4 -2
@@ -4147,6 +4147,7 @@ static int can_allocate_chunk(struct btrstatic int find_free_extent_update_loop (struct btrfs_fs_info *fs_info,struct btrfs_key *ins,struct find_free_extent_ctl *ffe_ctl, +struct btrfs_space_info *space_info,bool full_search) {struct btrfs_root *root = fs_info->chunk_root;
@@ -4201,7 +4202,7 @@ static int find_free_extent_update_loop(return ret; } - ret =btrfs_chunk_alloc (trans, ffe_ctl->flags, + ret =btrfs_chunk_alloc (trans, space_info, ffe_ctl->flags,CHUNK_ALLOC_FORCE_FOR_EXTENT );/* Do not bail out on ENOSPC since we can do more. */
@@ -4601,7 +4602,8 @@ loop: }up_read (&space_info->groups_sem); - ret =find_free_extent_update_loop (fs_info, ins, ffe_ctl, full_search); + ret =find_free_extent_update_loop (fs_info, ins, ffe_ctl, space_info, + full_search);if (ret >0 ) goto search;
fs/btrfs/space-info.c +1 -1
@@ -850,7 +850,7 @@ static void flush_space(struct btrfs_fs_ ret =PTR_ERR (trans);break ; } - ret =btrfs_chunk_alloc (trans, + ret =btrfs_chunk_alloc (trans, space_info,btrfs_get_alloc_profile (fs_info, space_info->flags), (state ==ALLOC_CHUNK ) ?CHUNK_ALLOC_NO_FORCE :CHUNK_ALLOC_FORCE );
fs/btrfs/transaction.c +3 -2
@@ -764,9 +764,10 @@ got_it:* value here. */ if (do_chunk_alloc && num_bytes) { -u64 flags = h->block_rsv->space_info->flags; +struct btrfs_space_info *space_info = h->block_rsv->space_info; +u64 flags = space_info->flags; -btrfs_chunk_alloc (h,btrfs_get_alloc_profile (fs_info, flags), +btrfs_chunk_alloc (h, space_info,btrfs_get_alloc_profile (fs_info, flags),CHUNK_ALLOC_NO_FORCE ); }
Greg Kroah-Hartman
maintainerPATCH 145/220 btrfs: remove fs_info argument from btrfs_zoned_activate_one_bg()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <[email protected]>
[ Upstream commit a232ff90d14657c8637c6e94b606bb5d700a2ecb ]
We don't need it since we can grab fs_info from the given space_info. So remove the fs_info argument.
Stable-dep-of: 8bc4d7209611 ("btrfs: zoned: fix missing chunk metadata reservation")
--- fs/btrfs/block-group.c | 4 ++-- fs/btrfs/zoned.c | 5 ++--- fs/btrfs/zoned.h | 6 ++---- 3 files changed, 6 insertions(+), 9 deletions(-)
fs/btrfs/block-group.c +2 -2
@@ -3092,7 +3092,7 @@ int btrfs_inc_block_group_ro(struct btrf* We have allocated a new chunk. We also need to activate that chunk to * grant metadata tickets for zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (fs_info, space_info, true); + ret =btrfs_zoned_activate_one_bg (space_info, true);if (ret <0 ) goto out;
@@ -4350,7 +4350,7 @@ static void reserve_chunk_space(struct b* We have a new chunk. We also need to activate it for * zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (fs_info, info, true); + ret =btrfs_zoned_activate_one_bg (info, true);if (ret <0 )return ;
fs/btrfs/zoned.c +2 -3
@@ -2825,10 +2825,9 @@ int btrfs_zone_finish_one_bg(struct btrfreturn ret <0 ? ret :1 ; } -int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info, -bool do_finish) +int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish) { +struct btrfs_fs_info *fs_info = space_info->fs_info;struct btrfs_block_group *bg;int index;
fs/btrfs/zoned.h +2 -4
@@ -93,8 +93,7 @@ bool btrfs_zoned_should_reclaim(const stvoid btrfs_zoned_release_data_reloc_bg (struct btrfs_fs_info *fs_info,u64 logical,u64 length);int btrfs_zone_finish_one_bg (struct btrfs_fs_info *fs_info); -int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info,bool do_finish); +int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish);void btrfs_check_active_zone_reservation (struct btrfs_fs_info *fs_info);#else /* CONFIG_BLK_DEV_ZONED */
@@ -258,8 +257,7 @@ static inline int btrfs_zone_finish_one_return 1 ; } -static inline int btrfs_zoned_activate_one_bg (struct btrfs_fs_info *fs_info, -struct btrfs_space_info *space_info, +static inline int btrfs_zoned_activate_one_bg (struct btrfs_space_info *space_info,bool do_finish) {/* Consider all the block groups are active */
Greg Kroah-Hartman
maintainerPATCH 146/220 btrfs: zoned: fix missing chunk metadata reservation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
[ Upstream commit 8bc4d7209611e8aa9d5409b6a4a86a9eb91b69a3 ]
reserve_chunk_space() stores the return value of btrfs_zoned_activate_one_bg() in ret. The helper can return 1 after successfully activating a block group, but ret is later used to decide whether to reserve metadata for chunk tree updates.
As a result, successful activation skips btrfs_block_rsv_add() and leaves trans->chunk_bytes_reserved unchanged. Use a separate variable for the activation result so positive success does not affect the later reservation. Keep activation failures in ret instead of returning early so the function uses the common tail path.
--- fs/btrfs/block-group.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
fs/btrfs/block-group.c +19 -15
@@ -4346,25 +4346,29 @@ static void reserve_chunk_space(struct bif (IS_ERR (bg)) { ret =PTR_ERR (bg); }else { +int activate_ret; +/* * We have a new chunk. We also need to activate it for * zoned filesystem. */ - ret =btrfs_zoned_activate_one_bg (info, true); -if (ret <0 ) -return ; - -/* -* If we fail to add the chunk item here, we end up -* trying again at phase 2 of chunk allocation, at -* btrfs_create_pending_block_groups(). So ignore -* any error here. An ENOSPC here could happen, due to -* the cases described at do_chunk_alloc() - the system -* block group we just created was just turned into RO -* mode by a scrub for example, or a running discard -* temporarily removed its free space entries, etc. -*/ -btrfs_chunk_alloc_add_chunk_item (trans, bg); + activate_ret =btrfs_zoned_activate_one_bg (info, true); +if (activate_ret <0 ) { + ret = activate_ret; + }else { +/* +* If we fail to add the chunk item here, we end +* up trying again at phase 2 of chunk allocation, +* at btrfs_create_pending_block_groups(). So +* ignore any error here. An ENOSPC here could +* happen, due to the cases described at +* do_chunk_alloc() - the system block group we +* just created was just turned into RO mode by a +* scrub for example, or a running discard +* temporarily removed its free space entries, etc. +*/ +btrfs_chunk_alloc_add_chunk_item (trans, bg); + } } }
Greg Kroah-Hartman
maintainerPATCH 147/220 KVM: x86: Cancel delayed I/O APIC EOI handling before destroying vCPUs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 9910e835580fef3bef53b70241dd00c4bffad693 ]
Cancel (and flush) the I/O APIC's delayed EOI handling work during the "pre VM destroy" phase, before vCPUs are destroyed, as processing the EOI broadcast will inject another IRQ if the line is asserted, i.e. will try to deliver an IRQ to the target vCPU(s). Canceling the work after vCPUs are destroyed leads to UAF if the delayed work is processed after vCPUs are destroyed.
BUG: KASAN: slab-use-after-free in __kvm_irq_delivery_to_apic_fast+0x9bf/0xa20 arch/x86/kvm/lapic.c:1250 Read of size 8 at addr ffff8880499abea0 by task kworker/1:2/1218 CPU: 1 UID: 0 PID: 1218 Comm: kworker/1:2 Not tainted 7.1.0-rc7 #5 PREEMPT(lazy) Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: events kvm_ioapic_eoi_inject_work Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 print_report+0x139/0x4ad mm/kasan/report.c:482 kasan_report+0xe4/0x1d0 mm/kasan/report.c:595 __kvm_irq_delivery_to_apic_fast+0x9bf/0xa20 arch/x86/kvm/lapic.c:1250 __kvm_irq_delivery_to_apic+0xd8/0xbf0 arch/x86/kvm/lapic.c:1345 kvm_irq_delivery_to_apic arch/x86/kvm/lapic.h:129 ioapic_service+0x308/0x590 arch/x86/kvm/ioapic.c:492 kvm_ioapic_eoi_inject_work+0x13c/0x190 arch/x86/kvm/ioapic.c:532 process_one_work+0xa59/0x19a0 kernel/workqueue.c:3314 process_scheduled_works kernel/workqueue.c:3397 worker_thread+0x5eb/0xe50 kernel/workqueue.c:3478 kthread+0x370/0x450 kernel/kthread.c:436 ret_from_fork+0x72b/0xd30 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK>
Note, the VM is unreachable once kvm_destroy_vm() starts, and scheduling new work via kvm_ioapic_send_eoi() can only be done via KVM_RUN, i.e. requires a live vCPU.
Alternatively, KVM could simply destroy the I/O APIC during the "pre" phase of VM destruction, but that gets more than a bit sketchy as KVM expects the I/O APIC to exist if ioapic_in_kernel() is true, and nested virtualization in particular has a bad habit of touching VM-scope state during vCPU destruction. E.g. attempting to free the PIC during the pre phase would lead to a NULL pointer dereference in kvm_cpu_has_extint(), and it's not hard to imagine the I/O APIC having a similar flaw.
Message-ID: <[email protected]>
--- arch/x86/kvm/x86.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/x86/kvm/x86.c +13 -0
@@ -12982,6 +12982,19 @@ EXPORT_SYMBOL_GPL(__x86_set_memory_regiovoid kvm_arch_pre_destroy_vm (struct kvm *kvm) { +/* +* Cancel (and flush) the I/O APIC's delayed EOI handling before vCPUs +* are destroyed, as processing the EOI broadcast will inject another +* IRQ if the line is asserted, i.e. will try to deliver an IRQ to the +* target vCPU(s). +* +* Do NOT free the in-kernel PIC or I/O APIC here (but do make sure to +* flush any background work), as KVM expects interrupt routing +* structures to be valid until vCPUs are destroyed. +*/ +if (kvm->arch.vioapic) +cancel_delayed_work_sync (&kvm->arch.vioapic->eoi_inject); +kvm_mmu_pre_destroy_vm (kvm); }
Greg Kroah-Hartman
maintainerPATCH 148/220 ASoC: tas2562: Validate values for volume writes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Brown <[email protected]>
[ Upstream commit 8fb41964f7e4e4207c8999af2056894caa7a252a ]
tas2562_volume_control_put() does not do any validation of the control value written by userspace, it uses it to look up a value in a fixed size array which can easily be overflowed and then writes whatever value it gets back to the device. Add validation that we are loading a value we have in the array.
--- sound/soc/codecs/tas2562.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
sound/soc/codecs/tas2562.c +7 -2
@@ -472,10 +472,15 @@ static int tas2562_volume_control_put(st {struct snd_soc_component *component =snd_soc_kcontrol_component (kcontrol);struct tas2562_data *tas2562 =snd_soc_component_get_drvdata (component); -int ret; +int ret, index;u32 reg_val; - reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; + index = ucontrol->value.integer.value[0 ] /2 ; +if (index <0 || index >=ARRAY_SIZE (float_vol_db_lookup)) +return -EINVAL ; + + reg_val = float_vol_db_lookup[index]; +/* * The device applies the 32-bit coefficient to the playback path on * the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the
Greg Kroah-Hartman
maintainerPATCH 149/220 ata: libata-scsi: terminate deferred commands on time out
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Le Moal <[email protected]>
[ Upstream commit 2e1d2e65e773d67dab163127f11a47dab0fbca9f ]
If a command times out while we have deferred non-NCQ commands waiting to be issued, the SCSI EH task is not immediately woken up as the waiting deferred commands are never issued nor completed, thus leaving the SCSI host in a busy state (shost->host_failed != scsi_host_busy(shost)) which prevents the SCSI EH task from being woken up. Eventually, when the deferred commands also time out, the SCSI EH task is woken up and the timeout processing occurs.
Avoid this unnecessary SCSI EH task wake-up additional time by scheduling a retry of all waiting deferred QCs, using the eh_timed_out SCSI host template operation. The function ata_scsi_eh_timed_out() is introduced to implement this operation.
However, terminating deferred commands with DID_REQUEUE to force a retry by calling the function ata_scsi_requeue_deferred_qc() may still keep the SCSI host in a busy state because the block layer may immediately re-issue these commands. The solution to this is to schedule libata EH for the port which suffered the command timeout to prevent accepting any new command. ata_scsi_requeue_deferred_qc() is modified to add a call to ata_port_schedule_eh() for this purpose.
In addition to this change, ata_scsi_requeue_deferred_qc() is also modified to take a new timedout_scmd scsi command argument which indicates the SCSI command that timed out. With this additional argument, ata_scsi_requeue_deferred_qc() can now also terminate with DID_TIME_OUT any timed out deferred qc, which simplifies ata_scsi_cmd_error_handler(). In this case, ata_scsi_requeue_deferred_qc() returns SCSI_EH_DONE, with this return value propagated back to the ata_scsi_eh_timed_out() operation to indicate to scsi_timeout() that the timed out command was handled and no further processing is needed.
For non-timed out deferred qc that need to be retried, ata_scsi_requeue_deferred_qc() returns SCSI_EH_NOT_HANDLED, thus indicating to scsi_timeout() that the timed out command needs to go through the SCSI EH (and libata EH) processing by adding it to the EH work queue with scsi_eh_scmd_add().
One side effect of these changes is that the function atapi_qc_complete() needs to be modified to ensure that a deferred ATAPI command that needs to be retried is completed with DID_REQUEUE instead of the default SAM_STAT_GOOD status, and a command that timed out is completed with DID_TIME_OUT instead of SAM_STAT_CHECK_CONDITION.
--- drivers/ata/libata-eh.c | 29 ++--------- drivers/ata/libata-scsi.c | 115 ++++++++++++++++++++++++++++++++++++++++------ drivers/ata/libata.h | 3 - include/linux/libata.h | 2 4 files changed, 110 insertions(+), 39 deletions(-)
drivers/ata/libata-eh.c +6 -23
@@ -650,29 +650,12 @@ void ata_scsi_cmd_error_handler(struct Sset_host_byte (scmd,DID_OK );ata_qc_for_each_raw (ap, qc, i) { -if (qc->scsicmd != scmd) -continue ; -if ((qc->flags &ATA_QCFLAG_ACTIVE ) || - qc == qc->dev->link->deferred_qc) +if (qc->scsicmd == scmd && + qc->flags &ATA_QCFLAG_ACTIVE )break ; } -if (i <ATA_MAX_QUEUE && qc == qc->dev->link->deferred_qc) { -/* -* This is a deferred command that timed out while -* waiting for the command queue to drain. Since the qc -* is not active yet (deferred_qc is still set, so the -* deferred qc work has not issued the command yet), -* simply signal the timeout by finishing the SCSI -* command and clear the deferred qc to prevent the -* deferred qc work from issuing this qc. -*/ -WARN_ON_ONCE (qc->flags &ATA_QCFLAG_ACTIVE ); - qc->dev->link->deferred_qc =NULL ; -cancel_work (&qc->dev->link->deferred_qc_work); -set_host_byte (scmd,DID_TIME_OUT ); -scsi_eh_finish_cmd (scmd, &ap->eh_done_q); - }else if (i <ATA_MAX_QUEUE ) { +if (i <ATA_MAX_QUEUE ) {/* the scmd has an associated qc */ if (!(qc->flags &ATA_QCFLAG_EH )) {/* which hasn't failed yet, timeout */
@@ -946,10 +929,10 @@ static void ata_eh_set_pending(struct at ap->pflags |=ATA_PFLAG_EH_PENDING ;/* -* If we have a deferred qc, requeue it so that it is retried once EH -* completes. +* If we have deferred QCs, requeue them so that the SCSI EH task can +* run. */ -ata_scsi_requeue_deferred_qc (ap); +ata_scsi_requeue_deferred_qc (ap,NULL );if (!fastdrain)return ;
drivers/ata/libata-scsi.c +100 -15
150 lines not on this page · raw message
drivers/ata/libata.h +2 -1
@@ -176,7 +176,8 @@ int ata_scsi_dev_config(struct scsi_devi struct ata_device *dev);int __ata_scsi_queuecmd (struct scsi_cmnd *scmd,struct ata_device *dev);void ata_scsi_deferred_qc_work (struct work_struct *work); -void ata_scsi_requeue_deferred_qc (struct ata_port *ap); +enum scsi_timeout_action ata_scsi_requeue_deferred_qc (struct ata_port *ap, +struct scsi_cmnd *scmd);/* libata-eh.c */ extern unsigned int ata_internal_cmd_timeout (struct ata_device *dev,u8 cmd);
include/linux/libata.h +2 -0
@@ -1148,6 +1148,7 @@ extern int ata_scsi_ioctl(struct scsi_de#define ATA_SCSI_COMPAT_IOCTL /* empty */ #endif extern int ata_scsi_queuecmd (struct Scsi_Host *h,struct scsi_cmnd *cmd); +enum scsi_timeout_action ata_scsi_eh_timed_out (struct scsi_cmnd *cmd);#if IS_REACHABLE (CONFIG_ATA )bool ata_scsi_dma_need_drain (struct request *rq);#else
@@ -1461,6 +1462,7 @@ extern const struct attribute_group *ata .ioctl = ata_scsi_ioctl, \ATA_SCSI_COMPAT_IOCTL \ .queuecommand = ata_scsi_queuecmd, \ + .eh_timed_out = ata_scsi_eh_timed_out, \ .dma_need_drain = ata_scsi_dma_need_drain, \ .this_id = ATA_SHT_THIS_ID, \ .emulated = ATA_SHT_EMULATED, \
Greg Kroah-Hartman
maintainerPATCH 150/220 igc: remove napi_synchronize() in igc_down()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit 5ffab5b9589c50e4cfc0cf36ffd76c89422d4019 ]
When an AF_XDP zero-copy application is killed abruptly, the XSK pool is torn down but NAPI keeps polling. igc_clean_rx_irq_zc() then returns the full budget on every poll, so napi_complete_done() never clears NAPI_STATE_SCHED.
igc_down() calls napi_synchronize() before napi_disable(), so it spins forever waiting for that bit and the interface never goes down. Drop the napi_synchronize() and let napi_disable() do the job -- it sets NAPI_STATE_DISABLE, which forces the stuck poll to complete. Reorder it ahead of igc_set_queue_napi() so the NAPI mapping is cleared only after polling has stopped, matching the recent igb fix b1e067240379.
--- drivers/net/ethernet/intel/igc/igc_main.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/ethernet/intel/igc/igc_main.c +0 -1
@@ -5199,7 +5199,6 @@ void igc_down(struct igc_adapter *adaptefor (i =0 ; i < adapter->num_q_vectors; i++) {if (adapter->q_vector[i]) { -napi_synchronize (&adapter->q_vector[i]->napi);napi_disable (&adapter->q_vector[i]->napi); } }
Greg Kroah-Hartman
maintainerPATCH 151/220 ksmbd: conn lock to serialize smb2 negotiate
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit fe4ed2f09b492e3507615a053814daa8fafdecb1 ]
If client send parallel smb2 negotiate request on same connection, ksmbd_conn can be racy. smb2 negotiate handling that are not performance-related can be serialized with conn lock.
Stable-dep-of: cb469993b3a6 ("ksmbd: reject repeated SMB2 NEGOTIATE requests")
--- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/smb2pdu.c +2 -0
@@ -1120,6 +1120,7 @@ int smb2_handle_negotiate(struct ksmbd_wreturn rc; } +ksmbd_conn_lock (conn); smb2_buf_len =get_rfc1002_len (work->request_buf); smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects);if (smb2_neg_size > smb2_buf_len) {
@@ -1270,6 +1271,7 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_conn_set_need_setup (conn); err_out: +ksmbd_conn_unlock (conn);if (rc) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;
Greg Kroah-Hartman
maintainerPATCH 152/220 ksmbd: reject repeated SMB2 NEGOTIATE requests
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit cb469993b3a61a72653770856d37af616d72d05f ]
Unauthenticated client can send multiple successful SMB2 NEGOTIATE requests on one connection before SESSION_SETUP. While the connection is in KSMBD_SESS_NEED_SETUP, smb2_handle_negotiate() accepts another SMB3.1.1 NEGOTIATE and overwrites conn->preauth_info with a new allocation. Only the final allocation is freed when the connection is released, leaking one object for every additional successful request.
A repeated SMB2 NEGOTIATE after a dialect has been selected is a protocol violation. MS-SMB2 section 3.3.5.4 requires the server to disconnect without replying in this case. Set the connection exiting when rejecting the request, in addition to suppressing the response.
Reject SMB2 NEGOTIATE unless the connection is new or is waiting for the SMB2 NEGOTIATE that follows an SMB1 multi-protocol negotiate. Serialize both SMB1 and SMB2 negotiation paths under conn->srv_mutex, since they update connection-wide dialect and negotiation state.
Move the locking contract to ksmbd_smb_negotiate_common(), where the state and dialect are selected, and add ksmbd_conn_new() for consistent state access.
--- fs/smb/server/connection.h | 5 +++++ fs/smb/server/smb2pdu.c | 10 ++-------- fs/smb/server/smb_common.c | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 15 deletions(-)
fs/smb/server/connection.h +5 -0
@@ -195,6 +195,11 @@ void ksmbd_conn_r_count_dec(struct ksmbd* This is a hack. We will move status to a proper place once we land * a multi-sessions support. */ +static inline bool ksmbd_conn_new (struct ksmbd_conn *conn) +{ +return READ_ONCE (conn->status) ==KSMBD_SESS_NEW ; +} +static inline bool ksmbd_conn_good (struct ksmbd_conn *conn) {return READ_ONCE (conn->status) ==KSMBD_SESS_GOOD ;
fs/smb/server/smb2pdu.c +2 -8
@@ -1101,6 +1101,8 @@ static __le32 deassemble_neg_contexts(st* smb2_handle_negotiate() - handler for smb2 negotiate command * @work: smb work containing smb request buffer * +* The caller holds conn->srv_mutex. +* * Return: 0 */ int smb2_handle_negotiate (struct ksmbd_work *work)
@@ -1114,13 +1116,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_debug (SMB ,"Received negotiate request\n" ); conn->need_neg = false; -if (ksmbd_conn_good (conn)) { -pr_err ("conn->tcp_status is already in CifsGood State\n" ); - work->send_no_response =1 ; -return rc; - } - -ksmbd_conn_lock (conn); smb2_buf_len =get_rfc1002_len (work->request_buf); smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects);if (smb2_neg_size > smb2_buf_len) {
@@ -1271,7 +1266,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_conn_set_need_setup (conn); err_out: -ksmbd_conn_unlock (conn);if (rc) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;
fs/smb/server/smb_common.c +30 -7
@@ -592,23 +592,46 @@ int ksmbd_smb_negotiate_common(struct ksstruct ksmbd_conn *conn = work->conn;int ret; - conn->dialect = -ksmbd_negotiate_smb_dialect (work->request_buf); -ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); -if (command ==SMB2_NEGOTIATE_HE ) { +/* +* An SMB2 NEGOTIATE is valid for a new connection, or after an +* SMB1 multi-protocol negotiate has selected SMB2. Do not allow +* a second SMB2 NEGOTIATE to replace connection-wide state +* while a session setup is pending. KSMBD_SESS_NEED_RECONNECT +* is a transient session state and does not restart transport +* negotiation. +*/ +ksmbd_conn_lock (conn); +if (!ksmbd_conn_new (conn) && + !ksmbd_conn_need_negotiate (conn)) { + work->send_no_response =1 ; +ksmbd_conn_set_exiting (conn); +ksmbd_conn_unlock (conn); +return 0 ; + } + + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); ret =smb2_handle_negotiate (work); +ksmbd_conn_unlock (conn);return ret; }if (command ==SMB_COM_NEGOTIATE ) { +ksmbd_conn_lock (conn); + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect);if (__smb2_negotiate (conn)) {init_smb3_11_server (conn); -init_smb2_neg_rsp (work); + ret =init_smb2_neg_rsp (work);ksmbd_debug (SMB ,"Upgrade to SMB2 negotiation\n" ); -return 0 ; + }else { + ret =smb_handle_negotiate (work); } -return smb_handle_negotiate (work); +ksmbd_conn_unlock (conn); +return ret; }pr_err ("Unknown SMB negotiation command: %u\n" , command);
Greg Kroah-Hartman
maintainerPATCH 153/220 net: pktgen: fix code style (WARNING: Block comments)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Seiderer <[email protected]>
[ Upstream commit 870b856cb478bc02fffe4d89897e62c692efb09a ]
Fix checkpatch code style warnings:
WARNING: Block comments use a trailing */ on a separate line
+ * removal by worker thread */
WARNING: Block comments use * on subsequent lines
+ __u8 tos; /* six MSB of (former) IPv4 TOS
+ are for dscp codepoint */
WARNING: Block comments use a trailing */ on a separate line
+ are for dscp codepoint */
WARNING: Block comments use * on subsequent lines
+ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6
+ (see RFC 3260, sec. 4) */
WARNING: Block comments use a trailing */ on a separate line
+ (see RFC 3260, sec. 4) */
WARNING: Block comments use * on subsequent lines
+ /* = {
+ 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
WARNING: Block comments use * on subsequent lines
+ /* Field for thread to receive "posted" events terminate,
+ stop ifs etc. */
WARNING: Block comments use a trailing */ on a separate line
+ stop ifs etc. */
WARNING: Block comments should align the * on each line
+ * we go look for it ...
+*/
WARNING: Block comments use a trailing */ on a separate line
+ * we resolve the dst issue */
WARNING: Block comments use a trailing */ on a separate line
+ * with proc_create_data() */
Stable-dep-of: 817ff6efdb7f ("net: pktgen: fix proc entry use-after-free")
--- net/core/pktgen.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-)
net/core/pktgen.c +23 -16
@@ -285,7 +285,8 @@ struct pktgen_dev {int pkt_overhead;/* overhead for MPLS, VLANs, IPSEC etc */ int nfrags;int removal_mark;/* non-zero => the device is marked for -* removal by worker thread */ +* removal by worker thread +*/ struct page *page;u64 delay;/* nano-seconds */
@@ -348,10 +349,12 @@ struct pktgen_dev {__u16 udp_dst_max;/* exclusive, dest UDP port */ /* DSCP + ECN */ -__u8 tos;/* six MSB of (former) IPv4 TOS -are for dscp codepoint */ -__u8 traffic_class;/* ditto for the (former) Traffic Class in IPv6 -(see RFC 3260, sec. 4) */ +__u8 tos;/* six MSB of (former) IPv4 TOS +* are for dscp codepoint +*/ +__u8 traffic_class;/* ditto for the (former) Traffic Class in IPv6 +* (see RFC 3260, sec. 4) +*/ /* IMIX */ unsigned int n_imix_entries;
@@ -391,12 +394,12 @@ struct pktgen_dev {__u8 hh[14 ];/* = { -0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, - -We fill in SRC address later -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x08, 0x00 -}; +* 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, +* +* We fill in SRC address later +* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +* 0x08, 0x00 +* }; */ __u16 pad;/* pad out the hh struct to an even 16 bytes */
@@ -460,7 +463,8 @@ struct pktgen_thread {char result[512 ];/* Field for thread to receive "posted" events terminate, -stop ifs etc. */ +* stop ifs etc. +*/ u32 control;int cpu;
@@ -2364,7 +2368,7 @@ static inline int f_pick(struct pktgen_d#ifdef CONFIG_XFRM /* If there was already an IPSEC SA, we keep it as is, else * we go look for it ... -*/ +*/ #define DUMMY_MARK 0static void get_ipsec_sa (struct pktgen_dev *pkt_dev,int flow) {
@@ -2663,7 +2667,8 @@ static int pktgen_output_ipsec(struct skif (!x)return 0 ;/* XXX: we dont support tunnel mode for now until -* we resolve the dst issue */ +* we resolve the dst issue +*/ if ((x->props.mode !=XFRM_MODE_TRANSPORT ) && (pkt_dev->spi ==0 ))return 0 ;
@@ -3757,7 +3762,8 @@ static int add_dev_to_thread(struct pktg* userspace on another CPU than the kthread. The if_lock() * is used here to sync with concurrent instances of * _rem_dev_from_if_list() invoked via kthread, which is also -* updating the if_list */ +* updating the if_list +*/ if_lock (t);if (pkt_dev->pg_thread) {
@@ -3955,7 +3961,8 @@ static int pktgen_remove_device(struct p/* Remove proc before if_list entry, because add_device uses * list to determine if interface already exist, avoid race -* with proc_create_data() */ +* with proc_create_data() +*/ proc_remove (pkt_dev->entry);/* And update the thread if_list */
Greg Kroah-Hartman
maintainerPATCH 154/220 net: pktgen: fix proc entry use-after-free
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit 817ff6efdb7f484ea547218e11e17d8e43daa3b4 ]
pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock. pktgen_remove_device() removes the same entry before _rem_dev_from_if_list() takes that lock.
This allows the following interleaving:
CPU 0 (NETDEV_CHANGENAME) CPU 1 (kpktgend)
if_lock(t)
proc_remove(pkt_dev->entry)
proc_remove(pkt_dev->entry)
pkt_dev->entry = proc_create_data(...)
if_unlock(t)
The kthread can pass the stale proc_dir_entry to proc_remove() after the rename path has freed it. A reproducer with a widened race window reports:
BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80 Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67 Call Trace: proc_remove+0x78/0x80 pktgen_remove_device.isra.0+0x11c/0x4c0 pktgen_thread_worker+0x1214/0x6bc0 kthread+0x2c6/0x3b0 Allocated by task 95: __proc_create+0x204/0x790 proc_create_data+0x72/0xe0 pktgen_thread_write+0xd61/0x1510 Freed by task 28: kmem_cache_free+0xcb/0x3d0 proc_free_inode+0x5b/0x80 rcu_core+0x50a/0x1850 The buggy address belongs to the object at ffff8881478fea00 which belongs to the cache proc_dir_entry of size 192
Move proc_remove() into the if_lock-protected list removal helper. Keep it before list_del_rcu() to preserve the ordering required by add_device(). The rename path must then finish replacing the entry before removal, or it observes that the device is no longer on the list.
--- net/core/pktgen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/core/pktgen.c +1 -3
@@ -3934,6 +3934,7 @@ static void _rem_dev_from_if_list(structstruct pktgen_dev *p;if_lock (t); +proc_remove (pkt_dev->entry);list_for_each_safe (q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list);if (p == pkt_dev)
@@ -3963,9 +3964,6 @@ static int pktgen_remove_device(struct p* list to determine if interface already exist, avoid race * with proc_create_data() */ -proc_remove (pkt_dev->entry); - -/* And update the thread if_list */ _rem_dev_from_if_list (t, pkt_dev);#ifdef CONFIG_XFRM
Greg Kroah-Hartman
maintainerPATCH 155/220 binfmt_misc: dont leak the user namespace when the mount fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit b8206f516fe7cbe785cf44bf09c17c438d7c3cad ]
bm_get_tree() takes a reference to the user namespace and hands it to get_tree_keyed() as the sget key. sget_fc() moves that reference into sb->s_fs_info and clears fc->s_fs_info, so from that point on the superblock owns it and bm_free() doesn't see it anymore.
The superblock drops it in ->put_super(). But generic_shutdown_super() only calls ->put_super() from inside the if (sb->s_root) branch, so nothing releases it when bm_fill_super() fails:
- The kzalloc_obj() failure leaves s_root NULL and the whole branch is skipped.
- A simple_fill_super() failure in the file loop leaves s_root set, but s_op still points at simple_super_operations, which has no ->put_super(). bm_fill_super() installs s_ops only once simple_fill_super() returned success, and installing it earlier wouldn't help either because simple_fill_super() overwrites s_op.
Either way vfs_get_super() calls deactivate_locked_super() and the reference is gone for good. binfmt_misc mounts are available in a user namespace and both the inode and the dentry cache are SLAB_ACCOUNT, so an unprivileged caller under a tight memory cgroup can fail simple_fill_super() on demand and leak one user namespace per attempt.
Drop the reference in ->kill_sb() instead, which runs unconditionally, the same way nfsd and rpc_pipefs release their keyed s_fs_info.
That also stops ->put_super() from clearing s_fs_info while the superblock is still on @fs_supers. generic_shutdown_super() leaves it there on purpose so that sget_fc() keeps finding it until kill_sb() has run, but a NULL s_fs_info makes test_keyed_super() miss it, so a concurrent mount for the same user namespace skips the grab_super() wait and creates a second superblock for a namespace that is still being torn down.
--- fs/binfmt_misc.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)
fs/binfmt_misc.c +15 -17
@@ -958,18 +958,9 @@ static const struct file_operations bm_s/* Superblock handling */ -static void bm_put_super (struct super_block *sb) -{ -struct user_namespace *user_ns = sb->s_fs_info; - - sb->s_fs_info =NULL ; -put_user_ns (user_ns); -} -static const struct super_operations s_ops = { .statfs = simple_statfs, .evict_inode = bm_evict_inode, - .put_super = bm_put_super, };static int bm_fill_super (struct super_block *sb,struct fs_context *fc)
@@ -1028,13 +1019,12 @@ static int bm_fill_super(struct super_bl/* * When the binfmt_misc superblock for this userns is shutdown * ->enabled might have been set to false and we don't reinitialize -* ->enabled again in put_super() as someone might already be mounting -* binfmt_misc again. It also would be pointless since by the time -* ->put_super() is called we know that the binary type list for this -* bintfmt_misc mount is empty making load_misc_binary() return -* -ENOEXEC independent of whether ->enabled is true. Instead, if -* someone mounts binfmt_misc for the first time or again we simply -* reset ->enabled to true. +* ->enabled again during shutdown as someone might already be mounting +* binfmt_misc again. It also would be pointless since by then we know +* that the binary type list for this binfmt_misc mount is empty making +* load_misc_binary() return -ENOEXEC independent of whether ->enabled +* is true. Instead, if someone mounts binfmt_misc for the first time or +* again we simply reset ->enabled to true. */ misc->enabled = true;
@@ -1060,6 +1050,14 @@ static const struct fs_context_operation .get_tree = bm_get_tree, }; +static void bm_kill_sb (struct super_block *sb) +{ +struct user_namespace *user_ns = sb->s_fs_info; + +kill_litter_super (sb); +put_user_ns (user_ns); +} +static int bm_init_fs_context (struct fs_context *fc) { fc->ops = &bm_context_ops;
@@ -1076,7 +1074,7 @@ static struct file_system_type bm_fs_typ .name = "binfmt_misc", .init_fs_context = bm_init_fs_context, .fs_flags = FS_USERNS_MOUNT, - .kill_sb = kill_litter_super, + .kill_sb = bm_kill_sb, };MODULE_ALIAS_FS ("binfmt_misc" );
Greg Kroah-Hartman
maintainerPATCH 156/220 fsnotify, lsm: Decouple fsnotify from lsm
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Song Liu <[email protected]>
[ Upstream commit 1cda52f1b4611f4daa9d89e69d9428fb4137dc3f ]
Currently, fsnotify_open_perm() is called from security_file_open(). This is a a bit unexpected and creates otherwise unnecessary dependency of CONFIG_FANOTIFY_ACCESS_PERMISSIONS on CONFIG_SECURITY. Fix this by calling fsnotify_open_perm() directly.
Stable-dep-of: db1856ea9196 ("binfmt_misc: restore write access when removing an entry")
--- fs/notify/fanotify/Kconfig | 1 - fs/open.c | 4 ++++ security/security.c | 9 +-------- 3 files changed, 5 insertions(+), 9 deletions(-)
fs/notify/fanotify/Kconfig +0 -1
@@ -15,7 +15,6 @@ config FANOTIFY config FANOTIFY_ACCESS_PERMISSIONS bool "fanotify permissions checking" depends on FANOTIFY - depends on SECURITY default n help Say Y here is you want fanotify listeners to be able to make permissions
fs/open.c +4 -0
@@ -940,6 +940,10 @@ static int do_dentry_open(struct file *fif (error) goto cleanup_all; + error =fsnotify_open_perm (f); +if (error) + goto cleanup_all; + error =break_lease (file_inode (f), f->f_flags);if (error) goto cleanup_all;
security/security.c +1 -8
@@ -19,7 +19,6 @@#include <linux/kernel.h> #include <linux/kernel_read_file.h> #include <linux/lsm_hooks.h> -#include <linux/fsnotify.h> #include <linux/mman.h> #include <linux/mount.h> #include <linux/personality.h>
@@ -3214,13 +3213,7 @@ int security_file_receive(struct file *f*/ int security_file_open (struct file *file) { -int ret; - - ret =call_int_hook (file_open, file); -if (ret) -return ret; - -return fsnotify_open_perm (file); +return call_int_hook (file_open, file); }/**
Greg Kroah-Hartman
maintainerPATCH 157/220 fsnotify: opt-in for permission events at file open time
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit a94204f4d48e28a711b7ed10399f749286c433e3 ]
Legacy inotify/fanotify listeners can add watches for events on inode, parent or mount and expect to get events (e.g. FS_MODIFY) on files that were already open at the time of setting up the watches.
fanotify permission events are typically used by Anti-malware sofware, that is watching the entire mount and it is not common to have more that one Anti-malware engine installed on a system.
To reduce the overhead of the fsnotify_file_perm() hooks on every file access, relax the semantics of the legacy FAN_ACCESS_PERM event to generate events only if there were *any* permission event listeners on the filesystem at the time that the file was opened.
The new semantic is implemented by extending the FMODE_NONOTIFY bit into two FMODE_NONOTIFY_* bits, that are used to store a mode for which of the events types to report.
This is going to apply to the new fanotify pre-content events in order to reduce the cost of the new pre-content event vfs hooks.
[Thanks to Bert Karwatzki <[email protected]> for reporting a bug in this code with CONFIG_FANOTIFY_ACCESS_PERMISSIONS disabled]
Stable-dep-of: db1856ea9196 ("binfmt_misc: restore write access when removing an entry")
--- fs/notify/fsnotify.c | 38 ++++++++++++++++++++++++++++++++++++++ fs/open.c | 8 +++++++- include/linux/fs.h | 43 ++++++++++++++++++++++++++++++++++++++----- include/linux/fsnotify.h | 39 +++++++++++++++++++++++---------------- 4 files changed, 106 insertions(+), 22 deletions(-)
fs/notify/fsnotify.c +38 -0
@@ -630,6 +630,44 @@ out: }EXPORT_SYMBOL_GPL (fsnotify); +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS +/* +* At open time we check fsnotify_sb_has_priority_watchers() and set the +* FMODE_NONOTIFY_ mode bits accordignly. +* Later, fsnotify permission hooks do not check if there are permission event +* watches, but that there were permission event watches at open time. +*/ +void file_set_fsnotify_mode (struct file *file) +{ +struct super_block *sb = file->f_path.dentry->d_sb; + +/* Is it a file opened by fanotify? */ +if (FMODE_FSNOTIFY_NONE (file->f_mode)) +return ; + +/* +* Permission events is a super set of pre-content events, so if there +* are no permission event watchers, there are also no pre-content event +* watchers and this is implied from the single FMODE_NONOTIFY_PERM bit. +*/ +if (likely (!fsnotify_sb_has_priority_watchers (sb, +FSNOTIFY_PRIO_CONTENT ))) { + file->f_mode |=FMODE_NONOTIFY_PERM ; +return ; + } + +/* +* If there are permission event watchers but no pre-content event +* watchers, set FMODE_NONOTIFY | FMODE_NONOTIFY_PERM to indicate that. +*/ +if (likely (!fsnotify_sb_has_priority_watchers (sb, +FSNOTIFY_PRIO_PRE_CONTENT ))) { + file->f_mode |=FMODE_NONOTIFY |FMODE_NONOTIFY_PERM ; +return ; + } +} +#endif +static __init int fsnotify_init (void ) {int ret;
fs/open.c +7 -1
@@ -912,7 +912,7 @@ static int do_dentry_open(struct file *f f->f_sb_err =file_sample_sb_err (f);if (unlikely (f->f_flags &O_PATH )) { - f->f_mode =FMODE_PATH |FMODE_OPENED ; + f->f_mode =FMODE_PATH |FMODE_OPENED |FMODE_NONOTIFY ; f->f_op = &empty_fops;return 0 ; }
@@ -940,6 +940,12 @@ static int do_dentry_open(struct file *fif (error) goto cleanup_all; +/* +* Set FMODE_NONOTIFY_* bits according to existing permission watches. +* If FMODE_NONOTIFY was already set for an fanotify fd, this doesn't +* change anything. +*/ +file_set_fsnotify_mode (f); error =fsnotify_open_perm (f);if (error) goto cleanup_all;
include/linux/fs.h +38 -5
57 lines not on this page · raw message
include/linux/fsnotify.h +23 -16
@@ -108,38 +108,35 @@ static inline void fsnotify_dentry(strucfsnotify_parent (dentry, mask, dentry,FSNOTIFY_EVENT_DENTRY ); } -static inline int fsnotify_file (struct file *file,__u32 mask) +static inline int fsnotify_path (const struct path *path,__u32 mask) { -const struct path *path; +return fsnotify_parent (path->dentry, mask, path,FSNOTIFY_EVENT_PATH ); +} +static inline int fsnotify_file (struct file *file,__u32 mask) +{/* * FMODE_NONOTIFY are fds generated by fanotify itself which should not * generate new events. We also don't want to generate events for * FMODE_PATH fds (involves open & close events) as they are just * handle creation / destruction events and not "real" file events. */ -if (file->f_mode & (FMODE_NONOTIFY |FMODE_PATH )) +if (FMODE_FSNOTIFY_NONE (file->f_mode))return 0 ; - path = &file->f_path; -/* Permission events require group prio >= FSNOTIFY_PRIO_CONTENT */ -if (mask &ALL_FSNOTIFY_PERM_EVENTS && - !fsnotify_sb_has_priority_watchers (path->dentry->d_sb, -FSNOTIFY_PRIO_CONTENT )) -return 0 ; - -return fsnotify_parent (path->dentry, mask, path,FSNOTIFY_EVENT_PATH ); +return fsnotify_path (&file->f_path, mask); }#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + +void file_set_fsnotify_mode (struct file *file); +/* * fsnotify_file_area_perm - permission hook before access to file range */ static inline int fsnotify_file_area_perm (struct file *file,int perm_mask,const loff_t *ppos,size_t count) { -__u32 fsnotify_mask =FS_ACCESS_PERM ; -/* * filesystem may be modified in the context of permission events * (e.g. by HSM filling a file on access), so sb freeze protection
@@ -150,7 +147,10 @@ static inline int fsnotify_file_area_perif (!(perm_mask &MAY_READ ))return 0 ; -return fsnotify_file (file, fsnotify_mask); +if (likely (!FMODE_FSNOTIFY_PERM (file->f_mode))) +return 0 ; + +return fsnotify_path (&file->f_path,FS_ACCESS_PERM ); }/*
@@ -168,16 +168,23 @@ static inline int fsnotify_open_perm(str {int ret; +if (likely (!FMODE_FSNOTIFY_PERM (file->f_mode))) +return 0 ; +if (file->f_flags & __FMODE_EXEC) { - ret =fsnotify_file (file,FS_OPEN_EXEC_PERM ); + ret =fsnotify_path (&file->f_path,FS_OPEN_EXEC_PERM );if (ret)return ret; } -return fsnotify_file (file,FS_OPEN_PERM ); +return fsnotify_path (&file->f_path,FS_OPEN_PERM ); }#else +static inline void file_set_fsnotify_mode (struct file *file) +{ +} +static inline int fsnotify_file_area_perm (struct file *file,int perm_mask,const loff_t *ppos,size_t count) {
Greg Kroah-Hartman
maintainerPATCH 158/220 fs: dont block write during exec on pre-content watched files
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 0357ef03c94ef835bd44a0658b8edb672a9dbf51 ]
Commit 2a010c412853 ("fs: don't block i_writecount during exec") removed the legacy behavior of getting ETXTBSY on attempt to open and executable file for write while it is being executed.
This commit was reverted because an application that depends on this legacy behavior was broken by the change.
We need to allow HSM writing into executable files while executed to fill their content on-the-fly.
To that end, disable the ETXTBSY legacy behavior for files that are watched by pre-content events.
This change is not expected to cause regressions with existing systems which do not have any pre-content event listeners.
Stable-dep-of: db1856ea9196 ("binfmt_misc: restore write access when removing an entry")
--- fs/binfmt_elf.c | 4 ++-- fs/binfmt_elf_fdpic.c | 4 ++-- fs/exec.c | 8 ++++---- include/linux/fs.h | 22 ++++++++++++++++++++++ kernel/fork.c | 12 ++++++------ 5 files changed, 36 insertions(+), 14 deletions(-)
fs/binfmt_elf.c +2 -2
@@ -1257,7 +1257,7 @@ out_free_interp: } reloc_func_desc = interp_load_addr; -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter);kfree (interp_elf_ex);
@@ -1371,7 +1371,7 @@ out_free_dentry:kfree (interp_elf_ex);kfree (interp_elf_phdata); out_free_file: -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);if (interpreter)fput (interpreter); out_free_ph:
fs/binfmt_elf_fdpic.c +2 -2
@@ -398,7 +398,7 @@ static int load_elf_fdpic_binary(struct goto error; } -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter); interpreter =NULL ; }
@@ -471,7 +471,7 @@ static int load_elf_fdpic_binary(struct error:if (interpreter) { -allow_write_access (interpreter); +exe_file_allow_write_access (interpreter);fput (interpreter); }kfree (interpreter_name);
fs/exec.c +4 -4
@@ -912,7 +912,7 @@ static struct file *do_open_execat(int f path_noexec(&file->f_path))return ERR_PTR (-EACCES ); - err =deny_write_access (file); + err =exe_file_deny_write_access (file);if (err)return ERR_PTR (err);
@@ -927,7 +927,7 @@ static struct file *do_open_execat(int f* Returns ERR_PTR on failure or allocated struct file on success. * * As this is a wrapper for the internal do_open_execat(), callers -* must call allow_write_access() before fput() on release. Also see +* must call exe_file_allow_write_access() before fput() on release. Also see * do_close_execat(). */ struct file *open_exec (const char *name)
@@ -1501,7 +1501,7 @@ static void do_close_execat(struct file {if (!file)return ; -allow_write_access (file); +exe_file_allow_write_access (file);fput (file); }
@@ -1835,7 +1835,7 @@ static int exec_binprm(struct linux_binp bprm->file = bprm->interpreter; bprm->interpreter =NULL ; -allow_write_access (exec); +exe_file_allow_write_access (exec);if (unlikely (bprm->have_execfd)) {if (bprm->executable) {fput (exec);
include/linux/fs.h +22 -0
@@ -3085,6 +3085,28 @@ static inline void allow_write_access(stif (file)atomic_inc (&file_inode (file)->i_writecount); } + +/* +* Do not prevent write to executable file when watched by pre-content events. +* +* Note that FMODE_FSNOTIFY_HSM mode is set depending on pre-content watches at +* the time of file open and remains constant for entire lifetime of the file, +* so if pre-content watches are added post execution or removed before the end +* of the execution, it will not cause i_writecount reference leak. +*/ +static inline int exe_file_deny_write_access (struct file *exe_file) +{ +if (unlikely (FMODE_FSNOTIFY_HSM (exe_file->f_mode))) +return 0 ; +return deny_write_access (exe_file); +} +static inline void exe_file_allow_write_access (struct file *exe_file) +{ +if (unlikely (!exe_file ||FMODE_FSNOTIFY_HSM (exe_file->f_mode))) +return ; +allow_write_access (exe_file); +} +static inline bool inode_is_open_for_write (const struct inode *inode) {return atomic_read (&inode->i_writecount) >0 ;
kernel/fork.c +6 -6
@@ -627,8 +627,8 @@ static void dup_mm_exe_file(struct mm_st* We depend on the oldmm having properly denied write access to the * exe_file already. */ -if (exe_file &&deny_write_access (exe_file)) -pr_warn_once ("deny_write_access() failed in %s\n" , __func__); +if (exe_file &&exe_file_deny_write_access (exe_file)) +pr_warn_once ("exe_file_deny_write_access() failed in %s\n" , __func__); }#ifdef CONFIG_MMU
@@ -1439,13 +1439,13 @@ int set_mm_exe_file(struct mm_struct *mm* We expect the caller (i.e., sys_execve) to already denied * write access, so this is unlikely to fail. */ -if (unlikely (deny_write_access (new_exe_file))) +if (unlikely (exe_file_deny_write_access (new_exe_file)))return -EACCES ;get_file (new_exe_file); }rcu_assign_pointer (mm->exe_file, new_exe_file);if (old_exe_file) { -allow_write_access (old_exe_file); +exe_file_allow_write_access (old_exe_file);fput (old_exe_file); }return 0 ;
@@ -1486,7 +1486,7 @@ int replace_mm_exe_file(struct mm_structreturn ret; } - ret =deny_write_access (new_exe_file); + ret =exe_file_deny_write_access (new_exe_file);if (ret)return -EACCES ;get_file (new_exe_file);
@@ -1498,7 +1498,7 @@ int replace_mm_exe_file(struct mm_structmmap_write_unlock (mm);if (old_exe_file) { -allow_write_access (old_exe_file); +exe_file_allow_write_access (old_exe_file);fput (old_exe_file); }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 159/220 binfmt_misc: restore write access when removing an entry
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit db1856ea9196cf6e015d12199a34c0b9313c7bfa ]
Registering an entry with the MISC_FMT_OPEN_FILE flag opens the interpreter via open_exec() which denies write access to it for as long as the entry exists. Removing the entry closes the interpreter file via filp_close() but never restores write access, leaving the inode's i_writecount permanently negative. Opening the interpreter for writing keeps failing with ETXTBSY long after the entry is gone until the inode is evicted from the inode cache.
Commit 90f601b497d7 ("binfmt_misc: restore write access before closing files opened by open_exec()") fixed the same imbalance in the error path of bm_register_write() but the actual removal path has been leaking the write denial since the introduction of the flag.
Restore write access in put_binfmt_handler() before closing the interpreter file.
--- fs/binfmt_misc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/binfmt_misc.c +3 -1
@@ -161,8 +161,10 @@ static Node *get_binfmt_handler(struct bstatic void put_binfmt_handler (Node *e) {if (refcount_dec_and_test (&e->users)) { -if (e->flags &MISC_FMT_OPEN_FILE ) +if (e->flags &MISC_FMT_OPEN_FILE ) { +exe_file_allow_write_access (e->interp_file);filp_close (e->interp_file,NULL ); + }kfree (e); } }
Greg Kroah-Hartman
maintainerPATCH 160/220 vrf: Make pcpu_dstats update functions available to other modules.
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Nault <[email protected]>
[ Upstream commit 18eabadd73ae60023ab05e376246bd725fb0c113 ]
Currently vrf is the only module that uses NETDEV_PCPU_STAT_DSTATS. In order to make this kind of statistics available to other modules, we need to define the update functions in netdevice.h.
Therefore, let's define dev_dstats_*() functions for RX and TX packet updates (packets, bytes and drops). Use these new functions in vrf.c instead of vrf_rx_stats() and the other manual counter updates.
While there, update the type of the "len" variables to "unsigned int", so that there're aligned with both skb->len and the new dstats update functions.
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vrf.c | 49 +++++++++++++--------------------------------- include/linux/netdevice.h | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 35 deletions(-)
drivers/net/vrf.c +14 -35
@@ -122,16 +122,6 @@ struct net_vrf {int ifindex; }; -static void vrf_rx_stats (struct net_device *dev,int len) -{ -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -u64_stats_update_begin (&dstats->syncp); -u64_stats_inc (&dstats->rx_packets); -u64_stats_add (&dstats->rx_bytes, len); -u64_stats_update_end (&dstats->syncp); -} -static void vrf_tx_error (struct net_device *vrf_dev,struct sk_buff *skb) { vrf_dev->stats.tx_errors++;
@@ -367,7 +357,7 @@ static bool qdisc_tx_is_default(const ststatic int vrf_local_xmit (struct sk_buff *skb,struct net_device *dev,struct dst_entry *dst) { -int len = skb->len; +unsigned int len = skb->len;skb_orphan (skb);
@@ -380,15 +370,10 @@ static int vrf_local_xmit(struct sk_buff skb->protocol =eth_type_trans (skb, dev); -if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) { -vrf_rx_stats (dev, len); - }else { -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -u64_stats_update_begin (&dstats->syncp); -u64_stats_inc (&dstats->rx_drops); -u64_stats_update_end (&dstats->syncp); - } +if (likely (__netif_rx (skb) ==NET_RX_SUCCESS )) +dev_dstats_rx_add (dev, len); +else +dev_dstats_rx_dropped (dev);return NETDEV_TX_OK ; }
@@ -576,20 +561,14 @@ static netdev_tx_t is_ip_tx_frame(structstatic netdev_tx_t vrf_xmit (struct sk_buff *skb,struct net_device *dev) { -struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); - -int len = skb->len; -netdev_tx_t ret =is_ip_tx_frame (skb, dev); - -u64_stats_update_begin (&dstats->syncp); -if (likely (ret ==NET_XMIT_SUCCESS || ret ==NET_XMIT_CN )) { +unsigned int len = skb->len; +netdev_tx_t ret; -u64_stats_inc (&dstats->tx_packets); -u64_stats_add (&dstats->tx_bytes, len); - }else { -u64_stats_inc (&dstats->tx_drops); - } -u64_stats_update_end (&dstats->syncp); + ret =is_ip_tx_frame (skb, dev); +if (likely (ret ==NET_XMIT_SUCCESS || ret ==NET_XMIT_CN )) +dev_dstats_tx_add (dev, len); +else +dev_dstats_tx_dropped (dev);return ret; }
@@ -1371,7 +1350,7 @@ static struct sk_buff *vrf_ip6_rcv(strucif (!is_ndisc) {struct net_device *orig_dev = skb->dev; -vrf_rx_stats (vrf_dev, skb->len); +dev_dstats_rx_add (vrf_dev, skb->len); skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex;
@@ -1427,7 +1406,7 @@ static struct sk_buff *vrf_ip_rcv(struct goto out; } -vrf_rx_stats (vrf_dev, skb->len); +dev_dstats_rx_add (vrf_dev, skb->len);if (!list_empty (&vrf_dev->ptype_all)) {int err;
include/linux/netdevice.h +40 -0
@@ -2793,6 +2793,46 @@ static inline void dev_lstats_add(structu64_stats_update_end (&lstats->syncp); } +static inline void dev_dstats_rx_add (struct net_device *dev, +unsigned int len) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->rx_packets); +u64_stats_add (&dstats->rx_bytes, len); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_rx_dropped (struct net_device *dev) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->rx_drops); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_tx_add (struct net_device *dev, +unsigned int len) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->tx_packets); +u64_stats_add (&dstats->tx_bytes, len); +u64_stats_update_end (&dstats->syncp); +} + +static inline void dev_dstats_tx_dropped (struct net_device *dev) +{ +struct pcpu_dstats *dstats =this_cpu_ptr (dev->dstats); + +u64_stats_update_begin (&dstats->syncp); +u64_stats_inc (&dstats->tx_drops); +u64_stats_update_end (&dstats->syncp); +} +#define __netdev_alloc_pcpu_stats (type, gfp) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\
Greg Kroah-Hartman
maintainerPATCH 161/220 vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Nault <[email protected]>
[ Upstream commit be226352e8dc77d3313c096b2d8e7f69bf6980fc ]
VXLAN uses the TSTATS infrastructure (dev_sw_netstats_*()) for RX and TX packet counters. It also uses the device core stats (dev_core_stats_*()) for RX and TX drops.
Let's consolidate that using the DSTATS infrastructure, which can handle both packet counters and packet drops. Statistics that don't fit DSTATS are still updated atomically with DEV_STATS_INC().
While there, convert the "len" variable of vxlan_encap_bypass() to unsigned int, to respect the types of skb->len and dev_dstats_[rt]x_add().
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
--- drivers/net/vxlan/vxlan_core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/net/vxlan/vxlan_core.c +14 -14
@@ -1814,14 +1814,14 @@ static int vxlan_rcv(struct sock *sk, stif (unlikely (!(vxlan->dev->flags &IFF_UP ))) {rcu_read_unlock (); -dev_core_stats_rx_dropped_inc (vxlan->dev); +dev_dstats_rx_dropped (vxlan->dev);vxlan_vnifilter_count (vxlan, vni, vninode,VXLAN_VNI_STATS_RX_DROPS ,0 ); reason =SKB_DROP_REASON_DEV_READY ; goto drop; } -dev_sw_netstats_rx_add (vxlan->dev, skb->len); +dev_dstats_rx_add (vxlan->dev, skb->len);vxlan_vnifilter_count (vxlan, vni, vninode,VXLAN_VNI_STATS_RX , skb->len);gro_cells_receive (&vxlan->gro_cells, skb);
@@ -1876,7 +1876,7 @@ static int arp_reduce(struct net_device goto out;if (!pskb_may_pull (skb,arp_hdr_len (dev))) { -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 ); goto out;
@@ -1940,7 +1940,7 @@ static int arp_reduce(struct net_device reply->pkt_type =PACKET_HOST ;if (netif_rx (reply) ==NET_RX_DROP ) { -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2104,7 +2104,7 @@ static int neigh_reduce(struct net_devic goto out;if (netif_rx (reply) ==NET_RX_DROP ) { -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2289,8 +2289,8 @@ static void vxlan_encap_bypass(struct sk {union vxlan_addr loopback;union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip; +unsigned int len = skb->len;struct net_device *dev; -int len = skb->len; skb->pkt_type =PACKET_HOST ; skb->encapsulation =0 ;
@@ -2317,16 +2317,16 @@ static void vxlan_encap_bypass(struct skif ((dst_vxlan->cfg.flags &VXLAN_F_LEARN ) && snoop)vxlan_snoop (dev, &loopback,eth_hdr (skb)->h_source,0 , vni); -dev_sw_netstats_tx_add (src_vxlan->dev,1 , len); +dev_dstats_tx_add (src_vxlan->dev, len);vxlan_vnifilter_count (src_vxlan, vni,NULL ,VXLAN_VNI_STATS_TX , len);if (__netif_rx (skb) ==NET_RX_SUCCESS ) { -dev_sw_netstats_rx_add (dst_vxlan->dev, len); +dev_dstats_rx_add (dst_vxlan->dev, len);vxlan_vnifilter_count (dst_vxlan, vni,NULL ,VXLAN_VNI_STATS_RX , len); }else { drop: -dev_core_stats_rx_dropped_inc (dev); +dev_dstats_rx_dropped (dev);vxlan_vnifilter_count (dst_vxlan, vni,NULL ,VXLAN_VNI_STATS_RX_DROPS ,0 ); }
@@ -2630,7 +2630,7 @@ out_unlock:return ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);return ;
@@ -2671,7 +2671,7 @@ static void vxlan_xmit_nh(struct sk_buffreturn ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (netdev_priv (dev), vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);
@@ -2709,7 +2709,7 @@ static netdev_tx_t vxlan_xmit_nhid(strucreturn NETDEV_TX_OK ; drop: -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (netdev_priv (dev), vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );dev_kfree_skb (skb);
@@ -2808,7 +2808,7 @@ static netdev_tx_t vxlan_xmit(struct sk_ !is_multicast_ether_addr(eth->h_dest))vxlan_fdb_miss (vxlan, eth->h_dest); -dev_core_stats_tx_dropped_inc (dev); +dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );kfree_skb_reason (skb,SKB_DROP_REASON_NO_TX_TARGET );
@@ -3383,7 +3383,7 @@ static void vxlan_setup(struct net_devic dev->min_mtu =ETH_MIN_MTU ; dev->max_mtu =ETH_MAX_MTU ; - dev->pcpu_stat_type =NETDEV_PCPU_STAT_TSTATS ; + dev->pcpu_stat_type =NETDEV_PCPU_STAT_DSTATS ;INIT_LIST_HEAD (&vxlan->next);timer_setup (&vxlan->age_timer, vxlan_cleanup,TIMER_DEFERRABLE );
Greg Kroah-Hartman
maintainerPATCH 162/220 vxlan: use pskb_network_may_pull() for transmit path header pulls
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit b9553558b48db54ac9273e6b98d7263ef5c1a329 ]
In vxlan_xmit(), arp_reduce(), and vxlan_mdb_entry_skb_get(), pskb_may_pull() was being called to verify the availability of network layer headers (ARP, IPv6/ND, IP/IPv6 MDB keys).
However, during transmit skb->data points to the MAC header, so skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, len) only checks len bytes from skb->data rather than skb_network_offset(skb) + len, which can leave part of the network header in non-linear frags.
Replace these remaining pskb_may_pull() calls with pskb_network_may_pull() to properly account for the MAC header offset.
--- drivers/net/vxlan/vxlan_core.c | 6 +++--- drivers/net/vxlan/vxlan_mdb.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/vxlan/vxlan_core.c +3 -3
@@ -1875,7 +1875,7 @@ static int arp_reduce(struct net_deviceif (dev->flags &IFF_NOARP ) goto out; -if (!pskb_may_pull (skb,arp_hdr_len (dev))) { +if (!pskb_network_may_pull (skb,arp_hdr_len (dev))) {dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );
@@ -2757,8 +2757,8 @@ static netdev_tx_t vxlan_xmit(struct sk_return arp_reduce (dev, skb, vni); #if IS_ENABLED(CONFIG_IPV6) else if (ntohs(eth->h_proto) == ETH_P_IPV6 && - pskb_may_pull(skb, sizeof(struct ipv6hdr) + - sizeof(struct nd_msg)) && + pskb_network_may_pull(skb, sizeof(struct ipv6hdr) + + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {struct nd_msg *m = (struct nd_msg *)(ipv6_hdr (skb) +1 );
drivers/net/vxlan/vxlan_mdb.c +2 -2
@@ -1631,7 +1631,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_switch (skb->protocol) {case htons (ETH_P_IP ): -if (!pskb_may_pull (skb,sizeof (struct iphdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct iphdr )))return NULL ; group.dst.sa.sa_family =AF_INET ; group.dst.sin.sin_addr.s_addr =ip_hdr (skb)->daddr;
@@ -1640,7 +1640,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_break ;#if IS_ENABLED (CONFIG_IPV6 )case htons (ETH_P_IPV6 ): -if (!pskb_may_pull (skb,sizeof (struct ipv6hdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct ipv6hdr )))return NULL ; group.dst.sa.sa_family =AF_INET6 ; group.dst.sin6.sin6_addr =ipv6_hdr (skb)->daddr;
Greg Kroah-Hartman
maintainerPATCH 163/220 ice: fix VF interrupts cleanup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Osuchowski <[email protected]>
[ Upstream commit fb096882095e5a8d6b5159e43793d4a38a0c5b1f ]
When a virtual function sends an IRQ map command, the PF will set up interrupts according to that request. However, because these interrupts are never reset, the next time Virtual Function initializes, the interrupts are still enabled for a given VF, which leads to performance degradation in certain cases due to interrupts being unexpectedly enabled and thus causing interrupt floods.
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 27 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_vf_lib_private.h | 1 drivers/net/ethernet/intel/ice/ice_virtchnl.c | 21 +++++++++++++++ 3 files changed, 49 insertions(+)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +27 -0
@@ -848,6 +848,30 @@ static void ice_notify_vf_reset(struct i }/** +* ice_reset_interrupts - clear all queue interrupt configuration for a VSI +* @vsi: the VSI whose interrupt registers should be cleared +* +* Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues +* in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX, +* CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only +* clears the CAUSE_ENA bit. +*/ +void ice_reset_interrupts (struct ice_vsi *vsi) +{ +struct ice_pf *pf = vsi->back; +struct ice_hw *hw = &pf->hw; +int i; + +ice_for_each_alloc_rxq (vsi, i) +wr32 (hw,QINT_RQCTL (vsi->rxq_map[i]),0 ); + +ice_for_each_alloc_txq (vsi, i) +wr32 (hw,QINT_TQCTL (vsi->txq_map[i]),0 ); + +ice_flush (hw); +} + +/** * ice_reset_vf - Reset a particular VF * @vf: pointer to the VF structure * @flags: flags controlling behavior of the reset
@@ -929,6 +953,9 @@ int ice_reset_vf(struct ice_vf *vf, u32ice_dis_vf_qs (vf); +/* cleanup interrupt registers */ +ice_reset_interrupts (vsi); +/* Call Disable LAN Tx queue AQ whether or not queues are * enabled. This is needed for successful completion of VFR. */
drivers/net/ethernet/intel/ice/ice_vf_lib_private.h +1 -0
@@ -26,6 +26,7 @@void ice_initialize_vf_entry (struct ice_vf *vf);void ice_deinitialize_vf_entry (struct ice_vf *vf);void ice_dis_vf_qs (struct ice_vf *vf); +void ice_reset_interrupts (struct ice_vsi *vsi);int ice_check_vf_init (struct ice_vf *vf);enum virtchnl_status_code ice_err_to_virt_err (int err);struct ice_port_info *ice_vf_get_port_info (struct ice_vf *vf);
drivers/net/ethernet/intel/ice/ice_virtchnl.c +21 -0
@@ -1278,6 +1278,24 @@ static void ice_vf_ena_rxq_interrupt(str }/** +* ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL +* @vsi: VSI of the VF to configure +* @q_idx: VF queue index used to determine the queue in the PF's space +*/ +static void ice_vf_dis_rxq_interrupt (struct ice_vsi *vsi,u32 q_idx) +{ +struct ice_hw *hw = &vsi->back->hw; +u32 pfq = vsi->rxq_map[q_idx]; +u32 reg; + + reg =rd32 (hw,QINT_RQCTL (pfq)); + reg &= ~QINT_RQCTL_CAUSE_ENA_M ; +wr32 (hw,QINT_RQCTL (pfq), reg); + +ice_flush (hw); +} + +/** * ice_vc_ena_qs_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer
@@ -1470,6 +1488,8 @@ static int ice_vc_dis_qs_msg(struct ice_ goto error_param; } +for_each_set_bit (vf_q_id, &q_map,ICE_MAX_RSS_QS_PER_VF ) +ice_vf_dis_rxq_interrupt (vsi, vf_q_id);bitmap_zero (vf->rxq_ena,ICE_MAX_RSS_QS_PER_VF ); }else if (q_map) {for_each_set_bit (vf_q_id, &q_map,ICE_MAX_RSS_QS_PER_VF ) {
@@ -1490,6 +1510,7 @@ static int ice_vc_dis_qs_msg(struct ice_ goto error_param; } +ice_vf_dis_rxq_interrupt (vsi, vf_q_id);/* Clear enabled queues flag */ clear_bit (vf_q_id, vf->rxq_ena); }
Greg Kroah-Hartman
maintainerPATCH 164/220 include/linux/fs.h: add inode_lock_killable()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
[ Upstream commit d8c5507cd140d9471472ece673e70250b957c595 ]
Prepare for making inode operations killable while they're waiting for the lock.
Stable-dep-of: fa724e235cfd ("cifs: add fscache_resize_cookie() to cifs_setsize()")
--- include/linux/fs.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
include/linux/fs.h +10 -0
@@ -848,6 +848,11 @@ static inline void inode_lock(struct inodown_write (&inode->i_rwsem); } +static inline __must_check int inode_lock_killable (struct inode *inode) +{ +return down_write_killable (&inode->i_rwsem); +} +static inline void inode_unlock (struct inode *inode) {up_write (&inode->i_rwsem);
@@ -858,6 +863,11 @@ static inline void inode_lock_shared(strdown_read (&inode->i_rwsem); } +static inline __must_check int inode_lock_shared_killable (struct inode *inode) +{ +return down_read_killable (&inode->i_rwsem); +} +static inline void inode_unlock_shared (struct inode *inode) {up_read (&inode->i_rwsem);
Greg Kroah-Hartman
maintainerPATCH 165/220 smb: client: fix race with fallocate(2) and AIO+DIO
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit dba9f997c9d9a1cade05d006ed0429a63a4eed32 ]
AIO+DIO may extend the file size, hence we need to make sure ->i_size is stable across the entire fallocate(2) operation, otherwise it would become a truncate and then inode size reduced back down when it finishes.
Fix this by calling netfs_wait_for_outstanding_io() right after acquiring ->i_rwsem exclusively in cifs_fallocate() and then guarantee a stable ->i_size across fallocate(2).
Also call netfs_wait_for_outstanding_io() after truncating pagecache to avoid any potential races with writeback.
Stable-dep-of: fa724e235cfd ("cifs: add fscache_resize_cookie() to cifs_setsize()")
--- fs/smb/client/cifsfs.c | 22 +++++++++++++++++++--- fs/smb/client/inode.c | 1 + fs/smb/client/smb2ops.c | 18 ++++++------------ 3 files changed, 26 insertions(+), 15 deletions(-)
fs/smb/client/cifsfs.c +19 -3
@@ -359,11 +359,27 @@ static long cifs_fallocate(struct file *struct cifs_sb_info *cifs_sb =CIFS_FILE_SB (file);struct cifs_tcon *tcon =cifs_sb_master_tcon (cifs_sb);struct TCP_Server_Info *server = tcon->ses->server; +struct inode *inode =file_inode (file); +int rc; -if (server->ops->fallocate) -return server->ops->fallocate (file, tcon, mode, off, len); +if (!server->ops->fallocate) +return -EOPNOTSUPP ; -return -EOPNOTSUPP ; + rc =inode_lock_killable (inode); +if (rc) +return rc; + +netfs_wait_for_outstanding_io (inode); + + rc =file_modified (file); +if (rc) + goto out_unlock; + + rc = server->ops->fallocate (file, tcon, mode, off, len); + +out_unlock: +inode_unlock (inode); +return rc; } static int cifs_permission(struct mnt_idmap *idmap,
fs/smb/client/inode.c +1 -0
@@ -2965,6 +2965,7 @@ void cifs_setsize(struct inode *inode, l/* Cached inode must be refreshed on truncate */ cifs_i->time =0 ;truncate_pagecache (inode, offset); +netfs_wait_for_outstanding_io (inode); } static int
fs/smb/client/smb2ops.c +6 -12
@@ -3315,7 +3315,6 @@ static long smb3_zero_range(struct filetrace_smb3_zero_enter (xid, cfile->fid.persistent_fid, tcon->tid, ses->Suid, offset, len); -inode_lock (inode);filemap_invalidate_lock (inode->i_mapping); i_size =i_size_read (inode);
@@ -3333,6 +3332,7 @@ static long smb3_zero_range(struct file* first, otherwise the data may be inconsistent with the server. */ truncate_pagecache_range (inode, offset, offset + len -1 ); +netfs_wait_for_outstanding_io (inode);/* if file not oplocked can't be sure whether asking to extend size */ rc = -EOPNOTSUPP ;
@@ -3361,7 +3361,6 @@ static long smb3_zero_range(struct file zero_range_exit:filemap_invalidate_unlock (inode->i_mapping); -inode_unlock (inode);free_xid (xid);if (rc) trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
@@ -3385,7 +3384,6 @@ static long smb3_punch_hole(struct file xid =get_xid (); -inode_lock (inode);/* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ rc =smb2_set_sparse (xid, tcon, cfile, inode, set_sparse);
@@ -3398,6 +3396,7 @@ static long smb3_punch_hole(struct file* caches first, otherwise the data may be inconsistent with the server. */ truncate_pagecache_range (inode, offset, offset + len -1 ); +netfs_wait_for_outstanding_io (inode);cifs_dbg (FYI ,"Offset %lld len %lld\n" , offset, len);
@@ -3432,7 +3431,6 @@ static long smb3_punch_hole(struct file unlock:filemap_invalidate_unlock (inode->i_mapping); out: -inode_unlock (inode);free_xid (xid);return rc; }
@@ -3709,8 +3707,6 @@ static long smb3_collapse_range(struct f xid =get_xid (); -inode_lock (inode); - old_eof =i_size_read (inode);if ((off >= old_eof) || off + len >= old_eof) {
@@ -3725,6 +3721,7 @@ static long smb3_collapse_range(struct ftruncate_pagecache_range (inode, off, old_eof); ictx->zero_point = old_eof; +netfs_wait_for_outstanding_io (inode); rc =smb2_copychunk_range (xid, cfile, cfile, off + len, old_eof - off - len, off);
@@ -3745,8 +3742,7 @@ static long smb3_collapse_range(struct ffscache_resize_cookie (cifs_inode_cookie (inode), new_eof); out_2:filemap_invalidate_unlock (inode->i_mapping); - out: -inode_unlock (inode); +out:free_xid (xid);return rc; }
@@ -3763,8 +3759,6 @@ static long smb3_insert_range(struct fil xid =get_xid (); -inode_lock (inode); - old_eof =i_size_read (inode);if (off >= old_eof) { rc = -EINVAL ;
@@ -3779,6 +3773,7 @@ static long smb3_insert_range(struct filif (rc <0 ) goto out_2;truncate_pagecache_range (inode, off, old_eof); +netfs_wait_for_outstanding_io (inode); rc =SMB2_set_eof (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, cfile->pid, new_eof);
@@ -3801,8 +3796,7 @@ static long smb3_insert_range(struct fil rc =0 ; out_2:filemap_invalidate_unlock (inode->i_mapping); - out: -inode_unlock (inode); +out:free_xid (xid);return rc; }
Greg Kroah-Hartman
maintainerPATCH 166/220 cifs: add fscache_resize_cookie() to cifs_setsize()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <[email protected]>
[ Upstream commit fa724e235cfdb0fb0bb427d0f9dfe864ae27403e ]
Several code paths update the VFS inode size by calling netfs_resize_file() and cifs_setsize(), but omit the corresponding fscache_resize_cookie() call, leaving the fscache cookie out of sync with the actual file size:
- cifs_file_set_size() in inode.c: server-side truncation via setattr
- cifs_do_truncate() in file.c: truncates to zero on O_TRUNC open
- smb2_duplicate_extents() in smb2ops.c: file clone extending EOF
- smb3_simple_falloc() in smb2ops.c: two branches that extend EOF via write-range and SMB2_set_eof respectively
Since every caller of cifs_setsize() must resize the fscache cookie, add the call to cifs_setsize() itself, consistent with how truncate_pagecache() is already consolidated there.
--- fs/smb/client/inode.c | 1 + 1 file changed, 1 insertion(+)
fs/smb/client/inode.c +1 -0
@@ -2966,6 +2966,7 @@ void cifs_setsize(struct inode *inode, l cifs_i->time =0 ;truncate_pagecache (inode, offset);netfs_wait_for_outstanding_io (inode); +fscache_resize_cookie (cifs_inode_cookie (inode), offset); } static int
Greg Kroah-Hartman
maintainerPATCH 167/220 can: rcar_canfd: change the initializing flow for clocks and resets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tu Nguyen <[email protected]>
[ Upstream commit bef9004c5b91debfceaea2841855a4ebe81ff2b3 ]
Testing CANFD on RZ/G3E shows that many registers do not reset to their initial values with the current flow of deasserting resets first and then enabling clocks.
Based on the HW manual, clocks should be supplied first and the resets deasserted afterward.
section 7.4.3 Procedure for Activating Modules: RZ/G2L section 4.4.9.3 Procedure for Starting up Units: RZ/G3E
So, update the order of the initializing flow for resets and clocks to match the hardware manual, resetting all CANFD registers to their initial values. Also update rcar_canfd_global_deinit() to assert resets before disabling clocks, so the teardown path mirrors the new init ordering.
--- drivers/net/can/rcar/rcar_canfd.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/net/can/rcar/rcar_canfd.c +14 -14
@@ -1989,27 +1989,27 @@ static int rcar_canfd_probe(struct platf } } - err =reset_control_reset (gpriv->rstc1); -if (err) - goto fail_dev; - err =reset_control_reset (gpriv->rstc2); -if (err) { -reset_control_assert (gpriv->rstc1); - goto fail_dev; - } -/* Enable peripheral clock for register access */ err =clk_prepare_enable (gpriv->clkp);if (err) {dev_err (dev,"failed to enable peripheral clock: %pe\n" ,ERR_PTR (err)); - goto fail_reset; + goto fail_dev; + } + + err =reset_control_reset (gpriv->rstc1); +if (err) + goto fail_clk; + err =reset_control_reset (gpriv->rstc2); +if (err) { +reset_control_assert (gpriv->rstc1); + goto fail_clk; } err =rcar_canfd_reset_controller (gpriv);if (err) {dev_err (dev,"reset controller failed: %pe\n" ,ERR_PTR (err)); - goto fail_clk; + goto fail_reset; }/* Controller in Global reset & Channel reset mode */
@@ -2061,11 +2061,11 @@ fail_channel:rcar_canfd_channel_remove (gpriv, ch); fail_mode:rcar_canfd_disable_global_interrupts (gpriv); -fail_clk: -clk_disable_unprepare (gpriv->clkp); fail_reset:reset_control_assert (gpriv->rstc1);reset_control_assert (gpriv->rstc2); +fail_clk: +clk_disable_unprepare (gpriv->clkp); fail_dev:return err; }
@@ -2085,9 +2085,9 @@ static void rcar_canfd_remove(struct pla/* Enter global sleep mode */ rcar_canfd_set_bit (gpriv->base,RCANFD_GCTR ,RCANFD_GCTR_GSLPR ); -clk_disable_unprepare (gpriv->clkp);reset_control_assert (gpriv->rstc1);reset_control_assert (gpriv->rstc2); +clk_disable_unprepare (gpriv->clkp); }static int __maybe_unused rcar_canfd_suspend (struct device *dev)
Greg Kroah-Hartman
maintainerPATCH 168/220 drm/amd/pm: Use same metric table for APU
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 56cbb36696407a27cfbfdbc2dee0b1e206178cec ]
Use same metric table for APU and Non APU systems for smu_v_13_0_6 to get metric data based on newer pmfw versions
v2: Use inline func to check for unified metrics support
Stable-dep-of: 048f4541b71f ("drm/amd/pm: fix torn gpu metrics reads")
--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 102 ++++++++++--------- 1 file changed, 55 insertions(+), 47 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +55 -47
@@ -102,6 +102,12 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin"#define MCA_BANK_IPID (_ip, _hwid, _type) \ [AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, } +static inline bool smu_v13_0_6_is_unified_metrics (struct smu_context *smu) +{ +return (smu->adev->flags &AMD_IS_APU ) && + smu->smc_fw_version <=0x4556900 ; +} +struct mca_bank_ipid {enum amdgpu_mca_ip ip;uint16_t hwid;
@@ -253,7 +259,7 @@ struct PPTable_t {#define SMUQ10_TO_UINT (x) ((x) >> 10)#define SMUQ10_FRAC (x) ((x) & 0x3ff)#define SMUQ10_ROUND (x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) -#define GET_METRIC_FIELD (field) ((adev->flags & AMD_IS_APU) ?\ +#define GET_METRIC_FIELD (field, flag) ((flag) ?\ (metrics_a->field) : (metrics_x->field))struct smu_v13_0_6_dpm_map {
@@ -584,7 +590,7 @@ static int smu_v13_0_6_setup_driver_pptaMetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table;struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; -struct amdgpu_device *adev = smu->adev; +bool flag =smu_v13_0_6_is_unified_metrics (smu);int ret, i, retry =100 ;uint32_t table_version;
@@ -596,7 +602,7 @@ static int smu_v13_0_6_setup_driver_pptareturn ret;/* Ensure that metrics have been updated */ -if (GET_METRIC_FIELD (AccumulationCounter)) +if (GET_METRIC_FIELD (AccumulationCounter, flag))break ;usleep_range (1000 ,1100 );
@@ -613,29 +619,29 @@ static int smu_v13_0_6_setup_driver_ppta table_version; pptable->MaxSocketPowerLimit = -SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketPowerLimit)); +SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketPowerLimit, flag)); pptable->MaxGfxclkFrequency = -SMUQ10_ROUND (GET_METRIC_FIELD (MaxGfxclkFrequency)); +SMUQ10_ROUND (GET_METRIC_FIELD (MaxGfxclkFrequency, flag)); pptable->MinGfxclkFrequency = -SMUQ10_ROUND (GET_METRIC_FIELD (MinGfxclkFrequency)); +SMUQ10_ROUND (GET_METRIC_FIELD (MinGfxclkFrequency, flag));for (i =0 ; i <4 ; ++i) { pptable->FclkFrequencyTable[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (FclkFrequencyTable)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (FclkFrequencyTable, flag)[i]); pptable->UclkFrequencyTable[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequencyTable)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequencyTable, flag)[i]); pptable->SocclkFrequencyTable[i] =SMUQ10_ROUND ( -GET_METRIC_FIELD (SocclkFrequencyTable)[i]); +GET_METRIC_FIELD (SocclkFrequencyTable, flag)[i]); pptable->VclkFrequencyTable[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequencyTable)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequencyTable, flag)[i]); pptable->DclkFrequencyTable[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequencyTable)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequencyTable, flag)[i]); pptable->LclkFrequencyTable[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (LclkFrequencyTable)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (LclkFrequencyTable, flag)[i]); }/* use AID0 serial number by default */ - pptable->PublicSerialNumber_AID =GET_METRIC_FIELD (PublicSerialNumber_AID)[0 ]; + pptable->PublicSerialNumber_AID =GET_METRIC_FIELD (PublicSerialNumber_AID, flag)[0 ]; pptable->Init = true; }
@@ -958,6 +964,7 @@ static int smu_v13_0_6_get_smu_metrics_dstruct smu_table_context *smu_table = &smu->smu_table;MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table;MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table; +bool flag =smu_v13_0_6_is_unified_metrics (smu);struct amdgpu_device *adev = smu->adev;int ret =0 ;int xcc_id;
@@ -972,50 +979,50 @@ static int smu_v13_0_6_get_smu_metrics_dcase METRICS_AVERAGE_GFXCLK :if (smu->smc_fw_version >=0x552F00 ) { xcc_id =GET_INST (GC ,0 ); - *value =SMUQ10_ROUND (GET_METRIC_FIELD (GfxclkFrequency)[xcc_id]); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (GfxclkFrequency, flag)[xcc_id]); }else { *value =0 ; }break ;case METRICS_CURR_SOCCLK :case METRICS_AVERAGE_SOCCLK : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocclkFrequency)[0 ]); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocclkFrequency, flag)[0 ]);break ;case METRICS_CURR_UCLK :case METRICS_AVERAGE_UCLK : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequency)); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequency, flag));break ;case METRICS_CURR_VCLK : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequency)[0 ]); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequency, flag)[0 ]);break ;case METRICS_CURR_DCLK : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequency)[0 ]); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequency, flag)[0 ]);break ;case METRICS_CURR_FCLK : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (FclkFrequency)); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (FclkFrequency, flag));break ;case METRICS_AVERAGE_GFXACTIVITY : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusy)); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusy, flag));break ;case METRICS_AVERAGE_MEMACTIVITY : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilization)); + *value =SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilization, flag));break ;case METRICS_CURR_SOCKETPOWER : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocketPower)) <<8 ; + *value =SMUQ10_ROUND (GET_METRIC_FIELD (SocketPower, flag)) <<8 ;break ;case METRICS_TEMPERATURE_HOTSPOT : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketTemperature)) * + *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketTemperature, flag)) *SMU_TEMPERATURE_UNITS_PER_CENTIGRADES ;break ;case METRICS_TEMPERATURE_MEM : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxHbmTemperature)) * + *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxHbmTemperature, flag)) *SMU_TEMPERATURE_UNITS_PER_CENTIGRADES ;break ;/* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC : - *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxVrTemperature)) * + *value =SMUQ10_ROUND (GET_METRIC_FIELD (MaxVrTemperature, flag)) *SMU_TEMPERATURE_UNITS_PER_CENTIGRADES ;break ;default :
@@ -2303,6 +2310,7 @@ static ssize_t smu_v13_0_6_get_gpu_metristruct smu_table_context *smu_table = &smu->smu_table;struct gpu_metrics_v1_5 *gpu_metrics = (struct gpu_metrics_v1_5 *)smu_table->gpu_metrics_table; +bool flag =smu_v13_0_6_is_unified_metrics (smu);struct amdgpu_device *adev = smu->adev;int ret =0 , xcc_id, inst, i, j;MetricsTableX_t *metrics_x;
@@ -2321,50 +2329,50 @@ static ssize_t smu_v13_0_6_get_gpu_metrismu_cmn_init_soft_gpu_metrics (gpu_metrics,1 ,5 ); gpu_metrics->temperature_hotspot = -SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketTemperature)); +SMUQ10_ROUND (GET_METRIC_FIELD (MaxSocketTemperature, flag));/* Individual HBM stack temperature is not reported */ gpu_metrics->temperature_mem = -SMUQ10_ROUND (GET_METRIC_FIELD (MaxHbmTemperature)); +SMUQ10_ROUND (GET_METRIC_FIELD (MaxHbmTemperature, flag));/* Reports max temperature of all voltage rails */ gpu_metrics->temperature_vrsoc = -SMUQ10_ROUND (GET_METRIC_FIELD (MaxVrTemperature)); +SMUQ10_ROUND (GET_METRIC_FIELD (MaxVrTemperature, flag)); gpu_metrics->average_gfx_activity = -SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusy)); +SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusy, flag)); gpu_metrics->average_umc_activity = -SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilization)); +SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilization, flag)); gpu_metrics->curr_socket_power = -SMUQ10_ROUND (GET_METRIC_FIELD (SocketPower)); +SMUQ10_ROUND (GET_METRIC_FIELD (SocketPower, flag));/* Energy counter reported in 15.259uJ (2^-16) units */ - gpu_metrics->energy_accumulator =GET_METRIC_FIELD (SocketEnergyAcc); + gpu_metrics->energy_accumulator =GET_METRIC_FIELD (SocketEnergyAcc, flag);for (i =0 ; i <MAX_GFX_CLKS ; i++) { xcc_id =GET_INST (GC , i);if (xcc_id >=0 ) gpu_metrics->current_gfxclk[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (GfxclkFrequency)[xcc_id]); +SMUQ10_ROUND (GET_METRIC_FIELD (GfxclkFrequency, flag)[xcc_id]);if (i <MAX_CLKS ) { gpu_metrics->current_socclk[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (SocclkFrequency)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (SocclkFrequency, flag)[i]); inst =GET_INST (VCN , i);if (inst >=0 ) { gpu_metrics->current_vclk0[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequency)[inst]); +SMUQ10_ROUND (GET_METRIC_FIELD (VclkFrequency, flag)[inst]); gpu_metrics->current_dclk0[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequency)[inst]); +SMUQ10_ROUND (GET_METRIC_FIELD (DclkFrequency, flag)[inst]); } } } - gpu_metrics->current_uclk =SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequency)); + gpu_metrics->current_uclk =SMUQ10_ROUND (GET_METRIC_FIELD (UclkFrequency, flag));/* Throttle status is not reported through metrics now */ gpu_metrics->throttle_status =0 ;/* Clock Lock Status. Each bit corresponds to each GFXCLK instance */ - gpu_metrics->gfxclk_lock_status =GET_METRIC_FIELD (GfxLockXCDMak) >>GET_INST (GC ,0 ); + gpu_metrics->gfxclk_lock_status =GET_METRIC_FIELD (GfxLockXCDMak, flag) >>GET_INST (GC ,0 );if (!(adev->flags &AMD_IS_APU )) {/*Check smu version, PCIE link speed and width will be reported from pmfw metric
@@ -2405,22 +2413,22 @@ static ssize_t smu_v13_0_6_get_gpu_metri gpu_metrics->system_clock_counter =ktime_get_boottime_ns (); gpu_metrics->gfx_activity_acc = -SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusyAcc)); +SMUQ10_ROUND (GET_METRIC_FIELD (SocketGfxBusyAcc, flag)); gpu_metrics->mem_activity_acc = -SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilizationAcc)); +SMUQ10_ROUND (GET_METRIC_FIELD (DramBandwidthUtilizationAcc, flag));for (i =0 ; i <NUM_XGMI_LINKS ; i++) { gpu_metrics->xgmi_read_data_acc[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (XgmiReadDataSizeAcc)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (XgmiReadDataSizeAcc, flag)[i]); gpu_metrics->xgmi_write_data_acc[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (XgmiWriteDataSizeAcc)[i]); +SMUQ10_ROUND (GET_METRIC_FIELD (XgmiWriteDataSizeAcc, flag)[i]); }for (i =0 ; i < adev->jpeg.num_jpeg_inst; ++i) { inst =GET_INST (JPEG , i);for (j =0 ; j < adev->jpeg.num_jpeg_rings; ++j) { gpu_metrics->jpeg_activity[(i * adev->jpeg.num_jpeg_rings) + j] = -SMUQ10_ROUND (GET_METRIC_FIELD (JpegBusy) +SMUQ10_ROUND (GET_METRIC_FIELD (JpegBusy, flag) [(inst * adev->jpeg.num_jpeg_rings) + j]); } }
@@ -2428,13 +2436,13 @@ static ssize_t smu_v13_0_6_get_gpu_metrifor (i =0 ; i < adev->vcn.num_vcn_inst; ++i) { inst =GET_INST (VCN , i); gpu_metrics->vcn_activity[i] = -SMUQ10_ROUND (GET_METRIC_FIELD (VcnBusy)[inst]); +SMUQ10_ROUND (GET_METRIC_FIELD (VcnBusy, flag)[inst]); } - gpu_metrics->xgmi_link_width =SMUQ10_ROUND (GET_METRIC_FIELD (XgmiWidth)); - gpu_metrics->xgmi_link_speed =SMUQ10_ROUND (GET_METRIC_FIELD (XgmiBitrate)); + gpu_metrics->xgmi_link_width =SMUQ10_ROUND (GET_METRIC_FIELD (XgmiWidth, flag)); + gpu_metrics->xgmi_link_speed =SMUQ10_ROUND (GET_METRIC_FIELD (XgmiBitrate, flag)); - gpu_metrics->firmware_timestamp =GET_METRIC_FIELD (Timestamp); + gpu_metrics->firmware_timestamp =GET_METRIC_FIELD (Timestamp, flag); *table = (void *)gpu_metrics;kfree (metrics_x);
Greg Kroah-Hartman
maintainerPATCH 169/220 drm/amd/pm: Use macro to initialize metrics table
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <[email protected]>
[ Upstream commit 1327d8f4061c08c29ea8ce7bb89e209d3c1e8b29 ]
Helps to keep a build time check about usage of right datatype and avoids maintenance as new versions get added.
Stable-dep-of: 048f4541b71f ("drm/amd/pm: fix torn gpu metrics reads")
--- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 58 --------------------------------- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 14 ++++++- 2 files changed, 12 insertions(+), 60 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +0 -58
@@ -1051,64 +1051,6 @@ int smu_cmn_get_combo_pptable(struct smu false); } -void smu_cmn_init_soft_gpu_metrics (void *table,uint8_t frev,uint8_t crev) -{ -struct metrics_table_header *header = (struct metrics_table_header *)table; -uint16_t structure_size; - -#define METRICS_VERSION (a, b) ((a << 16) | b) - -switch (METRICS_VERSION (frev, crev)) { -case METRICS_VERSION (1 ,0 ): - structure_size =sizeof (struct gpu_metrics_v1_0 ); -break ; -case METRICS_VERSION (1 ,1 ): - structure_size =sizeof (struct gpu_metrics_v1_1 ); -break ; -case METRICS_VERSION (1 ,2 ): - structure_size =sizeof (struct gpu_metrics_v1_2 ); -break ; -case METRICS_VERSION (1 ,3 ): - structure_size =sizeof (struct gpu_metrics_v1_3 ); -break ; -case METRICS_VERSION (1 ,4 ): - structure_size =sizeof (struct gpu_metrics_v1_4 ); -break ; -case METRICS_VERSION (1 ,5 ): - structure_size =sizeof (struct gpu_metrics_v1_5 ); -break ; -case METRICS_VERSION (2 ,0 ): - structure_size =sizeof (struct gpu_metrics_v2_0 ); -break ; -case METRICS_VERSION (2 ,1 ): - structure_size =sizeof (struct gpu_metrics_v2_1 ); -break ; -case METRICS_VERSION (2 ,2 ): - structure_size =sizeof (struct gpu_metrics_v2_2 ); -break ; -case METRICS_VERSION (2 ,3 ): - structure_size =sizeof (struct gpu_metrics_v2_3 ); -break ; -case METRICS_VERSION (2 ,4 ): - structure_size =sizeof (struct gpu_metrics_v2_4 ); -break ; -case METRICS_VERSION (3 ,0 ): - structure_size =sizeof (struct gpu_metrics_v3_0 ); -break ; -default : -return ; - } - -#undef METRICS_VERSION - -memset (header,0xFF , structure_size); - - header->format_revision = frev; - header->content_revision = crev; - header->structure_size = structure_size; - -} -int smu_cmn_set_mp1_state (struct smu_context *smu,enum pp_mp1_state mp1_state) {
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +12 -2
@@ -40,6 +40,18 @@#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9 +#define smu_cmn_init_soft_gpu_metrics (ptr, frev, crev) \ + do { \ + typecheck(struct gpu_metrics_v##frev##_##crev, \ + typeof(*(ptr))); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)(ptr); \ + memset(header, 0xFF, sizeof(*(ptr))); \ + header->format_revision = frev; \ + header->content_revision = crev; \ + header->structure_size = sizeof(*(ptr)); \ + } while (0) +extern const int link_speed[];/* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */
@@ -125,8 +137,6 @@ int smu_cmn_get_metrics_table(struct smuint smu_cmn_get_combo_pptable (struct smu_context *smu); -void smu_cmn_init_soft_gpu_metrics (void *table,uint8_t frev,uint8_t crev); -int smu_cmn_set_mp1_state (struct smu_context *smu,enum pp_mp1_state mp1_state);
Greg Kroah-Hartman
maintainerPATCH 170/220 drm/amd/pm: fix torn gpu metrics reads
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit 048f4541b71fb19645fb79d6e62e6e4da23a4035 ]
amdgpu_dpm_get_gpu_metrics() returns a pointer to the shared metrics cache after dropping adev->pm.mutex. The sysfs path then copies from that pointer. Another reader can refresh the cache in place during the copy and return a snapshot containing data from two generations.
Pass caller-provided storage through the DPM interface and copy the metrics while the mutex is held. This keeps the cache pointer private and makes each sysfs read observe one complete sample.
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 12 +++++++++--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 8 +------- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +9 -3
@@ -1318,17 +1318,23 @@ int amdgpu_dpm_set_power_profile_mode(streturn ret; } -int amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void **table) +ssize_t amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void *buf, +size_t size) {const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; -int ret =0 ; +void *table; +ssize_t ret;if (!pp_funcs->get_gpu_metrics)return 0 ;mutex_lock (&adev->pm.mutex); ret = pp_funcs->get_gpu_metrics (adev->powerplay.pp_handle, - table); + &table); +if (ret >0 ) { + ret =min_t (ssize_t, ret, size); +memcpy (buf, table, ret); + }mutex_unlock (&adev->pm.mutex);return ret;
drivers/gpu/drm/amd/pm/amdgpu_pm.c +1 -7
@@ -1889,7 +1889,6 @@ static ssize_t amdgpu_get_gpu_metrics(st {struct drm_device *ddev =dev_get_drvdata (dev);struct amdgpu_device *adev =drm_to_adev (ddev); -void *gpu_metrics;ssize_t size =0 ;int ret;
@@ -1904,15 +1903,10 @@ static ssize_t amdgpu_get_gpu_metrics(streturn ret; } - size =amdgpu_dpm_get_gpu_metrics (adev, &gpu_metrics); + size =amdgpu_dpm_get_gpu_metrics (adev, buf,PAGE_SIZE -1 );if (size <=0 ) goto out; -if (size >=PAGE_SIZE ) - size =PAGE_SIZE -1 ; - -memcpy (buf, gpu_metrics, size); - out:pm_runtime_mark_last_busy (ddev->dev);pm_runtime_put_autosuspend (ddev->dev);
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +2 -1
@@ -513,7 +513,8 @@ int amdgpu_dpm_get_power_profile_mode(st char *buf);int amdgpu_dpm_set_power_profile_mode (struct amdgpu_device *adev,long *input,uint32_t size); -int amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void **table); +ssize_t amdgpu_dpm_get_gpu_metrics (struct amdgpu_device *adev,void *buf, +size_t size);/** * @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The
Greg Kroah-Hartman
maintainerPATCH 171/220 drm/amdgpu: remove unused function parameter
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunxiang Li <[email protected]>
[ Upstream commit a541a6e865ecd8dfd8df6eeb134cc20e7139d329 ]
amdgpu_vm_bo_invalidate doesn't use the adev parameter and not all callers have a reference to adev handy, so remove it for cleanliness.
Stable-dep-of: d8726ef11512 ("drm/amdgpu: move debug_vm handling to amdgpu_cs_parser_fini")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 3 +-- 6 files changed, 7 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +2 -2
@@ -1138,7 +1138,7 @@ static int amdgpu_cs_vm_handling(struct* We can't use gang submit on with reserved VMIDs when the VM changes * can't be invalidated by more than one engine at the same time. */ -if (p->gang_size >1 && !p->adev->vm_manager.concurrent_flush) { +if (p->gang_size >1 && !adev->vm_manager.concurrent_flush) {for (i =0 ; i < p->gang_size; ++i) {struct drm_sched_entity *entity = p->entities[i];struct drm_gpu_scheduler *sched = entity->rq->sched;
@@ -1222,7 +1222,7 @@ static int amdgpu_cs_vm_handling(structif (!bo)continue ; -amdgpu_vm_bo_invalidate (adev, bo, false); +amdgpu_vm_bo_invalidate (bo, false); } }
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +1 -1
@@ -382,7 +382,7 @@ amdgpu_dma_buf_move_notify(struct dma_bu/* FIXME: This should be after the "if", but needs a fix to make sure * DMABuf imports are initialized in the right VM list. */ -amdgpu_vm_bo_invalidate (adev, bo, false); +amdgpu_vm_bo_invalidate (bo, false);if (!bo->tbo.resource || bo->tbo.resource->mem_type ==TTM_PL_SYSTEM )return ;
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +1 -2
@@ -861,7 +861,6 @@ error:int amdgpu_gem_op_ioctl (struct drm_device *dev,void *data,struct drm_file *filp) { -struct amdgpu_device *adev =drm_to_adev (dev);struct drm_amdgpu_gem_op *args = data;struct drm_gem_object *gobj;struct amdgpu_vm_bo_base *base;
@@ -921,7 +920,7 @@ int amdgpu_gem_op_ioctl(struct drm_devic robj->allowed_domains |=AMDGPU_GEM_DOMAIN_GTT ;if (robj->flags &AMDGPU_GEM_CREATE_VM_ALWAYS_VALID ) -amdgpu_vm_bo_invalidate (adev, robj, true); +amdgpu_vm_bo_invalidate (robj, true);amdgpu_bo_unreserve (robj);break ;
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +1 -2
@@ -1152,7 +1152,6 @@ void amdgpu_bo_move_notify(struct ttm_bubool evict, struct ttm_resource *new_mem) { - struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct ttm_resource *old_mem = bo->resource;struct amdgpu_bo *abo;
@@ -1160,7 +1159,7 @@ void amdgpu_bo_move_notify(struct ttm_bureturn ; abo =ttm_to_amdgpu_bo (bo); -amdgpu_vm_bo_invalidate (adev, abo, evict); +amdgpu_vm_bo_invalidate (abo, evict);amdgpu_bo_kunmap (abo);
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +1 -3
@@ -2139,14 +2139,12 @@ bool amdgpu_vm_evictable(struct amdgpu_b/** * amdgpu_vm_bo_invalidate - mark the bo as invalid * -* @adev: amdgpu_device pointer * @bo: amdgpu buffer object * @evicted: is the BO evicted * * Mark @bo as invalid. */ -void amdgpu_vm_bo_invalidate (struct amdgpu_device *adev, -struct amdgpu_bo *bo,bool evicted) +void amdgpu_vm_bo_invalidate (struct amdgpu_bo *bo,bool evicted) {struct amdgpu_vm_bo_base *bo_base;
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +1 -2
@@ -511,8 +511,7 @@ int amdgpu_vm_bo_update(struct amdgpu_destruct amdgpu_bo_va *bo_va, bool clear);bool amdgpu_vm_evictable (struct amdgpu_bo *bo); -void amdgpu_vm_bo_invalidate (struct amdgpu_device *adev, -struct amdgpu_bo *bo,bool evicted); +void amdgpu_vm_bo_invalidate (struct amdgpu_bo *bo,bool evicted);uint64_t amdgpu_vm_map_gart (const dma_addr_t *pages_addr,uint64_t addr);struct amdgpu_bo_va *amdgpu_vm_bo_find (struct amdgpu_vm *vm,struct amdgpu_bo *bo);
Greg Kroah-Hartman
maintainerPATCH 172/220 drm/amdgpu: move debug_vm handling to amdgpu_cs_parser_fini
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pierre-Eric Pelloux-Prayer <[email protected]>
[ Upstream commit d8726ef11512754a68c0ab53c57634a569b8feff ]
The commit referenced below restarts the CS if the validation is still in progress. When debug_vm is enabled, all BOs from the CS are invalidated so we will hit an infinite loop.
To avoid that, defer BO invalidation to amdgpu_cs_parser_fini.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +16 -14
@@ -1213,19 +1213,6 @@ static int amdgpu_cs_vm_handling(struct job->vm_pd_addr =amdgpu_gmc_pd_addr (vm->root.bo); } -if (adev->debug_vm) { -/* Invalidate all BOs to test for userspace bugs */ -amdgpu_bo_list_for_each_entry (e, p->bo_list) { -struct amdgpu_bo *bo = e->bo; - -/* ignore duplicates */ -if (!bo) -continue ; - -amdgpu_vm_bo_invalidate (bo, false); - } - } -return 0 ; }
@@ -1412,6 +1399,8 @@ static int amdgpu_cs_submit(struct amdgp/* Cleanup the parser structure */ static void amdgpu_cs_parser_fini (struct amdgpu_cs_parser *parser) { +struct amdgpu_device *adev = parser->adev; +struct amdgpu_bo_list_entry *e;unsigned int i;amdgpu_sync_free (&parser->sync);
@@ -1427,8 +1416,21 @@ static void amdgpu_cs_parser_fini(structif (parser->ctx)amdgpu_ctx_put (parser->ctx); -if (parser->bo_list) +if (parser->bo_list) { +if (adev->debug_vm) { +/* Invalidate all BOs to test for userspace bugs */ +amdgpu_bo_list_for_each_entry (e, parser->bo_list) { +struct amdgpu_bo *bo = e->bo; + +/* ignore duplicates */ +if (!bo) +continue ; + +amdgpu_vm_bo_invalidate (bo, false); + } + }amdgpu_bo_list_put (parser->bo_list); + }for (i =0 ; i < parser->nchunks; i++)kvfree (parser->chunks[i].kdata);
Greg Kroah-Hartman
maintainerPATCH 173/220 drm/amd/pm: adjust the visibility of pp_table sysfs node
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit 5de8ce0f3709ad93ca5a579aa45cf1b52d72bc90 ]
v1:
- make pp_table invisible on VF mode (only valid on BM)
- make pp_table invisible on Mi* chips (Not supported)
- make pp_table invisible if scpm feature is enabled.
v2:
move pp_table invisible code logic into amdgpu_dpm_get_pp_table() function.
v3:
add table buffer pointer check both on powerplay & swsmu.
Stable-dep-of: bb493058c35c ("drm/amd/pm: fix pptable use-after-free")
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 12 +++++++++--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 11 ++++++++++- drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 5 ++++- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +9 -3
@@ -1064,8 +1064,11 @@ int amdgpu_dpm_get_pp_table(struct amdgpconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (!pp_funcs->get_pp_table) -return 0 ; +if (!table) +return -EINVAL ; + +if (amdgpu_sriov_vf (adev) || !pp_funcs->get_pp_table || adev->scpm_enabled) +return -EOPNOTSUPP ;mutex_lock (&adev->pm.mutex); ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle,
@@ -1575,7 +1578,10 @@ int amdgpu_dpm_set_pp_table(struct amdgpconst struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;int ret =0 ; -if (!pp_funcs->set_pp_table) +if (!buf || !size) +return -EINVAL ; + +if (amdgpu_sriov_vf (adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)return -EOPNOTSUPP ;mutex_lock (&adev->pm.mutex);
drivers/gpu/drm/amd/pm/amdgpu_pm.c +10 -1
@@ -2402,7 +2402,7 @@ static struct amdgpu_device_attr amdgpu_AMDGPU_DEVICE_ATTR_RO (pp_num_states,ATTR_FLAG_BASIC |ATTR_FLAG_ONEVF ),AMDGPU_DEVICE_ATTR_RO (pp_cur_state,ATTR_FLAG_BASIC |ATTR_FLAG_ONEVF ),AMDGPU_DEVICE_ATTR_RW (pp_force_state,ATTR_FLAG_BASIC |ATTR_FLAG_ONEVF ), -AMDGPU_DEVICE_ATTR_RW (pp_table,ATTR_FLAG_BASIC |ATTR_FLAG_ONEVF ), +AMDGPU_DEVICE_ATTR_RW (pp_table,ATTR_FLAG_BASIC ),AMDGPU_DEVICE_ATTR_RW (pp_dpm_sclk,ATTR_FLAG_BASIC |ATTR_FLAG_ONEVF , .attr_update = pp_dpm_clk_default_attr_update), AMDGPU_DEVICE_ATTR_RW(pp_dpm_mclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF,
@@ -2529,6 +2529,15 @@ static int default_attr_update(struct amif (amdgpu_dpm_get_apu_thermal_limit (adev, &limit) == -EOPNOTSUPP ) *states =ATTR_STATE_UNSUPPORTED ; + }else if (DEVICE_ATTR_IS (pp_table)) { +int ret; +char *tmp =NULL ; + + ret =amdgpu_dpm_get_pp_table (adev, &tmp); +if (ret == -EOPNOTSUPP || !tmp) + *states =ATTR_STATE_UNSUPPORTED ; +else + *states =ATTR_STATE_SUPPORTED ; }switch (gc_ver) {
drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +4 -1
@@ -650,9 +650,12 @@ static int pp_dpm_get_pp_table(void *han {struct pp_hwmgr *hwmgr = handle; -if (!hwmgr || !hwmgr->pm_en || !hwmgr->soft_pp_table) +if (!hwmgr || !hwmgr->pm_en || !table)return -EINVAL ; +if (!hwmgr->soft_pp_table) +return -EOPNOTSUPP ; + *table = (char *)hwmgr->soft_pp_table;return hwmgr->soft_pp_table_size; }
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +1 -1
@@ -580,7 +580,7 @@ static int smu_sys_get_pp_table(void *hareturn -EOPNOTSUPP ;if (!smu_table->power_play_table && !smu_table->hardcode_pptable) -return -EINVAL ; +return -EOPNOTSUPP ;if (smu_table->hardcode_pptable) *table = smu_table->hardcode_pptable;
Greg Kroah-Hartman
maintainerPATCH 174/220 drm/amd/pm: fix pptable use-after-free
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
[ Upstream commit bb493058c35c8676e48269ab6732688ea733d23c ]
amdgpu_dpm_get_pp_table() returns a pointer to a driver-owned power table after dropping adev->pm.mutex. The sysfs path then copies from that pointer. A concurrent pp_table write can replace and free the allocation during the copy, causing a use-after-free.
Change the DPM interface to copy into caller-provided storage while the mutex is held. Keep the size-only query for attribute discovery without exposing the driver-owned pointer.
--- drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 14 +++++++++++--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 13 +++---------- drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 3 ++- 3 files changed, 16 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_dpm.c +11 -3
@@ -1059,12 +1059,14 @@ int amdgpu_dpm_dispatch_task(struct amdgreturn ret; } -int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char **table) +int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char *table, +size_t size) {const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; +char *pptable =NULL ;int ret =0 ; -if (!table) +if ((!table && size) || (table && !size))return -EINVAL ;if (amdgpu_sriov_vf (adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
@@ -1072,7 +1074,13 @@ int amdgpu_dpm_get_pp_table(struct amdgpmutex_lock (&adev->pm.mutex); ret = pp_funcs->get_pp_table (adev->powerplay.pp_handle, - table); + &pptable); +if (ret >0 && !pptable) { + ret = -EINVAL ; + }else if (ret >0 && table) { + ret =min_t (size_t, ret, size); +memcpy (table, pptable, ret); + }mutex_unlock (&adev->pm.mutex);return ret;
drivers/gpu/drm/amd/pm/amdgpu_pm.c +3 -10
@@ -538,7 +538,6 @@ static ssize_t amdgpu_get_pp_table(struc {struct drm_device *ddev =dev_get_drvdata (dev);struct amdgpu_device *adev =drm_to_adev (ddev); -char *table =NULL ;int size, ret;if (amdgpu_in_reset (adev))
@@ -552,7 +551,7 @@ static ssize_t amdgpu_get_pp_table(strucreturn ret; } - size =amdgpu_dpm_get_pp_table (adev, &table); + size =amdgpu_dpm_get_pp_table (adev, buf,PAGE_SIZE -1 );pm_runtime_mark_last_busy (ddev->dev);pm_runtime_put_autosuspend (ddev->dev);
@@ -560,11 +559,6 @@ static ssize_t amdgpu_get_pp_table(strucif (size <=0 )return size; -if (size >=PAGE_SIZE ) - size =PAGE_SIZE -1 ; - -memcpy (buf, table, size); -return size; }
@@ -2531,10 +2525,9 @@ static int default_attr_update(struct am *states =ATTR_STATE_UNSUPPORTED ; }else if (DEVICE_ATTR_IS (pp_table)) {int ret; -char *tmp =NULL ; - ret =amdgpu_dpm_get_pp_table (adev, &tmp); -if (ret == -EOPNOTSUPP || !tmp) + ret =amdgpu_dpm_get_pp_table (adev,NULL ,0 ); +if (ret <=0 ) *states =ATTR_STATE_UNSUPPORTED ;else *states =ATTR_STATE_SUPPORTED ;
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +2 -1
@@ -483,7 +483,8 @@ int amdgpu_dpm_get_pp_num_states(structint amdgpu_dpm_dispatch_task (struct amdgpu_device *adev,enum amd_pp_task task_id,enum amd_pm_state_type *user_state); -int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char **table); +int amdgpu_dpm_get_pp_table (struct amdgpu_device *adev,char *table, +size_t size); int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev, uint32_t type, long *input,
Greg Kroah-Hartman
maintainerPATCH 175/220 net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongli Zhang <[email protected]>
[ Upstream commit 3874892dd27d5387aa9a06f58d9060f18f351d24 ]
The commit 4f61f133f354 ("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur.
However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash.
Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit().
--- drivers/net/tap.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/net/tap.c +14 -10
@@ -1199,10 +1199,21 @@ static int tap_get_user_xdp(struct tap_qskb_reset_mac_header (skb); skb->protocol =eth_hdr (skb)->h_proto; +rcu_read_lock (); + tap =rcu_dereference (q->tap); +if (!tap) { +kfree_skb (skb); +rcu_read_unlock (); +return 0 ; + } + skb->dev = tap->dev; +if (vnet_hdr_len) { err =virtio_net_hdr_to_skb (skb, gso,tap_is_little_endian (q)); -if (err) +if (err) { +rcu_read_unlock (); goto err_kfree; + } }/* Move network header to the right position for VLAN tagged packets */
@@ -1210,15 +1221,8 @@ static int tap_get_user_xdp(struct tap_q vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)skb_set_network_header (skb, depth); -rcu_read_lock (); - tap =rcu_dereference (q->tap); -if (tap) { - skb->dev = tap->dev; -skb_probe_transport_header (skb); -dev_queue_xmit (skb); - }else { -kfree_skb (skb); - } +skb_probe_transport_header (skb); +dev_queue_xmit (skb);rcu_read_unlock ();return 0 ;
Greg Kroah-Hartman
maintainerPATCH 176/220 drm/vmwgfx: take fman->lock around fence list mutation in fifo_down
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
[ Upstream commit 250af2e8c3e90dc978e062a936b633870a22e660 ]
vmw_fence_fifo_down() drops fman->lock to wait on a fence and, on timeout, mutates fman->fence_list via list_del_init() and signals the fence without re-acquiring the lock. __vmw_fences_update() walks and removes entries from the same list under fman->lock from any other waiter, the fence-IRQ thread, or vmw_fences_update(), so the unlocked list_del_init() can corrupt the list head.
Re-take fman->lock before manipulating fence->head and use dma_fence_signal_locked(). Wrap the locked signalling in dma_fence_begin_signalling() / dma_fence_end_signalling() so the lockdep annotation that dma_fence_signal() previously provided is preserved (the same pattern as __vmw_fences_update()).
dma_fence_put() is moved outside the lock to avoid a recursive acquire from vmw_fence_obj_destroy(), which also takes fman->lock.
--- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +9 -1
@@ -658,9 +658,14 @@ void vmw_fence_fifo_down(struct vmw_fenc ret =vmw_fence_obj_wait (fence, false, false,VMW_FENCE_WAIT_TIMEOUT ); +spin_lock (&fman->lock);if (unlikely (ret !=0 )) { +bool cookie =dma_fence_begin_signalling (); +list_del_init (&fence->head); -dma_fence_signal (&fence->base); +dma_fence_signal_locked (&fence->base); +dma_fence_end_signalling (cookie); +INIT_LIST_HEAD (&action_list);list_splice_init (&fence->seq_passed_actions, &action_list);
@@ -668,7 +673,10 @@ void vmw_fence_fifo_down(struct vmw_fenc }BUG_ON (!list_empty (&fence->head)); +spin_unlock (&fman->lock); +dma_fence_put (&fence->base); +spin_lock (&fman->lock); }spin_unlock (&fman->lock);
Greg Kroah-Hartman
maintainerPATCH 177/220 ring-buffer: Simplify functions with __free(kfree) to free allocations
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 99d232804405e35d7a9af1536a057578a1442e81 ]
The function rb_allocate_pages() allocates cpu_buffer and on error needs to free it. It has a single return. Use __free(kfree) and return directly on errors and have the return use return_ptr(cpu_buffer).
The function alloc_buffer() allocates buffer and on error needs to free it. It has a single return. Use __free(kfree) and return directly on errors and have the return use return_ptr(buffer).
The function __rb_map_vma() allocates a temporary array "pages". Have it use __free() and not worry about freeing it when returning.
Stable-dep-of: 6d014e44b68d ("ring-buffer: Initialise reader page order in rb_allocate_cpu_buffer()")
--- kernel/trace/ring_buffer.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-)
kernel/trace/ring_buffer.c +9 -18
@@ -2193,7 +2193,7 @@ static int rb_allocate_pages(struct ringstatic struct ring_buffer_per_cpu *rb_allocate_cpu_buffer (struct trace_buffer *buffer,long nr_pages,int cpu) { -struct ring_buffer_per_cpu *cpu_buffer; + struct ring_buffer_per_cpu *cpu_buffer __free(kfree) = NULL;struct ring_buffer_meta *meta;struct buffer_page *bpage;struct page *page;
@@ -2219,7 +2219,7 @@ rb_allocate_cpu_buffer(struct trace_buff bpage =kzalloc_node (ALIGN (sizeof (*bpage),cache_line_size ()),GFP_KERNEL ,cpu_to_node (cpu));if (!bpage) - goto fail_free_buffer; +return NULL ;rb_check_bpage (cpu_buffer, bpage);
@@ -2285,13 +2285,11 @@ rb_allocate_cpu_buffer(struct trace_buffrb_head_page_activate (cpu_buffer); } -return cpu_buffer; +return_ptr (cpu_buffer); fail_free_reader:free_buffer_page (cpu_buffer->reader_page); - fail_free_buffer: -kfree (cpu_buffer);return NULL ; }
@@ -2335,7 +2333,7 @@ static struct trace_buffer *alloc_bufferunsigned long end, struct lock_class_key *key) { - struct trace_buffer *buffer; + struct trace_buffer *buffer __free(kfree) = NULL;long nr_pages;int subbuf_size;int bsize;
@@ -2349,7 +2347,7 @@ static struct trace_buffer *alloc_bufferreturn NULL ;if (!zalloc_cpumask_var (&buffer->cpumask,GFP_KERNEL )) - goto fail_free_buffer; +return NULL ; buffer->subbuf_order = order; subbuf_size = (PAGE_SIZE << order);
@@ -2441,7 +2439,7 @@ static struct trace_buffer *alloc_bufferatomic_notifier_chain_register (&panic_notifier_list, &buffer->flush_nb); } -return buffer; +return_ptr (buffer); fail_free_buffers:for_each_buffer_cpu (buffer, cpu) {
@@ -2453,8 +2451,6 @@ static struct trace_buffer *alloc_buffer fail_free_cpumask:free_cpumask_var (buffer->cpumask); - fail_free_buffer: -kfree (buffer);return NULL ; }
@@ -7007,7 +7003,7 @@ static int __rb_map_vma(struct ring_buff {unsigned long nr_subbufs, nr_pages, nr_vma_pages, pgoff = vma->vm_pgoff;unsigned int subbuf_pages, subbuf_order; -struct page **pages; + struct page **pages __free(kfree) = NULL;int p =0 , s =0 ;int err;
@@ -7075,10 +7071,8 @@ static int __rb_map_vma(struct ring_buffstruct page *page;int off =0 ; -if (WARN_ON_ONCE (s >= nr_subbufs)) { - err = -EINVAL ; - goto out; - } +if (WARN_ON_ONCE (s >= nr_subbufs)) +return -EINVAL ; page =virt_to_page ((void *)cpu_buffer->subbuf_ids[s]);
@@ -7093,9 +7087,6 @@ static int __rb_map_vma(struct ring_buff err =vm_insert_pages (vma, vma->vm_start, pages, &nr_pages); -out: -kfree (pages); - return err; }#else
Greg Kroah-Hartman
maintainerPATCH 178/220 ring-buffer: Initialise reader page order in rb_allocate_cpu_buffer()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <[email protected]>
[ Upstream commit 6d014e44b68ddd43f71288d2a4dbb1a259869149 ]
In rb_allocate_cpu_buffer(), bpage->order was omitted, leaving it as 0. This is an issue for a ring-buffer with subbufs bigger than PAGE_SIZE if when freed: free_buffer_page() relies on this value. Align the value with the actual allocation size (buffer::subbuf_order).
--- kernel/trace/ring_buffer.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/ring_buffer.c +1 -0
@@ -2220,6 +2220,7 @@ rb_allocate_cpu_buffer(struct trace_buff GFP_KERNEL, cpu_to_node(cpu));if (!bpage)return NULL ; + bpage->order = cpu_buffer->buffer->subbuf_order;rb_check_bpage (cpu_buffer, bpage);
Greg Kroah-Hartman
maintainerPATCH 179/220 mm/pagewalk: split walk_page_range_novma() into kernel/user parts
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes <[email protected]>
[ Upstream commit 96d81e4766f9e88b66a0502b5a7f34a4c20ac754 ]
walk_page_range_novma() is rather confusing - it supports two modes, one used often, the other used only for debugging.
The first mode is the common case of traversal of kernel page tables, which is what nearly all callers use this for.
Secondly it provides an unusual debugging interface that allows for the traversal of page tables in a userland range of memory even for that memory which is not described by a VMA.
It is far from certain that such page tables should even exist, but perhaps this is precisely why it is useful as a debugging mechanism.
As a result, this is utilised by ptdump only. Historically, things were reversed - ptdump was the only user, and other parts of the kernel evolved to use the kernel page table walking here.
Since we have some complicated and confusing locking rules for the novma case, it makes sense to separate the two usages into their own functions.
Doing this also provide self-documentation as to the intent of the caller
- are they doing something rather unusual or are they simply doing a standard kernel page table walk?
We therefore establish two separate functions - walk_page_range_debug() for this single usage, and walk_kernel_page_table_range() for general kernel page table walking.
The walk_page_range_debug() function is currently used to traverse both userland and kernel mappings, so we maintain this and in the case of kernel mappings being traversed, we have walk_page_range_debug() invoke walk_kernel_page_table_range() internally.
We additionally make walk_page_range_debug() internal to mm.
Stable-dep-of: 27c32e553834 ("mm/ptdump: always stabilise against page table freeing using init_mm")
--- arch/loongarch/mm/pageattr.c | 2 - arch/openrisc/kernel/dma.c | 4 +- arch/riscv/mm/pageattr.c | 8 ++-- include/linux/pagewalk.h | 7 +-- mm/hugetlb_vmemmap.c | 2 - mm/internal.h | 6 +++ mm/pagewalk.c | 77 ++++++++++++++++++++++++++++++------------- mm/ptdump.c | 3 + 8 files changed, 74 insertions(+), 35 deletions(-)
arch/loongarch/mm/pageattr.c +1 -1
@@ -118,7 +118,7 @@ static int __set_memory(unsigned long adreturn 0 ;mmap_write_lock (&init_mm); - ret =walk_page_range_novma (&init_mm, start, end, &pageattr_ops,NULL , &masks); + ret =walk_kernel_page_table_range (start, end, &pageattr_ops,NULL , &masks);mmap_write_unlock (&init_mm);flush_tlb_kernel_range (start, end);
arch/openrisc/kernel/dma.c +2 -2
@@ -75,7 +75,7 @@ void *arch_dma_set_uncached(void *cpu_ad* them and setting the cache-inhibit bit. */ mmap_write_lock (&init_mm); - error =walk_page_range_novma (&init_mm, va, va + size, + error =walk_kernel_page_table_range (va, va + size, &set_nocache_walk_ops,NULL ,NULL );mmap_write_unlock (&init_mm);
@@ -90,7 +90,7 @@ void arch_dma_clear_uncached(void *cpu_ammap_write_lock (&init_mm);/* walk_page_range shouldn't be able to fail here */ -WARN_ON (walk_page_range_novma (&init_mm, va, va + size, +WARN_ON (walk_kernel_page_table_range (va, va + size, &clear_nocache_walk_ops,NULL ,NULL ));mmap_write_unlock (&init_mm); }
arch/riscv/mm/pageattr.c +4 -4
@@ -299,7 +299,7 @@ static int __set_memory(unsigned long adif (ret) goto unlock; - ret =walk_page_range_novma (&init_mm, lm_start, lm_end, + ret =walk_kernel_page_table_range (lm_start, lm_end, &pageattr_ops,NULL , &masks);if (ret) goto unlock;
@@ -317,13 +317,13 @@ static int __set_memory(unsigned long adif (ret) goto unlock; - ret =walk_page_range_novma (&init_mm, lm_start, lm_end, + ret =walk_kernel_page_table_range (lm_start, lm_end, &pageattr_ops,NULL , &masks);if (ret) goto unlock; } - ret =walk_page_range_novma (&init_mm, start, end, &pageattr_ops,NULL , + ret =walk_kernel_page_table_range (start, end, &pageattr_ops,NULL , &masks); unlock:
@@ -335,7 +335,7 @@ unlock:*/ flush_tlb_all ();#else - ret =walk_page_range_novma (&init_mm, start, end, &pageattr_ops,NULL , + ret =walk_kernel_page_table_range (start, end, &pageattr_ops,NULL , &masks);mmap_write_unlock (&init_mm);
include/linux/pagewalk.h +3 -4
@@ -117,10 +117,9 @@ struct mm_walk {int walk_page_range (struct mm_struct *mm,unsigned long start,unsigned long end,const struct mm_walk_ops *ops,void *private); -int walk_page_range_novma (struct mm_struct *mm,unsigned long start, -unsigned long end,const struct mm_walk_ops *ops, -pgd_t *pgd, -void *private); +int walk_kernel_page_table_range (unsigned long start, +unsigned long end,const struct mm_walk_ops *ops, +pgd_t *pgd,void *private);int walk_page_range_vma (struct vm_area_struct *vma,unsigned long start,unsigned long end,const struct mm_walk_ops *ops,void *private);
mm/hugetlb_vmemmap.c +1 -1
@@ -166,7 +166,7 @@ static int vmemmap_remap_range(unsignedVM_BUG_ON (!PAGE_ALIGNED (start | end));mmap_read_lock (&init_mm); - ret =walk_page_range_novma (&init_mm, start, end, &vmemmap_remap_ops, + ret =walk_kernel_page_table_range (start, end, &vmemmap_remap_ops,NULL , walk);mmap_read_unlock (&init_mm);if (ret)
mm/internal.h +6 -0
@@ -12,6 +12,7 @@#include <linux/mm.h> #include <linux/mm_inline.h> #include <linux/pagemap.h> +#include <linux/pagewalk.h> #include <linux/rmap.h> #include <linux/swap.h> #include <linux/swapops.h>
@@ -1540,4 +1541,9 @@ static inline void accept_page(struct pa }#endif /* CONFIG_UNACCEPTED_MEMORY */ +/* pagewalk.c */ +int walk_page_range_debug (struct mm_struct *mm,unsigned long start, +unsigned long end,const struct mm_walk_ops *ops, +pgd_t *pgd,void *private); +#endif /* __MM_INTERNAL_H */
mm/pagewalk.c +55 -22
118 lines not on this page · raw message
mm/ptdump.c +2 -1
@@ -4,6 +4,7 @@#include <linux/debugfs.h> #include <linux/ptdump.h> #include <linux/kasan.h> +#include "internal.h" #if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )/*
@@ -156,7 +157,7 @@ void ptdump_walk_pgd(struct ptdump_stateget_online_mems ();mmap_write_lock (mm);while (range->start != range->end) { -walk_page_range_novma (mm, range->start, range->end, +walk_page_range_debug (mm, range->start, range->end, &ptdump_ops, pgd, st); range++; }
Greg Kroah-Hartman
maintainerPATCH 180/220 mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit 26444eb71465c9934d9d418ef69c43f61185329b ]
Patch series "mm: fix UAF caused by race between ptdump and vmap pgtable freeing", v6.
Kernel page table walkers fall into two broad categories - those ranges where no exclusion is required via walk_kernel_page_table_range_lockless() and those where exclusion is required via walk_kernel_page_table_range() or walk_page_range_debug().
The former category is used only by arm64 arch code operating on ranges it both wholly owns and does not concurrently write.
The latter category consists of kernel page table walkers operating on ranges that are wholly owned (but which need exclusion against concurrent writers).
The lock used for exclusion is the mmap lock, and for kernel ranges this is the mmap lock on init_mm.
ptdump is a special case being both the only user of walk_page_range_debug(), and the only case in which it walks ranges it does not own.
This presents a problem, as page tables may be freed under ptdump. And indeed there is a use-after-free bug in the kernel as a result, which this series addresses.
vmap promotes page tables to huge leaf entries where possible, freeing the lower page table when it does. It does this with no meaningful locks held against concurrent ptdump walks.
As a result, use-after-free can currently occur. This series addresses the issue by having the vmap huge promotion logic acquire the mmap read lock while both setting the huge page table entry and freeing the prior leaf page table.
The ptdump code already acquires the mmap write lock, so by doing so we ensure that the ptdump walker only ever observes either the huge page table entry or the existing page table entry, and nothing is freed underneath it.
A mitigation for this issue was already applied for arm64 in commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump"), which this series has to deal with carefully.
This mitigation resolves the issue by acquiring the mmap read lock on init_mm on vmap page table free if a ptdump is in progress.
However the fix in this series would cause a deadlock if we were to simply apply it for arm64 without also reverting the change.
This is because vmap may acquire the read lock before ptdump attempts to acquire the write lock, which then gets queued, and rwsem starvation rules mean that the (unacknowledged) nested mmap read lock in the arm64 code would also block, meaning the original read lock is never released and thus deadlock.
This series works around this by #ifndef CONFIG_ARM64'ing the mmap read lock in vmap logic, then partially reverting commit fa93b45fd397 ("arm64:
Enable vmalloc-huge with ptdump"), keeping the enablement of huge vmap support, and removing the ifdeffery with the partial revert patch.
There are related issues that are also addressed in this series:
* x86 page attribute logic, specifically Change Page Attributes (CPA), implements a feature whereby huge ranges can be collapsed into huge leaf entries. This can similarly cause a UAF when done in parallel with a ptdump walk, so similarly acquire the init_mm mmap lock to avoid this.
* The CPA logic allows concurrent page table manipulation and CPA collapse, meaning the former risks accessing a page table the latter frees. Fix this by acquiring mmap write lock on init_mm across the whole CPA collapse operation and read lock on the page table manipulation.
* x86 and arm64 permit walks of non-kernel mm's (both allowing efi mm walks, and in x86's case arbitrary mm's), so we ensure kernel mappings remain stable by locking the init_mm as well as the mm being walked.
The ordering of patches is established for both strict dependencies (the arm64 partial revert in particular has to be done after the vmap changes) and logical ones (the non-kernel mm fix only makes sense once the vmap/CPA fixes are in place).
This patch (of 3):
Currently there is a nasty race between ptdump and vmap when attempting to map a huge P4D, PUD or PMD entry:
* ptdump walks kernel page table ranges it doesn't own.
* When vmap maps ranges it tries to promotes existing ones to huge page tables in vmap_try_huge_[p4d,pud,pmd]() at P4D, PUD and PMD level, freeing the lower page table in [p4d,pud,pmd]_free_[pud,pmd,pte]_page() when it succeeds.
Both of these things can happen at the same time and as a result ptdump can access a freed page table, resulting in a use-after-free and memory corruption.
This is possible because while ptdump_walk_pgd() holds both the mem hotplug lock and the mmap write lock before invoking walk_page_range_debug(), vmap takes no relevant locks at all.
Fix this by holding the mmap read lock in vmap_try_huge_*() when freeing page tables.
The read lock is sufficient: ptdump is the only walker that must be excluded and it holds the mmap write lock. Other holders of the read lock may run concurrently, but each exclusively owns the range it operates on and cannot reach the page tables freed here.
We also hold the lock while assigning the huge page table entry, which means page table walkers observe only the huge or non-huge page table entry.
We use a trylock to prevent ptdump from blocking vmap making forward progress. This is fine because it's an optimisation in any case, and thus the vmap can safely proceed regardless.
All other kernel page table walkers that touch vmalloc ranges either exclusively own the memory walked or acquire the mmap lock, so this correctly excludes those walkers.
One wrinkle here is commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump"), which addresses the issue for arm64 only by explicitly acquiring the mmap read lock on kernel page table freeing should a concurrent ptdump be in progress.
This is problematic as vmap may acquire the mmap read lock prior to ptdump attempting to acquire an mmap write lock, leading to a deadlock when the mmap read lock is slept upon on page table freeing due to rwsem anti-starvation.
We work around this by predicating the mmap lock being taken on !CONFIG_ARM64 for the time being.
With this patch applied, a follow up will partially revert commit fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump") and at that stage remove the arm64 ifdeffery.
We also update walk_page_range_debug() to assert the mmap write lock unconditionally and update the comment here to reflect this change.
The issue has existed as long as ptdump was available and vmap freed page tables when promoting to a huge leaf entry, that is, since commit b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table") for huge ioremap, and commit 121e6f3258fe ("mm/vmalloc: hugepage vmalloc mappings") for huge vmalloc.
Since the former is the earlier of the two we choose that for our Fixes tag.
We also define a guard class for mmap_read_trylock() so we can use cleanup.h to make the scope handling cleaner in the implementation.
This patch is based on work by David Carlier (linked), with gratitude!
Stable-dep-of: 27c32e553834 ("mm/ptdump: always stabilise against page table freeing using init_mm")
--- mm/pagewalk.c | 22 +++++++++++---------- mm/vmalloc.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 16 deletions(-)
mm/pagewalk.c +12 -10
@@ -561,6 +561,8 @@ int walk_kernel_page_table_range(unsigne* will also not lock the PTEs for the pte_entry() callback. * * This is for debugging purposes ONLY. +* +* The mmap write lock must be held. */ int walk_page_range_debug(struct mm_struct *mm, unsigned long start, unsigned long end, const struct mm_walk_ops *ops,
@@ -574,6 +576,16 @@ int walk_page_range_debug(struct mm_stru .no_vma = true }; +/* +* When walking userland page tables, an mmap write lock must be held to +* account for munmap() downgrading to an mmap read lock when tearing +* down page tables. +* +* When walking kernel page tables, an mmap write lock must also be held +* to account for page table freeing on vmap huge page mapping. +*/ +mmap_assert_write_locked (mm); +/* For convenience, we allow traversal of kernel mappings. */ if (mm == &init_mm) return walk_kernel_page_table_range(start, end, ops,
@@ -581,16 +593,6 @@ int walk_page_range_debug(struct mm_struif (start >= end || !walk.mm)return -EINVAL ; -/* -* The mmap lock protects the page walker from changes to the page -* tables during the walk. However a read lock is insufficient to -* protect those areas which don't have a VMA as munmap() detaches -* the VMAs before downgrading to a read lock and actually tearing -* down PTEs/page tables. In which case, the mmap write lock should -* be held. -*/ -mmap_assert_write_locked (mm); -return walk_pgd_range (start, end, &walk); }
mm/vmalloc.c +54 -6
102 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 181/220 mm/ptdump: always stabilise against page table freeing using init_mm
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit 27c32e5538344b13c1505a08861e04620c125d47 ]
Previous commits have established the invariant that kernel page table freeing is performed while an mmap read lock on init_mm is held, which fixes races between ptdump and kernel page table freeing over init_mm.
However, x86 and arm64 can perform a ptdump over an mm other than init_mm via ptdump_walk_pgd() and since kernel memory ranges are shared across non-kernel mm's, this means that the race still exists for these cases.
Fix this by acquiring a nested mmap write lock for init_mm in ptdump_walk_pgd().
This is safe as we take this after mmap write locking the mm, and nothing acquires the init_mm lock first before locking an arbitrary mm, so no deadlock is possible.
Also update walk_page_range_debug() to assert that init_mm is write locked, add a comment explaining why and remove some redundant code, and eliminate the unnecessary and confusing invocation of walk_kernel_page_table_range().
We can safely remove the non-NULL check for walk.mm, as the mmap lock asserts would NULL pointer deref if it was (and of course no callers do this).
The first point at which ptdump can race kernel page table freeing is commit b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table"), so we target this in the Fixes tag.
--- mm/pagewalk.c | 14 +++++++++----- mm/ptdump.c | 7 +++++++ 2 files changed, 16 insertions(+), 5 deletions(-)
mm/pagewalk.c +9 -5
@@ -585,12 +585,16 @@ int walk_page_range_debug(struct mm_stru* to account for page table freeing on vmap huge page mapping. */ mmap_assert_write_locked (mm); +/* +* x86, arm64 ptdump allow walks of efi mm's and x86 ptdump allows walks +* of arbitrary mm's. +* +* However, they both must also hold the init_mm lock to account for +* concurrent kernel page table freeing. +*/ +mmap_assert_write_locked (&init_mm); -/* For convenience, we allow traversal of kernel mappings. */ -if (mm == &init_mm) -return walk_kernel_page_table_range (start, end, ops, - pgd, private); -if (start >= end || !walk.mm) +if (start >= end)return -EINVAL ;return walk_pgd_range (start, end, &walk);
mm/ptdump.c +7 -0
@@ -156,11 +156,18 @@ void ptdump_walk_pgd(struct ptdump_stateget_online_mems ();mmap_write_lock (mm); +/* To stabilise kernel page tables we must hold the init_mm lock too. */ +if (mm != &init_mm) +mmap_write_lock_nested (&init_mm,SINGLE_DEPTH_NESTING ); +while (range->start != range->end) {walk_page_range_debug (mm, range->start, range->end, &ptdump_ops, pgd, st); range++; } + +if (mm != &init_mm) +mmap_write_unlock (&init_mm);mmap_write_unlock (mm);put_online_mems ();
Greg Kroah-Hartman
maintainerPATCH 182/220 KVM: SVM: Serialize accesses to the owner and mirror list with separate lock
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini <[email protected]>
[ Upstream commit 1d78d33275ef2a16c6d080910b291d0a97a0e613 ]
Interaction between KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM and KVM_CAP_VM_COPY_ENC_CONTEXT_FROM can cause two separate issues:
- in sev_migrate_from(), when the destination KVM is a mirror, the mirror entry is moved from the source's list to the owner's mirror_vms list, without holding the owner's lock unlike other writers of the owner's mirror list (sev_vm_copy_enc_context_from(), sev_vm_destroy()). A concurrent COPY or destroy can race with sev_migrate_from() and corrupt the list.
- In sev_vm_destroy(), the *owner* is still active and could receive concurrently a KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM that causes sev->enc_context_owner to change. In this case the incorrect VM receives kvm_put_kvm().
The second issue needs particular care because the owner could disappear altogether (even though the race window is impossibly small) between reading it and locking it. There is thus no way to perform the checks under the owner lock without putting struct kvm under SLAB_TYPESAFE_BY_RCU (which would allow kvm_get_kvm_safe() under RCU critical section).
It is much simpler to just use a global lock, since the critical sections are so small and the new lock is always a leaf lock.
--- arch/x86/kvm/svm/sev.c | 39 +++++++++++++++++++++++++++------------ arch/x86/kvm/svm/svm.h | 1 + 2 files changed, 28 insertions(+), 12 deletions(-)
arch/x86/kvm/svm/sev.c +27 -12
@@ -82,6 +82,8 @@ static u64 sev_supported_vmsa_features;static u8 sev_enc_bit;static DECLARE_RWSEM (sev_deactivate_lock);static DEFINE_MUTEX (sev_bitmap_lock); +/* Protects kvm_sev_info's enc_context_owner, mirror_vms and mirror_entry. */ +static DEFINE_MUTEX (sev_mirror_lock);unsigned int max_sev_asid;static unsigned int min_sev_asid;static unsigned long sev_me_mask;
@@ -1989,7 +1991,6 @@ static void sev_migrate_from(struct kvm dst->asid = src->asid; dst->handle = src->handle; dst->pages_locked = src->pages_locked; - dst->enc_context_owner = src->enc_context_owner; dst->es_active = src->es_active; dst->vmsa_features = src->vmsa_features;
@@ -1997,11 +1998,12 @@ static void sev_migrate_from(struct kvm src->active = false; src->handle =0 ; src->pages_locked =0 ; - src->enc_context_owner =NULL ; src->es_active = false;list_cut_before (&dst->regions_list, &src->regions_list, &src->regions_list); +mutex_lock (&sev_mirror_lock); +/* * If this VM has mirrors, "transfer" each mirror's refcount of the * source to the destination (this KVM). The caller holds a reference
@@ -2018,13 +2020,15 @@ static void sev_migrate_from(struct kvm* If this VM is a mirror, remove the old mirror from the owners list * and add the new mirror to the list. */ -if (is_mirroring_enc_context (dst_kvm)) { -struct kvm_sev_info *owner_sev_info = - &to_kvm_svm (dst->enc_context_owner)->sev_info; +if (is_mirroring_enc_context (src_kvm)) { +struct kvm_sev_info *owner_sev_info =to_kvm_sev_info (src->enc_context_owner); + dst->enc_context_owner = src->enc_context_owner; + src->enc_context_owner =NULL ;list_del (&src->mirror_entry);list_add_tail (&dst->mirror_entry, &owner_sev_info->mirror_vms); } +mutex_unlock (&sev_mirror_lock);kvm_for_each_vcpu (i, dst_vcpu, dst_kvm) { dst_svm =to_svm (dst_vcpu);
@@ -2843,13 +2847,16 @@ int sev_vm_copy_enc_context_from(struct* The mirror kvm holds an enc_context_owner ref so its asid can't * disappear until we're done with it */ - source_sev = &to_kvm_svm (source_kvm)->sev_info; -kvm_get_kvm (source_kvm); - mirror_sev = &to_kvm_svm (kvm)->sev_info; -list_add_tail (&mirror_sev->mirror_entry, &source_sev->mirror_vms); + source_sev =to_kvm_sev_info (source_kvm); + mirror_sev =to_kvm_sev_info (kvm);/* Set enc_context_owner and copy its encryption context over */ +mutex_lock (&sev_mirror_lock); +kvm_get_kvm (source_kvm); +list_add_tail (&mirror_sev->mirror_entry, &source_sev->mirror_vms); mirror_sev->enc_context_owner = source_kvm; +mutex_unlock (&sev_mirror_lock); + mirror_sev->active = true; mirror_sev->asid = source_sev->asid; mirror_sev->fd = source_sev->fd;
@@ -2909,11 +2916,19 @@ void sev_vm_destroy(struct kvm *kvm)/* If this is a mirror_kvm release the enc_context_owner and skip sev cleanup */ if (is_mirroring_enc_context (kvm)) { -struct kvm *owner_kvm = sev->enc_context_owner; +struct kvm *owner_kvm; -mutex_lock (&owner_kvm->lock); +mutex_lock (&sev_mirror_lock); + owner_kvm = sev->enc_context_owner;list_del (&sev->mirror_entry); -mutex_unlock (&owner_kvm->lock); + sev->enc_context_owner =NULL ; + +/* +* The reference to owner_kvm cannot move after sev_mirror_lock is +* released. Release it before kvm_put_kvm() so that owner_kvm is +* never destroyed inside sev_mirror_lock. +*/ +mutex_unlock (&sev_mirror_lock);kvm_put_kvm (owner_kvm);return ; }
arch/x86/kvm/svm/svm.h +1 -0
@@ -103,6 +103,7 @@ struct kvm_sev_info {u64 ap_jump_table;/* SEV-ES AP Jump Table address */ u64 vmsa_features;u16 ghcb_version;/* Highest guest GHCB protocol version allowed */ +/* The three fields below are protected by sev_mirror_lock */ struct kvm *enc_context_owner;/* Owner of copied encryption context */ struct list_head mirror_vms;/* List of VMs mirroring */ struct list_head mirror_entry;/* Use as a list entry of mirrors */
Greg Kroah-Hartman
maintainerPATCH 183/220 ring-buffer: Simplify ring_buffer_read_page() with guard()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit b2e7c6ed26e90fab1e5e626071e54e3b9ec9cb5a ]
The function ring_buffer_read_page() had two gotos. One was simply returning "ret" and the other was unlocking the reader_lock.
There's no reason to use goto to simply return the "ret" variable. Instead just return the value.
The jump to the unlocking of the reader_lock can be replaced by guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock).
With these two changes the "ret" variable is no longer used and can be removed. The return value on non-error is what was read and is stored in the "read" variable.
Stable-dep-of: 7c727dfce6be ("ring-buffer: Prevent resizing of persistent ring buffer")
--- kernel/trace/ring_buffer.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-)
kernel/trace/ring_buffer.c +11 -17
@@ -6480,38 +6480,37 @@ int ring_buffer_read_page(struct trace_bstruct buffer_data_page *bpage;struct buffer_page *reader;unsigned long missed_events; -unsigned long flags;unsigned int commit;unsigned int read;u64 save_timestamp; -int ret =-1 ;if (!cpumask_test_cpu (cpu, buffer->cpumask)) - goto out; +return -1 ;/* * If len is not big enough to hold the page header, then * we can not copy anything. */ if (len <=BUF_PAGE_HDR_SIZE ) - goto out; +return -1 ; len -=BUF_PAGE_HDR_SIZE ;if (!data_page || !data_page->data) - goto out; +return -1 ; +if (data_page->order != buffer->subbuf_order) - goto out; +return -1 ; bpage = data_page->data;if (!bpage) - goto out; +return -1 ; -raw_spin_lock_irqsave (&cpu_buffer->reader_lock, flags); +guard (raw_spinlock_irqsave)(&cpu_buffer->reader_lock); reader =rb_get_reader_page (cpu_buffer);if (!reader) - goto out_unlock; +return -1 ; event =rb_reader_event (cpu_buffer);
@@ -6545,7 +6544,7 @@ int ring_buffer_read_page(struct trace_bif (full && (!read || (len < (commit - read)) || cpu_buffer->reader_page == cpu_buffer->commit_page)) - goto out_unlock; +return -1 ;if (len > (commit - read)) len = (commit - read);
@@ -6554,7 +6553,7 @@ int ring_buffer_read_page(struct trace_b size =rb_event_ts_length (event);if (len < size) - goto out_unlock; +return -1 ;/* save the current timestamp, since the user will need it */ save_timestamp = cpu_buffer->read_stamp;
@@ -6612,7 +6611,6 @@ int ring_buffer_read_page(struct trace_bif (reader->real_end)local_set (&bpage->commit, reader->real_end); } - ret = read; cpu_buffer->lost_events =0 ;
@@ -6639,11 +6637,7 @@ int ring_buffer_read_page(struct trace_bif (commit < buffer->subbuf_size)memset (&bpage->data[commit],0 , buffer->subbuf_size - commit); - out_unlock: -raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags); - - out: -return ret; +return read; }EXPORT_SYMBOL_GPL (ring_buffer_read_page);
Greg Kroah-Hartman
maintainerPATCH 184/220 ring-buffer: Make ring_buffer_{un}map() simpler with guard(mutex)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 60bc720e10eac397b3adae975095df77bc368b88 ]
Convert the taking of the buffer->mutex and the cpu_buffer->mapping_lock over to guard(mutex) and simplify the ring_buffer_map() and ring_buffer_unmap() functions.
Stable-dep-of: 7c727dfce6be ("ring-buffer: Prevent resizing of persistent ring buffer")
--- kernel/trace/ring_buffer.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-)
kernel/trace/ring_buffer.c +11 -24
@@ -7097,36 +7097,34 @@ int ring_buffer_map(struct trace_buffer {struct ring_buffer_per_cpu *cpu_buffer;unsigned long flags, *subbuf_ids; -int err =0 ; +int err;if (!cpumask_test_cpu (cpu, buffer->cpumask))return -EINVAL ; cpu_buffer = buffer->buffers[cpu]; -mutex_lock (&cpu_buffer->mapping_lock); +guard (mutex)(&cpu_buffer->mapping_lock);if (cpu_buffer->user_mapped) { err =__rb_map_vma (cpu_buffer, vma);if (!err) err =__rb_inc_dec_mapped (cpu_buffer, true); -mutex_unlock (&cpu_buffer->mapping_lock);return err; }/* prevent another thread from changing buffer/sub-buffer sizes */ -mutex_lock (&buffer->mutex); +guard (mutex)(&buffer->mutex); err =rb_alloc_meta_page (cpu_buffer);if (err) - goto unlock; +return err;/* subbuf_ids include the reader while nr_pages does not */ subbuf_ids =kcalloc (cpu_buffer->nr_pages +1 ,sizeof (*subbuf_ids),GFP_KERNEL );if (!subbuf_ids) {rb_free_meta_page (cpu_buffer); - err = -ENOMEM ; - goto unlock; +return -ENOMEM ; }atomic_inc (&cpu_buffer->resize_disabled);
@@ -7154,11 +7152,7 @@ int ring_buffer_map(struct trace_bufferatomic_dec (&cpu_buffer->resize_disabled); } -unlock: -mutex_unlock (&buffer->mutex); -mutex_unlock (&cpu_buffer->mapping_lock); - -return err; +return 0 ; }/*
@@ -7186,24 +7180,22 @@ int ring_buffer_unmap(struct trace_buffe {struct ring_buffer_per_cpu *cpu_buffer;unsigned long flags; -int err =0 ;if (!cpumask_test_cpu (cpu, buffer->cpumask))return -EINVAL ; cpu_buffer = buffer->buffers[cpu]; -mutex_lock (&cpu_buffer->mapping_lock); +guard (mutex)(&cpu_buffer->mapping_lock);if (!cpu_buffer->user_mapped) { - err = -ENODEV ; - goto out; +return -ENODEV ; }else if (cpu_buffer->user_mapped >1 ) {__rb_inc_dec_mapped (cpu_buffer, false); - goto out; +return 0 ; } -mutex_lock (&buffer->mutex); +guard (mutex)(&buffer->mutex);raw_spin_lock_irqsave (&cpu_buffer->reader_lock, flags);/* This is the last user space mapping */
@@ -7218,12 +7210,7 @@ int ring_buffer_unmap(struct trace_bufferb_free_meta_page (cpu_buffer);atomic_dec (&cpu_buffer->resize_disabled); -mutex_unlock (&buffer->mutex); - -out: -mutex_unlock (&cpu_buffer->mapping_lock); - -return err; +return 0 ; }int ring_buffer_map_get_reader (struct trace_buffer *buffer,int cpu)
Re: [PATCH 6.12 184/220] ring-buffer: Make ring_buffer_{un}map() simpler with guard(mutex)
Hi Greg/Sasha,
Quoted 69 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit
60bc720e10eac397b3adae975095df77bc368b88]Convert the taking of the
buffer->mutexand thecpu_buffer->mapping_lockover to guard(mutex) and simplify thering_buffer_map()andring_buffer_unmap()functions.Cc Masami Hiramatsu <[email protected]>Cc Mathieu Desnoyers <[email protected]>Cc Vincent Donnefort <[email protected]>Signed-off-by Steven Rostedt (Google) <[email protected]>Stable-dep-of:
7c727dfce6be("ring-buffer: Prevent resizing of persistent ring buffer")Signed-off-by Sasha Levin <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- kernel/trace/ring_buffer.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-)kernel/trace/ring_buffer.c +5
-7@@ -7097,36 +7097,34 @@ int ring_buffer_map(struct trace_buffer {struct ring_buffer_per_cpu *cpu_buffer;unsigned long flags, *subbuf_ids; -int err =0 ; +int err;if (!cpumask_test_cpu (cpu, buffer->cpumask))return -EINVAL ; cpu_buffer = buffer->buffers[cpu]; -mutex_lock (&cpu_buffer->mapping_lock); +guard (mutex)(&cpu_buffer->mapping_lock);if (cpu_buffer->user_mapped) { err =__rb_map_vma (cpu_buffer, vma);if (!err) err =__rb_inc_dec_mapped (cpu_buffer, true); -mutex_unlock (&cpu_buffer->mapping_lock);return err; }/* prevent another thread from changing buffer/sub-buffer sizes */ -mutex_lock (&buffer->mutex); +guard (mutex)(&buffer->mutex); err =rb_alloc_meta_page (cpu_buffer);if (err) - goto unlock; +return err;/* subbuf_ids include the reader while nr_pages does not */ subbuf_ids =kcalloc (cpu_buffer->nr_pages +1 ,sizeof (*subbuf_ids),GFP_KERNEL );if (!subbuf_ids) {rb_free_meta_page (cpu_buffer); - err = -ENOMEM ; - goto unlock; +return -ENOMEM ; }atomic_inc (&cpu_buffer->resize_disabled);
kernel/trace/ring_buffer.c int ring_buffer_map(struct trace_buffer · line 7155
Quoted 9 lines
kernel/trace/ring_buffer.c +1
-5@@ -7154,11 +7152,7 @@ int ring_buffer_map(struct trace_bufferatomic_dec (&cpu_buffer->resize_disabled); } -unlock: -mutex_unlock (&buffer->mutex); -mutex_unlock (&cpu_buffer->mapping_lock); - -return err; +return 0 ;
^^^
I ran an AI-assisted backport review and then checked c7f40b670e5c against the 6.12.y code. The refactor changes the first-map exit in ring_buffer_map() from:
return err;
to:
return 0;
That unconditional success remains in 6.12.y. If __rb_map_vma() rejects a writable, executable, private, wrongly sized, or otherwise invalid mapping, ring_buffer_map() rolls its setup back but masks the error. As a result, tracing_buffers_mmap() reports the rejected mapping as successful instead of taking its error-cleanup path.
Upstream fixes this with de4cbd704731 ("ring buffer: Propagate __rb_map_vma return value to caller"). I think we need to take this as well.
thanks,
Harshit
Quoted 1 line
kernel/trace/ring_buffer.c +0
-0}
Re: [PATCH 6.12 184/220] ring-buffer: Make ring_buffer_{un}map() simpler with guard(mutex)
Quoted 9 lines
I ran an AI-assisted backport review and then checked
c7f40b670e5cagainst the 6.12.y code. The refactor changes the first-map exit inring_buffer_map()from:return err;to:
return 0;
Queued for 6.12, thanks.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 185/220 ring-buffer: Prevent resizing of persistent ring buffer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <[email protected]>
[ Upstream commit 7c727dfce6be04dd009b29091a4a17d952dbfe03 ]
Dynamically resizing a persistent ring buffer is not possible. Disable the feature.
--- kernel/trace/ring_buffer.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/ring_buffer.c +2 -0
@@ -2239,6 +2239,8 @@ rb_allocate_cpu_buffer(struct trace_buffif (cpu_buffer->ring_meta->head_buffer)rb_meta_buffer_update (cpu_buffer, bpage); bpage->range =1 ; + +atomic_inc (&cpu_buffer->resize_disabled); }else { page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
Greg Kroah-Hartman
maintainerPATCH 186/220 x86/mce: Remove __mcheck_cpu_init_early()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yazen Ghannam <[email protected]>
[ Upstream commit 9f34032ec0deef58bd0eb7475f1981adfa998648 ]
The __mcheck_cpu_init_early() function was introduced so that some vendor-specific features are detected before the first MCA polling event done in __mcheck_cpu_init_generic().
Currently, __mcheck_cpu_init_early() is only used on AMD-based systems and additional code will be needed to support various system configurations.
However, the current and future vendor-specific code should be done during vendor init. This keeps all the vendor code in a common location and simplifies the generic init flow.
Move all the __mcheck_cpu_init_early() code into mce_amd_feature_init().
Stable-dep-of: a213dfaa2596 ("x86/mce: Set up the polling timer before CMCI discovery")
--- arch/x86/kernel/cpu/mce/amd.c | 4 ++++ arch/x86/kernel/cpu/mce/core.c | 14 -------------- 2 files changed, 4 insertions(+), 14 deletions(-)
arch/x86/kernel/cpu/mce/amd.c +4 -0
@@ -674,6 +674,10 @@ void mce_amd_feature_init(struct cpuinfou32 low =0 , high =0 , address =0 ;int offset =-1 ; + mce_flags.overflow_recov =cpu_feature_enabled (X86_FEATURE_OVERFLOW_RECOV ); + mce_flags.succor =cpu_feature_enabled (X86_FEATURE_SUCCOR ); + mce_flags.smca =cpu_feature_enabled (X86_FEATURE_SMCA ); + mce_flags.amd_threshold =1 ;for (bank =0 ; bank <this_cpu_read (mce_num_banks); ++bank) {if (mce_flags.smca)
arch/x86/kernel/cpu/mce/core.c +0 -14
@@ -2011,19 +2011,6 @@ static int __mcheck_cpu_ancient_init(strreturn 0 ; } -/* -* Init basic CPU features needed for early decoding of MCEs. -*/ -static void __mcheck_cpu_init_early (struct cpuinfo_x86 *c) -{ -if (c->x86_vendor ==X86_VENDOR_AMD || c->x86_vendor ==X86_VENDOR_HYGON ) { - mce_flags.overflow_recov = !!cpu_has (c,X86_FEATURE_OVERFLOW_RECOV ); - mce_flags.succor = !!cpu_has (c,X86_FEATURE_SUCCOR ); - mce_flags.smca = !!cpu_has (c,X86_FEATURE_SMCA ); - mce_flags.amd_threshold =1 ; - } -} -static void mce_centaur_feature_init (struct cpuinfo_x86 *c) {struct mca_config *cfg = &mca_cfg;
@@ -2266,7 +2253,6 @@ void mcheck_cpu_init(struct cpuinfo_x86 mca_cfg.initialized =1 ; -__mcheck_cpu_init_early (c);__mcheck_cpu_init_generic ();__mcheck_cpu_init_vendor (c);__mcheck_cpu_init_clear_banks ();
Greg Kroah-Hartman
maintainerPATCH 187/220 x86/mce: Set CR4.MCE last during init
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yazen Ghannam <[email protected]>
[ Upstream commit cfffcf97997bd35f4a59e035523d1762568bdbad ]
Set the CR4.MCE bit as the last step during init. This brings the MCA init order closer to what is described in the x86 docs.
x86 docs:
AMD Intel
MCG_CTL
MCA_CONFIG MCG_EXT_CTL
MCi_CTL MCi_CTL
MCG_CTL
CR4.MCE CR4.MCE
Current Linux:
AMD Intel
CR4.MCE CR4.MCE
MCG_CTL MCG_CTL
MCA_CONFIG MCG_EXT_CTL
MCi_CTL MCi_CTL
Updated Linux:
AMD Intel
MCG_CTL MCG_CTL
MCA_CONFIG MCG_EXT_CTL
MCi_CTL MCi_CTL
CR4.MCE CR4.MCE
The new init flow will match Intel's docs, but there will still be a mismatch for AMD regarding MCG_CTL. However, there is no known issue with this ordering, so leave it for now.
Stable-dep-of: a213dfaa2596 ("x86/mce: Set up the polling timer before CMCI discovery")
--- arch/x86/kernel/cpu/mce/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/mce/core.c +3 -2
@@ -1836,8 +1836,6 @@ static void __mcheck_cpu_init_generic(vobitmap_fill (all_banks,MAX_NR_BANKS );machine_check_poll (MCP_UC |MCP_QUEUE_LOG | m_fl, &all_banks); -cr4_set_bits (X86_CR4_MCE ); -rdmsrl (MSR_IA32_MCG_CAP , cap);if (cap &MCG_CTL_P )wrmsr (MSR_IA32_MCG_CTL ,0xffffffff ,0xffffffff );
@@ -2258,6 +2256,7 @@ void mcheck_cpu_init(struct cpuinfo_x86__mcheck_cpu_init_clear_banks ();__mcheck_cpu_check_banks ();__mcheck_cpu_setup_timer (); +cr4_set_bits (X86_CR4_MCE ); }/*
@@ -2425,6 +2424,7 @@ static void mce_syscore_resume(void)__mcheck_cpu_init_generic ();__mcheck_cpu_init_vendor (raw_cpu_ptr (&cpu_info));__mcheck_cpu_init_clear_banks (); +cr4_set_bits (X86_CR4_MCE ); }static struct syscore_ops mce_syscore_ops = {
@@ -2444,6 +2444,7 @@ static void mce_cpu_restart(void *data)__mcheck_cpu_init_generic ();__mcheck_cpu_init_clear_banks ();__mcheck_cpu_init_timer (); +cr4_set_bits (X86_CR4_MCE ); }/* Reinit MCEs after user configuration changes */
Greg Kroah-Hartman
maintainerPATCH 188/220 x86/mce: Set up the polling timer before CMCI discovery
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit a213dfaa2596c1c0dc4dae91c14fbfa499c03223 ]
I hit the following on one of my machines:
mce: CPU0 BANK15 CMCI inherited storm
------------[ cut here ]------------ ODEBUG: assert_init not available (active state 0) object: (____ptrval____) object type: timer_list hint: 0x0 WARNING: lib/debugobjects.c:632 at debug_object_assert_init+0x178/0x230, CPU#0: swapper/0/0 CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.2.0-rc5 #3 PREEMPTLAZY RIP: 0010:debug_object_assert_init+0x18f/0x230 Call Trace: <TASK> __mod_timer mce_timer_kick cmci_discover intel_init_cmci mce_intel_feature_init mcheck_cpu_init identify_cpu identify_boot_cpu arch_cpu_finalize_init start_kernel
A second splat follows right after, from timer_setup() finding that same timer already queued:
ODEBUG: init active (active state 0) object: (____ptrval____) object type: timer_list hint: stub_timer+0x0/0x10
This is happening because CMCI storm detection is trying to modify the timer before latter was properly set up.
Set up the timer first. __mcheck_cpu_setup_timer() only calls timer_setup(), and depends on neither the generic nor the vendor init.
[ bp: Massage commit message. ]
--- arch/x86/kernel/cpu/mce/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/cpu/mce/core.c +1 -1
@@ -2251,11 +2251,11 @@ void mcheck_cpu_init(struct cpuinfo_x86 mca_cfg.initialized =1 ; +__mcheck_cpu_setup_timer ();__mcheck_cpu_init_generic ();__mcheck_cpu_init_vendor (c);__mcheck_cpu_init_clear_banks ();__mcheck_cpu_check_banks (); -__mcheck_cpu_setup_timer ();cr4_set_bits (X86_CR4_MCE ); }
Greg Kroah-Hartman
maintainerPATCH 189/220 ipv4: start using dst_dev_rcu()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8 ]
Change icmpv4_xrlim_allow(), ip_defrag() to prevent possible UAF.
Change ipmr_prepare_xmit(), ipmr_queue_fwd_xmit(), ip_mr_output(), ipv4_neigh_lookup() to use lockdep enabled dst_dev_rcu().
--- net/ipv4/icmp.c | 6 +++--- net/ipv4/ip_fragment.c | 6 ++++-- net/ipv4/ipmr.c | 4 ++-- net/ipv4/route.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-)
net/ipv4/icmp.c +3 -3
@@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct nereturn true;/* No rate limit on loopback */ - dev =dst_dev (dst); +rcu_read_lock (); + dev =dst_dev_rcu (dst);if (dev && (dev->flags &IFF_LOOPBACK )) goto out; -rcu_read_lock (); peer =inet_getpeer_v4 (net->ipv4.peers, fl4->daddr,l3mdev_master_ifindex_rcu (dev)); rc =inet_peer_xrlim_allow (peer,READ_ONCE (net->ipv4.sysctl_icmp_ratelimit)); -rcu_read_unlock (); out: +rcu_read_unlock ();if (!rc)__ICMP_INC_STATS (net,ICMP_MIB_RATELIMITHOST );else
net/ipv4/ip_fragment.c +4 -2
@@ -483,13 +483,15 @@ out_fail:/* Process an incoming IP datagram fragment. */ int ip_defrag (struct net *net,struct sk_buff *skb,u32 user) { -struct net_device *dev = skb->dev ? :skb_dst_dev (skb); -int vif =l3mdev_master_ifindex_rcu (dev); +struct net_device *dev;struct ipq *qp; +int vif;__IP_INC_STATS (net,IPSTATS_MIB_REASMREQDS );/* Lookup (or create) queue header */ + dev = skb->dev ? :skb_dst_dev_rcu (skb); + vif =l3mdev_master_ifindex_rcu (dev); qp =ip_find (net,ip_hdr (skb), user, vif);if (qp) {int ret;
net/ipv4/ipmr.c +2 -2
@@ -1906,7 +1906,7 @@ static void ipmr_queue_xmit(struct net * goto out_free; } - encap +=LL_RESERVED_SPACE (dev) + rt->dst.header_len; + encap +=LL_RESERVED_SPACE (dst_dev_rcu (&rt->dst)) + rt->dst.header_len;if (skb_cow (skb, encap)) {ip_rt_put (rt);
@@ -1943,7 +1943,7 @@ static void ipmr_queue_xmit(struct net ** result in receiving multiple packets. */ NF_HOOK (NFPROTO_IPV4 ,NF_INET_FORWARD , - net,NULL , skb, skb->dev, dev, + net,NULL , skb, skb->dev,dst_dev_rcu (&rt->dst), ipmr_forward_finish);return ;
net/ipv4/route.c +2 -2
@@ -413,11 +413,11 @@ static struct neighbour *ipv4_neigh_look const void *daddr) { const struct rtable *rt = container_of(dst, struct rtable, dst); -struct net_device *dev =dst_dev (dst); +struct net_device *dev;struct neighbour *n;rcu_read_lock (); - + dev =dst_dev_rcu (dst);if (likely (rt->rt_gw_family ==AF_INET )) { n =ip_neigh_gw4 (dev, rt->rt_gw4); }else if (rt->rt_gw_family ==AF_INET6 ) {
Re: [PATCH 6.12 189/220] ipv4: start using dst_dev_rcu()
Hi,
I think I made a mistake on my backport :
Le 20/08/2026 à 16:56, Greg Kroah-Hartman a écrit :
Quoted 58 lines
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit
6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8]Change
icmpv4_xrlim_allow(),ip_defrag()to prevent possible UAF.Change
ipmr_prepare_xmit(),ipmr_queue_fwd_xmit(),ip_mr_output(),ipv4_neigh_lookup()to use lockdep enableddst_dev_rcu().Fixes 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")Signed-off-by Eric Dumazet <[email protected]>Reviewed-by David Ahern <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>[ minor modifications to fix conflict ]Signed-off-by Miguel Gazquez <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- net/ipv4/icmp.c | 6 +++--- net/ipv4/ip_fragment.c | 6 ++++-- net/ipv4/ipmr.c | 4 ++-- net/ipv4/route.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-)net/ipv4/icmp.c +3
-3@@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct nereturn true;/* No rate limit on loopback */ - dev =dst_dev (dst); +rcu_read_lock (); + dev =dst_dev_rcu (dst);if (dev && (dev->flags &IFF_LOOPBACK )) goto out; -rcu_read_lock (); peer =inet_getpeer_v4 (net->ipv4.peers, fl4->daddr,l3mdev_master_ifindex_rcu (dev)); rc =inet_peer_xrlim_allow (peer,READ_ONCE (net->ipv4.sysctl_icmp_ratelimit)); -rcu_read_unlock (); out: +rcu_read_unlock ();if (!rc)__ICMP_INC_STATS (net,ICMP_MIB_RATELIMITHOST );else net/ipv4/ip_fragment.c +0
-1@@ -483,13 +483,15 @@ out_fail:/* Process an incoming IP datagram fragment. */ int ip_defrag (struct net *net,struct sk_buff *skb,u32 user) { -struct net_device *dev = skb->dev ? :skb_dst_dev (skb);
net/ipv4/ip_fragment.c out_fail: · line 494
Quoted 10 lines
net/ipv4/ip_fragment.c +4
-1-int vif =l3mdev_master_ifindex_rcu (dev); +struct net_device *dev;struct ipq *qp; +int vif;__IP_INC_STATS (net,IPSTATS_MIB_REASMREQDS );/* Lookup (or create) queue header */ + dev = skb->dev ? :skb_dst_dev_rcu (skb); + vif =l3mdev_master_ifindex_rcu (dev);
Here, the upstream version has a rcu_read_lock(); that I think should be added. I will send an updated version.
Quoted 41 lines
net/ipv4/ip_fragment.c +0
-0qp =ip_find (net,ip_hdr (skb), user, vif);if (qp) {int ret;net/ipv4/ipmr.c +2
-2@@ -1906,7 +1906,7 @@ static void ipmr_queue_xmit(struct net * goto out_free; } - encap +=LL_RESERVED_SPACE (dev) + rt->dst.header_len; + encap +=LL_RESERVED_SPACE (dst_dev_rcu (&rt->dst)) + rt->dst.header_len;if (skb_cow (skb, encap)) {ip_rt_put (rt);@@ -1943,7 +1943,7 @@ static void ipmr_queue_xmit(struct net ** result in receiving multiple packets. */ NF_HOOK (NFPROTO_IPV4 ,NF_INET_FORWARD , - net,NULL , skb, skb->dev, dev, + net,NULL , skb, skb->dev,dst_dev_rcu (&rt->dst), ipmr_forward_finish);return ;net/ipv4/route.c +2
-2@@ -413,11 +413,11 @@ static struct neighbour *ipv4_neigh_look const void *daddr) { const struct rtable *rt = container_of(dst, struct rtable, dst); -struct net_device *dev =dst_dev (dst); +struct net_device *dev;struct neighbour *n;rcu_read_lock (); - + dev =dst_dev_rcu (dst);if (likely (rt->rt_gw_family ==AF_INET )) { n =ip_neigh_gw4 (dev, rt->rt_gw4); }else if (rt->rt_gw_family ==AF_INET6 ) {
Signature · 3 lines
Miguel Gazquez, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Greg Kroah-Hartman
maintainerRe: [PATCH 6.12 189/220] ipv4: start using dst_dev_rcu()
Quoted 64 lines · Miguel Gazquez
Hi,
I think I made a mistake on my backport :
Le 20/08/2026 à 16:56, Greg Kroah-Hartman a écrit :
Quoted 59 lines
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit
6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8]Change
icmpv4_xrlim_allow(),ip_defrag()to prevent possible UAF.Change
ipmr_prepare_xmit(),ipmr_queue_fwd_xmit(),ip_mr_output(),ipv4_neigh_lookup()to use lockdep enableddst_dev_rcu().Fixes 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")Signed-off-by Eric Dumazet <[email protected]>Reviewed-by David Ahern <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>[ minor modifications to fix conflict ]Signed-off-by Miguel Gazquez <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- net/ipv4/icmp.c | 6 +++--- net/ipv4/ip_fragment.c | 6 ++++-- net/ipv4/ipmr.c | 4 ++-- net/ipv4/route.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-)net/ipv4/icmp.c +3
-3@@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct nereturn true;/* No rate limit on loopback */ - dev =dst_dev (dst); +rcu_read_lock (); + dev =dst_dev_rcu (dst);if (dev && (dev->flags &IFF_LOOPBACK )) goto out; -rcu_read_lock (); peer =inet_getpeer_v4 (net->ipv4.peers, fl4->daddr,l3mdev_master_ifindex_rcu (dev)); rc =inet_peer_xrlim_allow (peer,READ_ONCE (net->ipv4.sysctl_icmp_ratelimit)); -rcu_read_unlock (); out: +rcu_read_unlock ();if (!rc)__ICMP_INC_STATS (net,ICMP_MIB_RATELIMITHOST );else net/ipv4/ip_fragment.c +1
-2@@ -483,13 +483,15 @@ out_fail:/* Process an incoming IP datagram fragment. */ int ip_defrag (struct net *net,struct sk_buff *skb,u32 user) { -struct net_device *dev = skb->dev ? :skb_dst_dev (skb); -int vif =l3mdev_master_ifindex_rcu (dev); +struct net_device *dev;struct ipq *qp;
Quoted 8 lines
net/ipv4/ip_fragment.c out_fail: · line 494
Quoted 5 lines
net/ipv4/ip_fragment.c +3
-0+int vif;__IP_INC_STATS (net,IPSTATS_MIB_REASMREQDS );/* Lookup (or create) queue header */ + dev = skb->dev ? :skb_dst_dev_rcu (skb); + vif =l3mdev_master_ifindex_rcu (dev);Here, the upstream version has a
rcu_read_lock();that I think should be added. I will send an updated version.
I will drop this now, thanks.
greg k-h
Sasha Levin
maintainerRe: [PATCH 6.12 189/220] ipv4: start using dst_dev_rcu()
In reply to Miguel GazquezQuoted 5 lines · Miguel Gazquez
net/ipv4/ip_fragment.c out_fail: · line 494
Quoted 2 lines
net/ipv4/ip_fragment.c +2
-0+ dev = skb->dev ? :skb_dst_dev_rcu (skb); + vif =l3mdev_master_ifindex_rcu (dev);Here, the upstream version has a
rcu_read_lock();that I think should be added. I will send an updated version.
Agreed, and confirmed here. Upstream that hunk lands after the rcu_read_lock() introduced by ca0359df45a5 ("inet: frags: save a pair of atomic operations in reassembly", v6.15), which isn't in 6.12 - so as backported, ip_defrag() reaches skb_dst_dev_rcu() -> dst_dev_rcu() -> rcu_dereference() with no RCU read-side critical section of its own, where the pre-patch 6.12 code used skb_dst_dev() -> READ_ONCE() and had no such requirement.
In practice every in-tree ip_defrag() caller already runs under RCU (netfilter hooks or the NAPI receive path), so this is a lockdep / correctness defect rather than a guaranteed CONFIG_PROVE_RCU splat, but it does defeat the point of the conversion.
Dropped from the 6.12 queue, thanks - please do send the v2.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 190/220 ASoC: SOF: ipc4-topology: Refresh copier IPC payload before widget setup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit 0c0e418dbcf0582bf80d8dbfd9b306607c065992 upstream.
The ipc_config_data buffer for copier widgets is built once during ipc_prepare (called from sof_pcm_setup_connected_widgets) and cached for reuse. For host copiers this buffer contains the copier_data with gtw_cfg.node_id (host DMA ID). For DAI copiers it additionally includes a dma_config_tlv trailer with stream_id and dma_channel_id for HDA link DMA.
On suspend/resume, both host and link DMA streams are released and re-allocated with potentially different stream tags. The underlying copier_data and dma_config_tlv structures are correctly updated by host_config and sdw_hda_dai_hw_params respectively. However, since the widget list (spcm->stream[].list) persists across suspend, sof_pcm_hw_params skips sof_pcm_setup_connected_widgets and ipc_prepare never runs again to rebuild ipc_config_data. The stale cached payload is then sent to firmware with boot-time DMA channel assignments, causing DMA channel conflicts that lead to firmware errors and crashes.
Fix this by refreshing copier_data and dma_config_tlv portions of ipc_config_data in sof_ipc4_widget_setup right before the IPC message is sent. This ensures the payload always reflects the current DMA state regardless of whether ipc_prepare ran.
For DAI copiers, the gtw_cfg.config_length in copier_data is temporarily inflated to include the TLV size (matching the ipc_config_data layout) before copying, then restored, mirroring what sof_ipc4_prepare_copier_module does when first building the buffer.
--- sound/soc/sof/ipc4-topology.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
sound/soc/sof/ipc4-topology.c +33 -0
@@ -2654,6 +2654,15 @@ static int sof_ipc4_widget_setup(struct ipc_size = ipc4_copier->ipc_config_size; ipc_data = ipc4_copier->ipc_config_data; +/* +* Refresh copier_data in ipc_config_data for host copiers. +* The node_id may have been updated by host_config after +* ipc_prepare, e.g. when host stream tags change after a +* suspend/resume cycle. +*/ +if (swidget->id != snd_soc_dapm_buffer) +memcpy (ipc_data, &ipc4_copier->data,sizeof (ipc4_copier->data)); + msg = &ipc4_copier->msg;break ; }
@@ -2662,6 +2671,9 @@ static int sof_ipc4_widget_setup(struct {struct snd_sof_dai *dai = swidget->private;struct sof_ipc4_copier *ipc4_copier = dai->private; +struct sof_ipc4_copier_data *copier_data; +u32 gtw_cfg_config_length; +u32 tlv_size; pipeline = pipe_widget->private;if (pipeline->use_chain_dma)
@@ -2670,6 +2682,27 @@ static int sof_ipc4_widget_setup(struct ipc_size = ipc4_copier->ipc_config_size; ipc_data = ipc4_copier->ipc_config_data; +/* +* Refresh copier_data and dma_config_tlv in ipc_config_data. +* These may have been updated after ipc_prepare, e.g. when +* link DMA stream tags change after a suspend/resume cycle. +* +* copier_data->gtw_cfg.config_length does not include the +* TLV size (it was restored after sof_ipc4_prepare_copier_module), +* so temporarily inflate it to match the ipc_config_data layout. +*/ + copier_data = &ipc4_copier->data; + gtw_cfg_config_length = copier_data->gtw_cfg.config_length *4 ; + tlv_size = ipc_size -sizeof (*copier_data) - gtw_cfg_config_length; + + copier_data->gtw_cfg.config_length += tlv_size /4 ; +memcpy (ipc_data, copier_data,sizeof (*copier_data)); + copier_data->gtw_cfg.config_length = gtw_cfg_config_length /4 ; + +if (tlv_size) +memcpy (ipc_data +sizeof (*copier_data) + gtw_cfg_config_length, + &ipc4_copier->dma_config_tlv, tlv_size); + msg = &ipc4_copier->msg;break ; }
Greg Kroah-Hartman
maintainerPATCH 191/220 net/x25: fix use-after-free of the socket by its timers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 2195424c3da2ef1829a63b807e3a900a90e57d85 upstream.
The x25 timers are armed with mod_timer() and cancelled with timer_delete(), so a pending timer holds no reference on the socket and a cancel does not wait for a callback already running on another CPU.
x25_heartbeat_expiry() also rearms unconditionally, so it can reinstall sk->sk_timer after __x25_destroy_socket() has passed its cancel point. The following __sock_put() frees the socket while the timer is still queued, and the next expiry uses freed memory. KASAN reports a slab-use-after-free on the kmalloc-2k object freed by close().
timer_delete_sync() cannot be used here: x25_heartbeat_expiry() and x25_timer_expiry() both reach the cancels from inside the timer they would wait on, through __x25_destroy_socket() and x25_disconnect().
Arm the timers with sk_reset_timer() and cancel them with sk_stop_timer() so that an armed timer owns a reference, and release it in both expiry handlers. Rearm the heartbeat only while sk_hashed(sk) is still true, since __x25_destroy_socket() unlinks the socket before dropping it. Arm the deferred destroy timer the same way and drop its reference in x25_destroy_timer().
Reproduced on net with KASAN, with the heartbeat period shortened so the window recurs. With this patch the reproducer no longer triggers a report and /proc/net/x25 drains.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- net/x25/af_x25.c | 4 ++-- net/x25/x25_timer.c | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-)
net/x25/af_x25.c +2 -2
@@ -362,6 +362,7 @@ static void x25_destroy_timer(struct timstruct sock *sk =from_timer (sk, t, sk_timer);x25_destroy_socket_from_timer (sk); +sock_put (sk); }/*
@@ -397,9 +398,8 @@ static void __x25_destroy_socket(structif (sk_has_allocations (sk)) {/* Defer: outstanding buffers */ - sk->sk_timer.expires = jiffies +10 *HZ ; sk->sk_timer.function = x25_destroy_timer; -add_timer (&sk->sk_timer); +sk_reset_timer (sk, &sk->sk_timer, jiffies +10 *HZ ); }else {/* drop last reference so sock_put will free */ __sock_put (sk);
net/x25/x25_timer.c +16 -9
@@ -36,45 +36,45 @@ void x25_init_timers(struct sock *sk)void x25_start_heartbeat (struct sock *sk) { -mod_timer (&sk->sk_timer, jiffies +5 *HZ ); +sk_reset_timer (sk, &sk->sk_timer, jiffies +5 *HZ ); }void x25_stop_heartbeat (struct sock *sk) { -del_timer (&sk->sk_timer); +sk_stop_timer (sk, &sk->sk_timer); }void x25_start_t2timer (struct sock *sk) {struct x25_sock *x25 =x25_sk (sk); -mod_timer (&x25->timer, jiffies + x25->t2); +sk_reset_timer (sk, &x25->timer, jiffies + x25->t2); }void x25_start_t21timer (struct sock *sk) {struct x25_sock *x25 =x25_sk (sk); -mod_timer (&x25->timer, jiffies + x25->t21); +sk_reset_timer (sk, &x25->timer, jiffies + x25->t21); }void x25_start_t22timer (struct sock *sk) {struct x25_sock *x25 =x25_sk (sk); -mod_timer (&x25->timer, jiffies + x25->t22); +sk_reset_timer (sk, &x25->timer, jiffies + x25->t22); }void x25_start_t23timer (struct sock *sk) {struct x25_sock *x25 =x25_sk (sk); -mod_timer (&x25->timer, jiffies + x25->t23); +sk_reset_timer (sk, &x25->timer, jiffies + x25->t23); }void x25_stop_timer (struct sock *sk) { -del_timer (&x25_sk (sk)->timer); +sk_stop_timer (sk, &x25_sk (sk)->timer); }unsigned long x25_display_timer (struct sock *sk)
@@ -108,7 +108,7 @@ static void x25_heartbeat_expiry(struct sock_flag(sk, SOCK_DEAD))) {bh_unlock_sock (sk);x25_destroy_socket_from_timer (sk); -return ; + goto out; }break ;
@@ -120,8 +120,14 @@ static void x25_heartbeat_expiry(structbreak ; } restart_heartbeat: -x25_start_heartbeat (sk); +/* Do not rearm once __x25_destroy_socket() has unlinked the socket: +* it is past its cancel point and owns the teardown from there on. +*/ +if (sk_hashed (sk)) +x25_start_heartbeat (sk);bh_unlock_sock (sk); +out: +sock_put (sk); }/*
@@ -166,4 +172,5 @@ static void x25_timer_expiry(struct time }else x25_do_timer_expiry (sk);bh_unlock_sock (sk); +sock_put (sk); }
Greg Kroah-Hartman
maintainerPATCH 192/220 arm64: tegra: Add EL2 virtual timer interrupt for Tegra194
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jon Hunter <[email protected]>
[ Upstream commit a7c28483fd57dd0e1487024af70622315320774b ]
Commit d87773de9efe ("clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE") updated the ARM arch timer driver to use the virtual timer by default if the CPU is running at EL2 with VHE enabled. If the CPU is running at EL2 with VHE enabled but there is no interrupt provided for the virtual timer, then the following warning is displayed:
arch_timer: [Firmware Bug]: VHE-capable CPU without EL2 virtual timer
interrupt
This warning is observed on Tegra194 platforms. Tegra194 SoC includes NVIDIA Carmel ARM v8.2 CPUs and support an EL2 virtual timer. Fix the above warning by adding the PPI for the EL2 virtual timer interrupt for Tegra194.
--- arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/boot/dts/nvidia/tegra194.dtsi +2 -0
@@ -3161,6 +3161,8 @@ timer { <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 15 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; interrupt-parent = <&gic>; always-on;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 192/220] arm64: tegra: Add EL2 virtual timer interrupt for Tegra194
Hi Greg/Sasha,
Quoted 36 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jon Hunter <[email protected]>
[ Upstream commit
a7c28483fd57dd0e1487024af70622315320774b]Commit
d87773de9efe("clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE") updated the ARM arch timer driver to use the virtual timer by default if the CPU is running at EL2 with VHE enabled. If the CPU is running at EL2 with VHE enabled but there is no interrupt provided for the virtual timer, then the following warning is displayed:
arch_timer: [Firmware Bug]: VHE-capable CPU without EL2 virtual timer
interruptThis warning is observed on Tegra194 platforms. Tegra194 SoC includes NVIDIA Carmel ARM v8.2 CPUs and support an EL2 virtual timer. Fix the above warning by adding the PPI for the EL2 virtual timer interrupt for Tegra194.
Fixes 5425fb15d8ee ("arm64: tegra: Add Tegra194 chip device tree")Signed-off-by Jon Hunter <[email protected]>Signed-off-by Thierry Reding <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 ++ 1 file changed, 2 insertions(+)arch/arm64/boot/dts/nvidia/tegra194.dtsi +0
-0
arch/arm64/boot/dts/nvidia/tegra194.dtsi timer { · line 3166
Quoted 6 lines
arch/arm64/boot/dts/nvidia/tegra194.dtsi +2
-0@@ -3161,6 +3161,8 @@ timer { <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 15 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
I ran an AI-assisted backport review and then checked a70b2fbe03d0 against the 6.12.y timer driver. The patch adds Tegra194's fifth timer interrupt, PPI 15, but 6.12.y still selects the timer as follows:
if (is_kernel_in_hyp_mode())
return ARCH_TIMER_HYP_PPI;Upstream a7c28483fd57 follows d87773de9efe ("clocksource/drivers/arm_arch_timer: Default to EL2 virtual timer when running VHE"). That earlier commit selects ARCH_TIMER_HYP_VIRT_PPI when PPI 15 is available and supplies the matching virtual event, counter, IRQ, and KVM PTP handling. In 6.12.y the DT parser records PPI 15, but no path selects it, so this DTS backport is inert and cannot provide its stated VHE timer behavior.
d87773de9efe is a broader generic arm64 VHE timer-policy change, not a small Tegra-only data prerequisite, pulling that feature stack into 6.12.y solely for this DTS change does not look suitable for stable.
I don't think it is a functional regression that could be caused by this, so we probbaly need not do anything but maybe authors of this patch could confirm.
thanks,
Harshit
Quoted 2 lines
arch/arm64/boot/dts/nvidia/tegra194.dtsi +0
-0interrupt-parent = <&gic>; always-on;
Greg Kroah-Hartman
maintainerPATCH 193/220 crypto: ccm - Set rfc4309 maxauthsize from child
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herbert Xu <[email protected]>
[ Upstream commit 438f4896f78f69ec73d5f32d2c024193f1223569 ]
Set the maxauthsize of rfc4309 using that of the child algorithm.
--- crypto/ccm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/ccm.c +1 -1
@@ -751,7 +751,7 @@ static int crypto_rfc4309_create(struct crypto_template *tmpl, inst->alg.ivsize =8 ; inst->alg.chunksize =crypto_aead_alg_chunksize (alg); - inst->alg.maxauthsize =16 ; + inst->alg.maxauthsize =crypto_aead_alg_maxauthsize (alg); inst->alg.base.cra_ctxsize =sizeof (struct crypto_rfc4309_ctx );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 194/220 crypto: tegra - fix rctx->cryptlen calculation in tegra_gcm_do_one_req()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladislav Dronov <[email protected]>
[ Upstream commit 360f2974fcea49c61f6d6f81554741a9eeee7168 ]
Perform rctx->cryptlen calculation in tegra_gcm_do_one_req() the same way it is done in tegra_ccm_crypt_init(). The current formulae may lead to a crash if a caller does not call tegra_gcm_setauthsize() and so ctx->authsize remains zero. Then a decrypt operation with incorrect rctx->cryptlen will lead to a write beyound rctx->dst_sg buffer.
As a follow-up cleanup delete struct tegra_aead_ctx->authsize field since it appears to be completely unused. Also simplify tegra_ccm_setauthsize() and tegra_gcm_setauthsize() functions respectively.
--- drivers/crypto/tegra/tegra-se-aes.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-)
drivers/crypto/tegra/tegra-se-aes.c +3 -19
@@ -45,7 +45,6 @@ struct tegra_aes_reqctx {struct tegra_aead_ctx {struct tegra_se *se; -unsigned int authsize;u32 alg;u32 key_id;u32 keylen;
@@ -1290,7 +1289,7 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)if (rctx->encrypt) rctx->cryptlen = req->cryptlen;else - rctx->cryptlen = req->cryptlen - ctx->authsize; + rctx->cryptlen = req->cryptlen - rctx->authsize;memcpy (rctx->iv, req->iv,GCM_AES_IV_SIZE ); rctx->iv[3 ] = (1 <<24 );
@@ -1394,8 +1393,6 @@ static int tegra_aead_cra_init(struct crypto_aead *tfm)static int tegra_ccm_setauthsize (struct crypto_aead *tfm,unsigned int authsize) { -struct tegra_aead_ctx *ctx =crypto_aead_ctx (tfm); -switch (authsize) {case 4 :case 6 :
@@ -1404,28 +1401,15 @@ static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsizecase 12 :case 14 :case 16 : -break ; +return 0 ;default :return -EINVAL ; } - - ctx->authsize = authsize; - -return 0 ; }static int tegra_gcm_setauthsize (struct crypto_aead *tfm,unsigned int authsize) { -struct tegra_aead_ctx *ctx =crypto_aead_ctx (tfm); -int ret; - - ret =crypto_gcm_check_authsize (authsize); -if (ret) -return ret; - - ctx->authsize = authsize; - -return 0 ; +return crypto_gcm_check_authsize (authsize); }static void tegra_aead_cra_exit (struct crypto_aead *tfm)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/220 netfilter: ipset: fix refcount race between list:set GC and swap
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit 0c88868271653537ed443272dd8e7d13634d214b ]
__ip_set_put_byindex() resolved the index to a set pointer under RCU, then took ip_set_ref_lock in __ip_set_put() to decrement set->ref. ip_set_swap() holds that same lock while swapping both the ip_set_list slots and the two sets' ref counters, so it can interleave between the dereference and the lock acquisition, leaving the caller to decrement a set whose reference already moved to the other index and hit BUG_ON(set->ref == 0). list_set_gc() reaches this from timer softirq, which the nfnl mutex does not serialize against swap: an expiring list:set member calls list_set_del() -> ip_set_put_byindex() while IPSET_CMD_SWAP runs on the referenced sets.
Resolve the index and decrement under ip_set_ref_lock, as ip_set_swap() already does, keeping the refcount tied to the index rather than to a stale set pointer.
kernel BUG at net/netfilter/ipset/ip_set_core.c:685!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI RIP: 0010:ip_set_put_byindex (net/netfilter/ipset/ip_set_core.c:870) Call Trace: <IRQ> list_set_del (net/netfilter/ipset/ip_set_list_set.c:159) set_cleanup_entries (net/netfilter/ipset/ip_set_list_set.c:181) list_set_gc (net/netfilter/ipset/ip_set_list_set.c:578) call_timer_fn (kernel/time/timer.c:1748) __run_timers (kernel/time/timer.c:1799 kernel/time/timer.c:2374) run_timer_softirq (kernel/time/timer.c:2405) </IRQ> Kernel panic - not syncing: Fatal exception in interrupt
--- net/netfilter/ipset/ip_set_core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
net/netfilter/ipset/ip_set_core.c +13 -6
@@ -679,11 +679,18 @@ __ip_set_get(struct ip_set *set) }static void -__ip_set_put (struct ip_set *set) +__ip_set_put_locked (struct ip_set *set) { -write_lock_bh (&ip_set_ref_lock); +lockdep_assert_held (&ip_set_ref_lock);BUG_ON (set->ref ==0 ); set->ref--; +} + +static void +__ip_set_put (struct ip_set *set) +{ +write_lock_bh (&ip_set_ref_lock); +__ip_set_put_locked (set);write_unlock_bh (&ip_set_ref_lock); }
@@ -854,11 +861,11 @@ __ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index) {struct ip_set *set; -rcu_read_lock (); - set =rcu_dereference (inst->ip_set_list)[index]; +write_lock_bh (&ip_set_ref_lock); + set =ip_set (inst, index);if (set) -__ip_set_put (set); -rcu_read_unlock (); +__ip_set_put_locked (set); +write_unlock_bh (&ip_set_ref_lock); }void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/220 netfilter: nf_tables_offload: suppress WARN_ON_ONCE for ENOMEM in abort path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Velichayshiy <[email protected]>
[ Upstream commit d02f592064347e0c1e0d84f24941ad338838cc48 ]
In nft_flow_rule_offload_abort(), WARN_ON_ONCE(err) is triggered on every error during rollback, including -ENOMEM. Memory allocation failures are expected under low-memory conditions and do not indicate a kernel bug.
Trace for example:nft_flow_offload_chain() // FLOW_BLOCK_BIND
nft_flow_block_chain()
nft_chain_offload_cmd()
nft_block_offload_cmd()
->ndo_setup_tc()
nsim_setup_tc()
flow_block_cb_setup_simple()
flow_block_cb_alloc() // fails to -ENOMEMThe warning was reproduced on the 5.10 stable kernel under memory pressure via fault injection, but the underlying bug exists in mainline as well, as demonstrated by the ENOMEM trace above. The following splat was triggered during nf_tables transaction processing:
WARNING: CPU: 0 PID: 8567 at net/netfilter/nf_tables_offload.c:532 nft_flow_rule_offload_abort net/netfilter/nf_tables_offload.c:532 [inline] WARNING: CPU: 0 PID: 8567 at net/netfilter/nf_tables_offload.c:532 nft_flow_rule_offload_commit+0x971/0xcd0 net/netfilter/nf_tables_offload.c:591 Modules linked in: CPU: 0 PID: 8567 Comm: syz-executor.0 Not tainted 5.10.260-syzkaller #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 RIP: 0010:nft_flow_rule_offload_abort net/netfilter/nf_tables_offload.c:532 [inline] RIP: 0010:nft_flow_rule_offload_commit+0x971/0xcd0 net/netfilter/nf_tables_offload.c:591 Call Trace: nf_tables_commit+0x3bd/0x4bd0 net/netfilter/nf_tables_api.c:8604 nfnetlink_rcv_batch+0xb1e/0x1f20 net/netfilter/nfnetlink.c:509 nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:579 [inline] nfnetlink_rcv+0x3b3/0x420 net/netfilter/nfnetlink.c:597 netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline] netlink_unicast+0x6cd/0xa00 net/netfilter/af_netlink.c:1340 netlink_sendmsg+0x906/0xe10 net/netfilter/af_netlink.c:1919 sock_sendmsg_nosec net/socket.c:651 [inline] __sock_sendmsg+0x155/0x190 net/socket.c:663 ____sys_sendmsg+0x705/0x870 net/socket.c:2379 ___sys_sendmsg+0x100/0x170 net/socket.c:2433 __sys_sendmsg+0xe9/0x1c0 net/socket.c:2462 do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 entry_SYSCALL_64_after_hwframe+0x67/0xd1
Change the condition to WARN_ON_ONCE(err && err != -ENOMEM) so that warnings are only emitted for unexpected errors. This aligns with the common kernel practice of not warning on -ENOMEM.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- net/netfilter/nf_tables_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nf_tables_offload.c +1 -1
@@ -551,7 +551,7 @@ static void nft_flow_rule_offload_abort(struct net *net,break ; } -if (WARN_ON_ONCE (err)) +if (WARN_ON_ONCE (err && err != -ENOMEM ))break ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/220 netfilter: flowtable: publish GC-visible tuple last
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
[ Upstream commit 2014ac62df9d45bb9a004a043e85df7be09ed780 ]
nf_flow_table_iterate() only treats original-direction tuple nodes as owning entries. Publishing the original node first lets GC observe and free a flow while flow_offload_add() is still inserting the reply node. Publish the reply node first and the original node last so GC never sees a partially installed flow.
KASAN can trigger slab-use-after-free read and write reports in the flowtable/rhashtable path (rht_deferred_worker, jhash, flow_offload_del, flow_offload_lookup, etc.).
--- net/netfilter/nf_flow_table_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
net/netfilter/nf_flow_table_core.c +4 -3
@@ -279,17 +279,18 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) flow->timeout = nf_flowtable_time_stamp +flow_offload_get_timeout (flow); err =rhashtable_insert_fast (&flow_table->rhashtable, - &flow->tuplehash[0 ].node, + &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY ].node, nf_flow_offload_rhash_params);if (err <0 )return err; +/* GC only iterates original-direction entries; publish original last. */ err =rhashtable_insert_fast (&flow_table->rhashtable, - &flow->tuplehash[1 ].node, + &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL ].node, nf_flow_offload_rhash_params);if (err <0 ) {rhashtable_remove_fast (&flow_table->rhashtable, - &flow->tuplehash[0 ].node, + &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY ].node, nf_flow_offload_rhash_params);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 198/220 netfilter: ipset: fix list type element drift bug
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 4cbd69766b35a089664cadb1f613bb85f7ef77a9 ]
If list_set_uadd() calls list_set_replace() to swap an expired entry, the element count remains the same, therefore the increment must be elided.
--- net/netfilter/ipset/ip_set_list_set.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/netfilter/ipset/ip_set_list_set.c +5 -2
@@ -301,9 +301,12 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, e->set = set;INIT_LIST_HEAD (&e->list);list_set_init_extensions (set, ext, e); -if (n) +if (n) {list_set_replace (set, e, n); -else if (next) +return 0 ; + } + +if (next)list_add_tail_rcu (&e->list, &next->list);else if (prev)list_add_rcu (&e->list, &prev->list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 199/220 netfilter: ipset: let destroy callbacks adjust ext mem size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 490937b88cb592cc0c5367758edd700fd5abd15c ]
For bitmap this change makes no difference, because destructors are called synchronously.
List type however calls them via call_rcu() so accounting decrement can happen after list_set_flush() set ext_size to 0.
'set->elements = 0' can be removed for the same reason in the list type case, it calls 'set->elements--' for each element.
--- net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- net/netfilter/ipset/ip_set_list_set.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-)
net/netfilter/ipset/ip_set_bitmap_gen.h +1 -1
@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)mtype_ext_cleanup (set);bitmap_zero (map->members, map->elements); set->elements =0 ; -atomic64_set (&set->ext_size,0 ); +DEBUG_NET_WARN_ON_ONCE (atomic64_read (&set->ext_size) >0 ); }/* Calculate the actual memory size of the set data */
net/netfilter/ipset/ip_set_list_set.c +1 -2
@@ -423,8 +423,7 @@ list_set_flush(struct ip_set *set)list_for_each_entry_safe (e, n, &map->members, list)list_set_del (set, e); - set->elements =0 ; -atomic64_set (&set->ext_size,0 ); +DEBUG_NET_WARN_ON_ONCE (set->elements >0 ); } static void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 200/220 ipvlan: inherit needed_headroom and needed_tailroom from phy_dev
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit e16e960d55a40d36bd7c2494cc005e757dc9a1ef ]
ipvlan devices inherit hard_header_len from phy_dev during ipvlan_init(), but leave needed_headroom and needed_tailroom set to 0.
When the underlying phy_dev (or stacked lower device) requires extra headroom or tailroom for headers/trailers (e.g. macsec, ipsec, wireguard, tunnels, or veth with rx headroom), upper layers calculating packet headroom and tailroom fail to reserve sufficient space.
This can result in reallocation overhead, skb headroom underflows, or KASAN slab-use-after-free crashes when dev_hard_header() / ipvlan_hard_header() prepends header data or when lower devices append tailroom.
Fix this by:
1. Inheriting needed_headroom and needed_tailroom from phy_dev in ipvlan_init().
2. Propagating needed_headroom and needed_tailroom updates to attached ipvlans in ipvlan_device_event() when receiving NETDEV_FEAT_CHANGE events.
--- drivers/net/ipvlan/ipvlan_main.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ipvlan/ipvlan_main.c +4 -0
@@ -145,6 +145,8 @@ static int ipvlan_init(struct net_device *dev) dev->lltx = true;netif_inherit_tso_max (dev, phy_dev); dev->hard_header_len = phy_dev->hard_header_len; + dev->needed_headroom = phy_dev->needed_headroom; + dev->needed_tailroom = phy_dev->needed_tailroom;netdev_lockdep_set_classes (dev);
@@ -770,6 +772,8 @@ static int ipvlan_device_event(struct notifier_block *unused,case NETDEV_FEAT_CHANGE :list_for_each_entry (ipvlan, &port->ipvlans, pnode) {netif_inherit_tso_max (ipvlan->dev, dev); + ipvlan->dev->needed_headroom = dev->needed_headroom; + ipvlan->dev->needed_tailroom = dev->needed_tailroom;netdev_update_features (ipvlan->dev); }break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 201/220 macvlan: inherit needed_headroom and needed_tailroom from lowerdev
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit cef51860becd9700217c81732ca1eb1ea6ed6fe1 ]
macvlan devices inherit hard_header_len from lowerdev during macvlan_init(), but leave needed_headroom and needed_tailroom set to 0.
When the underlying lowerdev requires extra headroom or tailroom for headers/trailers (e.g. macsec, ipsec, wireguard, tunnels, or veth with rx headroom), upper layers calculating packet headroom and tailroom fail to reserve sufficient space.
This can result in reallocation overhead, skb headroom underflows, or KASAN slab-use-after-free crashes when dev_hard_header() / macvlan_hard_header() prepends header data or when lower devices append tailroom.
Fix this by:
1. Inheriting needed_headroom and needed_tailroom from lowerdev in macvlan_init().
2. Propagating needed_headroom and needed_tailroom updates to attached macvlans in macvlan_device_event() when receiving NETDEV_FEAT_CHANGE events.
--- drivers/net/macvlan.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/macvlan.c +4 -0
@@ -942,6 +942,8 @@ static int macvlan_init(struct net_device *dev) dev->lltx = true;netif_inherit_tso_max (dev, lowerdev); dev->hard_header_len = lowerdev->hard_header_len; + dev->needed_headroom = lowerdev->needed_headroom; + dev->needed_tailroom = lowerdev->needed_tailroom;macvlan_set_lockdep_class (dev); vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
@@ -1813,6 +1815,8 @@ static int macvlan_device_event(struct notifier_block *unused,case NETDEV_FEAT_CHANGE :list_for_each_entry (vlan, &port->vlans, list) {netif_inherit_tso_max (vlan->dev, dev); + vlan->dev->needed_headroom = dev->needed_headroom; + vlan->dev->needed_tailroom = dev->needed_tailroom;netdev_update_features (vlan->dev); }break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 202/220 veth: fix queue index used to wake the peer txq in veth_poll
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonas Köppeler <[email protected]>
[ Upstream commit 60db47f02bfa2aa688938aa199117ec4f8e31d23 ]
veth_poll() derives the index of the peer TX queue to wake from rq->xdp_rxq.queue_index. That field is only initialized by xdp_rxq_info_reg() in veth_enable_xdp_range(), which runs only when an XDP program is attached. On the plain GRO/NAPI path (veth_napi_enable_range()) xdp_rxq_info_reg() is never called, so queue_index stays 0 for every queue, as priv->rq is zero-allocated.
So in a multi-queue setup with GRO enabled and no XDP program attached, every NAPI instance looks at the peer's TX queue 0. If veth_xmit() stops peer TX queue 1 because the ptr_ring is full (NETDEV_TX_BUSY), nothing ever wakes it again: the poller draining queue 1 wakes queue 0 instead. veth implements no ndo_tx_timeout, so the netdev watchdog does not kick in either, and the queue stays stopped indefinitely.
Derive the index from the position of the rq within priv->rq instead, which is correct regardless of whether XDP was ever enabled.
Scripts to reproduce the stall are available at
https://github.com/netoptimizer/veth-backpressure-performance-testing
--- drivers/net/veth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/veth.c +1 -1
@@ -967,7 +967,7 @@ static int veth_poll(struct napi_struct *napi, int budget)struct veth_rq *rq = container_of(napi, struct veth_rq, xdp_napi);struct veth_priv *priv =netdev_priv (rq->dev); -int queue_idx = rq->xdp_rxq.queue_index; +int queue_idx = rq - priv->rq;struct netdev_queue *peer_txq;struct veth_stats stats = {};struct net_device *peer_dev;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 202/220] veth: fix queue index used to wake the peer txq in veth_poll
Hi Greg/Sasha
Quoted 44 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonas Köppeler <[email protected]>
[ Upstream commit
60db47f02bfa2aa688938aa199117ec4f8e31d23]
veth_poll()derives the index of the peer TX queue to wake fromrq->xdp_rxq.queue_index. That field is only initialized byxdp_rxq_info_reg()inveth_enable_xdp_range(), which runs only when an XDP program is attached. On the plain GRO/NAPI path (veth_napi_enable_range())xdp_rxq_info_reg()is never called, soqueue_indexstays 0 for every queue, aspriv->rqis zero-allocated.So in a multi-queue setup with GRO enabled and no XDP program attached, every NAPI instance looks at the peer's TX queue 0. If
veth_xmit()stops peer TX queue 1 because theptr_ringis full (NETDEV_TX_BUSY), nothing ever wakes it again: the poller draining queue 1 wakes queue 0 instead. veth implements nondo_tx_timeout, so the netdev watchdog does not kick in either, and the queue stays stopped indefinitely.Derive the index from the position of the rq within
priv->rqinstead, which is correct regardless of whether XDP was ever enabled.Scripts to reproduce the stall are available at
https://github.com/netoptimizer/veth-backpressure-performance-testingFixes dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops")Signed-off-by Jonas Köppeler <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- drivers/net/veth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/net/veth.c +0
-0
drivers/net/veth.c static int veth_poll(struct napi_struct *napi, int budget) · line 970
Quoted 5 lines
drivers/net/veth.c +1
-1@@ -967,7 +967,7 @@ static int veth_poll(struct napi_struct *napi, int budget)struct veth_rq *rq = container_of(napi, struct veth_rq, xdp_napi);struct veth_priv *priv =netdev_priv (rq->dev); -int queue_idx = rq->xdp_rxq.queue_index; +int queue_idx = rq - priv->rq;
^^^
I ran an AI-assisted backport review and then checked b662a1fb4f3a against upstream commit 60db47f02bfa ("veth: fix queue index used to wake the peer txq in veth_poll"). I think it is missing a required predecessor.
Upstream has:
peer_txq = (peer_dev &&
queue_idx < peer_dev->real_num_tx_queues) ?
netdev_get_tx_queue(peer_dev, queue_idx) : NULL;6.12.y has:
peer_txq = peer_dev ?
netdev_get_tx_queue(peer_dev, queue_idx) : NULL;
b662a1fb4f3a changes queue_idx to the position of rq in priv->rq. On
upstream that change follows 08f566e8f83b ("veth: fix OOB txq access inveth_poll() with asymmetric queue counts"), which added the bound above.
6.12.y lacks that commit and permits more RX rings than peer TX queues, so an XDP redirect can lead veth_poll() to resolve and inspect an out-of-range peer TX queue.
So I think wee need to backport 08f566e8f83b ("veth: fix OOB txq access in veth_poll() with asymmetric queue counts"), but I don't think this backport is wrong or anything.
thanks,
Harshit
Quoted 3 lines
drivers/net/veth.c +0
-0struct netdev_queue *peer_txq;struct veth_stats stats = {};struct net_device *peer_dev;
Re: [PATCH 6.12 202/220] veth: fix queue index used to wake the peer txq in veth_poll
Quoted 9 lines
Upstream has:
peer_txq = (peer_dev && queue_idx < peer_dev->real_num_tx_queues) ? netdev_get_tx_queue(peer_dev, queue_idx) : NULL;6.12.y has:
peer_tx
Queued for 6.18 and 6.12, thanks. 6.18 had the same gap.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 203/220 tcp: fix icsk_ack.ato bitfield overflow
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 60837e4b840a9c3f7ec826e3584df0bc6542a2c2 ]
On cross-region connections we observed delayed ACKs suddenly turning into immediate ACKs plus a TCP_MAX_QUICKACKS burst, as if the connection had just received its first data segment.
Commit 95b9a87c6a6b ("tcp: record last received ipv6 flowlabel") squeezed icsk_ack.ato into 8 bits, sized for TCP_DELACK_MAX. But both writers still bound ato by icsk_rto, which can be well above 255 jiffies, so the bitfield assignment silently wraps mod 256: repeated delack timer misses double ato up to icsk_rto, storing 320 as 64 and 256 as 0, and ato == 0 is the "first data packet" sentinel in tcp_event_data_recv().
Clamp both writers to TCP_DELACK_MAX, which the static_assert already guarantees to fit and tcp_send_delayed_ack() effectively caps ato at anyway.
--- net/ipv4/tcp_input.c | 6 +++--- net/ipv4/tcp_timer.c | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-)
net/ipv4/tcp_input.c +3 -3
@@ -853,9 +853,9 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)/* The fastest case is the first. */ icsk->icsk_ack.ato = (icsk->icsk_ack.ato >>1 ) +TCP_ATO_MIN /2 ; }else if (m < icsk->icsk_ack.ato) { - icsk->icsk_ack.ato = (icsk->icsk_ack.ato >>1 ) + m; -if (icsk->icsk_ack.ato > icsk->icsk_rto) - icsk->icsk_ack.ato = icsk->icsk_rto; + icsk->icsk_ack.ato =min3 ((icsk->icsk_ack.ato >>1 ) + (u32 )m, + icsk->icsk_rto, + (u32 )TCP_DELACK_MAX ); }else if (m > icsk->icsk_rto) {/* Too long gap. Apparently sender failed to * restart window, so that we send ACKs quickly.
net/ipv4/tcp_timer.c +3 -1
@@ -332,7 +332,9 @@ void tcp_delack_timer_handler(struct sock *sk)if (inet_csk_ack_scheduled (sk)) {if (!inet_csk_in_pingpong_mode (sk)) {/* Delayed ACK missed: inflate ATO. */ - icsk->icsk_ack.ato =min_t (u32, icsk->icsk_ack.ato <<1 , icsk->icsk_rto); + icsk->icsk_ack.ato =min3 ((u32 )icsk->icsk_ack.ato <<1 , + icsk->icsk_rto, + (u32 )TCP_DELACK_MAX ); }else {/* Delayed ACK missed: leave pingpong mode and * deflate ATO.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 204/220 net: packet: fix wrong transport_header when sending VLAN-tagged frame
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <[email protected]>
[ Upstream commit 01fdecc0480d916c799dbee584833a4a37e94d06 ]
In packet_parse_headers(), when processing a VLAN-tagged frame, skb_set_network_header() is called to advance network_header past the VLAN tag to the inner protocol header. skb_probe_transport_header() is then called with skb->protocol still set to the outer VLAN EtherType (e.g. ETH_P_8021Q), while nhoff (derived from skb_network_offset()) already points past the VLAN tag to the inner protocol header.
In __skb_flow_dissect(), proto is initialized to ETH_P_8021Q and nhoff points past the VLAN tag. When the dissector hits case ETH_P_8021Q, it reads a struct vlan_hdr at nhoff via __skb_header_pointer(), but that offset contains the inner protocol header (e.g. an IP header). The bytes are misinterpreted as a VLAN header, yielding a garbage encapsulated EtherType that matches no known protocol. The dissector returns false, so skb_probe_transport_header() never calls skb_set_transport_header(), leaving transport_header at its uninitialized sentinel value (~0U).
Move skb_probe_transport_header() to before skb_set_network_header(). At the time skb_probe_transport_header() is called, network_header still points to the VLAN header, so nhoff correctly points to the VLAN header. The flow dissector can then parse the VLAN header, extract the inner EtherType, and advance nhoff to the inner protocol header, allowing transport_header to be set correctly.
--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/packet/af_packet.c +2 -2
@@ -1995,13 +1995,13 @@ static void packet_parse_headers(struct sk_buff *skb, struct socket *sock) sock->type == SOCK_RAW) skb->protocol =dev_parse_header_protocol (skb); +skb_probe_transport_header (skb); +/* Move network header to the right position for VLAN tagged packets */ if (likely (skb->dev->type ==ARPHRD_ETHER ) &ð_type_vlan (skb->protocol) &&vlan_get_protocol_and_depth (skb, skb->protocol, &depth) !=0 )skb_set_network_header (skb, depth); - -skb_probe_transport_header (skb); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 205/220 net/tls: Fail tls_sw_splice_read() after a failed async decrypt
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 976df67f463db1fddaf2a32fb04f57ad2891a23d ]
When an async decrypt fails, tls_decrypt_done() records the error in ctx->async_wait.err and calls tls_err_abort(), which stores it in sk_err. tls_sw_recvmsg() and tls_sw_read_sock() each read async_wait.err once they hold the reader lock and fail the call: a record that did not authenticate breaks the connection.
tls_sw_splice_read() has no such check, and sk_err does not stand in for one. tls_rx_rec_wait() tests sk_err only inside the loop it skips whenever a record is already parsed, and the first reader to reach sock_error() clears it, while async_wait.err persists. A splice therefore keeps delivering records on a connection that recvmsg() and read_sock() refuse to read.
Read async_wait.err in tls_sw_splice_read() as the other two readers do.
--- net/tls/tls_sw.c | 5 +++++ 1 file changed, 5 insertions(+)
net/tls/tls_sw.c +5 -0
@@ -2284,6 +2284,11 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,if (err <0 )return err; +/* If crypto failed the connection is broken */ + err = ctx->async_wait.err; +if (err) + goto splice_read_end; +if (!skb_queue_empty (&ctx->rx_list)) { skb =__skb_dequeue (&ctx->rx_list); }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 206/220 ASoC: xilinx: formatter_pcm: pass aud_drv_data to irq handlers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit f12afefb7b01f94d6d66d397f323a9914edbf70e ]
The irq handlers take a struct device pointer and call dev_get_drvdata() to obtain the driver data. However, the driver data is only set at the end of probe, after devm_request_irq(), so an interrupt taken in between causes the handlers to pass a NULL pointer to readl() and crash.
Pass the private data directly as the devm_request_irq() argument instead of the device pointer, matching what the handlers expect.
--- sound/soc/xilinx/xlnx_formatter_pcm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
sound/soc/xilinx/xlnx_formatter_pcm.c +4 -6
@@ -281,8 +281,7 @@ static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg) {u32 val;void __iomem *reg; -struct device *dev = arg; -struct xlnx_pcm_drv_data *adata =dev_get_drvdata (dev); +struct xlnx_pcm_drv_data *adata = arg; reg = adata->mmio +XLNX_MM2S_OFFSET +XLNX_AUD_STS ; val =readl (reg);
@@ -300,8 +299,7 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) {u32 val;void __iomem *reg; -struct device *dev = arg; -struct xlnx_pcm_drv_data *adata =dev_get_drvdata (dev); +struct xlnx_pcm_drv_data *adata = arg; reg = adata->mmio +XLNX_S2MM_OFFSET +XLNX_AUD_STS ; val =readl (reg);
@@ -637,7 +635,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) } ret =devm_request_irq (dev, aud_drv_data->mm2s_irq, xlnx_mm2s_irq_handler,0 , -"xlnx_formatter_pcm_mm2s_irq" , dev); +"xlnx_formatter_pcm_mm2s_irq" , aud_drv_data);if (ret) {dev_err (dev,"xlnx audio mm2s irq request failed\n" ); goto clk_err;
@@ -664,7 +662,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) ret =devm_request_irq (dev, aud_drv_data->s2mm_irq, xlnx_s2mm_irq_handler,0 ,"xlnx_formatter_pcm_s2mm_irq" , - dev); + aud_drv_data);if (ret) {dev_err (dev,"xlnx audio s2mm irq request failed\n" ); goto clk_err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 207/220 af_packet: Dont send zero-byte data in tpacket_snd().
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 6bcd76c134c55c697148acb5c0194e9666abdf84 ]
syzbot reported a WARNING in __dev_queue_xmit() triggered via tpacket_snd():
skb_assert_len
WARNING: at include/linux/skbuff.h:2753 skb_assert_len WARNING: at __dev_queue_xmit+0x21bc/0x4970 net/core/dev.c:4781 Call Trace: <TASK> dev_queue_xmit include/linux/netdevice.h:3448 [inline] packet_xmit+0x243/0x310 net/packet/af_packet.c:276 tpacket_snd net/packet/af_packet.c:2907 [inline] packet_sendmsg+0x28d6/0x4eb0 net/packet/af_packet.c:3134
When sending 0-byte packets via TPACKET ring buffer on devices with no hard header (e.g. dev->hard_header_len == 0), tpacket_fill_skb() populates an skb with skb->len == 0 and returns 0. tpacket_snd() then forwards this empty skb to packet_xmit(), causing __dev_queue_xmit() to hit skb_assert_len(skb).
Similar checks exist in packet_snd() via commit dc633700f00f ("net/af_packet: check len when min_header_len equals to 0") and in packet_sendmsg_spkt() via commit 6a341729fb31 ("af_packet: Don't send zero-byte data in packet_sendmsg_spkt().").
Return -EINVAL in tpacket_fill_skb() when skb->len is zero to reject zero-length packets in tpacket_snd().
--- net/packet/af_packet.c | 3 +++ 1 file changed, 3 insertions(+)
net/packet/af_packet.c +3 -0
@@ -2712,6 +2712,9 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, len = ((to_write > len_max) ? len_max : to_write); } +if (unlikely (!skb->len)) +return -EINVAL ; +packet_parse_headers (skb, sock);return tp_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 208/220 net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit f60b396ee174206fe08ebf997d16cd3801b77b22 ]
tcf_action_exec() handles TC_ACT_GOTO_CHAIN by first checking rcu_access_pointer(a->goto_chain) and then calling tcf_action_goto_chain_exec(), which does a second, independent rcu_dereference_bh(a->goto_chain) read and immediately dereferences chain->filter_chain. A concurrent tcf_action_set_ctrlact() (e.g. the gact replace path) can clear a->goto_chain between the two reads, so the second read returns NULL and tcf_action_goto_chain_exec() dereferences NULL.
Fix the race by doing a single rcu_dereference_bh() read of a->goto_chain in tcf_action_exec(), checking it once for NULL, and passing the resulting chain pointer into tcf_action_goto_chain_exec(). This turns the split check/use into a single check/use on one value.
--- net/sched/act_api.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/sched/act_api.c +5 -5
@@ -41,11 +41,9 @@ int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb)) }EXPORT_SYMBOL_GPL (tcf_dev_queue_xmit); -static void tcf_action_goto_chain_exec (const struct tc_action *a, +static void tcf_action_goto_chain_exec (const struct tcf_chain *chain,struct tcf_result *res) { -const struct tcf_chain *chain =rcu_dereference_bh (a->goto_chain); - res->goto_tp =rcu_dereference_bh (chain->filter_chain); }
@@ -1117,12 +1115,14 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,return TC_ACT_OK ; } }else if (TC_ACT_EXT_CMP (ret,TC_ACT_GOTO_CHAIN )) { -if (unlikely (!rcu_access_pointer (a->goto_chain))) { +struct tcf_chain *chain =rcu_dereference_bh (a->goto_chain); + +if (unlikely (!chain)) {tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_CHAIN_NOTFOUND );return TC_ACT_SHOT ; } -tcf_action_goto_chain_exec (a, res); +tcf_action_goto_chain_exec (chain, res); }if (ret !=TC_ACT_PIPE )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 209/220 net/sched: cls_u32: skip hash tables in u32_bind_class()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Changzhong <[email protected]>
[ Upstream commit 6d3724e616faf952c3adcf8414fc21a828ef3709 ]
u32_walk() enumerates both struct tc_u_hnode and struct tc_u_knode through the walker callback. u32_bind_class() unconditionally casts the passed fh to tc_u_knode and accesses &n->res, so when fh is actually a tc_u_hnode, which has no tcf_result member, this results in a slab-out-of-bounds read of res->classid in tc_cls_bind_class().
The issue can be reproduced with the following commands:
tc qdisc add dev lo root handle 1: hfsc
tc class add dev lo parent 1: classid 1:1 hfsc sc rate 1000kbit
tc filter add dev lo parent 1:1 protocol ip prio 1 u32 match u32 0 0 flowid 1:1 tc class add dev lo parent 1: classid 1:2 hfsc sc rate 2000kbit
Fix this by skipping hash tables via the TC_U32_KEY(handle) check.
--- net/sched/cls_u32.c | 3 +++ 1 file changed, 3 insertions(+)
net/sched/cls_u32.c +3 -0
@@ -1336,6 +1336,9 @@ static void u32_bind_class(void *fh, u32 classid, unsigned long cl, void *q, {struct tc_u_knode *n = fh; +if (TC_U32_KEY (n->handle) ==0 ) +return ; +tc_cls_bind_class (classid, cl, q, &n->res, base); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 210/220 m68k: Define NR_CPUS to 1
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 1fd495ef09eef96169a379a749c24b5e69974bb8 ]
This fixes a Kconfig warning
fs/erofs/Kconfig:137:warning: range is invalid
which originates from EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS using NR_CPUS which up to now didn't exist for ARCH=m68k. All other architectures define this symbol, so fix the outlier.
[geert] This also fixes:
- CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS being set to the literal NR_CPUS instead of a number by automatic configs like "make allmodconfig" or "make olddefconfig",
- An infinite loop in manual configs like "make oldconfig" when CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS is not present or has an invalid value in your existing .config.
--- arch/m68k/Kconfig.cpu | 4 ++++ 1 file changed, 4 insertions(+)
arch/m68k/Kconfig.cpu +4 -0
@@ -538,6 +538,10 @@ config CACHE_COPYBACK endchoice endif # HAVE_CACHE_CB +config NR_CPUS + int + default "1" + # Coldfire cores that do not have a data cache configured can do coherent DMA. config COLDFIRE_COHERENT_DMA bool
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 211/220 net: ethernet: ti: am65-cpsw-nuss: Fix port_id extraction from SRC TAG
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Siddharth Vadapalli <[email protected]>
[ Upstream commit 36a05d2820077bb3955acb8111e1041d39148037 ]
On the packet reception path, the ID of the MAC Port on which the packet was received, is embedded in the RX DMA Descriptor's metadata. The ID is extracted using the helper function cppi5_desc_get_tags_ids() which fills in the 16-bit Source Tag into the 'port_id' variable. However, it is only the lower 8-bits of the 16-bit Source Tag that represent the MAC Port ID, while the upper 8-bits are Hardware-Reserved and carry an arbitrary value. With the existing logic, sporadic kernel crash is observed due to the subsequent driver code accessing out-of-bound memory because of an invalid port_id.
Hence, fix the port_id extraction logic to use only the lower 8-bits of the Source Tag as the MAC Port ID.
--- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/ti/am65-cpsw-nuss.c +2 -0
@@ -1190,6 +1190,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,k3_udma_glue_rx_cppi5_to_dma_addr (rx_chn->rx_chn, &buf_dma); pkt_len =cppi5_hdesc_get_pktlen (desc_rx);cppi5_desc_get_tags_ids (&desc_rx->hdr, &port_id,NULL ); +/* Port ID is contained in the lower 8-bits of the 16-bit Source Tag */ + port_id &=0xFF ;dev_dbg (dev,"%s rx port_id:%d\n" , __func__, port_id); port =am65_common_get_port (common, port_id); ndev = port->ndev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 212/220 net/sched: cls_bpf: reject dev-bound programs bound to a different device
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 120977e2c096deea4e866e4273be9220b957c29e ]
cls_bpf_prog_from_efd() obtained a SCHED_CLS program via bpf_prog_get_type_dev() but never verified that a device-bound (offloaded) program's bound netdev matches the TC netdev the classifier is being attached to. This let a program loaded with prog_ifindex for device A be attached via cls_bpf + skip_sw to device B; deleting device A then destroyed the program's offload state while it was still attached to device B, triggering a netdevsim WARN (panic with panic_on_warn=1).
Mirror the XDP attach path (net/core/dev.c) and reject the attach with -EINVAL when a dev-bound program's bound device does not match the target device.
--- net/sched/cls_bpf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
net/sched/cls_bpf.c +16 -2
@@ -374,7 +374,8 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog) }static int cls_bpf_prog_from_efd (struct nlattr **tb,struct cls_bpf_prog *prog, -u32 gen_flags,const struct tcf_proto *tp) +u32 gen_flags,const struct tcf_proto *tp, +struct netlink_ext_ack *extack) {struct bpf_prog *fp;char *name =NULL ;
@@ -388,6 +389,19 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,if (IS_ERR (fp))return PTR_ERR (fp); +if (bpf_prog_is_dev_bound (fp->aux)) { +struct tcf_block *block = tp->chain->block; +struct net_device *dev; + + dev = block->q ?qdisc_dev (block->q) :NULL ; +if (!dev || !bpf_offload_dev_match (fp, dev)) { +NL_SET_ERR_MSG (extack, +"Program is bound to a different device" ); +bpf_prog_put (fp); +return -EINVAL ; + } + } +if (tb[TCA_BPF_NAME ]) { name =nla_memdup (tb[TCA_BPF_NAME ],GFP_KERNEL );if (!name) {
@@ -492,7 +506,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, prog->gen_flags = gen_flags; ret = is_bpf ?cls_bpf_prog_from_ops (tb, prog) : -cls_bpf_prog_from_efd (tb, prog, gen_flags, tp); +cls_bpf_prog_from_efd (tb, prog, gen_flags, tp, extack);if (ret <0 ) goto errout_idr;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 213/220 drm/xe/oa: Fix sync entry leak on OA config emit failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 8d33c4987cd162527375a3905017ae129ba7c3fe ]
xe_oa_emit_oa_config() releases the sync entries and the syncs array only on its success path. When it fails before the point of no return (fence allocation, config buffer allocation or batch submission), it returns without touching stream->syncs.
The stream open path handles such failures in the caller, but xe_oa_config_locked() propagates the error without any cleanup, so the syncs array and the fence references held by the parsed entries are leaked. The next config ioctl overwrites stream->syncs, making the memory unreachable for good.
Clean up the parsed syncs when xe_oa_emit_oa_config() fails, matching the cleanup done by the stream open error path.
--- drivers/gpu/drm/xe/xe_oa.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/xe/xe_oa.c +4 -0
@@ -1483,6 +1483,10 @@ static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg) config =xchg (&stream->oa_config, config);drm_dbg (&stream->oa->xe->drm,"changed to oa config uuid=%s\n" , stream->oa_config->uuid); + }else { +while (param.num_syncs--) +xe_sync_entry_cleanup (¶m.syncs[param.num_syncs]); +kfree (param.syncs); } err_config_put:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 214/220 erofs: fix EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS on some UP platforms
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit a64d500b0078e16e9abb25baca4dee1dbc9054fc ]
CONFIG_NR_CPUS doesn't define on some UP platforms (e.g. arm), so this can cause make oldconfig to loop indefinitely when CONFIG_SMP=n:
$ make ARCH=arm allmodconfig $ sed -i "/CONFIG_SMP=y/d" .config $ sed -i "/CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS.*/d" .config
EROFS LZMA default maximum decompression streams (EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS) [0] (NEW) EROFS LZMA default maximum decompression streams (EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS) [0] (NEW)
...
Let's guard NR_CPUS with SMP instead of using a hardcoded arbitrary CPU uplimit here, similar to commit a3344078101c ("mm: make SPLIT_PTE_PTLOCKS depend on SMP").
The initial report from SJ Park was for m68k [1] (m68k is the only arch without NR_CPUS in Kconfig), and that got fixed in commit 1fd495ef09ee ("m68k: Define NR_CPUS to 1")
--- fs/erofs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/erofs/Kconfig +2 -1
@@ -117,7 +117,8 @@ config EROFS_FS_ZIP_LZMA config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS int "EROFS LZMA default maximum decompression streams" depends on EROFS_FS_ZIP_LZMA - range 1 NR_CPUS + range 1 NR_CPUS if SMP + range 1 1 if !SMP default 16 help By default EROFS allocates one LZMA decompression stream per CPU.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 215/220 perf: Unify perf_event_free_task() / perf_event_exit_task_context()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra <[email protected]>
commit 90661365021a6d0d7f3a2c5046ebe33e4df53b92 upstream.
Both perf_event_free_task() and perf_event_exit_task_context() are very similar, except perf_event_exit_task_context() is a little more generic / makes less assumptions.
Stable-dep-of: 42c5ca1f0a28 ("perf/core: Fix group leader use-after-free after sibling detach")
--- kernel/events/core.c | 93 +++++++++++++-------------------------------------- 1 file changed, 25 insertions(+), 68 deletions(-)
kernel/events/core.c +25 -68
@@ -13522,13 +13522,11 @@ perf_event_exit_event(struct perf_eventperf_event_wakeup (event); } -static void perf_event_exit_task_context (struct task_struct *child) +static void perf_event_exit_task_context (struct task_struct *child,bool exit) {struct perf_event_context *child_ctx, *clone_ctx =NULL ;struct perf_event *child_event, *next; -WARN_ON_ONCE (child != current); - child_ctx =perf_pin_task_context (child);if (!child_ctx)return ;
@@ -13551,7 +13549,8 @@ static void perf_event_exit_task_context* in. */ raw_spin_lock_irq (&child_ctx->lock); -task_ctx_sched_out (child_ctx,NULL ,EVENT_ALL ); +if (exit) +task_ctx_sched_out (child_ctx,NULL ,EVENT_ALL );/* * Now that the context is inactive, destroy the task <-> ctx relation
@@ -13560,7 +13559,7 @@ static void perf_event_exit_task_contextRCU_INIT_POINTER (child->perf_event_ctxp,NULL );put_ctx (child_ctx);/* cannot be last */ WRITE_ONCE (child_ctx->task,TASK_TOMBSTONE ); -put_task_struct (current);/* cannot be last */ +put_task_struct (child);/* cannot be last */ clone_ctx =unclone_ctx (child_ctx);raw_spin_unlock_irq (&child_ctx->lock);
@@ -13573,13 +13572,31 @@ static void perf_event_exit_task_context* won't get any samples after PERF_RECORD_EXIT. We can however still * get a few PERF_RECORD_READ events. */ -perf_event_task (child, child_ctx,0 ); +if (exit) +perf_event_task (child, child_ctx,0 );list_for_each_entry_safe (child_event, next, &child_ctx->event_list, event_entry)perf_event_exit_event (child_event, child_ctx,0 );mutex_unlock (&child_ctx->mutex); +if (!exit) { +/* +* perf_event_release_kernel() could still have a reference on +* this context. In that case we must wait for these events to +* have been freed (in particular all their references to this +* task must've been dropped). +* +* Without this copy_process() will unconditionally free this +* task (irrespective of its reference count) and +* _free_event()'s put_task_struct(event->hw.target) will be a +* use-after-free. +* +* Wait for all events to drop their context reference. +*/ +wait_var_event (&child_ctx->refcount, +refcount_read (&child_ctx->refcount) ==1 ); + }put_ctx (child_ctx); }
@@ -13607,7 +13624,7 @@ void perf_event_exit_task(struct task_st }mutex_unlock (&child->perf_event_mutex); -perf_event_exit_task_context (child); +perf_event_exit_task_context (child, true);/* * The perf_event_exit_task_context calls perf_event_task
@@ -13618,25 +13635,6 @@ void perf_event_exit_task(struct task_stperf_event_task (child,NULL ,0 ); } -static void perf_free_event (struct perf_event *event, -struct perf_event_context *ctx) -{ -struct perf_event *parent = event->parent; - -if (WARN_ON_ONCE (!parent)) -return ; - -mutex_lock (&parent->child_mutex); -list_del_init (&event->child_list); -mutex_unlock (&parent->child_mutex); - -raw_spin_lock_irq (&ctx->lock); -perf_group_detach (event); -list_del_event (event, ctx); -raw_spin_unlock_irq (&ctx->lock); -put_event (event); -} -/* * Free a context as created by inheritance by perf_event_init_task() below, * used by fork() in case of fail.
@@ -13646,48 +13644,7 @@ static void perf_free_event(struct perf_*/ void perf_event_free_task (struct task_struct *task) { -struct perf_event_context *ctx; -struct perf_event *event, *tmp; - - ctx =rcu_access_pointer (task->perf_event_ctxp); -if (!ctx) -return ; - -mutex_lock (&ctx->mutex); -raw_spin_lock_irq (&ctx->lock); -/* -* Destroy the task <-> ctx relation and mark the context dead. -* -* This is important because even though the task hasn't been -* exposed yet the context has been (through child_list). -*/ -RCU_INIT_POINTER (task->perf_event_ctxp,NULL ); -WRITE_ONCE (ctx->task,TASK_TOMBSTONE ); -put_task_struct (task);/* cannot be last */ -raw_spin_unlock_irq (&ctx->lock); - - -list_for_each_entry_safe (event, tmp, &ctx->event_list, event_entry) -perf_free_event (event, ctx); - -mutex_unlock (&ctx->mutex); - -/* -* perf_event_release_kernel() could've stolen some of our -* child events and still have them on its free_list. In that -* case we must wait for these events to have been freed (in -* particular all their references to this task must've been -* dropped). -* -* Without this copy_process() will unconditionally free this -* task (irrespective of its reference count) and -* _free_event()'s put_task_struct(event->hw.target) will be a -* use-after-free. -* -* Wait for all events to drop their context reference. -*/ -wait_var_event (&ctx->refcount,refcount_read (&ctx->refcount) ==1 ); -put_ctx (ctx);/* must be last */ +perf_event_exit_task_context (task, false); }void perf_event_delayed_put (struct task_struct *task)
Greg Kroah-Hartman
maintainerPATCH 216/220 perf/core: Fix group leader use-after-free after sibling detach
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Chillara <[email protected]>
commit 42c5ca1f0a288a52878bd72a5595b08261057438 upstream.
perf_group_detach() handles leader and sibling detach differently. When the group leader is detached, all siblings are promoted to singleton events and their group_leader pointer is reset to themselves. When a sibling is detached, it is removed from the leader's sibling_list, but its group_leader pointer is left pointing at the old leader.
That is harmless when the sibling is being closed and freed immediately, as in the DETACH_DEAD path. It is not safe when the sibling is detached but kept alive, such as during CPU hotplug with DETACH_GROUP. In that case the sibling is removed from the context, while its file descriptor can still keep it alive.
A typical failing sequence is:
- A group contains leader L and sibling S.
- CPU hot-unplug detaches S with DETACH_GROUP, removing it from
L->sibling_list but leaving S->group_leader == L.
- L is later closed and freed.
- A PERF_IOC_FLAG_GROUP ioctl on S follows S->group_leader and dereferences the freed leader.
This was reproduced by running the perf event fuzzer, CPU hotplug, and a stress workload concurrently:
Unable to handle kernel paging request at virtual address 006b6b6b6b6b6cdb CPU: 2 PID: 12489 Comm: perf_fuzzer 6.18.7 PREEMPT pc : perf_ioctl+0x34c/0xc68 x20: ffffff89a3fa2c70 x8 : 6b6b6b6b6b6b6b6b Code: 943c4a0e 340047a0 f9404a94 f9411e88 (f940b908) Call trace: perf_ioctl+0x34c/0xc68 (P) __arm64_sys_ioctl+0xa0/0xf4 invoke_syscall+0x58/0xe4 el0_svc_common+0xa8/0xdc do_el0_svc+0x1c/0x28 el0_svc+0x40/0xc0 el0t_64_sync_handler+0x68/0xdc el0t_64_sync+0x1c4/0x1c8
The fault happened in perf_ioctl(), where perf_event_for_each() follows the stale group_leader pointer and perf_event_for_each_child() then dereferences the freed leader's context.
Fix the use-after-free by promoting the detached sibling to a singleton. Also fix __event_disable() cgroup accounting and event state change.
--- kernel/events/core.c | 66 ++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 29 deletions(-)
kernel/events/core.c +37 -29
@@ -2206,6 +2206,34 @@ static inline struct list_head *get_even &event->pmu_ctx->flexible_active; } +/* @sibling must already be unlinked from its old leader's sibling_list. */ +static void perf_promote_sibling_to_leader (struct perf_event *sibling, +struct perf_event_context *ctx, +int group_caps) +{ +/* +* Events that have PERF_EV_CAP_SIBLING require being part of +* a group and cannot exist on their own, schedule them out +* and move them into the ERROR state. Also see +* _perf_event_enable(), it will not be able to recover this +* ERROR state. +*/ +if (sibling->event_caps &PERF_EV_CAP_SIBLING ) +__event_disable (sibling, ctx,PERF_EVENT_STATE_ERROR ); + + sibling->group_leader = sibling; + sibling->group_caps = group_caps; + +if (sibling->attach_state &PERF_ATTACH_CONTEXT ) { +add_event_to_groups (sibling, ctx); + +if (sibling->state ==PERF_EVENT_STATE_ACTIVE ) +list_add_tail (&sibling->active_list,get_event_list (sibling)); + } + +perf_event__header_size (sibling); +} +static void perf_group_detach (struct perf_event *event) {struct perf_event *leader = event->group_leader;
@@ -2229,8 +2257,9 @@ static void perf_group_detach(struct per*/ if (leader != event) {list_del_init (&event->sibling_list); - event->group_leader->nr_siblings--; - event->group_leader->group_generation++; + leader->nr_siblings--; + leader->group_generation++; +perf_promote_sibling_to_leader (event, ctx, event->event_caps); goto out; }
@@ -2240,32 +2269,14 @@ static void perf_group_detach(struct per* to whatever list we are on. */ list_for_each_entry_safe (sibling, tmp, &event->sibling_list, sibling_list) { - -/* -* Events that have PERF_EV_CAP_SIBLING require being part of -* a group and cannot exist on their own, schedule them out -* and move them into the ERROR state. Also see -* _perf_event_enable(), it will not be able to recover this -* ERROR state. -*/ -if (sibling->event_caps &PERF_EV_CAP_SIBLING ) -__event_disable (sibling, ctx,PERF_EVENT_STATE_ERROR ); - - sibling->group_leader = sibling;list_del_init (&sibling->sibling_list);/* Inherit group flags from the previous leader */ - sibling->group_caps = event->group_caps; - -if (sibling->attach_state &PERF_ATTACH_CONTEXT ) { -add_event_to_groups (sibling, event->ctx); - -if (sibling->state ==PERF_EVENT_STATE_ACTIVE ) -list_add_tail (&sibling->active_list,get_event_list (sibling)); - } +perf_promote_sibling_to_leader (sibling, ctx, event->group_caps);WARN_ON_ONCE (sibling->ctx != event->ctx); } + event->nr_siblings =0 ; out:for_each_sibling_event (tmp, leader)
@@ -2443,12 +2454,8 @@ __perf_remove_from_context(struct perf_eif (flags &DETACH_DEAD ) state =PERF_EVENT_STATE_DEAD ; -event_sched_out (event, ctx); - -if (event->state >PERF_EVENT_STATE_OFF ) -perf_cgroup_event_disable (event, ctx); +__event_disable (event, ctx, state); -perf_event_set_state (event,min (event->state, state));if (flags &DETACH_GROUP )perf_group_detach (event);if (flags &DETACH_CHILD )
@@ -2517,8 +2524,9 @@ static void __event_disable(struct perf_ enum perf_event_state state) {event_sched_out (event, ctx); -perf_cgroup_event_disable (event, ctx); -perf_event_set_state (event, state); +if (event->state >PERF_EVENT_STATE_OFF ) +perf_cgroup_event_disable (event, ctx); +perf_event_set_state (event,min (event->state, state)); }/*
Greg Kroah-Hartman
maintainerPATCH 217/220 fs: unlock the superblock during iterate_supers_type
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 0b9d62a47149083d581d8b2abb04124b6175cb29 upstream.
This function takes super_lock in shared mode, so it should release the same lock.
--- fs/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/super.c +3 -1
@@ -970,8 +970,10 @@ void iterate_supers_type(struct file_sysspin_unlock (&sb_lock); locked =super_lock_shared (sb); -if (locked) +if (locked) {f (sb, arg); +super_unlock_shared (sb); + }spin_lock (&sb_lock);if (p)
Greg Kroah-Hartman
maintainerPATCH 218/220 binfmt_misc: use exe_file_deny_write_access() for the interpreter clone
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit fa5990ca8fd917003e526036bcc50413edb9722c upstream.
For MISC_FMT_OPEN_FILE entries load_misc_binary() clones the registered interpreter file and denies write access to the clone via plain deny_write_access(). The clone is installed as bprm->interpreter and later released by the exec machinery through exe_file_allow_write_access() which skips the i_writecount increment for files with FMODE_FSNOTIFY_HSM set.
The deny and allow side can therefore come to different conclusions when pre-content watches are in play: if a pre-content watch is added to the interpreter after registration every subsequent exec through that entry takes a write denial on the clone that is never paired with a write allowance, driving the interpreter inode's i_writecount further down with each exec and leaving the interpreter unwritable even after the entry and all its users are gone.
Take the write denial via exe_file_deny_write_access() so both sides of the pairing base their decision on the same file mode, and propagate failure instead of silently ignoring it: an interpreter that is concurrently open for writing now fails the exec with ETXTBSY, exactly like an interpreter freshly opened via open_exec() would.
--- fs/binfmt_misc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/binfmt_misc.c +8 -2
@@ -248,8 +248,14 @@ static int load_misc_binary(struct linuxif (fmt->flags &MISC_FMT_OPEN_FILE ) { interp_file =file_clone_open (fmt->interp_file); -if (!IS_ERR (interp_file)) -deny_write_access (interp_file); +if (!IS_ERR (interp_file)) { +int err =exe_file_deny_write_access (interp_file); + +if (err) { +fput (interp_file); + interp_file =ERR_PTR (err); + } + } }else { interp_file =open_exec (fmt->interpreter); }
Greg Kroah-Hartman
maintainerPATCH 219/220 net: harmonize tstats and dstats
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
commit d3ed6dee73c560fad0a8e152c8e233b3fb3a2e44 upstream.
After the blamed commits below, some UDP tunnel use dstats for accounting. On the xmit path, all the UDP-base tunnels ends up using iptunnel_xmit_stats() for stats accounting, and the latter assumes the relevant (tunnel) network device uses tstats.
The end result is some 'funny' stat report for the mentioned UDP tunnel, e.g. when no packet is actually dropped and a bunch of packets are transmitted:
gnv2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue \
state UNKNOWN mode DEFAULT group default qlen 1000
link/ether ee:7d:09:87:90:ea brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
14916 23 0 15 0 0
TX: bytes packets errors dropped carrier collsns
0 1566 0 0 0 0
Address the issue ensuring the same binary layout for the overlapping fields of dstats and tstats. While this solution is a bit hackish, is smaller and with no performance pitfall compared to other alternatives i.e. supporting both dstat and tstat in iptunnel_xmit_stats() or reverting the blamed commit.
With time we should possibly move all the IP-based tunnel (and virtual devices) to dstats.
--- include/linux/netdevice.h | 2 +- net/core/dev.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-)
include/linux/netdevice.h +1 -1
@@ -2746,9 +2746,9 @@ struct pcpu_sw_netstats {struct pcpu_dstats {u64_stats_t rx_packets;u64_stats_t rx_bytes; -u64_stats_t rx_drops;u64_stats_t tx_packets;u64_stats_t tx_bytes; +u64_stats_t rx_drops;u64_stats_t tx_drops;struct u64_stats_sync syncp; }__aligned(8 * sizeof(u64)) ;
net/core/dev.c +14 -0
@@ -11070,6 +11070,20 @@ struct rtnl_link_stats64 *dev_get_stats(const struct net_device_ops *ops = dev->netdev_ops;const struct net_device_core_stats __percpu *p; +/* +* IPv{4,6} and udp tunnels share common stat helpers and use +* different stat type (NETDEV_PCPU_STAT_TSTATS vs +* NETDEV_PCPU_STAT_DSTATS). Ensure the accounting is consistent. +*/ +BUILD_BUG_ON (offsetof(struct pcpu_sw_netstats , rx_bytes) != + offsetof(struct pcpu_dstats , rx_bytes)); +BUILD_BUG_ON (offsetof(struct pcpu_sw_netstats , rx_packets) != + offsetof(struct pcpu_dstats , rx_packets)); +BUILD_BUG_ON (offsetof(struct pcpu_sw_netstats , tx_bytes) != + offsetof(struct pcpu_dstats , tx_bytes)); +BUILD_BUG_ON (offsetof(struct pcpu_sw_netstats , tx_packets) != + offsetof(struct pcpu_dstats , tx_packets)); +if (ops->ndo_get_stats64) {memset (storage,0 ,sizeof (*storage)); ops->ndo_get_stats64 (dev, storage);
Greg Kroah-Hartman
maintainerPATCH 220/220 ip_tunnel: adapt iptunnel_xmit_stats() to NETDEV_PCPU_STAT_DSTATS
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 8431c602f551549f082bbfa67f3003f2d8e3e132 upstream.
Blamed commits forgot that vxlan/geneve use udp_tunnel[6]_xmit_skb() which call iptunnel_xmit_stats().
iptunnel_xmit_stats() was assuming tunnels were only using NETDEV_PCPU_STAT_TSTATS.
@syncp offset in pcpu_sw_netstats and pcpu_dstats is different.
32bit kernels would either have corruptions or freezes if the syncp sequence was overwritten.
This patch also moves pcpu_stat_type closer to dev->{t,d}stats to avoid a potential cache line miss since iptunnel_xmit_stats() needs to read it.
--- include/linux/netdevice.h | 3 +-- include/net/ip_tunnels.h | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-)
include/linux/netdevice.h +1 -2
@@ -2069,6 +2069,7 @@ struct net_device {unsigned long state;unsigned int flags;unsigned short hard_header_len; + enum netdev_stat_type pcpu_stat_type:8;netdev_features_t features;struct inet6_dev __rcu *ip6_ptr;__cacheline_group_end (net_device_read_txrx);
@@ -2314,8 +2315,6 @@ struct net_device {void *ml_priv;enum netdev_ml_priv_type ml_priv_type; - enum netdev_stat_type pcpu_stat_type:8; -#if IS_ENABLED (CONFIG_GARP )struct garp_port __rcu *garp_port;#endif
include/net/ip_tunnels.h +22 -6
@@ -651,13 +651,29 @@ static inline int iptunnel_pull_offloadsstatic inline void iptunnel_xmit_stats (struct net_device *dev,int pkt_len) {if (pkt_len >0 ) { -struct pcpu_sw_netstats *tstats =get_cpu_ptr (dev->tstats); +if (dev->pcpu_stat_type ==NETDEV_PCPU_STAT_DSTATS ) { +struct pcpu_dstats *dstats =get_cpu_ptr (dev->dstats); -u64_stats_update_begin (&tstats->syncp); -u64_stats_add (&tstats->tx_bytes, pkt_len); -u64_stats_inc (&tstats->tx_packets); -u64_stats_update_end (&tstats->syncp); -put_cpu_ptr (tstats); +u64_stats_update_begin (&dstats->syncp); +u64_stats_add (&dstats->tx_bytes, pkt_len); +u64_stats_inc (&dstats->tx_packets); +u64_stats_update_end (&dstats->syncp); +put_cpu_ptr (dstats); +return ; + } +if (dev->pcpu_stat_type ==NETDEV_PCPU_STAT_TSTATS ) { +struct pcpu_sw_netstats *tstats =get_cpu_ptr (dev->tstats); + +u64_stats_update_begin (&tstats->syncp); +u64_stats_add (&tstats->tx_bytes, pkt_len); +u64_stats_inc (&tstats->tx_packets); +u64_stats_update_end (&tstats->syncp); +put_cpu_ptr (tstats); +return ; + } +pr_err_once ("iptunnel_xmit_stats pcpu_stat_type=%d\n" , + dev->pcpu_stat_type); +WARN_ON_ONCE (1 );return ; }
Hi!
Quoted 4 lines
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.12.y
Best regards,
Pavel
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.105-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.12.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.12.105-rc1-g071632e1c770 #1 SMP PREEMPT_DYNAMIC Thu Aug 20 19:54:19 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Greg Kroah-Hartman wrote on Thu, Aug 20, 2026 at 04:53:10PM +0200:
Quoted 5 lines
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 8 lines
Responses should be made by Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.105-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.12.y
and the diffstat can be found below.
Tested 071632e1c770 ("Linux 6.12.105-rc1") on:
- arm i.MX6ULL (Armadillo 640)
- arm64 i.MX8ULP (Armadillo IoT A9E)
No obvious regression in dmesg or basic tests:
Signature · 1 line
Dominique Martinet
Quoted 8 lines · On Thu, 20 Aug 2026 16:53:10 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64:
Thanks!
Cheers,
Miguel
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Am 20.08.2026 um 16:53 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.105-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.12.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 22 Aug 2026 14:51:11 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.105-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.12.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.12.105 release. There are 220 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.