5.10.261-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 268/699 netfilter: nf_conncount: callers must hold rcu read lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 64d7d5abe2160bba369b4a8f06bdf5630573bab0 ]
rcu_derefence_raw() should not have been used here, it concealed this bug. Its used because struct rb_node lacks __rcu annotated pointers, so plain rcu_derefence causes sparse warnings.
The major tradeoff is that rcu_derefence_raw() doesn't warn when the caller isn't in a rcu read section.
Extend the rcu read lock scope accordingly and cause sparse warnings, those warnings are the lesser evil.
--- net/netfilter/nf_conncount.c | 6 +++--- net/openvswitch/conntrack.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_conncount.c +3 -3
@@ -499,7 +499,7 @@ count_tree(struct net *net, hash =jhash2 (key, data->keylen, conncount_rnd) %CONNCOUNT_SLOTS ; root = &data->root[hash]; - parent =rcu_dereference_raw (root->rb_node); + parent =rcu_dereference (root->rb_node);while (parent) {int diff;
@@ -507,9 +507,9 @@ count_tree(struct net *net, diff =key_diff (key, rbconn->key, data->keylen);if (diff <0 ) { - parent =rcu_dereference_raw (parent->rb_left); + parent =rcu_dereference (parent->rb_left); }else if (diff >0 ) { - parent =rcu_dereference_raw (parent->rb_right); + parent =rcu_dereference (parent->rb_right); }else {int ret;
net/openvswitch/conntrack.c +1 -1
@@ -2076,10 +2076,10 @@ static int ovs_ct_limit_get_zone_limit(struct net *net, }else {rcu_read_lock (); limit =ct_limit_get (info, zone); -rcu_read_unlock (); err =__ovs_ct_limit_get_zone_limit ( net, info->data, zone, limit, reply); +rcu_read_unlock ();if (err)return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 269/699 bpf, sockmap: reject overflowing copy + len in bpf_msg_push_data()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 0c0a8ed85349dae298712d79cb276acfeb794d82 ]
When the scatterlist ring is full or nearly full, bpf_msg_push_data() enters a copy fallback path and computes copy + len for the page allocation size. Since len comes from BPF with arg3_type = ARG_ANYTHING and both are u32, a crafted len can wrap the sum to a small value, causing an undersized allocation followed by an out-of-bounds memcpy.
BUG: unable to handle page fault for address: ffffed104089a402 Oops: Oops: 0000 [#1] SMP KASAN NOPTI Call Trace: __asan_memcpy (mm/kasan/shadow.c:105) bpf_msg_push_data (net/core/filter.c:2852 net/core/filter.c:2788) bpf_prog_9ed8b5711920a7d7+0x2e/0x36 sk_psock_msg_verdict (net/core/skmsg.c:934) tcp_bpf_sendmsg (net/ipv4/tcp_bpf.c:421 net/ipv4/tcp_bpf.c:584) __sys_sendto (net/socket.c:2206) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
Add an overflow check before the allocation.
--- net/core/filter.c | 3 +++ 1 file changed, 3 insertions(+)
net/core/filter.c +3 -0
@@ -2819,6 +2819,9 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,if (!space || (space ==1 && start != offset)) copy = msg->sg.data[i].length; +if (unlikely (copy + len < copy)) +return -EINVAL ; + page =alloc_pages (__GFP_NOWARN |GFP_ATOMIC | __GFP_COMP,get_order (copy + len));if (unlikely (!page))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 270/699 bpf, sockmap: fix integer overflow in bpf_msg_pop_data() bounds check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit a48802fb2cd2d1e23651989f8ff4d15e9d5dad54 ]
start and len are u32, so
u64 last = start + len;
evaluates start + len in 32-bit and wraps before storing it in last. The bounds check
if (start >= offset + l || last > msg->sg.size) return -EINVAL;
can then be passed with an out-of-range start/len, after which the pop loop runs off the end of the scatterlist and sk_msg_shift_left() calls put_page() on the empty msg->sg.end slot:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:sk_msg_shift_left net/core/filter.c:2957 [inline] RIP: 0010:____bpf_msg_pop_data net/core/filter.c:3103 [inline] RIP: 0010:bpf_msg_pop_data+0x753/0x1a10 net/core/filter.c:2984 Call Trace: <TASK> bpf_prog_4cc92c278f4d5d56+0x1b1/0x1e8 bpf_prog_run_pin_on_cpu+0x107/0x320 include/linux/filter.h:746 sk_psock_msg_verdict+0x357/0x7f0 net/core/skmsg.c:934 tcp_bpf_send_verdict net/ipv4/tcp_bpf.c:420 [inline] tcp_bpf_sendmsg+0x766/0x1ae0 net/ipv4/tcp_bpf.c:583 __sock_sendmsg+0x153/0x1c0 net/socket.c:802 __sys_sendto+0x326/0x430 net/socket.c:2265 __x64_sys_sendto+0xe3/0x100 net/socket.c:2268 do_syscall_64+0x14c/0x480 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
Widen the addition with a (u64) cast so the bound is evaluated in 64-bit and a len near U32_MAX no longer wraps below msg->sg.size.
While here, change pop from int to u32. It counts bytes against the unsigned scatterlist lengths and can never be negative, so the signed type only invites sign-confusion in the pop loop.
--- net/core/filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/filter.c +2 -2
@@ -2985,8 +2985,8 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, u32, len, u64, flags) {u32 i =0 , l =0 , space, offset =0 ; -u64 last = start + len; -int pop; +u64 last = (u64 )start + len; +u32 pop;if (unlikely (flags))return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 271/699 MIPS: mm: Fix out-of-bounds write in maar_res_walk()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yadan Fan <[email protected]>
[ Upstream commit 1b001b16bc88f3f7817e228acfd91ee01bdcfcce ]
maar_res_walk() uses wi->num_cfg as the index into the fixed-size wi->cfg array, but checks whether the array is full only after it has filled the selected entry. If walk_system_ram_range() reports more than 16 memory ranges, the overflow call writes one struct maar_config past the end of the array before WARN_ON() prevents num_cfg from advancing.
Move the full-array check before taking the array slot and return non-zero when the scratch array is full, so walk_system_ram_range() terminates the walk instead of invoking the callback for further ranges.
--- arch/mips/mm/init.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
arch/mips/mm/init.c +8 -4
@@ -277,9 +277,15 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages, void *data) {struct maar_walk_info *wi = data; -struct maar_config *cfg = &wi->cfg[wi->num_cfg]; +struct maar_config *cfg;unsigned int maar_align; +/* Ensure we don't overflow the cfg array */ +if (WARN_ON (wi->num_cfg >=ARRAY_SIZE (wi->cfg))) +return -1 ; + + cfg = &wi->cfg[wi->num_cfg]; +/* MAAR registers hold physical addresses right shifted by 4 bits */ maar_align =BIT (MIPS_MAAR_ADDR_SHIFT +4 );
@@ -288,9 +294,7 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages, cfg->upper =ALIGN_DOWN (PFN_PHYS (start_pfn + nr_pages), maar_align) -1 ; cfg->attrs =MIPS_MAAR_S ; -/* Ensure we don't overflow the cfg array */ -if (!WARN_ON (wi->num_cfg >=ARRAY_SIZE (wi->cfg))) - wi->num_cfg++; + wi->num_cfg++;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 272/699 powerpc/perf: fix preempt count underflow in fsl_emb_pmu_del
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 81e3a86030462824a67d697739cf3f387f4ba350 ]
fsl_emb_pmu_del() unconditionally calls put_cpu_var(cpu_hw_events) at the 'out:' label, but only calls the matching get_cpu_var() after the 'i < 0' early-return check. When event->hw.idx is negative the function jumps to 'out:' without having taken get_cpu_var(), and the trailing put_cpu_var() then issues an unmatched preempt_enable(), underflowing preempt_count.
On a CONFIG_PREEMPT=y kernel preempt_count would underflow and eventually present as a 'scheduling while atomic' BUG.
Move put_cpu_var() to pair with get_cpu_var() so the percpu access is correctly bracketed and the 'out:' label only handles perf_pmu_enable.
--- arch/powerpc/perf/core-fsl-emb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/perf/core-fsl-emb.c +2 -1
@@ -366,9 +366,10 @@ static void fsl_emb_pmu_del(struct perf_event *event, int flags) cpuhw->n_events--; +put_cpu_var (cpu_hw_events); + out:perf_pmu_enable (event->pmu); -put_cpu_var (cpu_hw_events); }static void fsl_emb_pmu_start (struct perf_event *event,int ef_flags)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 273/699 powerpc/powernv: fix preempt count leak in pnv_kexec_wait_secondaries_down
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 0ecd26e93e698c8327521910fc6296f5b84a4b92 ]
pnv_kexec_wait_secondaries_down() calls get_cpu() to obtain the current CPU id but never calls the matching put_cpu(), leaking one preempt_disable() nesting level on every invocation.
In practice the imbalance does not trigger a visible splat because the kexec teardown path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.
The function only needs the current CPU id, and this path runs with interrupts disabled and the CPU pinned, so the preempt_disable() side-effect of get_cpu() is unnecessary. Replace it with raw_smp_processor_id().
--- arch/powerpc/platforms/powernv/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/platforms/powernv/setup.c +2 -1
@@ -362,7 +362,8 @@ static void pnv_kexec_wait_secondaries_down(void) {int my_cpu, i, notified =-1 ; - my_cpu =get_cpu (); +/* Called with interrupts disabled, so the CPU is pinned. */ + my_cpu =raw_smp_processor_id ();for_each_online_cpu (i) {uint8_t status;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 274/699 powerpc/kexec: fix double get_cpu() imbalance in kexec_prepare_cpus
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 5c86f1c1f972761a04bf22f4c0618d1aa714185b ]
kexec_prepare_cpus_wait() calls get_cpu() internally to obtain the current CPU id. kexec_prepare_cpus() calls kexec_prepare_cpus_wait() twice -- once for KEXEC_STATE_IRQS_OFF and once for KEXEC_STATE_REAL_MODE -- but only issues a single put_cpu() at the end, leaving preempt_count elevated by one extra nesting level.
In practice the imbalance does not trigger a 'scheduling while atomic' splat because the kexec path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.
kexec_prepare_cpus() calls local_irq_disable()/hard_irq_disable() before invoking kexec_prepare_cpus_wait(), so the CPU is already pinned and the get_cpu()/put_cpu() preempt_disable() bracketing is unnecessary. Only the current CPU id is needed, so replace get_cpu() with raw_smp_processor_id() and drop the now-unneeded put_cpu().
--- arch/powerpc/kexec/core_64.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kexec/core_64.c +1 -3
@@ -163,7 +163,7 @@ static void kexec_prepare_cpus_wait(int wait_state)int my_cpu, i, notified=-1 ;hw_breakpoint_disable (); - my_cpu =get_cpu (); + my_cpu =raw_smp_processor_id ();/* Make sure each CPU has at least made it to the state we need. * * FIXME: There is a (slim) chance of a problem if not all of the CPUs
@@ -242,8 +242,6 @@ static void kexec_prepare_cpus(void)/* after we tell the others to go down */ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); - - put_cpu(); }#else /* ! SMP */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 275/699 KEYS: Use acquire when reading state in keyring search
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit c1201b37f666f6466ab1fd3a381c2b7a4b7e9fee ]
The negative-key race fix added release/acquire ordering for key use.
Publish payload before state; read state before payload.
keyring_search_iterator() still uses READ_ONCE() before match callbacks. An asymmetric match callback calls asymmetric_key_ids(), which reads key->payload.data[asym_key_ids].
Use key_read_state() there to complete that ordering.
--- security/keys/keyring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/keys/keyring.c +1 -1
@@ -576,7 +576,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)struct keyring_search_context *ctx = iterator_data;const struct key *key =keyring_ptr_to_key (object);unsigned long kflags =READ_ONCE (key->flags); -short state =READ_ONCE (key->state); +short state =key_read_state (key);kenter ("{%d}" , key->serial);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 276/699 tipc: fix UAF in tipc_l2_send_msg()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit f4c3d89fc986b0da196ddfc6cfe0ea5d5d08bec6 ]
Syzbot reported a slab-use-after-free in ipvlan_hard_header() when called from tipc_l2_send_msg().
The root cause is that tipc_disable_l2_media() calls synchronize_net() while b->media_ptr is still valid. This allows concurrent RCU readers to obtain the device pointer after synchronize_net() has finished. The pointer is cleared later in bearer_disable(), but without any subsequent synchronization, allowing the device to be freed while still in use by readers.
Fix this by clearing b->media_ptr in tipc_disable_l2_media() before calling synchronize_net().
This is safe to do now because the call order in bearer_disable() was reversed in 0d051bf93c06 ("tipc: make bearer packet filtering generic") to call tipc_node_delete_links() (which needs the pointer) before disable_media().
https: //lore.kernel.org/netdev/[email protected]/T/#u
--- net/tipc/bearer.c | 1 + 1 file changed, 1 insertion(+)
net/tipc/bearer.c +1 -0
@@ -469,6 +469,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b) dev = (struct net_device *)rtnl_dereference (b->media_ptr);dev_remove_pack (&b->pt);RCU_INIT_POINTER (dev->tipc_ptr,NULL ); +RCU_INIT_POINTER (b->media_ptr,NULL );synchronize_net ();dev_put (dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 277/699 tcp: ipv6: clamp default adverting MSS to avoid GSO_BY_FRAGS (0xFFFF)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 2bf43d0e2e6a27d52a7d624e2d6b9116972e8a22 ]
When MTU is large, ip6_default_advmss() can return IPV6_MAXPLEN (65535). This is interpreted by TCP as mss_clamp, allowing the MSS to reach 65535.
However, 0xFFFF is also used as a magic value GSO_BY_FRAGS in the kernel. If a TCP packet with gso_size=0xFFFF is passed to skb_segment(), it will be mistakenly treated as GSO_BY_FRAGS, leading to a NULL pointer dereference because local TCP packets do not use frag_list.
Fix this by returning min(IPV6_MAXPLEN, GSO_BY_FRAGS - 1) (65534) from ip6_default_advmss() when MTU is large.
Also update the stale comment in ip6_default_advmss() which suggested that IPV6_MAXPLEN is returned to mean "any MSS".
--- net/ipv6/route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/ipv6/route.c +3 -3
@@ -3072,11 +3072,11 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)/* * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. -* IPV6_MAXPLEN is also valid and means: "any MSS, -* rely only on pmtu discovery" +* Limit the default MSS to GSO_BY_FRAGS - 1 to avoid +* collision with the GSO_BY_FRAGS magic value (0xFFFF). */ if (mtu >IPV6_MAXPLEN -sizeof (struct tcphdr )) - mtu =IPV6_MAXPLEN ; + mtu = min_t(unsigned int, IPV6_MAXPLEN, GSO_BY_FRAGS - 1);return mtu; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 278/699 ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit ff6f26c58421614b02694ac9d219ac61d924bc68 ]
A circular locking dependency involves INODE_ALLOC_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, and ORPHAN_DIR_SYSTEM_INODE.
1. ocfs2_mknod() acquires INODE_ALLOC then EXTENT_ALLOC.
2. ocfs2_dio_end_io_write() acquires EXTENT_ALLOC for unwritten extents, then ORPHAN_DIR via ocfs2_del_inode_from_orphan() while still holding EXTENT_ALLOC.
3. ocfs2_wipe_inode() acquires ORPHAN_DIR then INODE_ALLOC via ocfs2_remove_inode.
Break the cycle in ocfs2_dio_end_io_write() by freeing the allocation contexts (releasing EXTENT_ALLOC) before acquiring ORPHAN_DIR.
WARNING: possible circular locking dependency detected
------------------------------------------------------
is trying to acquire lock:ffff8881e78b33a0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}, at:ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299
but task is already holding lock:ffff8881e78b4fa0 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}, at:ocfs2_evict_inode+0xe97/0x43b0 fs/ocfs2/inode.c:1299
the existing dependency chain (in reverse order) is:
-> #2 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}:
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_del_inode_from_orphan+0x12e/0x7a0 fs/ocfs2/namei.c:2728
ocfs2_dio_end_io+0xf9c/0x1370 fs/ocfs2/aops.c:2418
dio_complete+0x25b/0x790 fs/direct-io.c:281-> #1 (&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_reserve_suballoc_bits+0x16d/0x4840 fs/ocfs2/suballoc.c:882
ocfs2_reserve_new_metadata_blocks+0x415/0x9a0
fs/ocfs2/suballoc.c:1078
ocfs2_mknod+0x10f3/0x2260 fs/ocfs2/namei.c:351-> #0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:
__lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237
lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5868
down_write+0x96/0x200 kernel/locking/rwsem.c:1625
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_remove_inode fs/ocfs2/inode.c:733 [inline]
ocfs2_wipe_inode fs/ocfs2/inode.c:896 [inline]
ocfs2_delete_inode fs/ocfs2/inode.c:1157 [inline]
ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299
Chain exists of:
&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE] -->
&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE] -->
&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]
Possible unsafe locking scenario: CPU0 CPU1
---- ----
lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);
lock(&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]);
lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]); lock(&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]);
*** DEADLOCK ***
--- fs/ocfs2/aops.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/ocfs2/aops.c +9 -4
@@ -2403,6 +2403,15 @@ static int ocfs2_dio_end_io_write(struct inode *inode, unlock:up_write (&oi->ip_alloc_sem); +if (data_ac) { +ocfs2_free_alloc_context (data_ac); + data_ac =NULL ; + } +if (meta_ac) { +ocfs2_free_alloc_context (meta_ac); + meta_ac =NULL ; + } +/* everything looks good, let's start the cleanup */ if (!ret && dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
@@ -2414,10 +2423,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,ocfs2_inode_unlock (inode,1 );brelse (di_bh); out: -if (data_ac) -ocfs2_free_alloc_context (data_ac); -if (meta_ac) -ocfs2_free_alloc_context (meta_ac);ocfs2_run_deallocs (osb, &dealloc);ocfs2_dio_free_write_ctx (inode, dwc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 279/699 net/9p: fix race condition on rdma->state in trans_rdma.c
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit 7d54894a1ee265a72d70f7cae1da6cc774cccc71 ]
The rdma->state field is modified without holding req_lock in both recv_done() and p9_cm_event_handler(), while rdma_request() accesses the same field under the req_lock spinlock. This inconsistent locking creates a race condition:
- recv_done() running in softirq completion context sets rdma->state = P9_RDMA_FLUSHING without acquiring req_lock
- p9_cm_event_handler() modifies rdma->state at multiple points (ADDR_RESOLVED, ROUTE_RESOLVED, ESTABLISHED, CLOSED) without req_lock
- rdma_request() uses spin_lock_irqsave(&rdma->req_lock, flags) to protect the read-modify-write of rdma->state
The race can cause lost state transitions: recv_done() or the CM event handler could set state to FLUSHING/CLOSED while rdma_request() is concurrently checking or modifying state under the lock, leading to the FLUSHING transition being silently overwritten by CLOSING. This corrupts the connection state machine and can cause use-after-free on RDMA request objects during teardown.
Fix by adding req_lock protection to all rdma->state modifications in recv_done() and p9_cm_event_handler(), matching the pattern already used in rdma_request(). Use spin_lock_irqsave/spin_unlock_irqrestore in the CM event handler since it can race with recv_done() which runs in softirq context.
Tested with a kernel module that races two threads (simulating rdma_request and recv_done/CM handler) on rdma->state with proper
locking: 5.5M+ FLUSHING writes over 27M iterations with 0 lost transitions.
Message-ID: <[email protected]>
--- net/9p/trans_rdma.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
net/9p/trans_rdma.c +17 -2
@@ -241,25 +241,36 @@ p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) {struct p9_client *c = id->context;struct p9_trans_rdma *rdma = c->trans; +unsigned long flags; +switch (event->event) {case RDMA_CM_EVENT_ADDR_RESOLVED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_INIT ); rdma->state =P9_RDMA_ADDR_RESOLVED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_ROUTE_RESOLVED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_ADDR_RESOLVED ); rdma->state =P9_RDMA_ROUTE_RESOLVED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_ESTABLISHED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_ROUTE_RESOLVED ); rdma->state =P9_RDMA_CONNECTED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_DISCONNECTED : -if (rdma) +if (rdma) { +spin_lock_irqsave (&rdma->req_lock, flags); rdma->state =P9_RDMA_CLOSED ; +spin_unlock_irqrestore (&rdma->req_lock, flags); + } c->status = Disconnected;break ;
@@ -297,6 +308,7 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)struct p9_req_t *req;int err =0 ;int16_t tag; +unsigned long flags; req =NULL ; ib_dma_unmap_single(rdma->cm_id->device, c->busa, client->msize,
@@ -333,7 +345,10 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc) err_out:p9_debug (P9_DEBUG_ERROR ,"req %p err %d status %d\n" , req, err, wc->status); - rdma->state =P9_RDMA_FLUSHING ; +spin_lock_irqsave (&rdma->req_lock, flags); +if (rdma->state <P9_RDMA_FLUSHING ) + rdma->state =P9_RDMA_FLUSHING ; +spin_unlock_irqrestore (&rdma->req_lock, flags); client->status = Disconnected; goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 280/699 staging: nvec: fix use-after-free in nvec_rx_completed()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandru Hossu <[email protected]>
[ Upstream commit 26813881181deb3a32fbb59eadb2599cbe8423f6 ]
In nvec_rx_completed(), when an incomplete RX transfer is detected, nvec_msg_free() is called to return the message back to the pool by clearing its 'used' atomic flag. Immediately after this, the code accesses nvec->rx->data[0] to check the message type.
Since nvec_msg_free() marks the pool slot as available via atomic_set(), any concurrent or subsequent call to nvec_msg_alloc() could claim that same slot and overwrite its data[] array. Reading nvec->rx->data[0] after freeing the message is therefore a use-after-free.
Fix this by saving the message type byte before calling nvec_msg_free(), then using the saved value for the battery quirk check.
--- drivers/staging/nvec/nvec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/nvec/nvec.c +3 -1
@@ -488,6 +488,8 @@ static void nvec_tx_completed(struct nvec_chip *nvec)static void nvec_rx_completed (struct nvec_chip *nvec) {if (nvec->rx->pos !=nvec_msg_size (nvec->rx)) { +unsigned char msg_type = nvec->rx->data[0 ]; +dev_err (nvec->dev,"RX incomplete: Expected %u bytes, got %u\n" , (uint )nvec_msg_size (nvec->rx), (uint )nvec->rx->pos);
@@ -496,7 +498,7 @@ static void nvec_rx_completed(struct nvec_chip *nvec) nvec->state =0 ;/* Battery quirk - Often incomplete, and likes to crash */ -if (nvec->rx->data[0 ] ==NVEC_BAT ) +if (msg_type ==NVEC_BAT )complete (&nvec->ec_transfer);return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 281/699 coresight: cti: Fix DT filter signals silently ignored
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingchao Deng <[email protected]>
[ Upstream commit 551bb2fd5e4ed63d33aa11f07102cce5179b7595 ]
In cti_plat_process_filter_sigs(), after allocating a temporary cti_trig_grp struct via kzalloc_obj(), the code never assigns tg->nr_sigs = nr_filter_sigs. Since kzalloc zero-initialises the struct, tg->nr_sigs remains 0. cti_plat_read_trig_group() guards with:
if (!tgrp->nr_sigs)
return 0;so it returns immediately without reading any signal indices from DT.
Fix by assigning tg->nr_sigs before calling cti_plat_read_trig_group().
--- drivers/hwtracing/coresight/coresight-cti-platform.c | 1 + 1 file changed, 1 insertion(+)
drivers/hwtracing/coresight/coresight-cti-platform.c +1 -0
@@ -329,6 +329,7 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,if (!tg)return -ENOMEM ; + tg->nr_sigs = nr_filter_sigs; err =cti_plat_read_trig_group (tg, fwnode,CTI_DT_FILTER_OUT_SIGS );if (!err) drvdata->config.trig_out_filter |= tg->used_mask;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 282/699 x86/platform/olpc: xo15: Drop wakeup source on driver removal
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit cc966553e6ff0849978b5754531b768b0ff54985 ]
Prevent leaking a wakeup source object after removing the driver by adding appropriate cleanup code to its remove callback function.
--- arch/x86/platform/olpc/olpc-xo15-sci.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/platform/olpc/olpc-xo15-sci.c +1 -0
@@ -185,6 +185,7 @@ static int xo15_sci_add(struct acpi_device *device)static int xo15_sci_remove (struct acpi_device *device) { +device_init_wakeup (&device->dev, false);acpi_disable_gpe (NULL , xo15_sci_gpe);acpi_remove_gpe_handler (NULL , xo15_sci_gpe, xo15_sci_gpe_handler);cancel_work_sync (&sci_work);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 283/699 platform/x86: xo15-ebook: Fix wakeup source and GPE handling
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit b2fc2c6ebbd2d49935c8960755d8170faead2159 ]
The device_set_wakeup_enable() call in ebook_switch_add() doesn't actually do anything because power.can_wakeup is not set for ACPI device objects. Moreover, had it done anything, it would have registered a wakeup source object that wouldn't have been used going forward and that wakeup source would have been leaked after driver removal because ebook_switch_remove() doesn't clean it up. Accordingly, remove that call from ebook_switch_add().
Also prevent leaking an enabled ACPI GPE after removing the driver by adding appropriate cleanup code to ebook_switch_remove().
--- drivers/platform/x86/xo15-ebook.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/platform/x86/xo15-ebook.c +6 -1
@@ -40,6 +40,7 @@ MODULE_DEVICE_TABLE(acpi, ebook_device_ids);struct ebook_switch {struct input_dev *input;char phys[32 ];/* for input device */ +bool gpe_enabled; };static int ebook_send_state (struct acpi_device *device)
@@ -133,7 +134,7 @@ static int ebook_switch_add(struct acpi_device *device)/* Button's GPE is run-wake GPE */ acpi_enable_gpe (device->wakeup.gpe_device, device->wakeup.gpe_number); -device_set_wakeup_enable (&device->dev, true); + button->gpe_enabled = true; }return 0 ;
@@ -149,6 +150,10 @@ static int ebook_switch_remove(struct acpi_device *device) {struct ebook_switch *button =acpi_driver_data (device); +if (button->gpe_enabled) +acpi_disable_gpe (device->wakeup.gpe_device, + device->wakeup.gpe_number); +input_unregister_device (button->input);kfree (button);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 284/699 perf sched: Add missing mmap2 handler in timehist
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 91182741369b261c441e63e6678893032a6d7e4c ]
perf_sched__timehist() registers event handlers for options using the sched->tool struct. It registers handlers for MMAP, COMM, EXIT, FORK, etc. but completely omits registering a handler for MMAP2 events.
Failing to register both MMAP and MMAP2 handlers causes modern systems (which primarily output MMAP2 records) to silently drop VMA map mappings. This results in uninitialized machine/thread mapping structures, making it impossible to resolve shared library instruction pointers (IPs) to dynamic symbols/DSOs during timehist callchain analysis.
Fix this by correctly registering perf_event__process_mmap2 in sched->tool inside perf_sched__timehist().
--- tools/perf/builtin-sched.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/builtin-sched.c +1 -0
@@ -3001,6 +3001,7 @@ static int perf_sched__timehist(struct perf_sched *sched)*/ sched->tool.sample = perf_timehist__process_sample; sched->tool.mmap = perf_event__process_mmap; + sched->tool.mmap2 = perf_event__process_mmap2; sched->tool.comm = perf_event__process_comm; sched->tool.exit = perf_event__process_exit; sched->tool.fork = perf_event__process_fork;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 285/699 staging: most: video: avoid double free on video register failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 7cb1c5b32a2bfde961fff8d5204526b609bcb30a ]
comp_register_videodev() allocates a video_device with video_device_alloc() and releases it if video_register_device() fails.
This can double free the video_device when __video_register_device() reaches device_register() and that call fails:
video_register_device()
-> __video_register_device()
-> device_register() fails
-> put_device(&vdev->dev)
-> v4l2_device_release()
-> vdev->release(vdev)
-> video_device_release(vdev) comp_register_videodev()
-> video_device_release(mdev->vdev)
Use video_device_release_empty() while registering the device so that registration failure paths do not free mdev->vdev through vdev->release(). comp_register_videodev() then releases mdev->vdev exactly once on failure. Restore video_device_release() after successful registration so the registered device keeps its normal lifetime handling.
This issue was found by a static analysis tool I am developing.
--- drivers/staging/most/video/video.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/staging/most/video/video.c +6 -1
@@ -416,6 +416,7 @@ static int comp_register_videodev(struct most_video_dev *mdev)/* Fill the video capture device struct */ *mdev->vdev = comp_videodev_template; + mdev->vdev->release = video_device_release_empty; mdev->vdev->v4l2_dev = &mdev->v4l2_dev; mdev->vdev->lock = &mdev->lock; snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
@@ -428,9 +429,13 @@ static int comp_register_videodev(struct most_video_dev *mdev)v4l2_err (&mdev->v4l2_dev,"video_register_device failed (%d)\n" , ret);video_device_release (mdev->vdev); +return ret; } -return ret; + mdev->vdev->release = video_device_release; + +return 0 ; + }static void comp_unregister_videodev (struct most_video_dev *mdev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 286/699 usb: host: max3421: Fix shift-out-of-bounds in max3421_hub_control()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seungjin Bae <[email protected]>
[ Upstream commit cff06b03b530ae1fe8a13e93a7848f2130e00fb4 ]
The max3421_hub_control() function handles USB hub class requests to the virtual root hub. In the default branches of both the ClearPortFeature and SetPortFeature switch statements, it modifies max3421_hcd->port_status by left shifting 1 by the request's value parameter. However, it does not validate whether this shift will exceed the width of port_status.
So if a malicious userspace task with access to the root hub via /dev/bus/usb/.../001 issues a USBDEVFS_CONTROL ioctl with wValue greater than or equal to 32, the left shift operation invokes shift-out-of-bounds undefined behavior. This results in arbitrary bit corruption of port_status, including the normally-immutable change bits, which can bypass internal state checks and confuse the hub status.
Fix this by rejecting requests whose value exceeds the shift width before performing the shift.
This issue was found using a KLEE-based symbolic execution tool for kernel drivers that I'm currently developing.
--- drivers/usb/host/max3421-hcd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
@@ -1703,6 +1703,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, !pdata->vbus_active_level); fallthrough;default : +if (value >=32 ) + goto error; max3421_hcd->port_status &= ~(1 << value); }break ;
@@ -1756,6 +1758,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,max3421_reset_port (hcd); fallthrough;default : +if (value >=32 ) + goto error;if ((max3421_hcd->port_status &USB_PORT_STAT_POWER ) !=0 ) max3421_hcd->port_status |= (1 << value);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 287/699 usb: host: max3421: Reject hub port requests for non-existent ports
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seungjin Bae <[email protected]>
[ Upstream commit 11b5c101e2fd206104b05bc92554d356989423a8 ]
The max3421_hub_control() function handles USB hub class requests to the virtual root hub. The GetPortStatus case correctly rejects requests with index != 1, since the virtual root hub has only a single port. However, the ClearPortFeature and SetPortFeature cases lack the same check.
Fix this by extending the index != 1 rejection to both cases, matching the existing behavior of GetPortStatus.
--- drivers/usb/host/max3421-hcd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
@@ -1694,6 +1694,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,case ClearHubFeature:break ;case ClearPortFeature: +if (index !=1 ) + goto error;switch (value) {case USB_PORT_FEAT_SUSPEND :break ;
@@ -1737,6 +1739,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,break ;case SetPortFeature: +if (index !=1 ) + goto error;switch (value) {case USB_PORT_FEAT_LINK_STATE :case USB_PORT_FEAT_U1_TIMEOUT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 288/699 char: tlclk: fix use-after-free in tlclk_cleanup()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Kim <[email protected]>
[ Upstream commit bbf003b7794d6ad6f939fdd29f1f1bde8ac554c1 ]
This patch improves the module cleanup process in the tlclk driver to prevent potential use-after-free and race conditions.
Currently, the file_operations structure does not specify the .owner field, which could allow the module to be unloaded while user-space processes are still interacting with the device. Additionally, the tlclk_cleanup() function frees the alarm_events memory before ensuring that blocked processes in the waitqueue are fully awakened and that the switchover_timer has completed.
To address these cases, this patch:
- Sets '.owner = THIS_MODULE' in tlclk_fops to safely defer module unloading while the device is in use.
- Updates tlclk_cleanup() to explicitly wake up all blocked readers (wake_up_all), properly release hardware I/O regions, and safely delete the timer (timer_delete_sync) prior to freeing memory.
--- drivers/char/tlclk.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/char/tlclk.c +4 -0
@@ -263,6 +263,7 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, }static const struct file_operations tlclk_fops = { + .owner =THIS_MODULE , .read = tlclk_read, .open = tlclk_open, .release = tlclk_release,
@@ -852,6 +853,9 @@ static void __exit tlclk_cleanup(void)misc_deregister (&tlclk_miscdev);unregister_chrdev (tlclk_major,"telco_clock" ); + got_event =1 ; +wake_up_all (&wq); +release_region (TLCLK_BASE ,8 );del_timer_sync (&switchover_timer);kfree (alarm_events);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 289/699 iio: light: si1133: reset counter to prevent race condition
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit 0a5f45ed2342aabae1e32c72558d15be28940a95 ]
Sashiko reported a potential race condition happening when the driver returns an errno after a timeout in the si1133_command() function. The premature exit causes the hardware and software counters to become out of sync by not updating data->rsp_seq, therefore the internal hardware counter keeps incrementing.
Fix this by adding a call to si1133_cmd_reset_counter() before returning from timeout.
--- drivers/iio/light/si1133.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/iio/light/si1133.c +5 -0
@@ -427,6 +427,11 @@ static int si1133_command(struct si1133_data *data, u8 cmd)dev_warn (dev,"Failed to read command %#02hhx, ret=%d\n" , cmd, err); +/* +* Reset counter on err to prevent software and hardware +* counters being out of sync. +*/ +si1133_cmd_reset_counter (data); goto out; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 290/699 iio: light: si1133: prevent race condition on timeout
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit 8c50a95ceb230d17801758a9e41ffbbbe46f8b4d ]
Sashiko reported a bug where the si1133_command exits on timeout without halting the sensor or masking the interrupt. If the sensor completes the command later, any subsequent command to the sensor will cause the IRQ handler to complete immediately, returning stale data to the driver all while the command hasn't finished yet, shifting all potential reads in the future.
Fix this by masking the IRQ if wait_for_completion_timeout() fails. When initiating a new command, do a dummy read of the IRQ_STATUS register and turn the IRQ back on.
--- drivers/iio/light/si1133.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/iio/light/si1133.c +8 -1
@@ -395,8 +395,14 @@ static int si1133_command(struct si1133_data *data, u8 cmd) expected_seq = (data->rsp_seq +1 ) &SI1133_MAX_CMD_CTR ; -if (cmd ==SI1133_CMD_FORCE ) +if (cmd ==SI1133_CMD_FORCE ) { +/* Flush pending IRQs from a previous timeout. */ +regmap_read (data->regmap,SI1133_REG_IRQ_STATUS , &resp); +regmap_write (data->regmap,SI1133_REG_IRQ_ENABLE , +SI1133_IRQ_CHANNEL_ENABLE ); +reinit_completion (&data->completion); + } err =regmap_write (data->regmap,SI1133_REG_COMMAND , cmd);if (err) {
@@ -409,6 +415,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd)/* wait for irq */ if (!wait_for_completion_timeout (&data->completion,msecs_to_jiffies (SI1133_COMPLETION_TIMEOUT_MS ))) { +regmap_write (data->regmap,SI1133_REG_IRQ_ENABLE ,0 ); err = -ETIMEDOUT ; goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 291/699 iio: magnetometer: ak8975: fix potential kernel stack memory leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit a9a00d727b7bbc5e913a919530a9dd468935bf95 ]
Currently in the AK8975 driver there are four instances where potential uninitialized kernel stack memory leaks can occur. If i2c_smbus_read_i2c_block_data_or_emulated() returns a value less than the size of the buffer, uninitialized bytes are retained in the buffer and later the buffer is passed on to IIO buffers, potentially leaking memory to userspace.
Fix this by adding checks whether the return value of the function is equal to the size of the buffer and subsequently if the value is lesser than zero to distinguish from a returned error code.
--- drivers/iio/magnetometer/ak8975.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/iio/magnetometer/ak8975.c +14 -0
@@ -437,6 +437,10 @@ static int ak8975_who_i_am(struct i2c_client *client,dev_err (&client->dev,"Error reading WIA\n" );return ret; } +if (ret !=sizeof (wia_val)) { +dev_err (&client->dev,"Error reading WIA\n" ); +return -EIO ; + }if (wia_val[0 ] !=AK8975_DEVICE_ID )return -ENODEV ;
@@ -549,6 +553,10 @@ static int ak8975_setup(struct i2c_client *client)dev_err (&client->dev,"Not able to read asa data\n" );return ret; } +if (ret !=sizeof (data->asa)) { +dev_err (&client->dev,"Error reading asa data\n" ); +return -EIO ; + }/* After reading fuse ROM data set power-down mode */ ret =ak8975_set_mode (data,POWER_DOWN );
@@ -688,6 +696,10 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) sizeof(rval), (u8*)&rval);if (ret <0 ) goto exit; +if (ret !=sizeof (rval)) { + ret = -EIO ; + goto exit; + }/* Read out ST2 for release lock on measurment data. */ ret =i2c_smbus_read_byte_data (client, data->def->ctrl_regs[ST2 ]);
@@ -817,6 +829,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) (u8 *)fval);if (ret <0 ) goto unlock; +if (ret !=sizeof (fval)) + goto unlock;mutex_unlock (&data->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 292/699 iio: accel: mma8452: handle I2C read error(s) in mma8452_read()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
[ Upstream commit 5bdff291d20c31b365d9ddfe9c426fbfb41da5bb ]
Currently, If i2c_smbus_read_i2c_block_data() fails but mma8452_set_runtime_pm_state() succeeds, mma8452_read() returns 0.
As a result, the caller mma8452_read_raw() assumes the read was successful and proceeds to use a buffer containing uninitialized stack memory.
Add proper checking of the I2C read return value and propagate errors to the caller.
--- drivers/iio/accel/mma8452.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/accel/mma8452.c +2 -0
@@ -254,6 +254,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) ret =i2c_smbus_read_i2c_block_data (data->client,MMA8452_OUT_X ,3 *sizeof (__be16), (u8 *)buf); +if (ret <0 ) +return ret; ret =mma8452_set_runtime_pm_state (data->client, false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 293/699 HID: logitech-hidpp: remove excess kernel-doc member in hidpp_scroll_counter
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit f22a5db8a7d38152556f230d6d68e59dbc27971b ]
The @dev member described in the kernel-doc does not exist in the struct. Remove the stale entry.
--- drivers/hid/hid-logitech-hidpp.c | 1 - 1 file changed, 1 deletion(-)
drivers/hid/hid-logitech-hidpp.c +0 -1
@@ -150,7 +150,6 @@ struct hidpp_battery {/** * struct hidpp_scroll_counter - Utility class for processing high-resolution * scroll events. -* @dev: the input device for which events should be reported. * @wheel_multiplier: the scalar multiplier to be applied to each wheel event * @remainder: counts the number of high-resolution units moved since the last * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 294/699 perf: Fix off-by-one stack buffer overflow in kallsyms__parse()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rui Qi <[email protected]>
[ Upstream commit 68018df3f55eba96a20dd703f5f276a6518f4963 ]
In kallsyms__parse(), the loop reading symbol names iterates with i < sizeof(symbol_name), which allows i to reach sizeof(symbol_name) upon loop exit. The subsequent symbol_name[i] = '\0' then writes one byte past the end of the stack-allocated symbol_name[] array.
Fix this by changing the loop bound to KSYM_NAME_LEN, so the null terminator always lands within the array. The overflow is triggerable by a kallsyms entry with a symbol name of KSYM_NAME_LEN+1 or more characters (e.g., long Rust mangled names or a malicious /proc/kallsyms).
--- tools/lib/symbol/kallsyms.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
tools/lib/symbol/kallsyms.c +4 -1
@@ -60,7 +60,7 @@ int kallsyms__parse(const char *filename, void *arg,read_to_eol (&io);continue ; } -for (i =0 ; i <sizeof (symbol_name); i++) { +for (i =0 ; i <KSYM_NAME_LEN ; i++) { ch =io__get_char (&io);if (ch <0 || ch =='\n' )break ;
@@ -68,6 +68,9 @@ int kallsyms__parse(const char *filename, void *arg, } symbol_name[i] ='\0' ; +if (i ==KSYM_NAME_LEN ) +read_to_eol (&io); + err =process_symbol (arg, symbol_name, symbol_type, start);if (err)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 295/699 perf sched: Clean up idle_threads entry on init failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cda5a94ad9181cd60cbf04be11d524201bf489a2 ]
get_idle_thread() allocates a thread via thread__new() and stores it in idle_threads[cpu], then calls init_idle_thread() to set up the private data. If init_idle_thread() fails (e.g. OOM for the idle_thread_runtime struct), the function returns NULL but leaves the partially initialized thread in idle_threads[cpu].
On subsequent calls for the same CPU, get_idle_thread() finds a non-NULL idle_threads[cpu], skips allocation, and returns thread__get() on a thread that has no priv data. Callers then get a thread whose thread__priv() returns NULL, leading to unexpected behavior.
Release the thread and reset the slot to NULL on init failure so the entry doesn't persist in a corrupted state.
--- tools/perf/builtin-sched.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +4 -1
@@ -2279,8 +2279,11 @@ static struct thread *get_idle_thread(int cpu) idle_threads[cpu] =thread__new (0 ,0 );if (idle_threads[cpu]) { -if (init_idle_thread (idle_threads[cpu]) <0 ) +if (init_idle_thread (idle_threads[cpu]) <0 ) { +/* clean up so next call doesn't find a half-initialized thread */ +thread__zput (idle_threads[cpu]);return NULL ; + } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 296/699 perf sched: Replace BUG_ON and add NULL checks in replay event helpers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 75eafe4a3a93a0143a20c0cc286bfb9008ac1478 ]
get_new_event() has three issues:
1. The zalloc() result is dereferenced without a NULL check, crashing on allocation failure.
2. BUG_ON(!task->atoms) kills the process when realloc() fails. Since perf.data is untrusted input, this should be a graceful error.
3. The realloc pattern assigns directly to task->atoms, losing the old pointer on failure. task->nr_events is also incremented before the realloc, leaving corrupted state on failure.
Fix get_new_event() to:
- Check the zalloc() result before dereferencing
- Use a temporary for realloc() to avoid losing the old pointer
- Increment nr_events only after successful realloc
- Return NULL instead of calling BUG_ON on failure
Also fix add_sched_event_wakeup() where zalloc() for wait_sem is passed to sem_init() without a NULL check.
Update all callers (add_sched_event_run, add_sched_event_wakeup, add_sched_event_sleep) to handle NULL returns by returning early. The replay may produce incomplete output on OOM but will not crash.
--- tools/perf/builtin-sched.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-)
tools/perf/builtin-sched.c +25 -3
@@ -361,14 +361,25 @@ get_new_event(struct task_desc *task, u64 timestamp)struct sched_atom *event =zalloc (sizeof (*event));unsigned long idx = task->nr_events;size_t size; +struct sched_atom **atoms_p; + +if (event ==NULL ) { +pr_err ("ERROR: sched: failed to allocate event\n" ); +return NULL ; + } event->timestamp = timestamp; event->nr = idx; + size =sizeof (struct sched_atom *) * (task->nr_events +1 ); + atoms_p =realloc (task->atoms, size); +if (!atoms_p) { +pr_err ("ERROR: sched: failed to grow atoms array\n" ); +free (event); +return NULL ; + } + task->atoms = atoms_p; task->nr_events++; - size =sizeof (struct sched_atom *) * task->nr_events; - task->atoms =realloc (task->atoms, size); -BUG_ON (!task->atoms); task->atoms[idx] = event;
@@ -399,6 +410,8 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task } event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; event->type =SCHED_EVENT_RUN ; event->duration = duration;
@@ -412,6 +425,8 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *tstruct sched_atom *event, *wakee_event; event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; event->type =SCHED_EVENT_WAKEUP ; event->wakee = wakee;
@@ -426,6 +441,10 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t } wakee_event->wait_sem =zalloc (sizeof (*wakee_event->wait_sem)); +if (!wakee_event->wait_sem) { +pr_err ("ERROR: sched: failed to allocate semaphore\n" ); +return ; + }sem_init (wakee_event->wait_sem,0 ,0 ); wakee_event->specific_wait =1 ; event->wait_sem = wakee_event->wait_sem;
@@ -438,6 +457,9 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *ta {struct sched_atom *event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; + event->type =SCHED_EVENT_SLEEP ; sched->nr_sleep_events++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 297/699 perf mmap: Fix NULL deref in aio cleanup on alloc failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 25627346b10e6a564610ea2c49dc6dd54812226d ]
perf_mmap__aio_mmap() sets map->aio.nr_cblocks before allocating the data array. If calloc() for aiocb or cblocks fails before the data array is allocated, the return -1 path leads to perf_mmap__aio_munmap() which loops nr_cblocks times calling perf_mmap__aio_free(). Both versions of perf_mmap__aio_free() (NUMA and non-NUMA) dereference map->aio.data[idx] without checking if data is NULL, causing a NULL pointer dereference.
Add NULL checks for map->aio.data at the top of both perf_mmap__aio_free() variants so the cleanup path is safe when allocation fails partway through perf_mmap__aio_mmap().
--- tools/perf/util/mmap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
tools/perf/util/mmap.c +6 -4
@@ -88,10 +88,10 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)static void perf_mmap__aio_free (struct mmap *map,int idx) { -if (map->aio.data[idx]) { -munmap (map->aio.data[idx],mmap__mmap_len (map)); - map->aio.data[idx] =NULL ; - } +if (!map->aio.data || !map->aio.data[idx]) +return ; +munmap (map->aio.data[idx],mmap__mmap_len (map)); + map->aio.data[idx] =NULL ; }static int perf_mmap__aio_bind (struct mmap *map,int idx,int cpu,int affinity)
@@ -134,6 +134,8 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)static void perf_mmap__aio_free (struct mmap *map,int idx) { +if (!map->aio.data) +return ;zfree (&(map->aio.data[idx])); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 298/699 perf c2c: Fix use-after-free in he__get_c2c_hists() error path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 5e5e6196d737c5be03d20647428316b36621608d ]
he__get_c2c_hists() assigns c2c_he->hists before calling c2c_hists__init(). If init fails, the error path calls free(hists) but leaves c2c_he->hists pointing to freed memory. On teardown, c2c_he_free() finds the non-NULL pointer and calls hists__delete_entries() on it, causing a use-after-free.
Set c2c_he->hists to NULL before freeing so teardown skips the already-freed allocation.
--- tools/perf/builtin-c2c.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/builtin-c2c.c +1 -0
@@ -201,6 +201,7 @@ he__get_c2c_hists(struct hist_entry *he, ret =c2c_hists__init (hists, sort, nr_header_lines);if (ret) { + c2c_he->hists =NULL ;free (hists);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 299/699 dmaengine: Fix possible use after free
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuno Sá <[email protected]>
[ Upstream commit 92f853f0645aebf1d05d333e97ab7c342ace1892 ]
In dma_release_channel(), check chan->device->privatecnt after call dma_chan_put(). However, dma_chan_put() call dma_device_put() which could release the last reference of the device if the DMA provider is already gone and hence free it.
Fixes it by moving dma_chan_put() after the check.
--- drivers/dma/dmaengine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/dmaengine.c +2 -1
@@ -906,11 +906,12 @@ void dma_release_channel(struct dma_chan *chan)mutex_lock (&dma_list_mutex);WARN_ONCE (chan->client_count !=1 ,"chan reference count %d != 1\n" , chan->client_count); -dma_chan_put (chan);/* drop PRIVATE cap enabled by __dma_request_channel() */ if (--chan->device->privatecnt ==0 )dma_cap_clear (DMA_PRIVATE , chan->device->cap_mask); +dma_chan_put (chan); +if (chan->slave) {sysfs_remove_link (&chan->dev->device.kobj,DMA_SLAVE_NAME );sysfs_remove_link (&chan->slave->kobj, chan->name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 300/699 clk: qcom: a53: Corrected frequency multiplier for 1152MHz
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Phillip Varney <[email protected]>
[ Upstream commit bb56147ea9fce98ebde1d367335ba006cba61fbd ]
The 1152MHz frequency entry for the a53 currently selects a multiplier of 62, giving 1190MHz. This changes the mulitiplier to 60 giving the intended 1152MHz.
--- drivers/clk/qcom/a53-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/a53-pll.c +1 -1
@@ -18,7 +18,7 @@static const struct pll_freq_tbl a53pll_freq[] = { {998400000 ,52 ,0x0 ,0x1 ,0 }, {1094400000 ,57 ,0x0 ,0x1 ,0 }, - {1152000000 ,62 ,0x0 ,0x1 ,0 }, + {1152000000 ,60 ,0x0 ,0x1 ,0 }, {1209600000 ,63 ,0x0 ,0x1 ,0 }, {1248000000 ,65 ,0x0 ,0x1 ,0 }, {1363200000 ,71 ,0x0 ,0x1 ,0 },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 301/699 pNFS/filelayout: fix cheking if a layout is striped
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sagi Grimberg <[email protected]>
[ Upstream commit 91668417d4e925c98cae4a55b1b9860380ddbf16 ]
A layout can still be striped with num_fh = 1 as it is perfectly possible that both MDS and DSs can handle the same filehandle. Hence check according to stripe_count > 1, which is the correct check to begin with.
We should not be called with flseg->dsaddr = NULL, but if for some reason we do, return our best guess with is flseg->num_fh > 1.
--- fs/nfs/filelayout/filelayout.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfs/filelayout/filelayout.c +2 -0
@@ -784,6 +784,8 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,static bool filelayout_lseg_is_striped (const struct nfs4_filelayout_segment *flseg) { +if (flseg->dsaddr) +return flseg->dsaddr->stripe_count >1 ;return flseg->num_fh >1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 302/699 NFSv4/pnfs: defer return_range callbacks until after inode unlock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 77b160b2d863d37f36b6c38e80a7d259ce939e69 ]
Sometimes unmounting an NFS filesystem mounted with pNFS SCSI layouts triggers the following warning:
BUG: scheduling while atomic: umount.nfs4/...
__schedule_bug+0xbd/0x100
schedule_debug.constprop.0+0x19f/0x220
__schedule+0x10d/0x10a0
schedule+0x74/0x190
schedule_timeout+0xf5/0x220
io_schedule_timeout+0xd5/0x160
__wait_for_common+0x186/0x4b0
blk_execute_rq+0x2ef/0x3a0
scsi_execute_cmd+0x1ff/0x700
sd_pr_out_command.isra.0+0x242/0x380 [sd_mod]
bl_unregister_scsi.constprop.0+0x109/0x3c0 [blocklayoutdriver]
bl_unregister_dev+0x175/0x1c0 [blocklayoutdriver]
bl_free_device+0x1f/0x1b0 [blocklayoutdriver]
bl_free_deviceid_node+0x12/0x30 [blocklayoutdriver]
nfs4_put_deviceid_node+0x171/0x360 [nfsv4]
ext_tree_remove+0x11c/0x1d0 [blocklayoutdriver]
_pnfs_return_layout+0x416/0x900 [nfsv4]
nfs4_evict_inode+0x108/0x130 [nfsv4]
evict+0x316/0x750
dispose_list+0xf1/0x1a0
evict_inodes+0x33f/0x440
generic_shutdown_super+0xc9/0x4e0
kill_anon_super+0x3a/0x90
nfs_kill_super+0x44/0x60 [nfs]
deactivate_locked_super+0xb8/0x1b0
cleanup_mnt+0x25a/0x380
task_work_run+0x13e/0x210
exit_to_user_mode_loop+0x169/0x400
do_syscall_64+0x467/0x1550
entry_SYSCALL_64_after_hwframe+0x76/0x7eThe warning occurs because the block layout driver unregisters the SCSI device while the inode lock is still held. Device unregistration issues a SCSI PR command, which may sleep, resulting in a "scheduling while atomic" warning.
During layout return, ext_tree_remove() invokes the layout driver's return_range callback while holding the inode lock. For block layouts, this callback eventually calls bl_unregister_scsi(), which may block in scsi_execute_cmd() while issuing PR commands to the device.
Fix this by deferring the return_range callbacks until after the inode lock has been released. The layout header reference count is incremented before invoking return_range(), ensuring that the layout header remains valid while the layout driver removes extents from the extent tree.
--- fs/nfs/callback_proc.c | 9 +++++---- fs/nfs/pnfs.c | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-)
fs/nfs/callback_proc.c +5 -4
@@ -243,6 +243,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,struct pnfs_layout_hdr *lo;u32 rv =NFS4ERR_NOMATCHING_LAYOUT ;LIST_HEAD (free_me_list); +bool return_range = false; ino =nfs_layout_find_inode (clp, &args->cbl_fh, &args->cbl_stateid);if (IS_ERR (ino)) {
@@ -287,13 +288,13 @@ static u32 initiate_file_draining(struct nfs_client *clp,/* Embrace your forgetfulness! */ rv =NFS4ERR_NOMATCHING_LAYOUT ; -if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) { -NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, - &args->cbl_range); - } + return_range = true; } unlock:spin_unlock (&ino->i_lock); +if (return_range &&NFS_SERVER (ino)->pnfs_curr_ld->return_range) +NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, + &args->cbl_range);pnfs_free_lseg_list (&free_me_list);/* Free all lsegs that are attached to commit buckets */ nfs_commit_inode (ino,0 );
fs/nfs/pnfs.c +2 -2
@@ -1378,8 +1378,6 @@ _pnfs_return_layout(struct inode *ino)pnfs_clear_layoutcommit (ino, &tmp_list);pnfs_mark_matching_lsegs_return (lo, &tmp_list, &range,0 ); -if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) -NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, &range);/* Don't send a LAYOUTRETURN if list was initially empty */ if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) ||
@@ -1391,6 +1389,8 @@ _pnfs_return_layout(struct inode *ino) send =pnfs_prepare_layoutreturn (lo, &stateid, &cred,NULL );spin_unlock (&ino->i_lock); +if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) +NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, &range);if (send) status =pnfs_send_layoutreturn (lo, &stateid, &cred,IOMODE_ANY , true); out_wait_layoutreturn:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 303/699 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS on fatal DS connect errors
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 7a375cafc14ed151508f908ea5681caf0a9cc1d6 ]
Commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") teaches ff_layout_{read,write}_pagelist() to return PNFS_NOT_ATTEMPTED when nfs4_ff_layout_prepare_ds() fails with a nfs_error_is_fatal() errno (e.g. -ETIMEDOUT from a SOFTCONN connect deadline, -ENOMEM, -ERESTARTSYS), so that the client gives up instead of spinning. pnfs_do_{read,write}() then dispatches the I/O through pnfs_{read,write}_through_mds() → nfs_pageio_reset_{read,write}_mds().
That fallback is unconditional and silently violates FF_FLAGS_NO_IO_THRU_MDS:
when the layout segment carries the flag (typically single-mirror appliance layouts where MDS I/O is explicitly forbidden), theout_failed: path's \&& !ds_fatal_error\ clause overrides the flag's short-circuit through ff_layout_avoid_mds_available_ds() and routes the I/O to the MDS file handle anyway.
This is reachable in practice during a data-server restart: SOFTCONN exhaustion produces -ETIMEDOUT, which is fatal per nfs_error_is_fatal(), which triggers PNFS_NOT_ATTEMPTED, which silently goes to MDS.
Preserve the upstream "don't spin on fatal errors" intent for layouts that permit MDS fallback. For layouts with FF_FLAGS_NO_IO_THRU_MDS set, mark the layout for return and request PNFS_TRY_AGAIN instead; if the server cannot supply a usable layout the failure now surfaces cleanly via pnfs_update_layout(), rather than via silent MDS I/O that contradicts the flag.
--- fs/nfs/flexfilelayout/flexfilelayout.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +16 -0
@@ -1883,6 +1883,14 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr) out_failed:if (ff_layout_avoid_mds_available_ds (lseg) && !ds_fatal_error)return PNFS_TRY_AGAIN ; +if (ff_layout_no_fallback_to_mds (lseg)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET, +* never fall through to MDS I/O. +*/ +pnfs_error_mark_layout_for_return (hdr->inode, lseg); +return PNFS_TRY_AGAIN ; + }trace_pnfs_mds_fallback_read_pagelist (hdr->inode, hdr->args.offset, hdr->args.count,IOMODE_READ ,NFS_I (hdr->inode)->layout, lseg);
@@ -1954,6 +1962,14 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync) out_failed:if (ff_layout_avoid_mds_available_ds (lseg) && !ds_fatal_error)return PNFS_TRY_AGAIN ; +if (ff_layout_no_fallback_to_mds (lseg)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET, +* never fall through to MDS I/O. +*/ +pnfs_error_mark_layout_for_return (hdr->inode, lseg); +return PNFS_TRY_AGAIN ; + }trace_pnfs_mds_fallback_write_pagelist (hdr->inode, hdr->args.offset, hdr->args.count,IOMODE_RW ,NFS_I (hdr->inode)->layout, lseg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 304/699 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_write
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 1d62e659c0bf11649cf48e002c2a55d148f2610a ]
The FF_FLAGS_NO_IO_THRU_MDS flag lives on each lseg, so any fallback decision made when there is no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) cannot run the per-lseg check.
Introduce a sticky hdr-level ditto for FF_FLAGS_NO_IO_THRU_MDS in struct nfs4_flexfile_layout::flags (NFS4_FF_HDR_NO_IO_THRU_MDS bit), set whenever ff_layout_alloc_lseg() parses an lseg with the flag. The bit is never cleared for the lifetime of the layout hdr; the server is assumed to be consistent in its no-fallback policy per file. kzalloc() in ff_layout_alloc_layout_hdr() zero-initializes the field.
Use the new ff_layout_hdr_no_fallback_to_mds() helper to gate ff_layout_pg_get_mirror_count_write(): when pnfs_update_layout() returns NULL (e.g. NFS_LAYOUT_BULK_RECALL, pnfs_layout_io_test_failed, pnfs_layoutgets_blocked) the existing code unconditionally calls nfs_pageio_reset_write_mds(). This is a source of unwanted WRITE to MDS. Fix it by checking NFS4_FF_HDR_NO_IO_THRU_MDS bit, and if set surface -EAGAIN instead; the writepage-side caller (nfs_do_writepage() for buffered, nfs_direct_write_reschedule() for O_DIRECT) then redirties the request so writeback retries via pNFS.
--- fs/nfs/flexfilelayout/flexfilelayout.c | 13 +++++++++++++ fs/nfs/flexfilelayout/flexfilelayout.h | 16 ++++++++++++++++ 2 files changed, 29 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +13 -0
@@ -533,6 +533,9 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,if (!p) goto out_sort_mirrors; fls->flags =be32_to_cpup (p); +if (fls->flags &FF_FLAGS_NO_IO_THRU_MDS ) +set_bit (NFS4_FF_HDR_NO_IO_THRU_MDS , + &FF_LAYOUT_FROM_HDR (lh)->flags); p =xdr_inline_decode (&stream,4 );if (!p)
@@ -995,6 +998,16 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,0 ,NFS4_MAX_UINT64 ,IOMODE_RW ,NFS_I (pgio->pg_inode)->layout, pgio->pg_lseg); +if (NFS_I (pgio->pg_inode)->layout && +ff_layout_hdr_no_fallback_to_mds (NFS_I (pgio->pg_inode)->layout)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: no current lseg but the server's +* policy forbids MDS fallback. Surface -EAGAIN so writeback +* retries rather than silently issuing the WRITE via MDS. +*/ + pgio->pg_error = -EAGAIN ; + goto out; + }/* no lseg means that pnfs is not in use, so no mirroring here */ nfs_pageio_reset_write_mds (pgio); out:
fs/nfs/flexfilelayout/flexfilelayout.h +16 -0
@@ -102,12 +102,16 @@ struct nfs4_ff_layout_segment {struct nfs4_ff_layout_mirror *mirror_array[]; }; +/* nfs4_flexfile_layout::flags bit indices */ +#define NFS4_FF_HDR_NO_IO_THRU_MDS 0/* any lseg has had FF_FLAGS_NO_IO_THRU_MDS */ +struct nfs4_flexfile_layout {struct pnfs_layout_hdr generic_hdr;struct pnfs_ds_commit_info commit_info;struct list_head mirrors;struct list_head error_list;/* nfs4_ff_layout_ds_err */ ktime_t last_report_time;/* Layoutstat report times */ +unsigned long flags; };struct nfs4_flexfile_layoutreturn_args {
@@ -174,6 +178,18 @@ ff_layout_no_fallback_to_mds(struct pnfs_layout_segment *lseg)return FF_LAYOUT_LSEG (lseg)->flags &FF_FLAGS_NO_IO_THRU_MDS ; } +/* +* Sticky hdr-level mirror of FF_FLAGS_NO_IO_THRU_MDS so callers that have +* no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) can +* still honor the no-MDS-fallback policy. +*/ +static inline bool +ff_layout_hdr_no_fallback_to_mds (struct pnfs_layout_hdr *lo) +{ +return test_bit (NFS4_FF_HDR_NO_IO_THRU_MDS , + &FF_LAYOUT_FROM_HDR (lo)->flags); +} +static inline bool ff_layout_no_read_on_rw (struct pnfs_layout_segment *lseg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 305/699 PCI: mediatek: Fix operator precedence in PCIE_FTS_NUM_L0 macro
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit 282305d7e9c0e27fd8b4df34b7cd5506a1eccdd6 ]
The original PCIE_FTS_NUM_L0(x) macro was buggy due to improper operator precedence, where ((x) & 0xff << 8) was evaluated as ((x) & 0xff00).
Instead of just fixing the parentheses, use the standard FIELD_PREP() macro. This makes the code more robust by automatically handling masks and shifts, while also adding compile-time type and range checking to ensure the value fits within PCIE_FTS_NUM_MASK.
--- drivers/pci/controller/pcie-mediatek.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/pci/controller/pcie-mediatek.c +2 -1
@@ -7,6 +7,7 @@* Honghui Zhang <[email protected]> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/iopoll.h>
@@ -58,7 +59,7 @@/* MediaTek specific configuration registers */ #define PCIE_FTS_NUM 0x70c#define PCIE_FTS_NUM_MASK GENMASK(15, 8) -#define PCIE_FTS_NUM_L0 (x) ((x) & 0xff << 8) +#define PCIE_FTS_NUM_L0 (x) FIELD_PREP(PCIE_FTS_NUM_MASK, x)#define PCIE_FC_CREDIT 0x73c#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 306/699 perf tools: Fix get_max_num() size_t underflow on empty sysfs file
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 0a012113bb3a44482c163f16f4db03ccaa37a339 ]
get_max_num() reads a sysfs file (cpu/possible, cpu/present, or node/possible) and scans backward from the end to find the last number. If the file is empty, filename__read_str() returns num == 0. The loop while (--num) decrements the size_t from 0 to SIZE_MAX, reading backward across the heap until a comma or hyphen is found or unmapped memory is hit.
Add an early return for empty files before the backward scan.
--- tools/perf/util/cpumap.c | 6 ++++++ 1 file changed, 6 insertions(+)
tools/perf/util/cpumap.c +6 -0
@@ -280,6 +280,12 @@ static int get_max_num(char *path, int *max) buf[num] ='\0' ; +/* empty file — nothing to parse */ +if (num ==0 ) { + err =-1 ; + goto out; + } +/* start on the right, to find highest node num */ while (--num) {if ((buf[num] ==',' ) || (buf[num] =='-' )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 307/699 perf tools: Use perf_env__get_cpu_topology() in machine__resolve()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 5484b43a0ec8231c36fba6ead654cb72dbba8b8f ]
machine__resolve() accesses env->cpu[al->cpu].socket_id after checking al->cpu >= 0 and env->cpu != NULL, but without validating al->cpu against env->nr_cpus_avail. Since al->cpu comes from the untrusted perf.data sample, a crafted file with a large CPU index causes an out-of-bounds heap read.
Use perf_env__get_cpu_topology() which validates both NULL and bounds. Also bounds-check al->cpu before the cast to struct perf_cpu (int16_t):
without this, values like 65536 silently truncate to 0, bypassing the accessor's internal check and returning CPU 0's topology.
--- tools/perf/util/event.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
tools/perf/util/event.c +13 -2
@@ -12,6 +12,7 @@#include <linux/zalloc.h> #include "cpumap.h" #include "dso.h" +#include "env.h" #include "event.h" #include "debug.h" #include "hist.h"
@@ -656,8 +657,18 @@ int machine__resolve(struct machine *machine, struct addr_location *al,if (al->cpu >=0 ) {struct perf_env *env = machine->env; -if (env && env->cpu) - al->socket = env->cpu[al->cpu].socket_id; +/* +* Bounds-check al->cpu (s32) before casting to struct perf_cpu +* (int16_t): without this, e.g. 65536 truncates to 0 and silently +* returns CPU 0's topology. Can go once perf_cpu.cpu is widened. +*/ +if (env && al->cpu < env->nr_cpus_avail) { +struct cpu_topology_map *topo; + + topo =perf_env__get_cpu_topology (env, (struct perf_cpu ){ al->cpu }); +if (topo) + al->socket = topo->socket_id; + } }if (al->map) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 308/699 PCI: rcar-host: Remove unused LIST_HEAD(res)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lad Prabhakar <[email protected]>
[ Upstream commit 6ba90ce2069ae923b0ec787aebdf2d786e5d2a58 ]
Remove the unused LIST_HEAD(res) declaration from rcar_pcie_hw_enable().
The macro instantiation defines an unused 'struct list_head res' variable, which conflicts with a valid resource loop-local 'struct resource *res' declaration further down in the function, triggering a compiler variable shadowing warning:
drivers/pci/controller/pcie-rcar-host.c:357:34: warning: declaration of 'res' shadows a previous local [-Wshadow]
357 | struct resource *res = win->res;
--- drivers/pci/controller/pcie-rcar-host.c | 1 - 1 file changed, 1 deletion(-)
drivers/pci/controller/pcie-rcar-host.c +0 -1
@@ -261,7 +261,6 @@ static void rcar_pcie_hw_enable(struct rcar_pcie_host *host)struct rcar_pcie *pcie = &host->pcie;struct pci_host_bridge *bridge =pci_host_bridge_from_priv (host);struct resource_entry *win; -LIST_HEAD (res);int i =0 ;/* Try setting 5 GT/s link speed */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 309/699 perf sched: Fix idle-hist callchain display using wrong rb_first variant
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit d9b99dc8148e0c1f5da3942131b47e0d21187a32 ]
timehist_print_idlehist_callchain() calls rb_first_cached() on sorted_root, but the sort function (callchain_param.sort) populates it via rb_insert_color() on the plain rb_root member — not the cached variant. This means rb_leftmost is never set, so rb_first_cached() always returns NULL and the entire callchain summary is silently dropped from --idle-hist output.
The original code in ba957ebb54893aca ("perf sched timehist: Show callchains for idle stat") was correct — it used struct rb_root and rb_first(). The bug was introduced when sorted_root was converted to rb_root_cached without converting the sort insertion path to use rb_insert_color_cached().
Use rb_first(&root->rb_root) to match how the tree was populated.
--- tools/perf/builtin-sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +2 -1
@@ -2820,7 +2820,8 @@ static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)size_t ret =0 ;FILE *fp = stdout;struct callchain_node *chain; -struct rb_node *rb_node =rb_first_cached (root); +/* sort() uses rb_insert_color() on rb_root, not rb_root_cached */ +struct rb_node *rb_node =rb_first (&root->rb_root);printf (" %16s %8s %s\n" ,"Idle time (msec)" ,"Count" ,"Callchains" ); printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 310/699 perf bpf: Use scnprintf() in snprintf_hex() and synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cab3a9331ed0b3f884dd61c8a25b3cf123705982 ]
Both functions accumulate formatted output via ret += snprintf(buf + ret, size - ret, ...). If the buffer is too small and snprintf() returns more than the remaining space, ret exceeds size and the next 'size - ret' underflows, causing snprintf() to write past the buffer end.
Switch to scnprintf() which returns the actual number of bytes written, making the accumulation safe.
--- tools/perf/util/bpf-event.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
tools/perf/util/bpf-event.c +6 -5
@@ -29,7 +29,7 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)size_t i;for (i =0 ; i < len; i++) - ret +=snprintf (buf + ret, size - ret,"%02x" , data[i]); + ret +=scnprintf (buf + ret, size - ret,"%02x" , data[i]);return ret; }
@@ -130,7 +130,7 @@ static int synthesize_bpf_prog_name(char *buf, int size,const struct btf_type *t;int name_len; - name_len =snprintf (buf, size,"bpf_prog_" ); + name_len =scnprintf (buf, size,"bpf_prog_" ); name_len +=snprintf_hex (buf + name_len, size - name_len, prog_tags[sub_id],BPF_TAG_SIZE );if (btf) {
@@ -143,9 +143,10 @@ static int synthesize_bpf_prog_name(char *buf, int size, short_name = info->name; }else short_name ="F" ; -if (short_name) - name_len +=snprintf (buf + name_len, size - name_len, -"_%s" , short_name); +if (short_name) { + name_len +=scnprintf (buf + name_len, size - name_len, +"_%s" , short_name); + }return name_len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 311/699 perf hists: Fix snprintf() in hists__scnprintf_title() UID filter path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 227a8748742f0263f1fe3131449b44563b77a209 ]
hists__scnprintf_title() accumulates formatted output into a buffer using scnprintf() for all filter clauses except the UID filter, which uses snprintf(). If the buffer fills up and snprintf() returns more than the remaining space, printed exceeds size and the next 'size - printed' underflows, causing later scnprintf() calls to write past the buffer.
Switch the UID filter clause to scnprintf() to match the rest of the function.
--- tools/perf/util/hist.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/hist.c +4 -3
@@ -2728,9 +2728,10 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); -if (hists->uid_filter_str) - printed +=snprintf (bf + printed, size - printed, -", UID: %s" , hists->uid_filter_str); +if (hists->uid_filter_str) { + printed +=scnprintf (bf + printed, size - printed, +", UID: %s" , hists->uid_filter_str); + }if (thread) {if (hists__has (hists, thread)) { printed += scnprintf(bf + printed, size - printed,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 312/699 perf pmu: Fix perf_pmu__parse_scale/unit() OOB access on empty sysfs file
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 33035f7dd4e49f3f117e70c5e36c8c1ae88d37f2 ]
perf_pmu__parse_scale() reads a PMU scale file then accesses scale[sret - 1] to strip a trailing newline. Only sret < 0 is guarded, so an empty file (sret == 0) causes scale[-1] — a stack buffer underflow that reads and potentially writes out of bounds.
perf_pmu__parse_unit() has the same pattern: alias->unit[sret - 1] with sret == 0 accesses the byte before the struct member, which may corrupt the adjacent pmu_name pointer field.
Change both guards from sret < 0 to sret <= 0 so that empty files are treated as read errors.
--- tools/perf/util/pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/pmu.c +2 -2
@@ -158,7 +158,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * goto error; sret =read (fd, scale,sizeof (scale)-1 ); -if (sret <0 ) +if (sret <=0 ) goto error;if (scale[sret -1 ] =='\n' )
@@ -185,7 +185,7 @@ static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *nreturn -1 ; sret =read (fd, alias->unit,UNIT_MAX_LEN ); -if (sret <0 ) +if (sret <=0 ) goto error;close (fd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 313/699 tools lib api: Fix missing null termination in filename__read_int/ull()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 52b1f9678499b13b7aeb0186d9c6f486c043283f ]
filename__read_int() passes a stack buffer to read() using the full sizeof(line) and then hands it to atoi() without null-terminating. If a sysfs file fills the 64-byte buffer exactly, atoi() reads past the array into uninitialized stack memory.
filename__read_ull_base() has the same issue with strtoull().
Fix both by reading sizeof(line) - 1 bytes and explicitly null-terminating after a successful read.
--- tools/lib/api/fs/fs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +8 -2
@@ -321,11 +321,14 @@ int filename__read_int(const char *filename, int *value) {char line[64 ];int fd =open (filename,O_RDONLY ), err =-1 ; +ssize_t n;if (fd <0 )return -1 ; -if (read (fd, line,sizeof (line)) >0 ) { + n =read (fd, line,sizeof (line) -1 ); +if (n >0 ) { + line[n] ='\0' ; *value =atoi (line); err =0 ; }
@@ -339,11 +342,14 @@ static int filename__read_ull_base(const char *filename, {char line[64 ];int fd =open (filename,O_RDONLY ), err =-1 ; +ssize_t n;if (fd <0 )return -1 ; -if (read (fd, line,sizeof (line)) >0 ) { + n =read (fd, line,sizeof (line) -1 ); +if (n >0 ) { + line[n] ='\0' ; *value =strtoull (line,NULL , base);if (*value !=ULLONG_MAX ) err =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 314/699 perf symbols: Fix signed overflow in sysfs__read_build_id() size check
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 6eaa8ee3e2abe5112e80e94c27196bb175689469 ]
sysfs__read_build_id() reads ELF note headers from sysfs files. The note's namesz and descsz fields are used to compute the skip size:
int n = namesz + descsz;
if (n > (int)sizeof(bf))Both namesz and descsz are size_t from NOTE_ALIGN() of 32-bit note header fields. Their sum can exceed INT_MAX, overflowing the signed int n to a negative value. The check n > sizeof(bf) then evaluates false (negative < positive in signed comparison), and read(fd, bf, n) reinterprets the negative n as a huge size_t count — the kernel writes up to MAX_RW_COUNT bytes into the 8192-byte stack buffer.
In practice the overflow is bounded by the sysfs file's actual size, so a real sysfs notes file won't trigger it organically. But crafted input (e.g. via a mounted debugfs/sysfs image) could.
Fix by validating namesz and descsz individually against the buffer size before summing, and change n to size_t to avoid the signed overflow entirely.
--- tools/perf/util/symbol-elf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/util/symbol-elf.c +6 -3
@@ -656,14 +656,17 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) }else if (read (fd, bf, descsz) != (ssize_t )descsz)break ; }else { -int n = namesz + descsz; +size_t n; -if (n > (int )sizeof (bf)) { +/* int sum of namesz+descsz can overflow negative, bypassing size check */ +if (namesz >sizeof (bf) || descsz >sizeof (bf) - namesz) { n =sizeof (bf);pr_debug ("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n" , __func__, filename, nhdr.n_namesz, nhdr.n_descsz); + }else { + n = namesz + descsz; } -if (read (fd, bf, n) != n) +if (read (fd, bf, n) != (ssize_t )n)break ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 315/699 perf symbols: Bounds-check .gnu_debuglink section data
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 9c74f0aab398cb32ab250401f323c0fdc9a3a496 ]
filename__read_debuglink() copies .gnu_debuglink section data into a caller-provided buffer via:
strncpy(debuglink, data->d_buf, size);
where size is PATH_MAX. If the ELF section is smaller than size and lacks a null terminator, strncpy reads past data->d_buf into adjacent memory. A malformed ELF file can trigger this, potentially causing a segfault or leaking heap data.
Additionally, strncpy does not guarantee null termination when the source fills the buffer.
Replace with an explicit memcpy bounded by both the output buffer size and the actual section data size (data->d_size), followed by explicit null termination.
--- tools/perf/util/symbol-elf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +8 -1
@@ -753,7 +753,14 @@ int filename__read_debuglink(const char *filename, char *debuglink, goto out_elf_end;/* the start of this section is a zero-terminated string */ -strncpy (debuglink, data->d_buf, size); +if (data->d_size >0 ) { +size_t len =min (size -1 , data->d_size); + +memcpy (debuglink, data->d_buf, len); + debuglink[len] ='\0' ; + }else { + debuglink[0 ] ='\0' ; + } err =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 316/699 perf tools: Fix thread__set_comm_from_proc() on empty comm file
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 31d596054550f793508abe7dd593853ece47d428 ]
thread__set_comm_from_proc() calls procfs__read_str() then strips the trailing newline via comm[sz - 1] = '\0'. procfs__read_str() allocates the buffer before reading, so on an empty /proc/pid/comm (reachable during late exit teardown) it returns success with sz = 0 and an unterminated heap buffer.
The sz - 1 underflow was the original sashiko finding: it writes a null byte before the allocation. But even with a sz > 0 guard on the newline strip, the unterminated buffer would still be passed to thread__set_comm() which calls strlen() — an unbounded heap read.
Fix by treating sz == 0 as failure: free the buffer and return -1. This is consistent with pmu.c's perf_pmu__parse_scale/unit which already treat len == 0 from filename__read_str as an error.
--- tools/perf/util/thread.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/thread.c +5 -0
@@ -282,6 +282,11 @@ int thread__set_comm_from_proc(struct thread *thread)if (!(snprintf (path,sizeof (path),"%d/task/%d/comm" , thread->pid_, thread->tid) >= (int )sizeof (path)) &&procfs__read_str (path, &comm, &sz) ==0 ) { +/* sz==0: read got nothing, e.g. race during exit teardown */ +if (sz ==0 ) { +free (comm); +return -1 ; + } comm[sz -1 ] ='\0' ; err =thread__set_comm (thread, comm,0 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 317/699 perf symbols: Bounds-check descsz in sysfs__read_build_id() GNU fallback
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 1b4e9fbdeabc549965e70ac0cd8095d57ff6df06 ]
When sysfs__read_build_id() matches NT_GNU_BUILD_ID with the right namesz but the name content is not "GNU", it falls back to reading descsz bytes into the stack buffer bf[BUFSIZ]:
} else if (read(fd, bf, descsz) != (ssize_t)descsz)
Unlike the else branch which validates namesz + descsz against sizeof(bf), this path passes descsz directly to read() without any bounds check. A crafted sysfs file with a large n_descsz overflows the 8192-byte stack buffer.
Add a descsz > sizeof(bf) check before the read, breaking out of the loop on oversized values.
--- tools/perf/util/symbol-elf.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +7 -2
@@ -653,8 +653,13 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) err =0 ;break ; } - }else if (read (fd, bf, descsz) != (ssize_t )descsz) -break ; + }else { +/* descsz from untrusted file — clamp to buffer */ +if (descsz >sizeof (bf)) +break ; +if (read (fd, bf, descsz) != (ssize_t )descsz) +break ; + } }else {size_t n;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 318/699 tools lib api: Fix filename__write_int() writing uninitialized stack data
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 438ece06185696e14c63c6113d5e2d34ec0a9680 ]
filename__write_int() formats an integer into a 64-byte buffer with sprintf() then passes sizeof(buf) (64) as the write length. This writes all 64 bytes including uninitialized stack data past the formatted string. Most sysfs files reject the oversized write, making the function always return -1.
Fix by capturing the sprintf() return value and using it as the write length.
--- tools/lib/api/fs/fs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +3 -2
@@ -432,12 +432,13 @@ int filename__write_int(const char *filename, int value) {int fd =open (filename,O_WRONLY ), err =-1 ;char buf[64 ]; +int len;if (fd <0 )return err; -sprintf (buf,"%d" , value); -if (write (fd, buf,sizeof (buf)) ==sizeof (buf)) + len =sprintf (buf,"%d" , value); +if (write (fd, buf, len) == len) err =0 ;close (fd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 319/699 tools lib api: Fix mount_overload() snprintf truncation and toupper range
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fd1f70776add263f8ef38a87ae593c75303f1dcd ]
mount_overload() builds an environment variable name like "PERF_SYSFS_ENVIRONMENT" from fs->name. Two bugs:
1) snprintf() uses name_len as the buffer size instead of sizeof(upper_name). For fs->name = "sysfs" (len=5), the output is truncated to "PERF" (4 chars + null), so getenv() never finds the intended variable.
2) mem_toupper() only uppercases name_len bytes, converting just the "PERF" prefix rather than the full string including the filesystem name portion.
Fix by using sizeof(upper_name) for snprintf and strlen(upper_name) for mem_toupper, so the full "PERF_SYSFS_ENVIRONMENT" string is correctly formatted and uppercased.
--- tools/lib/api/fs/fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +2 -2
@@ -272,8 +272,8 @@ static const char *mount_overload(struct fs *fs)/* "PERF_" + name + "_ENVIRONMENT" + '\0' */ char upper_name[5 + name_len +12 +1 ]; -snprintf (upper_name, name_len,"PERF_%s_ENVIRONMENT" , fs->name); -mem_toupper (upper_name, name_len); +snprintf (upper_name,sizeof (upper_name),"PERF_%s_ENVIRONMENT" , fs->name); +mem_toupper (upper_name,strlen (upper_name));return getenv (upper_name) ?: *fs->mounts; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 320/699 perf bpf: Add NULL check for btf__type_by_id() in synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 903b0526dcf86d030c5970b4b0a67f9c227368e2 ]
synthesize_bpf_prog_name() calls btf__type_by_id() and immediately dereferences the result via t->name_off without checking for NULL. btf__type_by_id() returns NULL when the type_id is invalid or out of range. When processing perf.data files, finfo->type_id comes from untrusted input, so an invalid ID causes a NULL pointer dereference.
Fix by checking t for NULL before dereferencing.
--- tools/perf/util/bpf-event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/bpf-event.c +2 -1
@@ -136,7 +136,8 @@ static int synthesize_bpf_prog_name(char *buf, int size,if (btf) { finfo = func_infos + sub_id * info->func_info_rec_size; t =btf__type_by_id (btf, finfo->type_id); - short_name =btf__name_by_offset (btf, t->name_off); +if (t) + short_name =btf__name_by_offset (btf, t->name_off); }else if (sub_id ==0 && sub_prog_cnt ==1 ) {/* no subprog */ if (info->name[0 ])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 321/699 perf symbols: Add bounds checks to elf_read_build_id() note iteration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit acc56d3941fc2997a5a21ea9233a8ac3d87c4f2f ]
elf_read_build_id() iterates ELF notes using pointer arithmetic driven by n_namesz and n_descsz from the note headers. Neither the note header read nor the subsequent name/desc advances are checked against the section boundary. A malformed ELF file with oversized note sizes causes out-of-bounds reads past the section data buffer.
Add two bounds checks: verify the note header fits within the remaining section data, and verify that namesz + descsz (after alignment) fits before advancing the pointer.
--- tools/perf/util/symbol-elf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +16 -2
@@ -535,10 +535,24 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) ptr = data->d_buf;while (ptr < (data->d_buf + data->d_size)) {GElf_Nhdr *nhdr = ptr; -size_t namesz =NOTE_ALIGN (nhdr->n_namesz), - descsz =NOTE_ALIGN (nhdr->n_descsz); +size_t namesz, descsz, remaining;const char *name; +/* ensure the note header fits within the section */ +if (ptr +sizeof (*nhdr) > data->d_buf + data->d_size) +break ; + + namesz =NOTE_ALIGN (nhdr->n_namesz); + descsz =NOTE_ALIGN (nhdr->n_descsz); + +/* validate individually to avoid size_t overflow on 32-bit */ + remaining = data->d_buf + data->d_size - ptr -sizeof (*nhdr); +if (namesz > remaining || descsz > remaining - namesz) { +pr_warning ("%s: oversized note: n_namesz=%u, n_descsz=%u\n" , + __func__, nhdr->n_namesz, nhdr->n_descsz); +break ; + } + ptr +=sizeof (*nhdr); name = ptr; ptr += namesz;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 322/699 perf symbols: Add bounds checks to read_build_id() note iteration in minimal build
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 52e582e316c48c53bb3082c29f7862ebc554087e ]
symbol-minimal.c's read_build_id() iterates ELF notes with the same pattern as symbol-elf.c's elf_read_build_id(): pointer arithmetic driven by n_namesz and n_descsz from 32-bit note header fields, without validating that the name and desc fit within the note section data. A malformed ELF file with oversized note sizes causes out-of-bounds reads past the section data buffer.
Add the same bounds check as the libelf path: validate namesz and descsz individually against remaining data before advancing the pointer, avoiding size_t overflow on 32-bit.
--- tools/perf/util/symbol-minimal.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
tools/perf/util/symbol-minimal.c +10 -1
@@ -1,3 +1,4 @@ +#include "debug.h" #include "dso.h" #include "symbol.h" #include "symsrc.h"
@@ -45,7 +46,7 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid, ptr = note_data;while (ptr < (note_data + note_len)) {const char *name; -size_t namesz, descsz; +size_t namesz, descsz, remaining; nhdr = ptr;if (need_swap) {
@@ -57,6 +58,14 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid, namesz =NOTE_ALIGN (nhdr->n_namesz); descsz =NOTE_ALIGN (nhdr->n_descsz); +/* validate individually to avoid size_t overflow on 32-bit */ + remaining = note_data + note_len - ptr -sizeof (*nhdr); +if (namesz > remaining || descsz > remaining - namesz) { +pr_warning ("%s: oversized note: n_namesz=%u, n_descsz=%u\n" , + __func__, nhdr->n_namesz, nhdr->n_descsz); +break ; + } + ptr +=sizeof (*nhdr); name = ptr; ptr += namesz;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 323/699 PCI: mediatek: Fix possible truncation in mtk_pcie_parse_port()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryder Lee <[email protected]>
[ Upstream commit ab4a4043db1fcc4fd4c5745c5be8caf053502e29 ]
As reported by the W=1 warning below, content of the 'name' variable might get truncated with the existing size of 10 bytes. Though it is not practically possible to exceed the 10 bytes size, increase it to 20 to silence the warning for a clean W=1 build:
$ make W=1 drivers/pci/controller/pcie-mediatek.o
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
CC drivers/pci/controller/pcie-mediatek.o
drivers/pci/controller/pcie-mediatek.c: In function ‘mtk_pcie_parse_port’:
drivers/pci/controller/pcie-mediatek.c:963:43: error: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 6 [-Werror=format-truncation=]
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~
drivers/pci/controller/pcie-mediatek.c:963:38: note: directive argument in the range [0, 2147483647]
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~~~~~~~
drivers/pci/controller/pcie-mediatek.c:963:9: note: ‘snprintf’ output between 6 and 15 bytes into a destination of size 10
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Stable-dep-of: ebc1d9906894 ("PCI: mediatek: Use actual physical address instead of virt_to_phys()")
--- drivers/pci/controller/pcie-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/controller/pcie-mediatek.c +1 -1
@@ -914,7 +914,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,struct mtk_pcie_port *port;struct device *dev = pcie->dev;struct platform_device *pdev =to_platform_device (dev); -char name[10 ]; +char name[20 ];int err; port =devm_kzalloc (dev,sizeof (*port),GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 324/699 PCI: mediatek: Use actual physical address instead of virt_to_phys()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit ebc1d9906894703286d12306a6f242d90cfb49e8 ]
The driver previously used virt_to_phys() on the ioremapped register base (port->base) to compute the MSI message address. Using virt_to_phys() on an IO mapped address is incorrect because it expects a kernel virtual address.
To fix it, store the physical start of the I/O register region in mtk_pcie_port->phys_base and use it to build the MSI address. This replaces the incorrect virt_to_phys() usage and ensures MSI addresses are generated correctly.
--- drivers/pci/controller/pcie-mediatek.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/pci/controller/pcie-mediatek.c +13 -3
@@ -161,6 +161,7 @@ struct mtk_pcie_soc {/** * struct mtk_pcie_port - PCIe port information * @base: IO mapped register base +* @phys_base: Physical address of the I/O register base region * @list: port list * @pcie: pointer to PCIe host info * @reset: pointer to port reset control
@@ -183,6 +184,7 @@ struct mtk_pcie_soc {*/ struct mtk_pcie_port {void __iomem *base; +phys_addr_t phys_base;struct list_head list;struct mtk_pcie *pcie;struct reset_control *reset;
@@ -399,7 +401,7 @@ static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)phys_addr_t addr;/* MT2712/MT7622 only support 32-bit MSI addresses */ - addr =virt_to_phys (port->base +PCIE_MSI_VECTOR ); + addr = port->phys_base +PCIE_MSI_VECTOR ; msg->address_hi =0 ; msg->address_lo =lower_32_bits (addr);
@@ -522,7 +524,7 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)u32 val;phys_addr_t msg_addr; - msg_addr =virt_to_phys (port->base +PCIE_MSI_VECTOR ); + msg_addr = port->phys_base +PCIE_MSI_VECTOR ; val =lower_32_bits (msg_addr);writel (val, port->base +PCIE_IMSI_ADDR );
@@ -914,6 +916,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,struct mtk_pcie_port *port;struct device *dev = pcie->dev;struct platform_device *pdev =to_platform_device (dev); +struct resource *res;char name[20 ];int err;
@@ -922,7 +925,14 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,return -ENOMEM ;snprintf (name,sizeof (name),"port%d" , slot); - port->base =devm_platform_ioremap_resource_byname (pdev, name); + res =platform_get_resource_byname (pdev,IORESOURCE_MEM , name); +if (!res) { +dev_err (dev,"failed to get port%d base\n" , slot); +return -EINVAL ; + } + + port->phys_base = res->start; + port->base =devm_ioremap_resource (&pdev->dev, res);if (IS_ERR (port->base)) {dev_err (dev,"failed to map port%d base\n" , slot);return PTR_ERR (port->base);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 325/699 apparmor: check label build before no_new_privs test
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit a58cafd38b46fb1a2220e2fbbcfe291ea75fa147 ]
aa_change_profile() builds a replacement label with fn_label_build_in_scope() before the no_new_privs subset check. The build helper can fail and return NULL or an ERR_PTR, but the result was passed to aa_label_is_unconfined_subset() before the existing IS_ERR_OR_NULL() check.
Reuse the existing target-label build failure handling immediately after the build. This preserves the current audit handling while preventing the subset helper from dereferencing an invalid label.
--- security/apparmor/domain.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
security/apparmor/domain.c +15 -10
@@ -1404,6 +1404,8 @@ int aa_change_profile(const char *fqname, int flags) new =fn_label_build_in_ns (label, profile,GFP_KERNEL ,aa_get_label (target),aa_get_label (&profile->label)); +if (IS_ERR_OR_NULL (new)) + goto build_fail;/* * no new privs prevents domain transitions that would * reduce restrictions.
@@ -1421,16 +1423,8 @@ int aa_change_profile(const char *fqname, int flags)/* only transition profiles in the current ns */ if (stack) new =aa_label_merge (label, target,GFP_KERNEL ); -if (IS_ERR_OR_NULL (new)) { - info ="failed to build target label" ; -if (!new) - error = -ENOMEM ; -else - error =PTR_ERR (new); - new =NULL ; - perms.allow =0 ; - goto audit; - } +if (IS_ERR_OR_NULL (new)) + goto build_fail; error =aa_replace_current_label (new); }else {if (new) {
@@ -1442,6 +1436,17 @@ int aa_change_profile(const char *fqname, int flags) error =aa_set_current_onexec (target, stack); } + goto audit; + +build_fail: + info ="failed to build target label" ; +if (!new) + error = -ENOMEM ; +else + error =PTR_ERR (new); + new =NULL ; + perms.allow =0 ; + audit: error = fn_for_each_in_ns(label, profile, aa_audit_file(profile, &perms, op, request, auditname,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 326/699 apparmor: aa_label_alloc use aa_label_free on alloc failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit 654fe7505dc6889724d4094fa64f89991afabfc3 ]
aa_label_alloc() allocates a secid before allocating or taking the label proxy. If the later proxy step fails, the error path only freed the label memory, leaking any resources initialized by aa_label_init().
Use aa_label_free() on the failure path so partially initialized labels release their secid and other label resources before the backing memory is freed.
--- security/apparmor/label.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/apparmor/label.c +1 -1
@@ -450,7 +450,7 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)return new; fail: -kfree (new); +aa_label_free (new);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 327/699 apparmor: grab ns lock and refresh when looking up changehat child profiles
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Lee <[email protected]>
[ Upstream commit 32e92764d6f8d251c1bca62be33793287b453a81 ]
There was a race condition involving change_hat and profile replacement in which replacement of the parent profile during a changehat operation could result in the list of children becoming empty and the changehat operation failing. To prevent this:
- grab the namespace lock until we've built the hat transition, and
- use aa_get_newest_profile to avoid using stale profile objects.
--- security/apparmor/domain.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
security/apparmor/domain.c +31 -2
@@ -12,6 +12,7 @@#include <linux/fdtable.h> #include <linux/file.h> #include <linux/mount.h> +#include <linux/mutex.h> #include <linux/syscalls.h> #include <linux/tracehook.h> #include <linux/personality.h>
@@ -1034,6 +1035,7 @@ static struct aa_label *change_hat(struct aa_label *label, const char *hats[], int count, int flags) {struct aa_profile *profile, *root, *hat =NULL ; +struct aa_ns *ns, *new_ns;struct aa_label *new;struct label_it it;bool sibling = false;
@@ -1044,6 +1046,32 @@ static struct aa_label *change_hat(struct aa_label *label, const char *hats[],AA_BUG (!hats);AA_BUG (count <1 ); +/* +* Acquire the newest label and then hold the lock until we choose a +* hat, so that profile replacement doesn't atomically truncate the +* list of potential hats. Because we are getting the namespaces from +* the profiles and label, we can rely on the namespaces being live +* and avoid incrementing their refcounts while grabbing the lock. +*/ + label =aa_get_label (label); + ns =labels_ns (label); + +retry: +mutex_lock_nested (&ns->lock, ns->level); +if (label_is_stale (label)) { + new =aa_get_newest_label (label); + new_ns =labels_ns (new); +if (new_ns != ns) { +aa_put_label (new); +mutex_unlock (&ns->lock); + ns = new_ns; + label = new; + goto retry; + } +aa_put_label (label); + label = new; + } +if (PROFILE_IS_HAT (labels_profile (label))) sibling = true;
@@ -1052,7 +1080,7 @@ static struct aa_label *change_hat(struct aa_label *label, const char *hats[], name = hats[i];label_for_each_in_ns (it,labels_ns (label), label, profile) {if (sibling &&PROFILE_IS_HAT (profile)) { - root =aa_get_profile_rcu (&profile->parent); + root =aa_get_profile (profile->parent); }else if (!sibling && !PROFILE_IS_HAT (profile)) { root =aa_get_profile (profile); }else {/* conflicting change type */
@@ -1111,6 +1139,7 @@ static struct aa_label *change_hat(struct aa_label *label, const char *hats[], GLOBAL_ROOT_UID, info, error); } } +mutex_unlock (&ns->lock);return ERR_PTR (error); build:
@@ -1122,7 +1151,7 @@ static struct aa_label *change_hat(struct aa_label *label, const char *hats[], error = -ENOMEM ; goto fail; }/* else if (IS_ERR) build_change_hat has logged error so return new */ - +mutex_unlock (&ns->lock);return new; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 328/699 apparmor: fix potential UAF in aa_replace_profiles
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Bélair <[email protected]>
[ Upstream commit 7b42f95813dc9ceb6bda35afcf914630909a19f9 ]
The function aa_replace_profiles was accessing udata->size after calling aa_put_loaddata(udata), causing a potential UAF.
Fixed this by saving the size to a local variable before dropping the reference.
--- security/apparmor/policy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
security/apparmor/policy.c +4 -1
@@ -922,6 +922,7 @@ ssize_t aa_replace_profiles(struct aa_nsstruct aa_loaddata *rawdata_ent;const char *op;ssize_t count, error; +ssize_t udata_sz;LIST_HEAD (lh); op = mask &AA_MAY_REPLACE_POLICY ?OP_PROF_REPL :OP_PROF_LOAD ;
@@ -1106,13 +1107,15 @@ ssize_t aa_replace_profiles(struct aa_nsmutex_unlock (&ns->lock); out: + udata_sz = udata->size; +aa_put_ns (ns);aa_put_profile_loaddata (udata);kfree (ns_name);if (error)return error; -return udata->size; +return udata_sz; fail_lock:mutex_unlock (&ns->lock);
Greg Kroah-Hartman
maintainerPATCH 329/699 apparmor: aa_getprocattr free procattr leak on format failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit fea23bf73f0cae8ccb1d0684e4a3003874771f41 ]
aa_getprocattr() allocates the output string before rendering the label into it. If the second aa_label_snxprint() call fails, the function returned without freeing that allocation.
Free and clear the output pointer on the uncommon formatting failure path before dropping the namespace reference.
--- security/apparmor/procattr.c | 2 ++ 1 file changed, 2 insertions(+)
security/apparmor/procattr.c +2 -0
@@ -56,6 +56,8 @@ int aa_getprocattr(struct aa_label *label, char **string)FLAG_SHOW_MODE |FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED);if (len <0 ) { +kfree (*string); + *string =NULL ;aa_put_ns (current_ns);return len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 330/699 apparmor: put secmark label after secid lookup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit 340372688bb87da45ff8d4e2f82ccfd1b64c65ff ]
apparmor_secmark_init() parses a configured secmark label to obtain its secid. aa_label_strn_parse() returns a refcounted label, but the success path kept that reference after copying the secid.
--- security/apparmor/net.c | 1 + 1 file changed, 1 insertion(+)
security/apparmor/net.c +1 -0
@@ -208,6 +208,7 @@ static int apparmor_secmark_init(struct aa_secmark *secmark)return PTR_ERR (label); secmark->secid = label->secid; +aa_put_label (label);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 331/699 i3c: master: Prevent reuse of dynamic address on device add failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit b3ba8383da4d0cff15810e32ea785eceb0a80813 ]
i3c_master_add_i3c_dev_locked() is called after a device has already been assigned a dynamic address. If the function fails, the address remains marked as free and may be reallocated to another device, leading to address conflicts on the bus.
Ensure the address is not marked as free on failure, by updating the address slot state to prevent the address from being re-used.
Emit an error message to inform of the failure.
Opportunistically remove the !master check because it is impossible.
Note, directly resetting the device's dynamic address is no longer an option, since Direct RSTDAA was deprecated from I3C starting from version 1.1 and v1.1 (or later) target devices are meant to NACK it.
--- drivers/i3c/master.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/i3c/master.c +14 -5
@@ -1902,12 +1902,11 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,bool enable_ibi = false;int ret; -if (!master) -return -EINVAL ; - newdev =i3c_master_alloc_i3c_dev (master, &info); -if (IS_ERR (newdev)) -return PTR_ERR (newdev); +if (IS_ERR (newdev)) { + ret =PTR_ERR (newdev); + goto err_prevent_addr_reuse; + } ret =i3c_master_attach_i3c_dev (master, newdev);if (ret)
@@ -2028,6 +2027,16 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, err_free_dev:i3c_master_free_i3c_dev (newdev); +err_prevent_addr_reuse: +/* +* Although the device has not been added, the address has been +* assigned. Prevent the address from being used again. +*/ +if (i3c_bus_get_addr_slot_status (&master->bus, addr) ==I3C_ADDR_SLOT_FREE ) +i3c_bus_set_addr_slot_status (&master->bus, addr,I3C_ADDR_SLOT_I3C_DEV ); + +dev_err (&master->dev,"Failed to add I3C device at address %u, error %d\n" , addr, ret); +return ret; }EXPORT_SYMBOL_GPL (i3c_master_add_i3c_dev_locked);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 332/699 apparmor: fix label can not be immediately before a declaration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Johansen <[email protected]>
[ Upstream commit 1ed40bd525c00d22af666016af9aef7167f8085f ]
Fix error reported by kernel test robot
security/apparmor/policy.c:1381:2: error: a label can only be part of a statement and a declaration is not a statement
All errors (new ones prefixed by >>):
security/apparmor/policy.c: In function 'aa_replace_profiles':
Quoted 1 line
Quoted 1 line
security/apparmor/policy.c:1381:2: error: a label can only be part
of a statement and a declaration is not a statement
ssize_t udata_sz = udata->size;
^~~~~--- security/apparmor/policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
security/apparmor/policy.c +2 -1
@@ -1107,9 +1107,10 @@ ssize_t aa_replace_profiles(struct aa_nsmutex_unlock (&ns->lock); out: +aa_put_ns (ns); + udata_sz = udata->size; -aa_put_ns (ns);aa_put_profile_loaddata (udata);kfree (ns_name);
Greg Kroah-Hartman
maintainerPATCH 333/699 sparc: led: avoid trimming a newline from empty writes
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 7eb475e8a738ee6fd1260aa59ddccb610fdd4300 ]
led_proc_write() duplicates up to LED_MAX_LENGTH bytes with memdup_user_nul() and then unconditionally inspects buf[count - 1] to strip a trailing newline. A zero-length write therefore reads one byte before the duplicated buffer.
The previous version rejected empty writes, but empty input already falls through to the existing default case and turns the LED off like any other unrecognized string. Preserve that behavior and only skip the newline trim when there is no input byte to inspect.
--- arch/sparc/kernel/led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/sparc/kernel/led.c +1 -1
@@ -78,7 +78,7 @@ static ssize_t led_proc_write(struct file *file, const char __user *buffer,return PTR_ERR (buf);/* work around \n when echo'ing into proc */ -if (buf[count -1 ] =='\n' ) +if (count >0 && buf[count -1 ] =='\n' ) buf[count -1 ] ='\0' ;/* before we change anything we want to stop any running timers,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 334/699 perf symbols: Break infinite loop on zero-filled notes in sysfs__read_build_id()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 063c647b24f640657d6d9e2e90d620ea3ee19ae6 ]
sysfs__read_build_id() iterates ELF note headers from sysfs files in a while(1) loop. If the file contains a zero-filled note header (both n_namesz and n_descsz are 0), the code computes n = namesz + descsz = 0 and calls read(fd, bf, 0). read() with count 0 returns 0, which matches the expected (ssize_t)n value, so the error check passes and the loop repeats — reading the same zero bytes and spinning forever.
This can happen with corrupted or zero-padded sysfs pseudo-files.
Add a check for n == 0 before the read, since no valid ELF note has both name and description of zero length.
--- tools/perf/util/symbol-elf.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/symbol-elf.c +3 -0
@@ -685,6 +685,9 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) }else { n = namesz + descsz; } +/* no valid note has both namesz and descsz zero */ +if (n ==0 ) +break ;if (read (fd, bf, n) != (ssize_t )n)break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 335/699 perf tools: Use snprintf() for root_dir path construction
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 7b0df6f4d498b1608afccfd6dffb264e6da91693 ]
get_kernel_version() in machine.c and dso__load_guest_kernel_sym() in symbol.c use sprintf() to construct paths by prepending root_dir to "/proc/version" and "/proc/kallsyms" respectively. Both write into PATH_MAX stack buffers, but root_dir comes from --guestmount or KVM configuration and is not length-checked. A root_dir at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof(path) to prevent overflow.
--- tools/perf/util/machine.c | 2 +- tools/perf/util/symbol.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +1 -1
@@ -1309,7 +1309,7 @@ static char *get_kernel_version(const char *root_dir)char *name, *tmp;const char *prefix ="Linux version " ; -sprintf (version,"%s/proc/version" , root_dir); +snprintf (version,sizeof (version),"%s/proc/version" , root_dir); file =fopen (version,"r" );if (!file)return NULL ;
tools/perf/util/symbol.c +1 -1
@@ -2287,7 +2287,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)if (!kallsyms_filename)return -1 ; }else { -sprintf (path,"%s/proc/kallsyms" , machine->root_dir); +snprintf (path,sizeof (path),"%s/proc/kallsyms" , machine->root_dir); kallsyms_filename = path; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 336/699 perf bpf: Validate func_info_rec_size and sub_id in synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 10b3c3d63ecc17c6acb855bac5f40367f1115765 ]
synthesize_bpf_prog_name() computes a pointer into the func_info array using sub_id * info->func_info_rec_size without validating either value. Both come from perf.data and are untrusted:
- A func_info_rec_size smaller than sizeof(struct bpf_func_info) means the finfo pointer would reference a truncated entry, reading past it into adjacent data.
- A sub_id >= nr_func_info computes an offset past the func_info buffer, causing an out-of-bounds read.
Add bounds checks for both values before computing the pointer offset. When validation fails, fall through to the non-BTF name path instead of reading garbage.
--- tools/perf/util/bpf-event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/bpf-event.c +3 -1
@@ -133,7 +133,9 @@ static int synthesize_bpf_prog_name(char *buf, int size, name_len =scnprintf (buf, size,"bpf_prog_" ); name_len +=snprintf_hex (buf + name_len, size - name_len, prog_tags[sub_id],BPF_TAG_SIZE ); -if (btf) { +if (btf && + info->func_info_rec_size >=sizeof (*finfo) && + sub_id < info->nr_func_info) { finfo = func_infos + sub_id * info->func_info_rec_size; t =btf__type_by_id (btf, finfo->type_id);if (t)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 337/699 xfrm: validate selector family and prefixlen during match
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 40f0b1047918539f0b0f795ac65e35336b4c2c78 ]
syzbot reported a shift-out-of-bounds in xfrm_selector_match() due to AF_UNSPEC selector with large prefixlen (e.g. 128) matched against IPv4 flow (when XFRM_STATE_AF_UNSPEC is set).
Fix this by:
- Rejecting mismatched families in xfrm_selector_match.
- Returning false in addr4_match if prefixlen > 32.
- Returning false in addr_match if prefixlen > 128 (prevents overflow).
--- include/net/xfrm.h | 7 +++++++ net/xfrm/xfrm_policy.c | 3 +++ 2 files changed, 10 insertions(+)
include/net/xfrm.h +7 -0
@@ -821,6 +821,9 @@ static inline bool addr_match(const void *token1, const void *token2,unsigned int pdw;unsigned int pbi; +if (prefixlen >128 ) +return false; + pdw = prefixlen >>5 ;/* num of whole u32 in prefix */ pbi = prefixlen &0x1f ;/* num of bits in incomplete u32 in prefix */
@@ -845,6 +848,10 @@ static inline bool addr4_match(__be32 a1, __be32 a2, u8 prefixlen)/* C99 6.5.7 (3): u32 << 32 is undefined behaviour */ if (sizeof (long ) ==4 && prefixlen ==0 )return true; + +if (prefixlen >32 ) +return false; +return !((a1 ^ a2) &htonl (~0UL << (32 - prefixlen))); }
net/xfrm/xfrm_policy.c +3 -0
@@ -223,6 +223,9 @@ __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)bool xfrm_selector_match (const struct xfrm_selector *sel,const struct flowi *fl,unsigned short family) { +if (family != sel->family && sel->family !=AF_UNSPEC ) +return false; +switch (family) {case AF_INET :return __xfrm4_selector_match (sel, fl);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 338/699 perf machine: Use snprintf() for guestmount path construction
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fe63d3bca288c5bb983304efd5fc3a5ff3183403 ]
machines__findnew() and machines__create_guest_kernel_maps() use sprintf() to build paths by prepending symbol_conf.guestmount. Both write into PATH_MAX stack buffers, but guestmount comes from user configuration and is not length-checked. A guestmount path at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof() to prevent overflow. The subsequent access()/fopen() calls will fail on a truncated path.
--- tools/perf/util/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +4 -4
@@ -347,7 +347,7 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -sprintf (path,"%s/%d" , symbol_conf.guestmount, pid); +snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid);if (access (path,R_OK )) {static struct strlist *seen;
@@ -1231,9 +1231,9 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);continue ; } -sprintf (path,"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name); ret =access (path,R_OK );if (ret) {pr_debug ("Can't access file %s\n" , path);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 339/699 octeontx2-pf: Fix leak of SQ timestamp buffer on teardown
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit a056db30de92945ff8ee6033096678bfbae878e3 ]
The send-queue timestamp ring is allocated with qmem_alloc() when timestamping is used, but otx2_free_sq_res() never freed sq->timestamps, leaking that memory across ifdown and device removal. Add the missing qmem_free() alongside the other SQ companion buffers.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -0
@@ -1282,6 +1282,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf) sq = &qset->sq[qidx];qmem_free (pf->dev, sq->sqe);qmem_free (pf->dev, sq->tso_hdrs); +qmem_free (pf->dev, sq->timestamps);kfree (sq->sg);kfree (sq->sqb_ptrs); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 340/699 net: psample: fix info leak in PSAMPLE_ATTR_DATA
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit aedd02af1f8b0bceb7f42f5a21c41634ca9ed390 ]
psample open codes nla_put() presumably to avoid wiping the data with 0s just to override it with packet data. This open coding is missing clearing the pad, however, each netlink attr is padded to 4B and data_len may not be divisible by 4B.
--- net/psample/psample.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/psample/psample.c +4 -2
@@ -425,15 +425,17 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, goto error;if (data_len) { -int nla_len =nla_total_size (data_len); +int nla_len =nla_attr_size (data_len);struct nlattr *nla; nla =skb_put (nl_skb, nla_len); nla->nla_type =PSAMPLE_ATTR_DATA ; - nla->nla_len =nla_attr_size (data_len); + nla->nla_len = nla_len;if (skb_copy_bits (skb,0 ,nla_data (nla), data_len)) goto error; + +skb_put_zero (nl_skb,nla_padlen (data_len)); }#ifdef CONFIG_INET
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 341/699 sctp: hold socket lock when dumping endpoints in sctp_diag
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 7d8297e26b4e20b5d1c3c3fe51fe81a1c7fbc823 ]
SCTP_DIAG endpoint dumping was traversing endpoint address lists without holding lock_sock(), while those lists could change concurrently via socket operations (e.g., bindx changes). This creates a race where nla_reserve() counts addresses under RCU protection, but the subsequent copy may see fewer entries, potentially leaking uninitialized memory to userspace.
Fix this by:
- Taking a reference on each endpoint during hash traversal
- Moving socket operations (lock_sock()) outside read_lock_bh()
- Serializing address list access during dump
- Reworking sctp_for_each_endpoint() to support restart-based traversal with (net, pos) tracking
Also:
- Add WARN_ON_ONCE() for inconsistent address counts
- Fix idiag_states filtering for LISTEN vs association cases
- Skip dumping endpoints being freed (ep->base.dead)
- Move dump position tracking into iterator, removing cb->args[4] and its comment for sctp_ep_dump().,
- Update the comment for cb->args[4] and remove the comment for unused cb->args[5] for sctp_sock_dump().
Note: traversal is restart-based and may re-scan buckets multiple times, but this is acceptable due to small bucket sizes and required to support sleeping-safe callbacks.
This issue was reported by Nico Yip (@_cyeaa_) working with TrendAI Zero Day Initiative.
--- include/net/sctp/sctp.h | 3 +- net/sctp/diag.c | 67 ++++++++++++++++++++--------------------- net/sctp/socket.c | 29 +++++++++++++----- 3 files changed, 56 insertions(+), 43 deletions(-)
include/net/sctp/sctp.h +2 -1
@@ -115,7 +115,8 @@ int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net, const union sctp_addr *paddr, void *p);int sctp_transport_traverse_process (sctp_callback_t cb,sctp_callback_t cb_done,struct net *net,int *pos,void *p); -int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *),void *p); +int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *), +struct net *net,int *pos,void *p);int sctp_get_sctp_info (struct sock *sk,struct sctp_association *asoc,struct sctp_info *info);
net/sctp/diag.c +32 -35
121 lines not on this page · raw message
net/sctp/socket.c +22 -7
@@ -5200,24 +5200,39 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net, }int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *), -void *p) { -int err =0 ; -int hash =0 ; -struct sctp_endpoint *ep; +struct net *net,int *pos,void *p) { +int err, hash =0 , idx =0 , start;struct sctp_hashbucket *head; +struct sctp_endpoint *ep;for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; hash++, head++) { + start = idx; +again:read_lock_bh (&head->lock);sctp_for_each_hentry (ep, &head->chain) { - err =cb (ep, p); -if (err) +if (sock_net (ep->base.sk) != net) +continue ; +if (idx++ >= *pos) { +sctp_endpoint_hold (ep);break ; + } }read_unlock_bh (&head->lock); + +if (ep) { + err =cb (ep, p); +sctp_endpoint_put (ep); +if (err) +return err; + (*pos)++; + + idx = start; + goto again; + } } -return err; +return 0 ; }EXPORT_SYMBOL_GPL (sctp_for_each_endpoint);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 342/699 arm64/hw_breakpoint: reject unaligned watchpoints that would truncate BAS
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 4cc70f75853bebac022334b6a86b953348072f74 ]
hw_breakpoint_arch_parse() positions the BAS bit pattern in hw->ctrl.len with
offset = hw->address & alignment_mask; /* 0..7 */ hw->ctrl.len <<= offset;
ctrl.len is an 8-bit bitfield (struct arch_hw_breakpoint_ctrl::len is u32 :8), so the shift silently drops any bits past bit 7. For non-compat AArch64 watchpoints the offset is unbounded relative to ctrl.len: a perf_event_open(PERF_TYPE_BREAKPOINT) caller asking for HW_BREAKPOINT_W with bp_addr=page+1 and bp_len=HW_BREAKPOINT_LEN_8 ends up with 0xff << 1 = 0x1fe, stored as 0xfe. The kernel programs WCR.BAS=0xfe and the hardware watches bytes [1..7] instead of the requested [1..8] -- the eighth byte is silently dropped. The syscall still returns success, leaving userspace to discover the gap by empirical probing.
The same class affects HW_BREAKPOINT_LEN_{2,4} when offset pushes the high BAS bit past bit 7 (e.g. LEN_4 with offset=5 yields 0xe0 instead of 0x1e0). No memory-safety impact -- the value is masked into 8 bits before encoding -- but debuggers and perf users observe missed events on bytes they thought they were watching.
The AArch32 branch immediately above already rejects unrepresentable (offset, len) combinations via an explicit switch. Mirror that for the non-compat branch by checking that the shifted pattern fits in the BAS field, returning -EINVAL when it does not.
GDB and similar debuggers are unaffected by the stricter check. aarch64_linux_set_debug_regs() already treats EINVAL on NT_ARM_HW_WATCH as a downgrade signal: it clears kernel_supports_any_contiguous_range, calls aarch64_downgrade_regs() to round the BAS up to a legacy 0x01/03/0f/ff mask with an aligned base, and retries -- the same fallback path that PR-20207 introduced. The new -EINVAL is therefore reachable only from a raw perf_event_open() that pairs an unaligned base with an oversized bp_len, which is precisely the bug.
Reproducer:
struct perf_event_attr a = {
.type = PERF_TYPE_BREAKPOINT, .size = sizeof(a),
.bp_type = HW_BREAKPOINT_W,
.bp_addr = (uintptr_t)(buf + 1),
.bp_len = HW_BREAKPOINT_LEN_8,
.exclude_kernel = 1, .exclude_hv = 1, };
int fd = perf_event_open(&a, 0, -1, -1, 0);
/* before this fix: succeeds, watches 7 bytes (buf+1..buf+7) */
/* after this fix: fails with EINVAL */
--- arch/arm64/kernel/hw_breakpoint.c | 9 +++++++++ 1 file changed, 9 insertions(+)
arch/arm64/kernel/hw_breakpoint.c +9 -0
@@ -557,6 +557,15 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,else alignment_mask =0x7 ; offset = hw->address & alignment_mask; + +/* +* BAS is an 8-bit field in WCR/BCR; the shift below would +* silently drop the high bits of ctrl.len when offset + len +* exceeds 8, programming hardware to watch fewer bytes than +* the user requested. +*/ +if (((u32 )hw->ctrl.len << offset) >ARM_BREAKPOINT_LEN_8 ) +return -EINVAL ; } hw->address &= ~alignment_mask;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 343/699 thermal: intel: Fix dangling resources on thermal_throttle_online() failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Neri <[email protected]>
[ Upstream commit b91d287fa7a1ba0727eed5823c6ee4924ee5fa31 ]
The function thermal_throttle_add_dev() may fail and abort a CPU hotplug online operation. Since the failure occurs within the online callback, thermal_throttle_online(), the CPU hotplug framework does not invoke the corresponding offline callback. As a result, the hardware and software resources set up during the failed operation are not torn down.
Since only thermal_throttle_add_dev() can fail, call it before setting up the rest of the resources.
--- arch/x86/kernel/cpu/mce/therm_throt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/mce/therm_throt.c +6 -1
@@ -467,8 +467,13 @@ static int thermal_throttle_online(unsigned int cpu) {struct thermal_state *state = &per_cpu (thermal_state, cpu);struct device *dev =get_cpu_device (cpu); +int err;u32 l; + err =thermal_throttle_add_dev (dev, cpu); +if (err) +return err; + state->package_throttle.level =PACKAGE_LEVEL ; state->core_throttle.level =CORE_LEVEL ;
@@ -479,7 +484,7 @@ static int thermal_throttle_online(unsigned int cpu) l =apic_read (APIC_LVTTHMR );apic_write (APIC_LVTTHMR , l & ~APIC_LVT_MASKED ); -return thermal_throttle_add_dev (dev, cpu); +return err; }static int thermal_throttle_offline (unsigned int cpu)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 344/699 ACPI: resource: Amend kernel-doc style
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 78ad5c7722b7bed9d35ffc5b45eb0f12e2c22fee ]
The functions are referred as func() in the kernel-doc. The % (percent) character makes the rendering for constants as described in the respective documentation. Amend all these.
--- drivers/acpi/resource.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/acpi/resource.c +3 -3
@@ -688,7 +688,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,EXPORT_SYMBOL_GPL (acpi_dev_resource_interrupt);/** -* acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). +* acpi_dev_free_resource_list - Free resource from acpi_dev_get_resources(). * @list: The head of the resource list to free. */ void acpi_dev_free_resource_list (struct list_head *list)
@@ -808,7 +808,7 @@ static int __acpi_dev_get_resources(struct acpi_device *adev,* * The resultant struct resource objects are put on the list pointed to by * @list, that must be empty initially, as members of struct resource_entry -* objects. Callers of this routine should use %acpi_dev_free_resource_list() to +* objects. Callers of this routine should use acpi_dev_free_resource_list() to * free that list. * * The number of resources in the output list is returned on success, an error
@@ -846,7 +846,7 @@ static int is_memory(struct acpi_resource *ares, void *not_used)* The resultant struct resource objects are put on the list pointed to * by @list, that must be empty initially, as members of struct * resource_entry objects. Callers of this routine should use -* %acpi_dev_free_resource_list() to free that list. +* acpi_dev_free_resource_list() to free that list. * * The number of resources in the output list is returned on success, * an error code reflecting the error condition is returned otherwise.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 345/699 ieee802154: Remove WARN_ON() in cfg802154_pernet_exit()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Abramov <[email protected]>
[ Upstream commit e69ed6fc9fb3b386b5fcdb9f51623f122cee2ebd ]
There's no need to call WARN_ON() in cfg802154_pernet_exit(), since every point of failure in cfg802154_switch_netns() is covered with WARN_ON(), so remove it.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- net/ieee802154/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ieee802154/core.c +1 -1
@@ -324,7 +324,7 @@ static void __net_exit cfg802154_pernet_exit(struct net *net)rtnl_lock ();list_for_each_entry (rdev, &cfg802154_rdev_list, list) {if (net_eq (wpan_phy_net (&rdev->wpan_phy), net)) -WARN_ON (cfg802154_switch_netns (rdev, &init_net)); +cfg802154_switch_netns (rdev, &init_net); }rtnl_unlock (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 346/699 ieee802154: fix kernel-infoleak in dgram_recvmsg()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit 4db86f8ab11b5a41bfc36680be837e6ac1375ec6 ]
KMSAN reported a kernel-infoleak in move_addr_to_user():
BUG: KMSAN: kernel-infoleak in instrument_copy_to_user include/linux/instrumented.h:131 [inline] BUG: KMSAN: kernel-infoleak in _inline_copy_to_user include/linux/uaccess.h:205 [inline] BUG: KMSAN: kernel-infoleak in _copy_to_user+0xcc/0x120 lib/usercopy.c:26 instrument_copy_to_user include/linux/instrumented.h:131 [inline] _inline_copy_to_user include/linux/uaccess.h:205 [inline] _copy_to_user+0xcc/0x120 lib/usercopy.c:26 copy_to_user include/linux/uaccess.h:236 [inline] move_addr_to_user+0x2e7/0x440 net/socket.c:302 ____sys_recvmsg+0x232/0x610 net/socket.c:2925 ... Uninit was stored to memory at: ieee802154_addr_to_sa include/net/ieee802154_netdev.h:369 [inline] dgram_recvmsg+0xa09/0xbe0 net/ieee802154/socket.c:739
The issue occurs because the pan_id field of struct ieee802154_addr is left uninitialized when the address mode is IEEE802154_ADDR_NONE. The execution flow is as follows:
1. __ieee802154_rx_handle_packet() declares a local struct ieee802154_hdr hdr on the stack.
2. ieee802154_hdr_pull() calls ieee802154_hdr_get_addr() to parse the source and destination addresses into this structure.
3. If the address mode is IEEE802154_ADDR_NONE, ieee802154_hdr_get_addr() previously only set the mode field, leaving the pan_id field containing uninitialized stack memory.
4. This uninitialized pan_id is later copied into a struct sockaddr_ieee802154 in dgram_recvmsg() via ieee802154_addr_to_sa().
5. Finally, move_addr_to_user() copies the socket address structure to user space, leaking the uninitialized bytes.
Fix this by using memset to zero out the address structure in ieee802154_hdr_get_addr() when the mode is IEEE802154_ADDR_NONE.
--- net/ieee802154/header_ops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/ieee802154/header_ops.c +6 -3
@@ -126,10 +126,13 @@ ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan, {int pos =0 ; - addr->mode = mode; - -if (mode ==IEEE802154_ADDR_NONE ) +if (mode ==IEEE802154_ADDR_NONE ) { +memset (addr,0 ,sizeof (*addr)); + addr->mode =IEEE802154_ADDR_NONE ;return 0 ; + } + + addr->mode = mode;if (!omit_pan) {memcpy (&addr->pan_id, buf + pos,2 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 347/699 netfilter: ipset: fix order of kfree_rcu() and rcu_assign_pointer()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 3ca9982a8882470aa0ac4e8bb9a552b181d1efcd ]
Sashiko pointed out that kfree_rcu() was called before rcu_assign_pointer() in handling the comment extension. Fix the order so that rcu_assign_pointer() called first.
--- net/netfilter/ipset/ip_set_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/ipset/ip_set_core.c +2 -2
@@ -351,8 +351,8 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,if (unlikely (c)) { set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; -kfree_rcu (c, rcu);rcu_assign_pointer (comment->c,NULL ); +kfree_rcu (c, rcu); }if (!len)return ;
@@ -393,8 +393,8 @@ ip_set_comment_free(struct ip_set *set, void *ptr)if (unlikely (!c))return ; set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; -kfree_rcu (c, rcu);rcu_assign_pointer (comment->c,NULL ); +kfree_rcu (c, rcu); }typedef void (*destroyer )(struct ip_set *,void *);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 348/699 netfilter: nft_meta_bridge: fix NFT_META_BRI_IIFPVID stack leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 27dd2997746d54ebc079bb13161cc1bdd401d4a6 ]
This needs to test for nonzero retval.
--- net/bridge/netfilter/nft_meta_bridge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/bridge/netfilter/nft_meta_bridge.c +3 -1
@@ -41,7 +41,9 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,if (!br_dev || !br_vlan_enabled (br_dev)) goto err; -br_vlan_get_pvid_rcu (in, &p_pvid); +if (br_vlan_get_pvid_rcu (in, &p_pvid)) + goto err; +nft_reg_store16 (dest, p_pvid);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 349/699 irqchip/crossbar: Fix parent domain resource leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bhargav Joshi <[email protected]>
[ Upstream commit a1074dd62faa6572921d387e8a21589ccea00efc ]
irq_domain_alloc_irqs_parent() is called in allocate_gic_irq() but irq_domain_free_irqs_parent() is never called which causes a resource leak.
Fix this by calling irq_domain_free_irqs_parent() in crossbar_domain_free().
--- drivers/irqchip/irq-crossbar.c | 1 + 1 file changed, 1 insertion(+)
drivers/irqchip/irq-crossbar.c +1 -0
@@ -163,6 +163,7 @@ static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq, cb->write (d->hwirq, cb->safe_map); }raw_spin_unlock (&cb->lock); +irq_domain_free_irqs_parent (domain, virq, nr_irqs); } static int crossbar_domain_translate(struct irq_domain *d,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 350/699 selftests/mm: clarify alternate unmapping in compaction_test
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 69ba1d76d93ab818245333cf400928477ba72053 ]
Add a comment explaining that every other entry in the list is unmapped to intentionally create fragmentation with locked pages before invoking check_compaction().
--- tools/testing/selftests/vm/compaction_test.c | 3 +++ 1 file changed, 3 insertions(+)
tools/testing/selftests/vm/compaction_test.c +3 -0
@@ -231,6 +231,9 @@ int main(int argc, char **argv) mem_fragmentable_MB -=MAP_SIZE_MB ; } +/* Unmap every other entry in the list to create fragmentation with +* locked pages before invoking check_compaction(). +*/ for (entry = list; entry !=NULL ; entry = entry->next) {munmap (entry->map,MAP_SIZE );if (!entry->next)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 351/699 selftests/mm: allow PUD-level entries in compound testcase of hmm tests
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 224ed0e019b122d08580362abe57574a78f2b5fa ]
Patch series "selftests/mm: assorted fixes for hmm-tests", v3.
This series fixes a few issues in hmm-tests that show up when page-size and huge-page configuration differ from the hardcoded assumptions the tests were written for (PMD/THP sizing, default hugepage size, and related cases).
It also includes a fix to exclusive_cow: the test ignored the return value of fork(), so both parent and child ran the same teardown path.
This patch (of 3):
The HMM compound testcase currently assumes only PMD-level mappings and fails on systems where default_hugepagesz=1G is set, because the region is then reported by the device at PUD level.
Determine the mapping level (PMD or PUD) the device reports for the first page of the range and require every page to match that level exactly via ASSERT_EQ(). This accepts PUD-level mappings while preserving the expected/observed protection values printed on failure, and rejects a fragmented mapping that mixes PMD- and PUD-level entries within the same range (which a per-page OR check would have let pass).
--- tools/testing/selftests/vm/hmm-tests.c | 32 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-)
tools/testing/selftests/vm/hmm-tests.c +24 -8
@@ -1379,8 +1379,8 @@ TEST_F(hmm2, snapshot) }/* -* Test the hmm_range_fault() HMM_PFN_PMD flag for large pages that -* should be mapped by a large page table entry. +* Test the hmm_range_fault() handling of large pages (PMD or PUD) +* that should be mapped by a large page table entry. */ TEST_F(hmm, compound) {
@@ -1389,6 +1389,7 @@ TEST_F(hmm, compound)unsigned long size;int *ptr;unsigned char *m; +unsigned char prot;int ret;long pagesizes[4 ];int n, idx;
@@ -1428,11 +1429,20 @@ TEST_F(hmm, compound)ASSERT_EQ (ret,0 );ASSERT_EQ (buffer->cpages, npages); -/* Check what the device saw. */ +/* +* Check what the device saw. The region is backed by a single huge +* page that the device reports either at PMD or at PUD level depending +* on the configured default hugepage size. Determine that level from +* the first page and require every page in the range to match it +* exactly, so that a fragmented mapping mixing levels (or a missing +* large-page bit) is still caught and reported with its actual value. +*/ m = buffer->mirror; + prot =HMM_DMIRROR_PROT_WRITE | + ((m[0 ] &HMM_DMIRROR_PROT_PUD ) ?HMM_DMIRROR_PROT_PUD : +HMM_DMIRROR_PROT_PMD );for (i =0 ; i < npages; ++i) -ASSERT_EQ (m[i],HMM_DMIRROR_PROT_WRITE | -HMM_DMIRROR_PROT_PMD ); +ASSERT_EQ (m[i], prot);/* Make the region read-only. */ ret =mprotect (buffer->ptr, size,PROT_READ );
@@ -1443,11 +1453,17 @@ TEST_F(hmm, compound)ASSERT_EQ (ret,0 );ASSERT_EQ (buffer->cpages, npages); -/* Check what the device saw. */ +/* +* Check what the device saw after mprotect(PROT_READ). Same +* approach as above: determine the mapping level from the first +* page and require every page to match it exactly. +*/ m = buffer->mirror; + prot =HMM_DMIRROR_PROT_READ | + ((m[0 ] &HMM_DMIRROR_PROT_PUD ) ?HMM_DMIRROR_PROT_PUD : +HMM_DMIRROR_PROT_PMD );for (i =0 ; i < npages; ++i) -ASSERT_EQ (m[i],HMM_DMIRROR_PROT_READ | -HMM_DMIRROR_PROT_PMD ); +ASSERT_EQ (m[i], prot);free_hugepage_region (buffer->ptr); buffer->ptr =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 352/699 rtc: abx80x: fix the RTC_VL_CLR clearing all status flags
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Antoni Pokusinski <[email protected]>
[ Upstream commit 419719c514252a2dbb2e2976f564c83417dd6d0a ]
The RTC_VL_CLR ioctl intends to clear only the battery low flag (BLF), however the current implementation writes 0 to the status register, clearing all status bits.
Fix this by writing back the masked status value so that only BLF is cleared, preserving other status flags.
--- drivers/rtc/rtc-abx80x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/rtc/rtc-abx80x.c +2 -1
@@ -535,7 +535,8 @@ static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) status &= ~ABX8XX_STATUS_BLF ; - tmp =i2c_smbus_write_byte_data (client,ABX8XX_REG_STATUS ,0 ); + tmp =i2c_smbus_write_byte_data (client,ABX8XX_REG_STATUS , + status);if (tmp <0 )return tmp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 353/699 rtc: ds1307: handle oscillator stop flag for ds1337/ds1339/ds3231
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ronan Dalton <[email protected]>
[ Upstream commit a091e1ba3b68cabc9caedafc6f81d9fe9b3b2200 ]
Prior to commit 48458654659c ("rtc: ds1307: remove clear of oscillator stop flag (OSF) in probe"), the oscillator stop flag (OSF) bit was checked during device probe for the ds1337, ds1339, ds1341, and ds3231 chips; if it was set, it would be cleared and a warning would be logged saying "SET TIME!". Since that commit, the OSF bit is no longer cleared, but the warning is still printed.
Directly following that commit, there was no way to get rid of this warning because nothing cleared the OSF bit on these chips.
The commit associated with the previous commit, 523923cfd5d6 ("rtc:
ds1307: handle oscillator stop flag (OSF) for ds1341"), made proper use of the OSF when getting and setting the time in the RTC. However, the other RTC variants ds1337, ds1339 and ds3231 didn't have a corresponding change made.
Given that the OSF bit is no longer cleared at probe time when it is set, the remaining three chips should have the same handling as the ds1341 chip has for the OSF bit.
Fix the issue on the ds1337, ds1339 and ds3231 chips by applying the same logic as the ds1341 has to these chips.
Note that any devices brought up between the first referenced commit and this one may begin mistrusting the time reported by the RTC until it is set again, if the bit was never explicitly cleared.
Note that only the ds1339 was tested with this change, but the datasheets for the other chips contain essentially identical descriptions of the OSF bit so the same change should work.
--- drivers/rtc/rtc-ds1307.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
drivers/rtc/rtc-ds1307.c +17 -11
@@ -265,6 +265,16 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)if (tmp &DS1338_BIT_OSF )return -EINVAL ;break ; +case ds_1337: +case ds_1339: +case ds_1341: +case ds_3231: + ret =regmap_read (ds1307->regmap,DS1337_REG_STATUS , &tmp); +if (ret) +return ret; +if (tmp &DS1337_BIT_OSF ) +return -EINVAL ; +break ;case ds_1340:if (tmp & DS1340_BIT_nEOSC)return -EINVAL ;
@@ -275,13 +285,6 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)if (tmp &DS1340_BIT_OSF )return -EINVAL ;break ; -case ds_1341: - ret =regmap_read (ds1307->regmap,DS1337_REG_STATUS , &tmp); -if (ret) -return ret; -if (tmp &DS1337_BIT_OSF ) -return -EINVAL ; -break ;case ds_1388: ret =regmap_read (ds1307->regmap,DS1388_REG_FLAG , &tmp);if (ret)
@@ -376,14 +379,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)regmap_update_bits (ds1307->regmap,DS1307_REG_CONTROL ,DS1338_BIT_OSF ,0 );break ; -case ds_1340: -regmap_update_bits (ds1307->regmap,DS1340_REG_FLAG , -DS1340_BIT_OSF ,0 ); -break ; +case ds_1337: +case ds_1339:case ds_1341: +case ds_3231:regmap_update_bits (ds1307->regmap,DS1337_REG_STATUS ,DS1337_BIT_OSF ,0 );break ; +case ds_1340: +regmap_update_bits (ds1307->regmap,DS1340_REG_FLAG , +DS1340_BIT_OSF ,0 ); +break ;case ds_1388:regmap_update_bits (ds1307->regmap,DS1388_REG_FLAG ,DS1388_BIT_OSF ,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 354/699 bpf: Fix stack slot index in nospec checks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuoqi Gui <[email protected]>
[ Upstream commit d1d53aa30ab3b5ae89161c9cc840b3f7489ad386 ]
check_stack_write_fixed_off() computes the byte slot for a fixed-offset stack write as -off - 1, and records each written byte in slot_type[] with (slot - i) % BPF_REG_SIZE.
The Spectre v4 sanitization pre-check uses slot_type[i] instead. For a 4-byte write at fp-8 after the lower half of fp-8 has been zeroed, the pre-check scans bytes 0..3 and sees STACK_ZERO while the actual write updates bytes 7..4. That can leave the second half-slot write without nospec_result even though the bytes being overwritten still require sanitization.
Use the same slot index in the sanitization pre-check that the write path uses when updating slot_type[].
--- kernel/bpf/verifier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/bpf/verifier.c +2 -1
@@ -2523,7 +2523,8 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,bool sanitize = reg &&is_spillable_regtype (reg->type);for (i =0 ; i < size; i++) { -u8 type = state->stack[spi].slot_type[i]; +u8 type = state->stack[spi].slot_type[(slot - i) % +BPF_REG_SIZE ];if (type !=STACK_MISC && type !=STACK_ZERO ) { sanitize = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 355/699 drm/edid: fix OOB read in drm_parse_tiled_block()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit faaa1e1155833e7d4ce7e3cfaf64c0d636b190db ]
drm_parse_tiled_block() casts the DisplayID block to a struct displayid_tiled_block and reads the full fixed layout up to tile->topology_id[7] without checking block->num_bytes. The DisplayID iterator only validates the declared payload length, so a crafted EDID can advertise a tiled-display block (tag DATA_BLOCK_TILED_DISPLAY, or DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY for v2.0) with a small num_bytes at the end of a DisplayID extension. The read then runs past the end of the exact-sized kmemdup()'d EDID allocation, a heap out-of-bounds read.
Reject blocks shorter than the spec's 22-byte tiled payload before reading the fixed struct, as drm_parse_vesa_mso_data() already does.
BUG: KASAN: slab-out-of-bounds in drm_edid_connector_update Read of size 2 at addr ffff888010077700 by task exploit/147 dump_stack_lvl (lib/dump_stack.c:94 ...) print_report (mm/kasan/report.c:378 ...) kasan_report (mm/kasan/report.c:595) drm_edid_connector_update (drivers/gpu/drm/drm_edid.c:7581) bochs_connector_helper_get_modes (drivers/gpu/drm/tiny/bochs.c:574) drm_helper_probe_single_connector_modes (drivers/gpu/drm/drm_probe_helper.c:426) status_store (drivers/gpu/drm/drm_sysfs.c:219) ... vfs_write (fs/read_write.c:595 fs/read_write.c:688) ksys_write (fs/read_write.c:740)
--- drivers/gpu/drm/drm_edid.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/drm_edid.c +8 -0
@@ -5896,6 +5896,14 @@ static void drm_parse_tiled_block(struct drm_connector *connector,u8 num_v_tile, num_h_tile;struct drm_tile_group *tg; +/* tiled block payload per spec: cap 1 + topo 3 + size 4 + bezel 5 + id 9 = 22 */ +if (block->num_bytes <22 ) { +drm_dbg_kms (connector->dev, +"[CONNECTOR:%d:%s] Unexpected tiled block size %u\n" , + connector->base.id, connector->name, block->num_bytes); +return ; + } + w = tile->tile_size[0 ] | tile->tile_size[1 ] <<8 ; h = tile->tile_size[2 ] | tile->tile_size[3 ] <<8 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 356/699 ipv6: Fix null-ptr-deref in fib6_nh_mtu_change().
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 46c3b8191aad3d032776bf3bebf03efdf5f4b905 ]
fib6_nh_mtu_change() re-fetches idev via __in6_dev_get(arg->dev) and dereferences idev->cnf.mtu6 without a NULL check. addrconf_ifdown() clears dev->ip6_ptr with RCU_INIT_POINTER() after rt6_disable_ip() has released tb6_lock, so the RA-driven MTU walk can observe a NULL idev and oops. The caller rt6_mtu_change_route() guards its own __in6_dev_get(), but this re-fetch is unguarded; nexthop-backed routes survive addrconf_ifdown()'s flush, so the walk still reaches it after ip6_ptr is nulled.
Return 0 when idev is NULL, matching rt6_mtu_change_route() and the fib6_mtu() fix in commit 5ad509c1fdad ("ipv6: Fix null-ptr-deref in fib6_mtu().").
Oops: general protection fault, ... KASAN: null-ptr-deref in range
[0x00000000000002a8-0x00000000000002af]
RIP: 0010:fib6_nh_mtu_change+0x203/0x990
rt6_mtu_change_route+0x141/0x1d0
__fib6_clean_all+0xd0/0x160
rt6_mtu_change+0xb4/0x100
ndisc_router_discovery+0x24b5/0x2cb0
icmpv6_rcv+0x12e9/0x1710
ipv6_rcv+0x39b/0x410--- net/ipv6/route.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/route.c +3 -0
@@ -4829,6 +4829,9 @@ static int fib6_nh_mtu_change(struct fib6_nh *nh, void *_arg)struct inet6_dev *idev =__in6_dev_get (arg->dev);u32 mtu = f6i->fib6_pmtu; +if (!idev) +return 0 ; +if (mtu >= arg->mtu || (mtu < arg->mtu && mtu == idev->cnf.mtu6))fib6_metric_set (f6i,RTAX_MTU , arg->mtu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 357/699 ipv4: fib: Dont ignore error route in local/main tables.
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit b72f0db64205d9ce462038ba995d5d31eff32dc1 ]
When CONFIG_IP_MULTIPLE_TABLES is enabled but no rule is added, fib_lookup() performs route lookup directly on two tables.
Since the first lookup does not properly bail out, the result of an error route in the merged local/main table could be overwritten by another route in the default table:
# unshare -n
# ip link set lo up
# ip route add 192.168.0.0/24 dev lo table 253
# ip route add unreachable 192.168.0.0/24
# ip route get 192.168.0.1
192.168.0.1 dev lo table default uid 0
cache <local>Once a random rule is added, the error route is respected:
# ip rule add table 0 # ip rule del table 0 # ip route get 192.168.0.1 RTNETLINK answers: No route to host
Let's fix the inconsistent behaviour.
--- include/net/ip_fib.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
include/net/ip_fib.h +3 -4
@@ -365,7 +365,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res, unsigned int flags) {struct fib_table *tb; -int err = -ENETUNREACH ; +int err = -EAGAIN ; flags |=FIB_LOOKUP_NOREF ;if (net->ipv4.fib_has_custom_rules)
@@ -379,17 +379,16 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,if (tb) err =fib_table_lookup (tb, flp, res, flags); -if (!err) +if (err != -EAGAIN ) goto out; tb =rcu_dereference_rtnl (net->ipv4.fib_default);if (tb) err =fib_table_lookup (tb, flp, res, flags); -out:if (err == -EAGAIN ) err = -ENETUNREACH ; - +out:rcu_read_unlock ();return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 358/699 netfilter: nf_conncount: prevent connlimit drops for early confirmed ct
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit c8b6f36f766991e3ebebec6596daee4b04dcbc49 ]
Commit 69894e5b4c5e ("netfilter: nft_connlimit: update the count if add was skipped") introduced a regression where packets for valid connections are dropped when using connlimit for soft-limiting scenarios.
The issue occurs when a new connection reuses a socket currently in the TIME_WAIT state. In this scenario, the connection tracking entry is evaluated as already confirmed. Previously, __nf_conncount_add() assumed that if a connection was confirmed and did not originate from the loopback interface, it should skip the addition and return -EEXIST.
Skipping the addition triggers a garbage collection run that cleans up the TIME_WAIT connection. Consequently, the active connection count drops to 0, which xt_connlimit mishandles, leading to the false rejection of the perfectly valid new connection.
Fix this by replacing the interface check with protocol-agnostic state checks. We now skip the tree insertion and preserve the lockless garbage collection optimization only if the connection is IPS_ASSURED. This allows early-confirmed setup packets (such as reused TIME_WAIT sockets or locally generated SYN-ACKs) to be properly evaluated and counted without falsely dropping. The goto check_connections path is maintained to ensure these setup packets are deduplicated correctly.
This has been tested with slowhttptest and HTTP server configured locally to ensure we are not breaking soft-limiting scenarios for local or external connections. In addition, it was tested with a OVS zone limit too.
--- net/netfilter/nf_conncount.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/netfilter/nf_conncount.c +5 -6
@@ -179,17 +179,16 @@ static int __nf_conncount_add(struct net *net,return -ENOENT ;if (ct &&nf_ct_is_confirmed (ct)) { -/* local connections are confirmed in postrouting so confirmation -* might have happened before hitting connlimit +/* Connection is confirmed but might still be in the setup phase. +* Only skip the tracking if it is fully assured. This guarantees +* that setup packets or retransmissions are properly counted and +* deduplicated. */ -if (skb->skb_iif !=LOOPBACK_IFINDEX ) { +if (test_bit (IPS_ASSURED_BIT , &ct->status)) { err = -EEXIST ; goto out_put; } -/* this is likely a local connection, skip optimization to avoid -* adding duplicates from a 'packet train' -*/ goto check_connections; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 359/699 netfilter: nft_synproxy: stop bypassing the priv->info snapshot
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 11d4bc4e26fb66040a5b5d95e9abf37deac2b1fc ]
nft_synproxy_eval_v4() and nft_synproxy_eval_v6() already take a whole-object READ_ONCE() snapshot of the shared priv->info state before building the SYNACK reply, but nft_synproxy_tcp_options() still masks opts->options with priv->info.options from the live shared object.
When a named synproxy object is updated concurrently with SYN traffic, the eval path can then mix mss and timestamp handling from the local snapshot with an options mask taken from a newer configuration, so one SYNACK no longer reflects a coherent synproxy configuration.
Use info->options so nft_synproxy_tcp_options() stays on the same local snapshot that the eval path already copied from priv->info.
--- net/netfilter/nft_synproxy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
net/netfilter/nft_synproxy.c +4 -5
@@ -23,14 +23,13 @@ static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {static void nft_synproxy_tcp_options (struct synproxy_options *opts,const struct tcphdr *tcp,struct synproxy_net *snet, -struct nf_synproxy_info *info, -const struct nft_synproxy *priv) +struct nf_synproxy_info *info) {this_cpu_inc (snet->stats->syn_received);if (tcp->ece && tcp->cwr) opts->options |=NF_SYNPROXY_OPT_ECN ; - opts->options &= priv->info.options; + opts->options &= info->options; opts->mss_encode = opts->mss_option; opts->mss_option = info->mss;if (opts->options &NF_SYNPROXY_OPT_TIMESTAMP )
@@ -55,7 +54,7 @@ static void nft_synproxy_eval_v4(const struct nft_synproxy *priv,if (tcp->syn) {/* Initial SYN from client */ -nft_synproxy_tcp_options (opts, tcp, snet, &info, priv); +nft_synproxy_tcp_options (opts, tcp, snet, &info);synproxy_send_client_synack (net, skb, tcp, opts);consume_skb (skb); regs->verdict.code =NF_STOLEN ;
@@ -86,7 +85,7 @@ static void nft_synproxy_eval_v6(const struct nft_synproxy *priv,if (tcp->syn) {/* Initial SYN from client */ -nft_synproxy_tcp_options (opts, tcp, snet, &info, priv); +nft_synproxy_tcp_options (opts, tcp, snet, &info);synproxy_send_client_synack_ipv6 (net, skb, tcp, opts);consume_skb (skb); regs->verdict.code =NF_STOLEN ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 360/699 alpha/PCI: Add security_locked_down() check to pci_mmap_resource()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
[ Upstream commit 78a228f0aa0e9eba31955950c8a40a9945e2c8bb ]
Currently, Alpha's pci_mmap_resource() does not check security_locked_down(LOCKDOWN_PCI_ACCESS) before allowing userspace to mmap PCI BARs.
The generic version has had this check since commit eb627e17727e ("PCI:
Lock down BAR access when the kernel is locked down") to prevent DMA attacks when the kernel is locked down.
Add the same check to Alpha's pci_mmap_resource().
--- arch/alpha/kernel/pci-sysfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/alpha/kernel/pci-sysfs.c +6 -1
@@ -11,6 +11,7 @@*/ #include <linux/sched.h> +#include <linux/security.h> #include <linux/stat.h> #include <linux/slab.h> #include <linux/pci.h>
@@ -69,7 +70,11 @@ static int pci_mmap_resource(struct kobject *kobj,struct resource *res = attr->private;enum pci_mmap_state mmap_type;struct pci_bus_region bar; -int i; +int i, ret; + + ret =security_locked_down (LOCKDOWN_PCI_ACCESS ); +if (ret) +return ret;for (i =0 ; i <PCI_STD_NUM_BARS ; i++)if (res == &pdev->resource[i])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 361/699 alpha/PCI: Fix __pci_mmap_fits() overflow for zero-length BARs
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
[ Upstream commit 802a3b3f470b9bc1148f26e01fc9cbfeb4dfcb57 ]
Currently, __pci_mmap_fits() computes the BAR size using "pci_resource_len() - 1", which wraps to a large value when the BAR length is zero, causing the bounds check to incorrectly succeed.
Add an early return for empty resources.
--- arch/alpha/kernel/pci-sysfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/alpha/kernel/pci-sysfs.c +5 -1
@@ -37,12 +37,16 @@ static int hose_mmap_page_range(struct pci_controller *hose,static int __pci_mmap_fits (struct pci_dev *pdev,int num,struct vm_area_struct *vma,int sparse) { +resource_size_t len =pci_resource_len (pdev, num);unsigned long nr, start, size;int shift = sparse ?5 :0 ; +if (!len) +return 0 ; + nr =vma_pages (vma); start = vma->vm_pgoff; - size = ((pci_resource_len (pdev, num) -1 ) >> (PAGE_SHIFT - shift)) +1 ; + size = ((len -1 ) >> (PAGE_SHIFT - shift)) +1 ;if (start < size && size - start >= nr)return 1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 362/699 net: dsa: sja1105: round up PTP perout pin duration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandrova Alyona <[email protected]>
[ Upstream commit aee5836273b07b439fb245fb43930664d8b78518 ]
pin_duration is converted from the user-provided period to SJA1105 clock ticks and is later passed as the cycle_time argument to future_base_time().
Very small period values may become zero after the conversion, which can lead to a division by zero in future_base_time().
Round zero pin_duration up to 1 tick so that the smallest unsupported periods use the minimum non-zero hardware duration instead of passing zero to future_base_time().
--- drivers/net/dsa/sja1105/sja1105_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/sja1105/sja1105_ptp.c +1 -1
@@ -711,7 +711,7 @@ static int sja1105_per_out_enable(struct sja1105_private *priv,* 2 edges on PTP_CLK. So check for truncation which happens * at periods larger than around 68.7 seconds. */ - pin_duration =ns_to_sja1105_ticks (pin_duration /2 ); + pin_duration =max_t (u64,ns_to_sja1105_ticks (pin_duration /2 ),1 );if (pin_duration >U32_MAX ) { rc = -ERANGE ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 363/699 ipv6: fix error handling in disable_ipv6 sysctl
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit c779441e5070e2268bdfe77f6e2e0de926c431e3 ]
When writing to the disable_ipv6 sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6291,6 +6291,8 @@ static int addrconf_sysctl_disable(struct ctl_table *ctl, int write, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_disable_ipv6 (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 364/699 ipv6: fix error handling in ignore_routes_with_linkdown sysctl
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit cf4f2b14401f29ccac56393ca9e4b42a2505f540 ]
When writing to the ignore_routes_with_linkdown sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6489,6 +6489,8 @@ int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_fixup_linkdown (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 365/699 ipv6: fix error handling in forwarding sysctl
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 058b9b19f9639fe1e1225a17c540f61b65bee6ad ]
When writing to the forwarding sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure. In addition, adjust return code of addrconf_fixup_forwarding() for successful operation.
--- net/ipv6/addrconf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv6/addrconf.c +3 -1
@@ -907,7 +907,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)if (newf)rt6_purge_dflt_routers (net); -return 1 ; +return 0 ; }static void addrconf_linkdown_change (struct net *net,__s32 newf)
@@ -6194,6 +6194,8 @@ static int addrconf_sysctl_forward(struct ctl_table *ctl, int write, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_fixup_forwarding (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 366/699 ipv6: fix error handling in disable_policy sysctl
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 3e0e51c0ee1d08cc9d48dc17f3248d5b31cf8066 ]
When writing to the disable_policy sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is resetting the position argument even if an error occurred during proc_dointvec() and not only during sysctl restart.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6588,6 +6588,8 @@ static int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write, lctl = *ctl; lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write && (*valp != val)) ret =addrconf_disable_policy (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 367/699 smb/client: preserve errors from smb2_set_sparse()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
[ Upstream commit 2a4b3d2db5c6fcdba889baf7b2ae5661b0beac89 ]
smb2_set_sparse() converts every FSCTL_SET_SPARSE failure to false and marks sparse support as broken for the share. Callers therefore report EOPNOTSUPP even for errors such as ENOSPC or EACCES, and later sparse operations remain disabled until the share is unmounted.
Return the SMB2 ioctl error directly. Set broken_sparse_sup only for EOPNOTSUPP, which indicates that the server does not support the request.
Update smb3_punch_hole() to propagate the error returned by smb2_set_sparse().
--- fs/cifs/smb2ops.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
fs/cifs/smb2ops.c +15 -15
@@ -1941,8 +1941,9 @@ smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid, }/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */ -static bool smb2_set_sparse (const unsigned int xid,struct cifs_tcon *tcon, -struct cifsFileInfo *cfile,struct inode *inode,__u8 setsparse) +static int smb2_set_sparse (const unsigned int xid,struct cifs_tcon *tcon, +struct cifsFileInfo *cfile,struct inode *inode, +__u8 setsparse) {struct cifsInodeInfo *cifsi;int rc;
@@ -1951,31 +1952,31 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,/* if file already sparse don't bother setting sparse again */ if ((cifsi->cifsAttrs &FILE_ATTRIBUTE_SPARSE_FILE ) && setsparse) -return true;/* already sparse */ +return 0 ;/* already sparse */ if (!(cifsi->cifsAttrs &FILE_ATTRIBUTE_SPARSE_FILE ) && !setsparse) -return true;/* already not sparse */ +return 0 ;/* already not sparse */ /* * Can't check for sparse support on share the usual way via the * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share * since Samba server doesn't set the flag on the share, yet * supports the set sparse FSCTL and returns sparse correctly -* in the file attributes. If we fail setting sparse though we -* mark that server does not support sparse files for this share -* to avoid repeatedly sending the unsupported fsctl to server -* if the file is repeatedly extended. +* in the file attributes. If the server returns EOPNOTSUPP, mark +* that sparse files are not supported on this share to avoid +* repeatedly sending the unsupported FSCTL. */ if (tcon->broken_sparse_sup) -return false; +return -EOPNOTSUPP ; rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_SPARSE , &setsparse,1 , CIFSMaxBufSize,NULL ,NULL );if (rc) { - tcon->broken_sparse_sup = true; +if (rc == -EOPNOTSUPP ) + tcon->broken_sparse_sup = true;cifs_dbg (FYI ,"set sparse rc = %d\n" , rc); -return false; +return rc; }if (setsparse)
@@ -1983,7 +1984,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,else cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE ); -return true; +return 0 ; } static int
@@ -3480,10 +3481,9 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,inode_lock (inode);/* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ -if (!smb2_set_sparse (xid, tcon, cfile, inode, set_sparse)) { - rc = -EOPNOTSUPP ; + rc =smb2_set_sparse (xid, tcon, cfile, inode, set_sparse); +if (rc) goto out; - }/* * We implement the punch hole through ioctl, so we need remove the page
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 368/699 rtc: ds1307: Fix off-by-one issue with wday for rx8130
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fredrik M Olsson <[email protected]>
[ Upstream commit 6882aab3c66112b33b251be95c09c8ead3e8d580 ]
The RTC represent each weekday with a individual bit set in the WDAY register, where the 0th bit represent the first day of the week and the 6th bit represents the last day of the week. For each passed day the chip performs a rotary-left-shift by one to advance the weekday by one.
The tm_wday field represent weekdays by a value in the range of 0-6.
The fls() function return the bit index of the last bit set. To handle when there are no bits set it will return 0, and if the 0th bit is set it will return 1, and if the 1st bit is set it will return 2, and so on.
In order to make the result of the fls() function fall into the expected range of 0-6 (instead of 1-7) this patch subtracts one from the result (which matches how the value is written in ds1307_set_time()).
--- drivers/rtc/rtc-ds1307.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/rtc/rtc-ds1307.c +1 -1
@@ -307,7 +307,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_hour =bcd2bin (tmp);/* rx8130 is bit position, not BCD */ if (ds1307->type == rx_8130) - t->tm_wday =fls (regs[DS1307_REG_WDAY ] &0x7f ); + t->tm_wday =fls (regs[DS1307_REG_WDAY ] &0x7f ) -1 ;else t->tm_wday =bcd2bin (regs[DS1307_REG_WDAY ] &0x07 ) -1 ; t->tm_mday =bcd2bin (regs[DS1307_REG_MDAY ] &0x3f );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 369/699 rtc: cmos: unregister HPET IRQ handler on probe failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit a5bb580df018b5d1c5668f05f7979044fb19e23a ]
cmos_do_probe() registers cmos_interrupt() as the HPET RTC IRQ handler before requesting the RTC IRQ and registering the RTC device. If either request_irq() or devm_rtc_register_device() fails afterwards, the error path leaves the HPET RTC IRQ handler installed. This leaves a stale handler behind and make a later hpet_register_irq_handler() fail with -EBUSY.
Track whether the HPET handler was registered successfully and undo the registration on the probe error path. Also mask the HPET RTC IRQ bits to match the normal shutdown cleanup.
--- drivers/rtc/rtc-cmos.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/rtc/rtc-cmos.c +6 -0
@@ -929,6 +929,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)unsigned char rtc_control;unsigned address_space;u32 flags =0 ; +bool hpet_registered = false;struct nvmem_config nvmem_cfg = { .name ="cmos_nvram" , .word_size =1 ,
@@ -1079,6 +1080,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) " failed in rtc_init()."); goto cleanup1; } + hpet_registered = true; }else rtc_cmos_int_handler = cmos_interrupt;
@@ -1127,6 +1129,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)if (is_valid_irq (rtc_irq))free_irq (rtc_irq, cmos_rtc.rtc); cleanup1: +if (hpet_registered) { +hpet_mask_rtc_irq_bit (RTC_IRQMASK ); +hpet_unregister_irq_handler (cmos_interrupt); + } cmos_rtc.dev =NULL ; cleanup0:if (RTC_IOMAPPED )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 370/699 net: mvneta: re-enable percpu interrupt on resume
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit fd398d6480987e4c84fff0aaab6b9d6642a93343 ]
On Marvell MPIC platforms (Armada 370/XP/38x), mvneta uses a percpu IRQ disable/enable scheme for NAPI: the ISR (mvneta_percpu_isr) calls disable_percpu_irq() to mask the MPIC per-CPU interrupt and schedules NAPI poll, which calls enable_percpu_irq() on completion to unmask.
If suspend occurs while NAPI poll is pending (between disable_percpu_irq in the ISR and enable_percpu_irq in poll completion), the interrupt is never re-enabled:
1. mvneta_percpu_isr: disable_percpu_irq() + napi_schedule() => MPIC masked, percpu_enabled cpumask bit cleared
2. NAPI poll does not complete before suspend proceeds (on PREEMPT_RT this is highly likely since softirqs run in ksoftirqd which gets frozen; on non-RT it can happen when softirq processing is deferred to ksoftirqd)
3. mvneta_stop_dev => napi_disable(): cancels the pending poll without executing the completion path
4. suspend_device_irqs => IRQCHIP_MASK_ON_SUSPEND: masks MPIC (already masked, but records IRQS_SUSPENDED)
5. Resume: mpic_resume checks irq_percpu_is_enabled() => false (bit was cleared in step 1) => skips unmask
6. mvneta_start_dev only restores device-level INTR_NEW_MASK, does not touch the MPIC per-CPU mask
Result: MPIC per-CPU interrupt stays masked permanently. The NIC generates interrupts (INTR_NEW_CAUSE != 0) but the CPU never receives them, causing complete loss of network connectivity.
Fix by calling on_each_cpu(mvneta_percpu_enable) in the resume path to unconditionally unmask the MPIC per-CPU interrupt regardless of pre-suspend state.
--- drivers/net/ethernet/marvell/mvneta.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +3 -0
@@ -5434,6 +5434,9 @@ static int mvneta_resume(struct device *device)rtnl_unlock ();mvneta_set_rx_mode (dev); +if (!pp->neta_armada3700) +on_each_cpu (mvneta_percpu_enable, pp, true); + return 0; }#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 371/699 net: sungem: fix probe error cleanup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 36dea2f639249460d13f6ca66b2a9064187cd34d ]
gem_init_one() calls gem_remove_one() when register_netdev() fails. gem_remove_one() unregisters and frees resources owned by the net_device, including the DMA block, MMIO mapping, PCI regions, and the net_device itself. gem_init_one() then falls through to its own cleanup labels and frees the same resources again.
Keep the register_netdev() error path in gem_init_one(): clear drvdata so PM/remove paths do not see a half-registered device, remove the NAPI instance added during probe, and let the existing cleanup labels release the resources once.
The issue was found by a local static-analysis checker for probe error paths. The reported path was manually inspected before sending this fix.
Compile-tested with CONFIG_SUNGEM=y. Runtime testing was not performed because no sungem hardware is available.
--- drivers/net/ethernet/sun/sungem.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/net/ethernet/sun/sungem.c +9 -4
@@ -2983,10 +2983,10 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->max_mtu =GEM_MAX_MTU ;/* Register with kernel */ -if (register_netdev (dev)) { + err =register_netdev (dev); +if (err) {pr_err ("Cannot register net device, aborting\n" ); - err = -ENOMEM ; - goto err_out_free_consistent; + goto err_out_clear_drvdata; }/* Undo the get_cell with appropriate locking (we could use
@@ -3000,8 +3000,13 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr);return 0 ; +err_out_clear_drvdata: +pci_set_drvdata (pdev,NULL ); +netif_napi_del (&gp->napi); + err_out_free_consistent: -gem_remove_one (pdev); +dma_free_coherent (&pdev->dev,sizeof (struct gem_init_block ), + gp->init_block, gp->gblock_dvma); err_out_iounmap:gem_put_cell (gp);iounmap (gp->regs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 372/699 tracing: probes: fix typo in a log message
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
[ Upstream commit 72c8646956ffc8050bb8be5988a0f28fc37e1ac4 ]
Fix a typo ("Invalid $-variable") in a log message.
--- kernel/trace/trace_probe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_probe.h +1 -1
@@ -409,7 +409,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,C (RETVAL_ON_PROBE ,"$retval is not available on probe" ), \C (BAD_STACK_NUM ,"Invalid stack number" ), \C (BAD_ARG_NUM ,"Invalid argument number" ), \ -C (BAD_VAR ,"Invalid $-valiable specified" ), \ +C (BAD_VAR ,"Invalid $-variable specified" ), \C (BAD_REG_NAME ,"Invalid register name" ), \C (BAD_MEM_ADDR ,"Invalid memory address" ), \ C(BAD_IMM, "Invalid immediate value"), \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 373/699 spi: sh-msiof: abort transfers when reset times out
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 6dbaa4d288432c697cea47028480481b8b29bd6a ]
sh_msiof_spi_reset_regs() asserts TX/RX reset and polls until the reset bits clear, but the poll result is ignored. sh_msiof_transfer_one() can therefore continue programming a transfer after the controller did not leave reset.
Return the reset poll result from the helper and abort the transfer on timeout, matching the existing transfer path's error-return style.
--- drivers/spi/spi-sh-msiof.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/spi/spi-sh-msiof.c +6 -4
@@ -243,7 +243,7 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data)return IRQ_HANDLED ; } -static void sh_msiof_spi_reset_regs (struct sh_msiof_spi_priv *p) +static int sh_msiof_spi_reset_regs (struct sh_msiof_spi_priv *p) {u32 mask =SICTR_TXRST |SICTR_RXRST ;u32 data;
@@ -252,8 +252,8 @@ static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) data |= mask;sh_msiof_write (p,SICTR , data); -readl_poll_timeout_atomic (p->mapbase +SICTR , data, !(data & mask),1 , -100 ); +return readl_poll_timeout_atomic (p->mapbase +SICTR , data, + !(data & mask),1 ,100 ); }static const u32 sh_msiof_spi_div_array[] = {
@@ -923,7 +923,9 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,int ret;/* reset registers */ -sh_msiof_spi_reset_regs (p); + ret =sh_msiof_spi_reset_regs (p); +if (ret) +return ret;/* setup clocks (clock already enabled in chipselect()) */ if (!spi_controller_is_slave (p->ctlr))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 374/699 gpio: mvebu: fail probe if gpiochip registration fails
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 479e91fc92416a4d54d2b3150aa1e4550d9cc759 ]
mvebu_gpio_probe() registers the GPIO chip with devm_gpiochip_add_data() but ignores the return value. If registration fails, probe continues and leaves later code operating on a GPIO chip that was never published to gpiolib.
Return the registration error so the device fails probe cleanly.
--- drivers/gpio/gpio-mvebu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpio/gpio-mvebu.c +4 -1
@@ -1193,7 +1193,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)BUG (); } -devm_gpiochip_add_data (&pdev->dev, &mvchip->chip, mvchip); + err =devm_gpiochip_add_data (&pdev->dev, &mvchip->chip, mvchip); +if (err) +return dev_err_probe (&pdev->dev, err, +"failed to register gpiochip\n" );/* Some MVEBU SoCs have simple PWM support for GPIO lines */ if (IS_ENABLED (CONFIG_PWM )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 375/699 gpio: htc-egpio: use managed gpiochip registration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 17326db5f0ab4ec1901e75d052b5ebef486b467f ]
egpio_probe() registers each nested gpio_chip with gpiochip_add_data() but ignores the return value. If one registration fails, probe still returns success even though one of the chips was not published to gpiolib.
Use devm_gpiochip_add_data() and fail probe if any chip registration fails. This lets devres unwind already registered chips and prevents the driver from publishing a partially initialized device.
--- drivers/gpio/gpio-htc-egpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpio/gpio-htc-egpio.c +5 -1
@@ -268,6 +268,7 @@ static int __init egpio_probe(struct platform_device *pdev)struct gpio_chip *chip;unsigned int irq, irq_end;int i; +int ret;/* Initialize ei data structure. */ ei =devm_kzalloc (&pdev->dev,sizeof (*ei),GFP_KERNEL );
@@ -331,7 +332,10 @@ static int __init egpio_probe(struct platform_device *pdev) chip->base = pdata->chip[i].gpio_base; chip->ngpio = pdata->chip[i].num_gpios; -gpiochip_add_data (chip, &ei->chip[i]); + ret =devm_gpiochip_add_data (&pdev->dev, chip, &ei->chip[i]); +if (ret) +return dev_err_probe (&pdev->dev, ret, +"failed to register gpiochip %d\n" , i); }/* Set initial pin values */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 376/699 seg6: validate SRH length before reading fixed fields
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuoqi Gui <[email protected]>
[ Upstream commit a75d99f46bf21b45965ce39c5cfb3b8bb5ffb1aa ]
seg6_validate_srh() reads fixed SRH fields such as srh->type and srh->hdrlen before checking that the supplied length covers the fixed struct ipv6_sr_hdr fields.
The BPF SEG6 encap path reaches this with a BPF program-supplied pointer and length: bpf_lwt_push_encap() and the SEG6 local BPF END_B6 and END_B6_ENCAP actions call bpf_push_seg6_encap(), which forwards the length to seg6_validate_srh() with no minimum-size guard. A 2-byte SEG6 encap header can therefore make the validator read srh->type at offset 2 beyond the caller-supplied buffer.
Reject lengths shorter than the fixed SRH at the top of seg6_validate_srh(), before any field is read. This fixes the BPF helper path and keeps the common validator robust.
--- net/ipv6/seg6.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/seg6.c +3 -0
@@ -31,6 +31,9 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)int max_last_entry;int trailing; +if (len <sizeof (*srh)) +return false; +if (srh->type !=IPV6_SRCRT_TYPE_4 )return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 377/699 hwmon: adm1275: Prevent reading uninitialized stack
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matti Vaittinen <[email protected]>
[ Upstream commit 553f9517813912a5ab661af5504485d96824a61c ]
While adding support for the ROHM BD127X0 hot-swap controllers, sashiko reported an error in device-name comparison, which can lead to reading uninitialized stack memory.
Quoting Sashiko:
This is a pre-existing issue, but I noticed that just before this block in adm1275_probe(), there might be an out-of-bounds stack read:
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
if (ret < 0) { ... }
for (mid = adm1275_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}Since i2c_smbus_read_block_data() reads up to 32 bytes into the uninitialized stack array block_buffer without appending a null terminator, strncasecmp() could read past the valid bytes returned in ret.
For example, if the device returns a shorter string like "adm12", checking it against "adm1275" up to the length of "adm1275" will continue reading into uninitialized stack bounds.
Prevent reading uninitialized memory by zeroing the stack array.
--- drivers/hwmon/pmbus/adm1275.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/adm1275.c +1 -1
@@ -484,7 +484,7 @@ static int adm1275_enable_vout_temp(struct i2c_client *client, int config)static int adm1275_probe (struct i2c_client *client) {s32 (*config_read_fn)(const struct i2c_client *client,u8 reg); -u8 block_buffer[I2C_SMBUS_BLOCK_MAX +1 ]; +u8 block_buffer[I2C_SMBUS_BLOCK_MAX +1 ] = {0 };int config, device_config;int ret;struct pmbus_driver_info *info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 378/699 usbnet: gl620a: fix out-of-bounds read in genelink_rx_fixup()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 8ff7f2a6da4fccaa5cc9be7251a24e71e29fbd1a ]
genelink_rx_fixup() splits an aggregated RX frame into its individual packets, using a per-packet length taken from device-supplied data. That length is only bounded by GL_MAX_PACKET_LEN (1514); it is never compared against how many bytes were actually received.
A malicious GeneLink (GL620A) device can therefore send a short URB whose header claims packet_count > 1 and a first packet of up to 1514 bytes.
skb_put_data(gl_skb, packet->packet_data, size);
then copies past the end of the receive buffer and hands the adjacent slab contents up the network stack, an out-of-bounds read that leaks kernel heap. No privilege is required: the path runs in the usbnet RX softirq as soon as the interface is up.
BUG: KASAN: slab-out-of-bounds in genelink_rx_fixup (drivers/net/usb/gl620a.c:112)
Read of size 1514 at addr ffff888011309708 by task ksoftirqd/0/14
Call Trace:
...
__asan_memcpy (mm/kasan/shadow.c:105)
genelink_rx_fixup (include/linux/skbuff.h:2814 drivers/net/usb/gl620a.c:112)
usbnet_bh (drivers/net/usb/usbnet.c:572 drivers/net/usb/usbnet.c:1589)
process_one_work (kernel/workqueue.c:3322)
bh_worker (kernel/workqueue.c:3405)
tasklet_action (kernel/softirq.c:965)
handle_softirqs (kernel/softirq.c:622)
run_ksoftirqd (kernel/softirq.c:1076)
...skb_pull() already verifies that the requested length fits the buffer and returns NULL otherwise. Move it ahead of the copy and check its result, so a packet that overruns the received data is rejected before it is read. Well-formed frames, whose packets are fully present, are unaffected.
--- drivers/net/usb/gl620a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/usb/gl620a.c +3 -3
@@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)return 0 ; } +if (!skb_pull (skb, size +4 )) +return 0 ; +// allocate the skb for the individual packet gl_skb =alloc_skb (size,GFP_ATOMIC );if (gl_skb) {
@@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)// advance to the next packet packet = (struct gl_packet *)&packet->packet_data[size]; count--; - -// shift the data pointer to the next gl_packet -skb_pull (skb, size +4 ); }// skip the packet length field 4 bytes
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 379/699 tracing/events: Fix to check the simple_tsk_fn creation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit cda1fbfc5313bb90daa271d45eea4a8d317a8544 ]
Sashiko pointed that this sample code does not correctly handle the failure of thread creation because kthread_run() can return -errno.
Check the simple_tsk_fn is correctly initialized (created) or not.
--- samples/trace_events/trace-events-sample.c | 4 ++++ 1 file changed, 4 insertions(+)
samples/trace_events/trace-events-sample.c +4 -0
@@ -94,6 +94,10 @@ int foo_bar_reg(void)* for consistency sake, we still take the thread_mutex. */ simple_tsk_fn =kthread_run (simple_thread_fn,NULL ,"event-sample-fn" ); +if (IS_ERR_OR_NULL (simple_tsk_fn)) { +pr_err ("Failed to create simple_thread_fn\n" ); + simple_tsk_fn =NULL ; + } out:mutex_unlock (&thread_mutex);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 380/699 virtio_net: disable cb when NAPI is busy-polled
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Longjun Tang <[email protected]>
[ Upstream commit 1eb8fc67ca41db71c90866ff76c990d85247daef ]
When busy-poll is active, napi_schedule_prep() returns false in virtqueue_napi_schedule(), so virtqueue_disable_cb() is skipped. The device may keep firing irqs until reaches virtqueue_napi_complete(). Under load (received == budget), it will lead to a large number of spurious interrupts.
Fix it by disabling the callback at the virtnet_poll() entry. This keeps the callback off while we poll and it is re-enabled by virtqueue_napi_complete() when going idle.
--- drivers/net/virtio_net.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/virtio_net.c +3 -0
@@ -1555,6 +1555,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget)unsigned int received;unsigned int xdp_xmit =0 ; +if (budget) +virtqueue_disable_cb (rq->vq); +virtnet_poll_cleantx (rq, budget); received =virtnet_receive (rq, budget, &xdp_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 381/699 cxgb4: Fix decode strings dump for T6 adapters
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gleb Markov <[email protected]>
[ Upstream commit 5d6dc22d62682d93f5f55f145ad792f2891de911 ]
Depending on the value of chip_version, the correct decode set is selected. However, the subsequent matching with the t4 encoding type in the if-else block results in a reassignment, which leads to the loss of support for t6_decode as well as reinitializing of values t4_decode and t5_decode.
The component history shows that the if-else block previously used for this purpose, as well as the execution order, was not affected by the change.
Furthermore, it is suggested by the execution order that the scenario with overwriting and loss of support will be implemented.
Delete the if-else block.
--- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +0 -8
@@ -6767,14 +6767,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)return ; } -if (is_t4 (adapter->params.chip)) { - sge_idma_decode = (const char **)t4_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t4_decode); - }else { - sge_idma_decode = (const char **)t5_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t5_decode); - } -if (state < sge_idma_decode_nstates)CH_WARN (adapter,"idma state %s\n" , sge_idma_decode[state]);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 382/699 gpio: timberdale: Return -ENOMEM on dynamic memory allocation in probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 8d7e62d5e9b2d2ff146f472a9215d7e29c7e2307 ]
Out of memory situation on driver's probe is expected to be reported to the driver's framework with a proper -ENOMEM error code.
--- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-timberdale.c +1 -1
@@ -228,7 +228,7 @@ static int timbgpio_probe(struct platform_device *pdev) tgpio =devm_kzalloc (dev,sizeof (*tgpio),GFP_KERNEL );if (!tgpio) -return -EINVAL ; +return -ENOMEM ; tgpio->irq_base = pdata->irq_base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 383/699 net/sched: hhf: clear heavy-hitter state on reset
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit a225f8c20712713406ae47024b8df42deacddd4a ]
HHF reset does not clear the classifier state used to identify heavy hitters. Packets after reset can therefore be scheduled using flow history from before the reset.
The reset operation should return the qdisc to an empty state.
Clear the heavy-hitter classifier tables when HHF is reset.
--- net/sched/sch_hhf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
net/sched/sch_hhf.c +27 -0
@@ -461,12 +461,39 @@ static struct sk_buff *hhf_dequeue(struct Qdisc *sch)return skb; } +static void hhf_reset_classifier (struct hhf_sched_data *q) +{ +int i; + +if (!q->hh_flows) +return ; + +for (i =0 ; i <HH_FLOWS_CNT ; i++) { +struct hh_flow_state *flow, *next; +struct list_head *head = &q->hh_flows[i]; + +list_for_each_entry_safe (flow, next, head, flowchain) { +list_del (&flow->flowchain); +kfree (flow); + } + } +WRITE_ONCE (q->hh_flows_current_cnt,0 ); + +for (i =0 ; i <HHF_ARRAYS_CNT ; i++) { +if (q->hhf_valid_bits[i]) +bitmap_zero (q->hhf_valid_bits[i],HHF_ARRAYS_LEN ); + } + q->hhf_arrays_reset_timestamp =hhf_time_stamp (); +} +static void hhf_reset (struct Qdisc *sch) { +struct hhf_sched_data *q =qdisc_priv (sch);struct sk_buff *skb;while ((skb =hhf_dequeue (sch)) !=NULL )rtnl_kfree_skbs (skb, skb); +hhf_reset_classifier (q); }static void hhf_destroy (struct Qdisc *sch)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 384/699 afs: Fix error code in afs_extract_vl_addrs()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 4897cb71d4ab1f7e1a214adb1e4b80176702368d ]
The error codes on these paths are only set on the first iteration through the loop. Set the correct error code on every iteration.
--- fs/afs/vl_list.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +3 -1
@@ -95,7 +95,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, {struct afs_addr_list *alist;const u8 *b = *_b; -int ret = -EINVAL ; +int ret; alist =afs_alloc_addrlist (nr_addrs,VL_SERVICE , port);if (!alist)
@@ -113,6 +113,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV4 :if (end - b <4 ) {_leave (" = -EINVAL [short inet]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,4 );
@@ -123,6 +124,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV6 :if (end - b <16 ) {_leave (" = -EINVAL [short inet6]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,16 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 385/699 afs: Fix callback service message parsers to pass through -EAGAIN
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 0f36469d7ce98b362934113c550d08bb0c784231 ]
The AFS filesystem client uses an rxrpc server to listen for callback notifications. Each callback call type handler has a delivery function that parses the incoming request stream, and this should return -EAGAIN the last packet hasn't yet been seen, but all currently queued received data is consumed. afs_extract_data() does this, but the -EAGAIN return is switched to 0 inadvertantly
Fix callback service message parsers to pass through -EAGAIN
--- fs/afs/cmservice.c | 2 -- 1 file changed, 2 deletions(-)
fs/afs/cmservice.c +0 -2
@@ -386,7 +386,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
@@ -498,7 +497,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 386/699 afs: Fix vllist leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit fc10c0ecf06f2981af5d04357612b00051e03e9e ]
Fix a leak of the new vllist in afs_update_cell() in the event that it is an empty list (nr_servers == 0), in which case the old list isn't displaced unless the old list is also empty.
--- fs/afs/cell.c | 2 ++ 1 file changed, 2 insertions(+)
fs/afs/cell.c +2 -0
@@ -471,6 +471,8 @@ static int afs_update_cell(struct afs_cell *cell)rcu_assign_pointer (cell->vl_servers, vllist); cell->dns_source = vllist->source; old = p; + }else { + old = vllist; }write_unlock (&cell->vl_servers_lock);afs_put_vlserverlist (cell->net, old);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 387/699 afs: Fix unchecked-length string display in debug statement
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 903d37c97228258da71e092f8b4ab260ce81497d ]
Fix afs_extract_vlserver_list() to limit the length of the displayed string in a debug statement().
--- fs/afs/vl_list.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +5 -1
@@ -199,6 +199,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, b +=sizeof (*hdr);while (end - b >=sizeof (bs)) { +int nlen; + bs.name_len =afs_extract_le16 (&b); bs.priority =afs_extract_le16 (&b); bs.weight =afs_extract_le16 (&b);
@@ -208,10 +210,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, bs.protocol = *b++; bs.nr_addrs = *b++; + nlen =min3 (bs.name_len, end - b,255 ); +_debug ("extract %u %u %u %u %u %u %*.*s" , bs.name_len, bs.priority, bs.weight, bs.port, bs.protocol, bs.nr_addrs, - bs.name_len, bs.name_len, b); + bs.name_len, nlen, b);if (end - b < bs.name_len)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 388/699 ata: sata_gemini: unwind clocks on IDE pinctrl errors
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit c0ace4130e813acbabdfaa28d4e94a849c2ffdd7 ]
gemini_sata_bridge_init() prepares and enables both SATA PCLKs, then disables them again while keeping the clocks prepared for later bridge start and stop operations. If gemini_setup_ide_pins() fails after that, gemini_sata_probe() returns directly and skips the existing out_unprep_clk unwind path.
Route the IDE pinctrl failure through out_unprep_clk so the clocks prepared by gemini_sata_bridge_init() are unprepared before probe fails.
--- drivers/ata/sata_gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ata/sata_gemini.c +1 -1
@@ -391,7 +391,7 @@ static int gemini_sata_probe(struct platform_device *pdev)if (sg->ide_pins) { ret =gemini_setup_ide_pins (dev);if (ret) -return ret; + goto out_unprep_clk; }dev_info (dev,"set up the Gemini IDE/SATA nexus\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 389/699 HID: picolcd: prevent NULL pointer dereference in picolcd_send_and_wait()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Georgiy Osokin <[email protected]>
[ Upstream commit 0021eb09041f021c079be1022934a280f7f176c0 ]
In picolcd_send_and_wait(), an integer overflow of the signed loop counter 'k' can theoretically lead to a NULL pointer dereference of 'raw_data'. If the loop executes more than INT_MAX times, 'k' becomes negative, making the condition 'k < size' true even when 'size' is 0.
Change the type of 'k' to 'unsigned int' to prevent the overflow and eliminate the out-of-bounds access.
Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool.
--- drivers/hid/hid-picolcd_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hid/hid-picolcd_core.c +2 -1
@@ -72,7 +72,8 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,struct picolcd_pending *work;struct hid_report *report =picolcd_out_report (report_id, hdev);unsigned long flags; -int i, j, k; +int i, j; +unsigned int k;if (!report || !data)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 390/699 HID: core: Fix OOB read in hid_get_report for numbered reports
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit af1a9b65ebe8a948eda805c14b78d4d0767cb1b5 ]
When a caller passes a size of 0 to hid_report_raw_event() for a numbered report, the function originally called hid_get_report() before performing any size validation.
Inside hid_get_report(), if the report is numbered (report_enum->numbered is true), it unconditionally dereferences data[0] to extract the report ID. With a size of 0, this results in an out-of-bounds read or kernel panic.
Fix this by moving the numbered report size validation check before the call to hid_get_report(), ensuring that size is at least 1 before dereferencing the data pointer.
--- drivers/hid/hid-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/hid/hid-core.c +7 -0
@@ -1788,6 +1788,13 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data,u8 *cdata = data;int ret =0 ; +if (report_enum->numbered && (size <1 || bufsize <1 )) { +hid_warn_ratelimited (hid, +"Event data for numbered report is too short (%d vs %zu)\n" , + size, bufsize); +return -EINVAL ; + } + report =hid_get_report (report_enum, data);if (!report)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 391/699 net: usb: net1080: validate packet_len before pad-byte access in rx_fixup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 03f384bc0cb8d4a1301d4f5b0baef2d980258383 ]
For an even packet_len, net1080_rx_fixup() reads the pad byte at skb->data[packet_len] before the skb->len != packet_len check further down, and packet_len is only bounded against NC_MAX_PACKET. A malicious NetChip 1080 device can send a short frame advertising a large even packet_len (e.g. 0x4000), so the pad-byte read lands past the end of the skb:
BUG: KASAN: slab-out-of-bounds in net1080_rx_fixup Read of size 1 at addr ffff8880106c83c6 by task ksoftirqd/0/14 ... net1080_rx_fixup (drivers/net/usb/net1080.c:384) usbnet_bh (drivers/net/usb/usbnet.c:1589) process_one_work (kernel/workqueue.c:3322) bh_worker (kernel/workqueue.c:3708) tasklet_action (kernel/softirq.c:965) handle_softirqs (kernel/softirq.c:622) ...
Reject the frame when packet_len >= skb->len before reading.
--- drivers/net/usb/net1080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/usb/net1080.c +1 -1
@@ -381,7 +381,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)skb_trim (skb, skb->len -sizeof *trailer);if ((packet_len &0x01 ) ==0 ) { -if (skb->data [packet_len] !=PAD_BYTE ) { +if (packet_len >= skb->len || skb->data[packet_len] !=PAD_BYTE ) { dev->net->stats.rx_frame_errors++;netdev_dbg (dev->net,"bad pad\n" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 392/699 gue: validate REMCSUM private option length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qihang <[email protected]>
[ Upstream commit d335dcc6f521571d57117b8deeebc940836e5450 ]
GUE private flags can indicate that remote checksum offload metadata is present. The private flags field itself is accounted for by guehdr_flags_len(), but guehdr_priv_flags_len() currently returns 0 even when GUE_PFLAG_REMCSUM is set.
This lets a packet with only the private flags field pass validate_gue_flags(), after which gue_remcsum() and gue_gro_remcsum() read the missing REMCSUM start/offset fields from the following bytes.
Account for GUE_PLEN_REMCSUM when GUE_PFLAG_REMCSUM is present so that malformed packets are rejected during option validation.
--- include/net/gue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/net/gue.h +1 -1
@@ -77,7 +77,7 @@ static inline size_t guehdr_flags_len(__be16 flags)static inline size_t guehdr_priv_flags_len (__be32 flags) { -return 0 ; +return (flags &GUE_PFLAG_REMCSUM ) ?GUE_PLEN_REMCSUM :0 ; }/* Validate standard and private flags. Returns non-zero (meaning invalid)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 393/699 netfilter: xt_u32: reject invalid shift counts
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
[ Upstream commit 64cdf7d30ac18e43df6c48004435febb965809a8 ]
u32_match_it() executes rule-supplied shift operands on a 32-bit value. A malformed u32 rule can provide a shift count of 32 or more, triggering an undefined shift out-of-bounds during packet evaluation.
Validate XT_U32_LEFTSH and XT_U32_RIGHTSH operands in u32_mt_checkentry() and reject malformed rules before they reach the packet path.
--- net/netfilter/xt_u32.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/netfilter/xt_u32.c +11 -1
@@ -100,7 +100,7 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par) {const struct xt_u32 *data = par->matchinfo;const struct xt_u32_test *ct; -unsigned int i; +unsigned int i, j;if (data->ntests >ARRAY_SIZE (data->tests))return -EINVAL ;
@@ -111,6 +111,16 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par)if (ct->nnums >ARRAY_SIZE (ct->location) || ct->nvalues >ARRAY_SIZE (ct->value))return -EINVAL ; + +for (j =1 ; j < ct->nnums; ++j) { +switch (ct->location[j].nextop) { +case XT_U32_LEFTSH : +case XT_U32_RIGHTSH : +if (ct->location[j].number >=32 ) +return -EINVAL ; +break ; + } + } }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 394/699 netfilter: xt_rateest: fix u64 truncation in xt_rateest_mt()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Wu <[email protected]>
[ Upstream commit 444853cd438201007da5359821adcc2995655ab1 ]
On links faster than ~34 Gbps, where byte rate may exceed 2^32-1 (~ 4.3 GBps), the comparison result becomes incorrect because the truncated value no longer reflects the actual estimator rate.
Fix by changing the local variables to u64.
--- net/netfilter/xt_rateest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_rateest.c +1 -1
@@ -16,7 +16,7 @@ xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) {const struct xt_rateest_match_info *info = par->matchinfo;struct gnet_stats_rate_est64 sample = {0 }; -u_int32_t bps1, bps2, pps1, pps2; +u64 bps1, bps2, pps1, pps2;bool ret = true;gen_estimator_read (&info->est1->rate_est, &sample);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 395/699 netfilter: ip6tables: mark malformed IPv6 extension headers for hotdrop
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhixing Chen <[email protected]>
[ Upstream commit 43ccc20b5a733226417832cf16ef45322e594990 ]
The ah, hbh and rt matches check that the fixed extension header is present, then use the header length field to derive the advertised extension header length for matching.
For the ah match, add the missing advertised-length check. For hbh and rt, update the existing advertised-length checks. In all three cases, set hotdrop to true before returning false when the advertised extension header length exceeds the available skb data.
Returning false treats the packet as a rule mismatch. Set hotdrop to true and drop malformed packets so they cannot bypass rules intended to drop packets with these IPv6 extension headers.
--- net/ipv6/netfilter/ip6t_ah.c | 5 +++++ net/ipv6/netfilter/ip6t_hbh.c | 1 + net/ipv6/netfilter/ip6t_rt.c | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-)
net/ipv6/netfilter/ip6t_ah.c +5 -0
@@ -56,6 +56,11 @@ static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) } hdrlen =ipv6_authlen (ah); +if (skb->len - ptr < hdrlen) { +/* Packet smaller than its length field */ + par->hotdrop = true; +return false; + }pr_debug ("IPv6 AH LEN %u %u " , hdrlen, ah->hdrlen);pr_debug ("RES %04X " , ah->reserved);
net/ipv6/netfilter/ip6t_hbh.c +1 -0
@@ -75,6 +75,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (oh);if (skb->len - ptr < hdrlen) {/* Packet smaller than it's length field */ + par->hotdrop = true;return false; }
net/ipv6/netfilter/ip6t_rt.c +2 -1
@@ -56,7 +56,8 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (rh);if (skb->len - ptr < hdrlen) { -/* Pcket smaller than its length field */ +/* Packet smaller than its length field */ + par->hotdrop = true;return false; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 396/699 qede: fix off-by-one in BD ring consumption on build_skb failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shigeru Yoshida <[email protected]>
[ Upstream commit a0a558ca7e75b49e71f8c545c30e8c005e6e4e2f ]
qede_rx_build_skb() and qede_tpa_rx_build_skb() do not check for a NULL return from qede_build_skb(). When it returns NULL under memory pressure, the functions still consume a BD from the ring before returning NULL. The callers then recycle additional BDs, resulting in one extra BD being consumed (off-by-one). This desynchronizes the BD ring, which can corrupt DMA page reference counts and lead to SLUB freelist corruption.
Commit 4e910dbe3650 ("qede: confirm skb is allocated before using") added a NULL check inside qede_build_skb() to prevent a NULL pointer dereference, but did not address the missing NULL checks in the callers, making this off-by-one reachable.
Fix this by adding NULL checks for the return value of qede_build_skb() in both qede_rx_build_skb() and qede_tpa_rx_build_skb(), returning NULL immediately before any BD ring manipulation.
--- drivers/net/ethernet/qlogic/qede/qede_fp.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/qlogic/qede/qede_fp.c +5 -0
@@ -770,6 +770,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev,struct sk_buff *skb; skb =qede_build_skb (rxq, bd, len, pad); +if (unlikely (!skb)) +return NULL ; + bd->page_offset += rxq->rx_buf_seg_size;if (bd->page_offset ==PAGE_SIZE ) {
@@ -817,6 +820,8 @@ qede_rx_build_skb(struct qede_dev *edev, } skb =qede_build_skb (rxq, bd, len, pad); +if (unlikely (!skb)) +return NULL ;if (unlikely (qede_realloc_rx_buffer (rxq, bd))) {/* Incr page ref count to reuse on allocation failure so
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 397/699 net: qualcomm: rmnet: simplify some byte order logic
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Elder <[email protected]>
[ Upstream commit 50c62a111c4855510b0d8a2d8e50214172166b61 ]
In rmnet_map_ipv4_ul_csum_header() and rmnet_map_ipv6_ul_csum_header() the offset within a packet at which checksumming should commence is calculated. This calculation involves byte swapping and a forced type conversion that makes it hard to understand.
Simplify this by computing the offset in host byte order, then converting the result when assigning it into the header field.
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +6 -10
@@ -197,12 +197,10 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr,struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { - struct iphdr *ip4h = (struct iphdr *)iphdr; -__be16 *hdr = (__be16 *)ul_header, offset; + __be16 *hdr = (__be16 *)ul_header; +struct iphdr *ip4h = iphdr; - offset =htons ((__force u16)(skb_transport_header (skb) - - (unsigned char *)iphdr)); - ul_header->csum_start_offset = offset; + ul_header->csum_start_offset =htons (skb_network_header_len (skb)); ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled =1 ;if (ip4h->protocol ==IPPROTO_UDP )
@@ -239,12 +237,10 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { - struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr; -__be16 *hdr = (__be16 *)ul_header, offset; + __be16 *hdr = (__be16 *)ul_header; +struct ipv6hdr *ip6h = ip6hdr; - offset =htons ((__force u16)(skb_transport_header (skb) - - (unsigned char *)ip6hdr)); - ul_header->csum_start_offset = offset; + ul_header->csum_start_offset =htons (skb_network_header_len (skb)); ul_header->csum_insert_offset = skb->csum_offset; ul_header->csum_enabled =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 398/699 net: qualcomm: rmnet: kill RMNET_MAP_GET_*() accessor macros
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Elder <[email protected]>
[ Upstream commit 9d131d044f89a808f947d49f1a1865815c610158 ]
The following macros, defined in "rmnet_map.h", assume a socket buffer is provided as an argument without any real indication this is the case.
RMNET_MAP_GET_MUX_ID()
RMNET_MAP_GET_CD_BIT()
RMNET_MAP_GET_PAD()
RMNET_MAP_GET_CMD_START()
RMNET_MAP_GET_LENGTH()What they hide is pretty trivial accessing of fields in a structure, and it's much clearer to see this if we do these accesses directly.
So rather than using these accessor macros, assign a local variable of the map header pointer type to the socket buffer data pointer, and derereference that pointer variable.
In "rmnet_map_data.c", use sizeof(object) rather than sizeof(type) in one spot. Also, there's no need to byte swap 0; it's all zeros irrespective of endianness.
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 10 ++++++---- drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 12 ------------ .../net/ethernet/qualcomm/rmnet/rmnet_map_command.c | 11 ++++++++--- drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 4 ++-- 4 files changed, 16 insertions(+), 21 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +6 -4
@@ -56,20 +56,22 @@ static void __rmnet_map_ingress_handler(struct sk_buff *skb, struct rmnet_port *port) { + struct rmnet_map_header *map_header = (void *)skb->data;struct rmnet_endpoint *ep;u16 len, pad;u8 mux_id; -if (RMNET_MAP_GET_CD_BIT (skb)) { +if (map_header->cd_bit) { +/* Packet contains a MAP command (not data) */ if (port->data_format &RMNET_FLAGS_INGRESS_MAP_COMMANDS )return rmnet_map_command (skb, port); goto free_skb; } - mux_id =RMNET_MAP_GET_MUX_ID (skb); - pad =RMNET_MAP_GET_PAD (skb); - len =RMNET_MAP_GET_LENGTH (skb) - pad; + mux_id = map_header->mux_id; + pad = map_header->pad_len; + len =ntohs (map_header->pkt_len) - pad;if (mux_id >=RMNET_MAX_LOGICAL_EP ) goto free_skb;
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +0 -12
@@ -32,18 +32,6 @@ enum rmnet_map_commands { RMNET_MAP_COMMAND_ENUM_LENGTH }; -#define RMNET_MAP_GET_MUX_ID (Y ) (((struct rmnet_map_header *) \ - (Y)->data)->mux_id) -#define RMNET_MAP_GET_CD_BIT (Y ) (((struct rmnet_map_header *) \ - (Y)->data)->cd_bit) -#define RMNET_MAP_GET_PAD (Y ) (((struct rmnet_map_header *) \ - (Y)->data)->pad_len) -#define RMNET_MAP_GET_CMD_START (Y ) ((struct rmnet_map_control_command *) \ - ((Y)->data + \ - sizeof(struct rmnet_map_header))) -#define RMNET_MAP_GET_LENGTH (Y ) (ntohs(((struct rmnet_map_header *) \ - (Y)->data)->pkt_len)) -#define RMNET_MAP_COMMAND_REQUEST 0#define RMNET_MAP_COMMAND_ACK 1#define RMNET_MAP_COMMAND_UNSUPPORTED 2
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +8 -3
@@ -12,12 +12,13 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb, struct rmnet_port *port, int enable) { +struct rmnet_map_header *map_header = (void *)skb->data;struct rmnet_endpoint *ep;struct net_device *vnd;u8 mux_id;int r; - mux_id =RMNET_MAP_GET_MUX_ID (skb); + mux_id = map_header->mux_id;if (mux_id >=RMNET_MAX_LOGICAL_EP ) {kfree_skb (skb);
@@ -49,6 +50,7 @@ static void rmnet_map_send_ack(struct sk_buff *skb,unsigned char type, struct rmnet_port *port) { + struct rmnet_map_header *map_header = (void *)skb->data;struct rmnet_map_control_command *cmd;struct net_device *dev = skb->dev;
@@ -58,7 +60,8 @@ static void rmnet_map_send_ack(struct sk_buff *skb, skb->protocol =htons (ETH_P_MAP ); - cmd =RMNET_MAP_GET_CMD_START (skb); +/* Command data immediately follows the MAP header */ + cmd = (struct rmnet_map_control_command *)(map_header +1 ); cmd->cmd_type = type &0x03 ;netif_tx_lock (dev);
@@ -71,11 +74,13 @@ static void rmnet_map_send_ack(struct sk_buff *skb,*/ void rmnet_map_command (struct sk_buff *skb,struct rmnet_port *port) { +struct rmnet_map_header *map_header = (void *)skb->data;struct rmnet_map_control_command *cmd;unsigned char command_name;unsigned char rc =0 ; - cmd =RMNET_MAP_GET_CMD_START (skb); +/* Command data immediately follows the MAP header */ + cmd = (struct rmnet_map_control_command *)(map_header +1 ); command_name = cmd->command_name;switch (command_name) {
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +2 -2
@@ -315,7 +315,7 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,return NULL ; maph = (struct rmnet_map_header *)skb->data; - packet_len =ntohs (maph->pkt_len) +sizeof (struct rmnet_map_header ); + packet_len =ntohs (maph->pkt_len) +sizeof (*maph);if (port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV4 ) packet_len +=sizeof (struct rmnet_map_dl_csum_trailer );
@@ -324,7 +324,7 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,return NULL ;/* Some hardware can send us empty frames. Catch them */ -if (ntohs (maph->pkt_len) ==0 ) +if (!maph->pkt_len)return NULL ; skbn =alloc_skb (packet_len +RMNET_MAP_DEAGGR_SPACING ,GFP_ATOMIC );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 399/699 net: qualcomm: rmnet: use masks instead of C bit-fields
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Elder <[email protected]>
[ Upstream commit 16653c16d282e768763b2e8cc78f75df8fd53992 ]
The actual layout of bits defined in C bit-fields (e.g. int foo : 3) is implementation-defined. Structures defined in <linux/if_rmnet.h> address this by specifying all bit-fields twice, to cover two possible layouts.
I think this pattern is repetitive and noisy, and I find the whole notion of compiler "bitfield endianness" to be non-intuitive.
Stop using C bit-fields for the command/data flag and the pad length fields in the rmnet_map structure, and define a single-byte flags field instead. Define a mask for the single-bit "command" flag, and another mask for the encoded pad length. The content of both fields can be accessed using a simple bitwise AND operation.
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 4 ++-- .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 4 +++- include/linux/if_rmnet.h | 23 ++++++++----------- 3 files changed, 15 insertions(+), 16 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +2 -2
@@ -61,7 +61,7 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,u16 len, pad;u8 mux_id; -if (map_header->cd_bit) { +if (map_header->flags &MAP_CMD_FLAG ) {/* Packet contains a MAP command (not data) */ if (port->data_format &RMNET_FLAGS_INGRESS_MAP_COMMANDS )return rmnet_map_command (skb, port);
@@ -70,7 +70,7 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, } mux_id = map_header->mux_id; - pad = map_header->pad_len; + pad = map_header->flags &MAP_PAD_LEN_MASK ; len =ntohs (map_header->pkt_len) - pad;if (mux_id >=RMNET_MAX_LOGICAL_EP )
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +3 -1
@@ -280,6 +280,7 @@ struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,return map_header; } +BUILD_BUG_ON (MAP_PAD_LEN_MASK <3 ); padding =ALIGN (map_datalen,4 ) - map_datalen;if (padding ==0 )
@@ -293,7 +294,8 @@ struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb, done: map_header->pkt_len =htons (map_datalen + padding); - map_header->pad_len = padding &0x3F ; +/* This is a data packet, so the CMD bit is 0 */ + map_header->flags = padding &MAP_PAD_LEN_MASK ;return map_header; }
include/linux/if_rmnet.h +10 -13
@@ -6,21 +6,18 @@#define _LINUX_IF_RMNET_H_struct rmnet_map_header { -#if defined(__LITTLE_ENDIAN_BITFIELD) -u8 pad_len:6 ; -u8 reserved_bit:1 ; -u8 cd_bit:1 ; -#elif defined (__BIG_ENDIAN_BITFIELD) -u8 cd_bit:1 ; -u8 reserved_bit:1 ; -u8 pad_len:6 ; -#else -#error "Please fix <asm/byteorder.h>" -#endif -u8 mux_id; -__be16 pkt_len; +u8 flags;/* MAP_CMD_FLAG, MAP_PAD_LEN_MASK */ +u8 mux_id; +__be16 pkt_len;/* Length of packet, including pad */ }__aligned(1) ; +/* rmnet_map_header flags field: +* PAD_LEN: number of pad bytes following packet data +* CMD: 1 = packet contains a MAP command; 0 = packet contains data +*/ +#define MAP_PAD_LEN_MASK GENMASK(5, 0) +#define MAP_CMD_FLAG BIT(7) +struct rmnet_map_dl_csum_trailer {u8 reserved1;#if defined(__LITTLE_ENDIAN_BITFIELD)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 400/699 net: qualcomm: rmnet: dont use C bit-fields in rmnet checksum header
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Elder <[email protected]>
[ Upstream commit 86ca860e12ec0feab7d721d3b05e60fb86613540 ]
Replace the use of C bit-fields in the rmnet_map_ul_csum_header structure with a single two-byte (big endian) structure member, and use masks to encode or get values within it. The content of these fields can be accessed using simple bitwise AND and OR operations on the (host byte order) value of the new structure member.
Previously rmnet_map_ipv4_ul_csum_header() would update C bit-field values in host byte order, then forcibly fix their byte order using a combination of byte swap operations and types.
Instead, just compute the value that needs to go into the new structure member and save it with a simple byte-order conversion.
Make similar simplifications in rmnet_map_ipv6_ul_csum_header().
Finally, in rmnet_map_checksum_uplink_packet() a set of assignments zeroes every field in the upload checksum header. Replace that with a single memset() operation.
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 38 +++++++------------ include/linux/if_rmnet.h | 21 +++++----- 2 files changed, 23 insertions(+), 36 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +13 -25
@@ -197,20 +197,16 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr,struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { - __be16 *hdr = (__be16 *)ul_header; struct iphdr *ip4h = iphdr; +u16 val; - ul_header->csum_start_offset =htons (skb_network_header_len (skb)); - ul_header->csum_insert_offset = skb->csum_offset; - ul_header->csum_enabled =1 ; + val =MAP_CSUM_UL_ENABLED_FLAG ;if (ip4h->protocol ==IPPROTO_UDP ) - ul_header->udp_ind =1 ; -else - ul_header->udp_ind =0 ; + val |=MAP_CSUM_UL_UDP_FLAG ; + val |= skb->csum_offset &MAP_CSUM_UL_OFFSET_MASK ; -/* Changing remaining fields to network order */ - hdr++; - *hdr =htons ((__force u16)*hdr); + ul_header->csum_start_offset =htons (skb_network_header_len (skb)); + ul_header->csum_info =htons (val); skb->ip_summed =CHECKSUM_NONE ;
@@ -237,21 +233,16 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,struct rmnet_map_ul_csum_header *ul_header, struct sk_buff *skb) { - __be16 *hdr = (__be16 *)ul_header; struct ipv6hdr *ip6h = ip6hdr; +u16 val; - ul_header->csum_start_offset =htons (skb_network_header_len (skb)); - ul_header->csum_insert_offset = skb->csum_offset; - ul_header->csum_enabled =1 ; - + val =MAP_CSUM_UL_ENABLED_FLAG ;if (ip6h->nexthdr ==IPPROTO_UDP ) - ul_header->udp_ind =1 ; -else - ul_header->udp_ind =0 ; + val |=MAP_CSUM_UL_UDP_FLAG ; + val |= skb->csum_offset &MAP_CSUM_UL_OFFSET_MASK ; -/* Changing remaining fields to network order */ - hdr++; - *hdr =htons ((__force u16)*hdr); + ul_header->csum_start_offset =htons (skb_network_header_len (skb)); + ul_header->csum_info =htons (val); skb->ip_summed =CHECKSUM_NONE ;
@@ -419,10 +410,7 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, } sw_csum: - ul_header->csum_start_offset =0 ; - ul_header->csum_insert_offset =0 ; - ul_header->csum_enabled =0 ; - ul_header->udp_ind =0 ; +memset (ul_header,0 ,sizeof (*ul_header)); priv->stats.csum_sw++; }
include/linux/if_rmnet.h +10 -11
@@ -36,17 +36,16 @@ struct rmnet_map_dl_csum_trailer {struct rmnet_map_ul_csum_header {__be16 csum_start_offset; -#if defined(__LITTLE_ENDIAN_BITFIELD) -u16 csum_insert_offset:14 ; -u16 udp_ind:1 ; -u16 csum_enabled:1 ; -#elif defined (__BIG_ENDIAN_BITFIELD) -u16 csum_enabled:1 ; -u16 udp_ind:1 ; -u16 csum_insert_offset:14 ; -#else -#error "Please fix <asm/byteorder.h>" -#endif +__be16 csum_info;/* MAP_CSUM_UL_* */ }__aligned(1) ; +/* csum_info field: +* OFFSET: where (offset in bytes) to insert computed checksum +* UDP: 1 = UDP checksum (zero checkum means no checksum) +* ENABLED: 1 = checksum computation requested +*/ +#define MAP_CSUM_UL_OFFSET_MASK GENMASK(13, 0) +#define MAP_CSUM_UL_UDP_FLAG BIT(14) +#define MAP_CSUM_UL_ENABLED_FLAG BIT(15) +#endif /* !(_LINUX_IF_RMNET_H_) */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 401/699 net: ethernet: rmnet: Support for ingress MAPv5 checksum offload
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sharath Chandra Vurukala <[email protected]>
[ Upstream commit e1d9a90a9bfdb0735062d3adb16b07314b4b7b01 ]
Adding support for processing of MAPv5 downlink packets. It involves parsing the Mapv5 packet and checking the csum header to know whether the hardware has validated the checksum and is valid or not.
Based on the checksum valid bit the corresponding stats are incremented and skb->ip_summed is marked either CHECKSUM_UNNECESSARY or left as CHEKSUM_NONE to let network stack revalidate the checksum and update the respective snmp stats.
Current MAPV1 header has been modified, the reserved field in the Mapv1 header is now used for next header indication.
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 17 ++++-- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 3 +- .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 57 ++++++++++++++++++- include/linux/if_rmnet.h | 30 +++++++++- include/uapi/linux/if_link.h | 1 + 5 files changed, 96 insertions(+), 12 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +11 -6
@@ -1,5 +1,5 @@// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved. * * RMNET Data ingress/egress handler */
@@ -82,11 +82,16 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, skb->dev = ep->egress_dev; -/* Subtract MAP header */ -skb_pull (skb,sizeof (struct rmnet_map_header )); -rmnet_set_skb_proto (skb); - -if (port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV4 ) { +if ((port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV5 ) && + (map_header->flags &MAP_NEXT_HEADER_FLAG )) { +if (rmnet_map_process_next_hdr_packet (skb, len)) + goto free_skb; +skb_pull (skb,sizeof (*map_header)); +rmnet_set_skb_proto (skb); + }else if (port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV4 ) { +/* Subtract MAP header */ +skb_pull (skb,sizeof (*map_header)); +rmnet_set_skb_proto (skb);if (!rmnet_map_checksum_downlink_packet (skb, len + pad)) skb->ip_summed =CHECKSUM_UNNECESSARY ; }
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +2 -1
@@ -1,5 +1,5 @@/* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved. */ #ifndef _RMNET_MAP_H_
@@ -48,5 +48,6 @@ void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port);int rmnet_map_checksum_downlink_packet (struct sk_buff *skb,u16 len);void rmnet_map_checksum_uplink_packet (struct sk_buff *skb,struct net_device *orig_dev); +int rmnet_map_process_next_hdr_packet (struct sk_buff *skb,u16 len);#endif /* _RMNET_MAP_H_ */
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +55 -2
91 lines not on this page · raw message
include/linux/if_rmnet.h +27 -3
@@ -1,5 +1,5 @@/* SPDX-License-Identifier: GPL-2.0-only -* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +* Copyright (c) 2013-2019, 2021 The Linux Foundation. All rights reserved. */ #ifndef _LINUX_IF_RMNET_H_
@@ -12,10 +12,12 @@ struct rmnet_map_header { }__aligned(1) ;/* rmnet_map_header flags field: -* PAD_LEN: number of pad bytes following packet data -* CMD: 1 = packet contains a MAP command; 0 = packet contains data +* PAD_LEN: number of pad bytes following packet data +* CMD: 1 = packet contains a MAP command; 0 = packet contains data +* NEXT_HEADER: 1 = packet contains V5 CSUM header 0 = no V5 CSUM header */ #define MAP_PAD_LEN_MASK GENMASK(5, 0) +#define MAP_NEXT_HEADER_FLAG BIT(6)#define MAP_CMD_FLAG BIT(7)struct rmnet_map_dl_csum_trailer {
@@ -48,4 +50,26 @@ struct rmnet_map_ul_csum_header {#define MAP_CSUM_UL_UDP_FLAG BIT(14)#define MAP_CSUM_UL_ENABLED_FLAG BIT(15) +/* MAP CSUM headers */ +struct rmnet_map_v5_csum_header { +u8 header_info; +u8 csum_info; +__be16 reserved; +}__aligned(1) ; + +/* v5 header_info field +* NEXT_HEADER: represents whether there is any next header +* HEADER_TYPE: represents the type of this header +* +* csum_info field +* CSUM_VALID_OR_REQ: +* 1 = for UL, checksum computation is requested. +* 1 = for DL, validated the checksum and has found it valid +*/ + +#define MAPV5_HDRINFO_NXT_HDR_FLAG BIT(0) +#define MAPV5_HDRINFO_HDR_TYPE_FMASK GENMASK(7, 1) +#define MAPV5_CSUMINFO_VALID_FLAG BIT(7) + +#define RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD 2#endif /* !(_LINUX_IF_RMNET_H_) */
include/uapi/linux/if_link.h +1 -0
@@ -1232,6 +1232,7 @@ enum {#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3) +#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5 (1U << 4)enum {IFLA_RMNET_UNSPEC ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 402/699 net: qualcomm: rmnet: add tx packets aggregation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniele Palmas <[email protected]>
[ Upstream commit 64b5d1f8f2d1b3f039cfb0dd8035892015543e58 ]
Add tx packets aggregation.
Bidirectional TCP throughput tests through iperf with low-cat Thread-x based modems revelead performance issues both in tx and rx.
The Windows driver does not show this issue: inspecting USB packets revealed that the only notable change is the driver enabling tx packets aggregation.
Tx packets aggregation is by default disabled and can be enabled by increasing the value of ETHTOOL_A_COALESCE_TX_MAX_AGGR_FRAMES.
The maximum aggregated size is by default set to a reasonably low value in order to support the majority of modems.
This implementation is based on patches available in Code Aurora repositories (msm kernel) whose main authors are
Subash Abhinov Kasiviswanathan <[email protected]> Sean Tranchetti <[email protected]>
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../ethernet/qualcomm/rmnet/rmnet_config.c | 5 + .../ethernet/qualcomm/rmnet/rmnet_config.h | 20 ++ .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 18 +- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 6 + .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 191 ++++++++++++++++++ .../net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 9 +- .../net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 1 + 7 files changed, 246 insertions(+), 4 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +5 -0
@@ -12,6 +12,7 @@#include "rmnet_handlers.h" #include "rmnet_vnd.h" #include "rmnet_private.h" +#include "rmnet_map.h" /* Local Definitions and Declarations */
@@ -39,6 +40,8 @@ static int rmnet_unregister_real_device(struct net_device *real_dev)if (port->nr_rmnet_devs)return -EINVAL ; +rmnet_map_tx_aggregate_exit (port); +netdev_rx_handler_unregister (real_dev);kfree (port);
@@ -79,6 +82,8 @@ static int rmnet_register_real_device(struct net_device *real_dev,for (entry =0 ; entry <RMNET_MAX_LOGICAL_EP ; entry++)INIT_HLIST_HEAD (&port->muxed_ep[entry]); +rmnet_map_tx_aggregate_init (port); +netdev_dbg (real_dev,"registered with rmnet\n" );return 0 ; }
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +20 -0
@@ -5,6 +5,7 @@*/ #include <linux/skbuff.h> +#include <linux/time.h> #include <net/gro_cells.h> #ifndef _RMNET_CONFIG_H_
@@ -19,6 +20,12 @@ struct rmnet_endpoint {struct rcu_head rcu; }; +struct rmnet_egress_agg_params { +u32 bytes; +u32 count; +u64 time_nsec; +}; +/* One instance of this structure is instantiated for each real_dev associated * with rmnet. */
@@ -30,6 +37,19 @@ struct rmnet_port {struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP ];struct net_device *bridge_ep;struct net_device *rmnet_dev; + +/* Egress aggregation information */ +struct rmnet_egress_agg_params egress_agg_params; +/* Protect aggregation related elements */ +spinlock_t agg_lock; +struct sk_buff *skbagg_head; +struct sk_buff *skbagg_tail; +int agg_state; +u8 agg_count; +struct timespec64 agg_time; +struct timespec64 agg_last; +struct hrtimer hrtimer; +struct work_struct agg_wq; };extern struct rtnl_link_ops rmnet_link_ops;
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +16 -2
@@ -158,8 +158,18 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, map_header->mux_id = mux_id; - skb->protocol =htons (ETH_P_MAP ); +if (READ_ONCE (port->egress_agg_params.count) >1 ) { +unsigned int len; + + len =rmnet_map_tx_aggregate (skb, port, orig_dev); +if (likely (len)) { +rmnet_vnd_tx_fixup_len (len, orig_dev); +return -EINPROGRESS ; + } +return -ENOMEM ; + } + skb->protocol =htons (ETH_P_MAP );return 0 ; }
@@ -224,6 +234,7 @@ void rmnet_egress_handler(struct sk_buff *skb)struct rmnet_port *port;struct rmnet_priv *priv;u8 mux_id; +int err;sk_pacing_shift_update (skb->sk,8 );
@@ -236,8 +247,11 @@ void rmnet_egress_handler(struct sk_buff *skb)if (!port) goto drop; -if (rmnet_map_egress_handler (skb, port, mux_id, orig_dev)) + err =rmnet_map_egress_handler (skb, port, mux_id, orig_dev); +if (err == -ENOMEM ) goto drop; +else if (err == -EINPROGRESS ) +return ;rmnet_vnd_tx_fixup (skb, orig_dev);
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +6 -0
@@ -49,5 +49,11 @@ int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len);void rmnet_map_checksum_uplink_packet (struct sk_buff *skb,struct net_device *orig_dev);int rmnet_map_process_next_hdr_packet (struct sk_buff *skb,u16 len); +unsigned int rmnet_map_tx_aggregate (struct sk_buff *skb,struct rmnet_port *port, +struct net_device *orig_dev); +void rmnet_map_tx_aggregate_init (struct rmnet_port *port); +void rmnet_map_tx_aggregate_exit (struct rmnet_port *port); +void rmnet_map_update_ul_agg_config (struct rmnet_port *port,u32 size, +u32 count,u32 time);#endif /* _RMNET_MAP_H_ */
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +191 -0
200 lines not on this page · raw message
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +7 -2
@@ -28,7 +28,7 @@ void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev)u64_stats_update_end (&pcpu_ptr->syncp); } -void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev) +void rmnet_vnd_tx_fixup_len (unsigned int len,struct net_device *dev) {struct rmnet_priv *priv =netdev_priv (dev);struct rmnet_pcpu_stats *pcpu_ptr;
@@ -37,10 +37,15 @@ void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev)u64_stats_update_begin (&pcpu_ptr->syncp); pcpu_ptr->stats.tx_pkts++; - pcpu_ptr->stats.tx_bytes += skb->len; + pcpu_ptr->stats.tx_bytes += len;u64_stats_update_end (&pcpu_ptr->syncp); } +void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev) +{ +rmnet_vnd_tx_fixup_len (skb->len, dev); +} +/* Network Device Operations */ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h +1 -0
@@ -16,6 +16,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,int rmnet_vnd_dellink (u8 id,struct rmnet_port *port,struct rmnet_endpoint *ep);void rmnet_vnd_rx_fixup (struct sk_buff *skb,struct net_device *dev); +void rmnet_vnd_tx_fixup_len (unsigned int len,struct net_device *dev);void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev);void rmnet_vnd_setup (struct net_device *dev);int rmnet_vnd_validate_real_dev_mtu (struct net_device *real_dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 403/699 net: qualcomm: rmnet: validate MAP frame length before ingress parsing
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit f0f1887a9e30712a1df03e152dce6fb91344b1f3 ]
When ingress deaggregation is disabled, rmnet_map_ingress_handler() passes the skb straight to __rmnet_map_ingress_handler(), skipping the length validation that rmnet_map_deaggregate() performs on the aggregated path. The parser then dereferences the MAP header and csum header/trailer based on the on-wire pkt_len without checking skb->len, so a short frame is read out of bounds:
BUG: KASAN: slab-out-of-bounds in rmnet_map_checksum_downlink_packet Read of size 1 at addr ffff88801118ed00 by task exploit/147 Call Trace: ... rmnet_map_checksum_downlink_packet (drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c:413) __rmnet_map_ingress_handler (drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:96) rmnet_rx_handler (drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:129) __netif_receive_skb_core.constprop.0 (net/core/dev.c:6089) netif_receive_skb (net/core/dev.c:6460) tun_get_user (drivers/net/tun.c:1955) tun_chr_write_iter (drivers/net/tun.c:2001) vfs_write (fs/read_write.c:688) ksys_write (fs/read_write.c:740) do_syscall_64 (arch/x86/entry/syscall_64.c:94) ...
Factor that validation out of rmnet_map_deaggregate() into rmnet_map_validate_packet_len() and run it on the no-aggregation path too. The MAP header is bounds-checked first, since this path can receive a frame shorter than the header.
--- .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 5 +- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 1 + .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 72 ++++++++++--------- 3 files changed, 45 insertions(+), 33 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +4 -1
@@ -125,7 +125,10 @@ rmnet_map_ingress_handler(struct sk_buff *skb,consume_skb (skb); }else { -__rmnet_map_ingress_handler (skb, port); +if (rmnet_map_validate_packet_len (skb, port)) +__rmnet_map_ingress_handler (skb, port); +else +kfree_skb (skb); } }
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +1 -0
@@ -55,5 +55,6 @@ void rmnet_map_tx_aggregate_init(struct rmnet_port *port);void rmnet_map_tx_aggregate_exit (struct rmnet_port *port);void rmnet_map_update_ul_agg_config (struct rmnet_port *port,u32 size,u32 count,u32 time); +u32 rmnet_map_validate_packet_len (struct sk_buff *skb,struct rmnet_port *port);#endif /* _RMNET_MAP_H_ */
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +40 -32
94 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 404/699 net/smc: fix UAF in smc_cdc_rx_handler() by pinning the socket
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 9d160b35cc34a2ba8229d07651468a7848325135 ]
smc_cdc_rx_handler() looks up the connection by token under the link group's conns_lock, drops the lock, and then dereferences conn and the smc_sock derived from it, ending in sock_hold(&smc->sk) inside smc_cdc_msg_recv(). No reference is held across the lock release.
The only reference pinning the socket while the connection is discoverable in the link group is taken in smc_lgr_register_conn() (sock_hold) and dropped in __smc_lgr_unregister_conn() (sock_put), both under conns_lock. Once the handler drops conns_lock, a concurrent close() -> smc_release() -> smc_conn_free() -> smc_lgr_unregister_conn() can drop that reference and free the smc_sock, so the handler's later sock_hold() runs on freed memory:
WARNING: lib/refcount.c:25 at refcount_warn_saturate Workqueue: rxe_wq do_work refcount_warn_saturate (lib/refcount.c:25) smc_cdc_msg_recv (net/smc/smc_cdc.c:430) smc_cdc_rx_handler (net/smc/smc_cdc.c:502) smc_wr_rx_tasklet_fn (net/smc/smc_wr.c:445) tasklet_action_common (kernel/softirq.c:938) handle_softirqs (kernel/softirq.c:622) Kernel panic - not syncing: panic_on_warn set
Only SMC-R is affected. The SMC-D receive tasklet is stopped by tasklet_kill(&conn->rx_tsklet) in smc_conn_free() before the connection is unregistered, so it cannot run concurrently with the free.
Take the socket reference while still holding conns_lock, so the registration reference can no longer be the last one, and drop it once the handler is done.
--- net/smc/smc_cdc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
net/smc/smc_cdc.c +10 -5
@@ -423,9 +423,9 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) {struct smc_link *link = (struct smc_link *)wc->qp->qp_context;struct smc_cdc_msg *cdc = buf; +struct smc_sock *smc =NULL ;struct smc_connection *conn;struct smc_link_group *lgr; -struct smc_sock *smc;if (wc->byte_len < offsetof(struct smc_cdc_msg , reserved))return ;/* short message */
@@ -436,21 +436,26 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) lgr =smc_get_lgr (link);read_lock_bh (&lgr->conns_lock); conn =smc_lgr_find_conn (ntohl (cdc->token), lgr); -read_unlock_bh (&lgr->conns_lock); -if (!conn || conn->out_of_sync) +if (!conn || conn->out_of_sync) { +read_unlock_bh (&lgr->conns_lock);return ; + } smc = container_of(conn, struct smc_sock, conn); +sock_hold (&smc->sk); +read_unlock_bh (&lgr->conns_lock);if (cdc->prod_flags.failover_validation) {smc_cdc_msg_validate (smc, cdc, link); -return ; + goto out; }if (smc_cdc_before (ntohs (cdc->seqno), conn->local_rx_ctrl.seqno))/* received seqno is old */ -return ; + goto out;smc_cdc_msg_recv (smc, cdc); +out: +sock_put (&smc->sk); }static struct smc_wr_rx_handler smc_cdc_rx_handlers[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 405/699 Bluetooth: ISO: exclude RFU bits from ISO_SDU_Length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit fd076d8deeab6f9f18ef13400f89e1f550df665b ]
slen contains ISO_SDU_Length (12 bits), RFU (2 bits), Packet_Status_Flags (2 bits).
Exclude the RFU bits from hci_iso_data_len. Also add masks to the pack macro.
--- include/net/bluetooth/hci.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
include/net/bluetooth/hci.h +3 -2
@@ -2538,8 +2538,9 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)#define hci_iso_flags_pack (pb, ts) ((pb & 0x03) | ((ts & 0x01) << 2))/* ISO data length and flags pack/unpack */ -#define hci_iso_data_len_pack (h, f) ((__u16) ((h) | ((f) << 14))) -#define hci_iso_data_len (h) ((h) & 0x3fff) +#define hci_iso_data_len_pack (h, f) ((__u16) (((h) & 0x0fff) | \ + (((f) & 0x3) << 14))) +#define hci_iso_data_len (h) ((h) & 0x0fff)#define hci_iso_data_flags (h) ((h) >> 14)/* le24 support */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 406/699 Bluetooth: bpa10x: avoid OOB read of revision string in bpa10x_setup()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit dd068ef044128db655f48323a4acfd5907e04903 ]
bpa10x_setup() sends the vendor command 0xfc0e and passes the response to bt_dev_info() and hci_set_fw_info() as a "%s" string starting at skb->data + 1, without checking the length:
bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); hci_set_fw_info(hdev, "%s", skb->data + 1);
A device that returns a one-byte response (status only) leaves skb->data + 1 past the end of the data, and the %s walk reads adjacent slab memory until it meets a NUL. The same happens when the payload is not NUL-terminated within skb->len. The out-of-bounds bytes end up in the kernel log and the firmware-info debugfs file.
Print the revision string with a bounded "%.*s" limited to skb->len - 1 instead. This keeps the string readable for well-behaved devices while never reading past the received data, and does not fail setup, so a device returning a short or unterminated response keeps working.
--- drivers/bluetooth/bpa10x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/bluetooth/bpa10x.c +6 -2
@@ -254,9 +254,13 @@ static int bpa10x_setup(struct hci_dev *hdev)if (IS_ERR (skb))return PTR_ERR (skb); -bt_dev_info (hdev,"%s" , (char *)(skb->data +1 )); +/* Bounded print: the device controls skb->len. */ +if (skb->len >1 ) { +int len = skb->len -1 ; -hci_set_fw_info (hdev,"%s" , skb->data +1 ); +bt_dev_info (hdev,"%.*s" , len, (char *)(skb->data +1 )); +hci_set_fw_info (hdev,"%.*s" , len, skb->data +1 ); + }kfree_skb (skb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 407/699 ring-buffer: Fix event length with forced 8-byte alignment
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Wang <[email protected]>
[ Upstream commit c37e0a4b79a6bbb96ce5ffe279d7c001e20529e0 ]
When RB_FORCE_8BYTE_ALIGNMENT is true, rb_calculate_event_length() reserves the space of event->array[0] for placing the data length and rb_update_event() stores the data length in event->array[0] accordingly. As a result the whole event length will add extra 4 bytes for sizeof(event.array[0]) unconditionally.
But ring_buffer_event_length() only subtracts the sizeof(event->array[0]) for events larger than RB_MAX_SMALL_DATA + sizeof(event->array[0]). As a result, small events on architectures with RB_FORCE_8BYTE_ALIGNMENT=true report a data length that is 4 bytes larger than expected.
To fix it, add the RB_FORCE_8BYTE_ALIGNMENT as a condition to subtract the size of that length field whenever RB_FORCE_8BYTE_ALIGNMENT is true.
This issue is observed in a riscv64 kernel with CONFIG_HAVE_64BIT_ALIGNED_ACCESS set to y, when we run ftrace selftest trace_marker_raw.tc, we get the weird log: for cases where the id is 1..100, the number of data field is 8*N, but once id exceeds 100, the number of data field becomes 8*N+4:
# 1 buf: 58 00 00 00 80 5e d1 63 (number of data field is 8*1)
...
# a buf: 58 ... (number of data field is 8*2) ... # 64 buf: 58 ... (number of data field is 8*13) # 65 buf: 58 ... (number of data field is 8*13+4)
After applying this change, the number of data field keeps being 8*N+4 consistently.
--- kernel/trace/ring_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +2 -1
@@ -246,7 +246,8 @@ unsigned ring_buffer_event_length(struct ring_buffer_event *event)if (event->type_len >RINGBUF_TYPE_DATA_TYPE_LEN_MAX )return length; length -=RB_EVNT_HDR_SIZE ; -if (length >RB_MAX_SMALL_DATA +sizeof (event->array[0 ])) +if (length >RB_MAX_SMALL_DATA +sizeof (event->array[0 ]) || +RB_FORCE_8BYTE_ALIGNMENT ) length -=sizeof (event->array[0 ]);return length; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 408/699 net: usb: lan78xx: disable VLAN filter in promiscuous mode
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Enrico Pozzobon <[email protected]>
[ Upstream commit 60444706aa17616efc03190d099ac347e28b3d0a ]
The hardware VLAN filter (RFE_CTL_VLAN_FILTER_) drops VLAN-tagged frames whose VID has not been registered via lan78xx_vlan_rx_add_vid(). It is left enabled in promiscuous mode, so packet capture (e.g. tcpdump or Wireshark) does not see tagged frames for unregistered VIDs.
Clear the filter while the interface is promiscuous and restore it from NETIF_F_HW_VLAN_CTAG_FILTER otherwise. Enforce the same condition in lan78xx_set_features() so netdev_update_features() cannot re-enable the filter while promiscuous.
--- drivers/net/usb/lan78xx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/net/usb/lan78xx.c +14 -4
@@ -1092,6 +1092,17 @@ static void lan78xx_deferred_multicast_write(struct work_struct *param)lan78xx_write_reg (dev,RFE_CTL , pdata->rfe_ctl); } +static void lan78xx_update_vlan_filter (struct lan78xx_priv *pdata, +struct net_device *netdev, +netdev_features_t features) +{ +if ((features &NETIF_F_HW_VLAN_CTAG_FILTER ) && + !(netdev->flags &IFF_PROMISC )) + pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ; +else + pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_ ; +} +static void lan78xx_set_multicast (struct net_device *netdev) {struct lan78xx_net *dev =netdev_priv (netdev);
@@ -1126,6 +1137,8 @@ static void lan78xx_set_multicast(struct net_device *netdev) } } +lan78xx_update_vlan_filter (pdata, dev->net, dev->net->features); +if (netdev_mc_count (dev->net)) {struct netdev_hw_addr *ha;int i;
@@ -2397,10 +2410,7 @@ static int lan78xx_set_features(struct net_device *netdev,else pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_ ; -if (features &NETIF_F_HW_VLAN_CTAG_FILTER ) - pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ; -else - pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_ ; +lan78xx_update_vlan_filter (pdata, netdev, features);spin_unlock_irqrestore (&pdata->rfe_ctl_lock, flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 409/699 net/sched: cake: reject overhead values that underflow length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit b7f97cae7ec1b6c3c32843c42be218690d310467 ]
CAKE accepts signed overhead values and stores them in an s16, but the adjusted packet length calculation uses unsigned arithmetic. A negative effective length can therefore wrap to a large value.
Such configurations make rate accounting depend on integer wraparound rather than on the packet size userspace intended to model. A static netlink lower bound is not enough because packets reaching CAKE can be smaller than any reasonable manual-overhead allowance.
Fold the signed overhead adjustment into the existing datapath MPU clamp so negative adjusted lengths are clamped before link-layer framing adjustments.
--- net/sched/sch_cake.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
net/sched/sch_cake.c +1 -4
@@ -1381,10 +1381,7 @@ static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)if (q->min_netlen > len) q->min_netlen = len; - len += q->rate_overhead; - -if (len < q->rate_mpu) - len = q->rate_mpu; + len =max ((s32 )len + q->rate_overhead, (s32 )q->rate_mpu);if (q->atm_mode ==CAKE_ATM_ATM ) { len +=47 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 410/699 mld: convert from timer to delayed work
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit 2d9a93b4902be6a5504b5941dd15e9cd776aadca ]
mcast.c has several timers for delaying works.
Timer's expire handler is working under atomic context so it can't use sleepable things such as GFP_KERNEL, mutex, etc.
In order to use sleepable APIs, it converts from timers to delayed work. But there are some critical sections, which is used by both process and BH context. So that it still uses spin_lock_bh() and rwlock.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 8 +-- net/ipv6/mcast.c | 140 +++++++++++++++++++++++------------------ 2 files changed, 83 insertions(+), 65 deletions(-)
include/net/if_inet6.h +4 -4
@@ -124,7 +124,7 @@ struct ifmcaddr6 {unsigned int mca_sfmode;unsigned char mca_crcount;unsigned long mca_sfcount[2 ]; -struct timer_list mca_timer; +struct delayed_work mca_work;unsigned int mca_flags;int mca_users;refcount_t mca_refcnt;
@@ -183,9 +183,9 @@ struct inet6_dev {unsigned long mc_qri;/* Query Response Interval */ unsigned long mc_maxdelay; -struct timer_list mc_gq_timer;/* general query timer */ -struct timer_list mc_ifc_timer;/* interface change timer */ -struct timer_list mc_dad_timer;/* dad complete mc timer */ +struct delayed_work mc_gq_work;/* general query work */ +struct delayed_work mc_ifc_work;/* interface change work */ +struct delayed_work mc_dad_work;/* dad complete mc work */ struct ifacaddr6 *ac_list;rwlock_t lock;
net/ipv6/mcast.c +79 -61
350 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 411/699 mld: get rid of inet6_dev->mc_lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit cf2ce339b401bc53ee131f0ce38bae32a949925e ]
The purpose of mc_lock is to protect inet6_dev->mc_tomb. But mc_tomb is already protected by RTNL and all functions, which manipulate mc_tomb are called under RTNL.
So, mc_lock is not needed.
Furthermore, it is spinlock so the critical section is atomic. In order to reduce atomic context, it should be removed.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 1 - net/ipv6/mcast.c | 9 --------- 2 files changed, 10 deletions(-)
include/net/if_inet6.h +0 -1
@@ -171,7 +171,6 @@ struct inet6_dev {struct ifmcaddr6 *mc_list;struct ifmcaddr6 *mc_tomb; -spinlock_t mc_lock;unsigned char mc_qrv;/* Query Robustness Variable */ unsigned char mc_gq_running;
net/ipv6/mcast.c +0 -9
@@ -752,10 +752,8 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) }spin_unlock_bh (&im->mca_lock); -spin_lock_bh (&idev->mc_lock); pmc->next = idev->mc_tomb; idev->mc_tomb = pmc; -spin_unlock_bh (&idev->mc_lock); }static void mld_del_delrec (struct inet6_dev *idev,struct ifmcaddr6 *im)
@@ -764,7 +762,6 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)struct ip6_sf_list *psf;struct in6_addr *pmca = &im->mca_addr; -spin_lock_bh (&idev->mc_lock); pmc_prev =NULL ;for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) {if (ipv6_addr_equal (&pmc->mca_addr, pmca))
@@ -777,7 +774,6 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)else idev->mc_tomb = pmc->next; } -spin_unlock_bh (&idev->mc_lock);spin_lock_bh (&im->mca_lock);if (pmc) {
@@ -801,10 +797,8 @@ static void mld_clear_delrec(struct inet6_dev *idev) {struct ifmcaddr6 *pmc, *nextpmc; -spin_lock_bh (&idev->mc_lock); pmc = idev->mc_tomb; idev->mc_tomb =NULL ; -spin_unlock_bh (&idev->mc_lock);for (; pmc; pmc = nextpmc) { nextpmc = pmc->next;
@@ -1904,7 +1898,6 @@ static void mld_send_cr(struct inet6_dev *idev)int type, dtype;read_lock_bh (&idev->lock); -spin_lock (&idev->mc_lock);/* deleted MCA's */ pmc_prev =NULL ;
@@ -1938,7 +1931,6 @@ static void mld_send_cr(struct inet6_dev *idev) }else pmc_prev = pmc; } -spin_unlock (&idev->mc_lock);/* change recs */ for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
@@ -2579,7 +2571,6 @@ void ipv6_mc_up(struct inet6_dev *idev)void ipv6_mc_init_dev (struct inet6_dev *idev) {write_lock_bh (&idev->lock); -spin_lock_init (&idev->mc_lock); idev->mc_gq_running =0 ;INIT_DELAYED_WORK (&idev->mc_gq_work, mld_gq_work); idev->mc_tomb =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 412/699 mld: convert ipv6_mc_socklist->sflist to RCU
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit 882ba1f73c06831f2a21044ebd8864c485ac04f2 ]
The sflist has been protected by rwlock so that the critical section is atomic context.
In order to switch this context, changing locking is needed. The sflist actually already protected by RTNL So if it's converted to use RCU, its control path context can be switched to sleepable.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 4 ++-- net/ipv6/mcast.c | 52 ++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 32 deletions(-)
include/net/if_inet6.h +2 -2
@@ -82,6 +82,7 @@ struct inet6_ifaddr {struct ip6_sf_socklist {unsigned int sl_max;unsigned int sl_count; +struct rcu_head rcu;struct in6_addr sl_addr[]; };
@@ -95,8 +96,7 @@ struct ipv6_mc_socklist {int ifindex;unsigned int sfmode;/* MCAST_{INCLUDE,EXCLUDE} */ struct ipv6_mc_socklist __rcu *next; -rwlock_t sflock; -struct ip6_sf_socklist *sflist; +struct ip6_sf_socklist __rcu *sflist;struct rcu_head rcu; };
net/ipv6/mcast.c +22 -30
138 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 413/699 mld: convert ip6_sf_list to RCU
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit 4b200e398953c237c86d32bf26d4cb2a96556a6f ]
The ip6_sf_list has been protected by mca_lock(spin_lock) so that the critical section is atomic context. In order to switch this context, changing locking is needed. The ip6_sf_list actually already protected by RTNL So if it's converted to use RCU, its control path context can be switched to sleepable.
But It doesn't remove mca_lock yet because ifmcaddr6 isn't converted to RCU yet. So, It's not fully converted to the sleepable context.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 7 +- net/ipv6/mcast.c | 200 ++++++++++++++++++++++++++--------------- 2 files changed, 130 insertions(+), 77 deletions(-)
include/net/if_inet6.h +4 -3
@@ -101,12 +101,13 @@ struct ipv6_mc_socklist { };struct ip6_sf_list { -struct ip6_sf_list *sf_next; +struct ip6_sf_list __rcu *sf_next;struct in6_addr sf_addr;unsigned long sf_count[2 ];/* include/exclude counts */ unsigned char sf_gsresp;/* include in g & s response? */ unsigned char sf_oldin;/* change state */ unsigned char sf_crcount;/* retrans. left to send */ +struct rcu_head rcu; };#define MAF_TIMER_RUNNING 0x01
@@ -119,8 +120,8 @@ struct ifmcaddr6 {struct in6_addr mca_addr;struct inet6_dev *idev;struct ifmcaddr6 *next; -struct ip6_sf_list *mca_sources; -struct ip6_sf_list *mca_tomb; +struct ip6_sf_list __rcu *mca_sources; +struct ip6_sf_list __rcu *mca_tomb;unsigned int mca_sfmode;unsigned char mca_crcount;unsigned long mca_sfcount[2 ];
net/ipv6/mcast.c +126 -74
419 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 414/699 mld: convert ifmcaddr6 to RCU
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit 88e2ca3080947fe22eb520c1f8231e79a105d011 ]
The ifmcaddr6 has been protected by inet6_dev->lock(rwlock) so that the critical section is atomic context. In order to switch this context, changing locking is needed. The ifmcaddr6 actually already protected by RTNL So if it's converted to use RCU, its control path context can be switched to sleepable.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- drivers/s390/net/qeth_l3_main.c | 6 +- include/net/if_inet6.h | 7 +- net/batman-adv/multicast.c | 6 +- net/ipv6/addrconf.c | 9 +- net/ipv6/addrconf_core.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/mcast.c | 296 +++++++++++++------------------- 7 files changed, 140 insertions(+), 188 deletions(-)
drivers/s390/net/qeth_l3_main.c +3 -3
@@ -1104,8 +1104,9 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg) tmp.disp_flag =QETH_DISP_ADDR_ADD ; tmp.is_multicast =1 ; -read_lock_bh (&in6_dev->lock); -for (im6 = in6_dev->mc_list; im6 !=NULL ; im6 = im6->next) { +for (im6 =rtnl_dereference (in6_dev->mc_list); + im6; + im6 =rtnl_dereference (im6->next)) { tmp.u.a6.addr = im6->mca_addr; ipm =qeth_l3_find_addr_by_ip (card, &tmp);
@@ -1123,7 +1124,6 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg) qeth_l3_ipaddr_hash(ipm)); } -read_unlock_bh (&in6_dev->lock); out:return 0 ;
include/net/if_inet6.h +4 -3
@@ -119,7 +119,7 @@ struct ip6_sf_list {struct ifmcaddr6 {struct in6_addr mca_addr;struct inet6_dev *idev; -struct ifmcaddr6 *next; +struct ifmcaddr6 __rcu *next;struct ip6_sf_list __rcu *mca_sources;struct ip6_sf_list __rcu *mca_tomb;unsigned int mca_sfmode;
@@ -132,6 +132,7 @@ struct ifmcaddr6 {spinlock_t mca_lock;unsigned long mca_cstamp;unsigned long mca_tstamp; +struct rcu_head rcu; };/* Anycast stuff */
@@ -170,8 +171,8 @@ struct inet6_dev {struct list_head addr_list; -struct ifmcaddr6 *mc_list; -struct ifmcaddr6 *mc_tomb; +struct ifmcaddr6 __rcu *mc_list; +struct ifmcaddr6 __rcu *mc_tomb;unsigned char mc_qrv;/* Query Robustness Variable */ unsigned char mc_gq_running;
net/batman-adv/multicast.c +3 -3
@@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,return 0 ; } -read_lock_bh (&in6_dev->lock); -for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) { +for (pmc6 =rcu_dereference (in6_dev->mc_list); + pmc6; + pmc6 =rcu_dereference (pmc6->next)) {if (IPV6_ADDR_MC_SCOPE (&pmc6->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )continue ;
@@ -484,7 +485,6 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,hlist_add_head (&new->list, mcast_list); ret++; } -read_unlock_bh (&in6_dev->lock);rcu_read_unlock ();return ret;
net/ipv6/addrconf.c +5 -4
@@ -5174,17 +5174,20 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,break ; }case MULTICAST_ADDR : +read_unlock_bh (&idev->lock); fillargs->event =RTM_GETMULTICAST ;/* multicast address */ -for (ifmca = idev->mc_list; ifmca; - ifmca = ifmca->next, ip_idx++) { +for (ifmca =rcu_dereference (idev->mc_list); + ifmca; + ifmca =rcu_dereference (ifmca->next), ip_idx++) {if (ip_idx < s_ip_idx)continue ; err =inet6_fill_ifmcaddr (skb, ifmca, fillargs);if (err <0 )break ; } +read_lock_bh (&idev->lock);break ;case ANYCAST_ADDR : fillargs->event =RTM_GETANYCAST ;
@@ -6169,10 +6172,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)static void ipv6_ifa_notify (int event,struct inet6_ifaddr *ifp) { -rcu_read_lock_bh ();if (likely (ifp->idev->dead ==0 ))__ipv6_ifa_notify (event, ifp); -rcu_read_unlock_bh (); }#ifdef CONFIG_SYSCTL
net/ipv6/addrconf_core.c +1 -1
@@ -257,7 +257,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)struct net_device *dev = idev->dev;WARN_ON (!list_empty (&idev->addr_list)); -WARN_ON (idev->mc_list); +WARN_ON (rcu_access_pointer (idev->mc_list));WARN_ON (timer_pending (&idev->rs_timer));#ifdef NET_REFCNT_DEBUG
net/ipv6/af_inet6.c +1 -1
@@ -232,7 +232,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, inet->mc_loop =1 ; inet->mc_ttl =1 ; inet->mc_index =0 ; - inet->mc_list =NULL ; +RCU_INIT_POINTER (inet->mc_list,NULL ); inet->rcv_tos =0 ;if (READ_ONCE (net->ipv4.sysctl_ip_no_pmtu_disc))
net/ipv6/mcast.c +123 -173
815 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 415/699 mld: add new workqueues for process mld events
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit f185de28d9ae6c978135993769352e523ee8df06 ]
When query/report packets are received, mld module processes them. But they are processed under BH context so it couldn't use sleepable functions. So, in order to switch context, the two workqueues are added which processes query and report event.
In the struct inet6_dev, mc_{query | report}_queue are added so it is per-interface queue.
And mc_{query | report}_work are workqueue structure.
When the query or report event is received, skb is queued to proper queue and worker function is scheduled immediately. Workqueues and queues are protected by spinlock, which is mc_{query | report}_lock, and worker functions are protected by RTNL.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 9 +- include/net/mld.h | 3 + net/ipv6/icmp.c | 4 +- net/ipv6/mcast.c | 280 +++++++++++++++++++++++++++++------------ 4 files changed, 210 insertions(+), 86 deletions(-)
include/net/if_inet6.h +8 -1
@@ -129,7 +129,6 @@ struct ifmcaddr6 {unsigned int mca_flags;int mca_users;refcount_t mca_refcnt; -spinlock_t mca_lock;unsigned long mca_cstamp;unsigned long mca_tstamp;struct rcu_head rcu;
@@ -187,6 +186,14 @@ struct inet6_dev {struct delayed_work mc_gq_work;/* general query work */ struct delayed_work mc_ifc_work;/* interface change work */ struct delayed_work mc_dad_work;/* dad complete mc work */ +struct delayed_work mc_query_work;/* mld query work */ +struct delayed_work mc_report_work;/* mld report work */ + +struct sk_buff_head mc_query_queue;/* mld query queue */ +struct sk_buff_head mc_report_queue;/* mld report queue */ + +spinlock_t mc_query_lock;/* mld query queue lock */ +spinlock_t mc_report_lock;/* mld query report lock */ struct ifacaddr6 *ac_list;rwlock_t lock;
include/net/mld.h +3 -0
@@ -92,6 +92,9 @@ struct mld2_query {#define MLD_EXP_MIN_LIMIT 32768UL#define MLDV1_MRD_MAX_COMPAT (MLD_EXP_MIN_LIMIT - 1) +#define MLD_MAX_QUEUE 8 +#define MLD_MAX_SKBS 32 +static inline unsigned long mldv2_mrc (const struct mld2_query *mlh2) {/* RFC3810, 5.1.3. Maximum Response Code */
net/ipv6/icmp.c +2 -2
@@ -947,11 +947,11 @@ static int icmpv6_rcv(struct sk_buff *skb)case ICMPV6_MGM_QUERY :igmp6_event_query (skb); -break ; +return 0 ;case ICMPV6_MGM_REPORT :igmp6_event_report (skb); -break ; +return 0 ;case ICMPV6_MGM_REDUCTION :case ICMPV6_NI_QUERY :
net/ipv6/mcast.c +197 -83
712 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 416/699 mld: add mc_lock for protecting per-interface mld data
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
[ Upstream commit 63ed8de4be81b699ca727e9f8e3344bd487806d7 ]
The purpose of this lock is to avoid a bottleneck in the query/report event handler logic.
By previous patches, almost all mld data is protected by RTNL. So, the query and report event handler, which is data path logic acquires RTNL too. Therefore if a lot of query and report events are received, it uses RTNL for a long time.
So it makes the control-plane bottleneck because of using RTNL. In order to avoid this bottleneck, mc_lock is added.
mc_lock protect only per-interface mld data and per-interface mld data is used in the query/report event handler logic.
So, no longer rtnl_lock is needed in the query/report event handler logic. Therefore bottleneck will be disappeared by mc_lock.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/if_inet6.h | 1 + net/ipv6/mcast.c | 309 +++++++++++++++++++++++++---------------- 2 files changed, 194 insertions(+), 116 deletions(-)
include/net/if_inet6.h +1 -0
@@ -194,6 +194,7 @@ struct inet6_dev {spinlock_t mc_query_lock;/* mld query queue lock */ spinlock_t mc_report_lock;/* mld query report lock */ +struct mutex mc_lock;/* mld global lock */ struct ifacaddr6 *ac_list;rwlock_t lock;
net/ipv6/mcast.c +193 -116
1,024 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 417/699 ipv6: fix skb drops in igmp6_event_query() and igmp6_event_report()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 2d3916f3189172d5c69d33065c3c21119fe539fc ]
While investigating on why a synchronize_net() has been added recently in ipv6_mc_down(), I found that igmp6_event_query() and igmp6_event_report() might drop skbs in some cases.
Discussion about removing synchronize_net() from ipv6_mc_down() will happen in a different thread.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- include/net/ndisc.h | 4 ++-- net/ipv6/mcast.c | 32 ++++++++++++-------------------- 2 files changed, 14 insertions(+), 22 deletions(-)
include/net/ndisc.h +2 -2
@@ -487,9 +487,9 @@ int igmp6_late_init(void);void igmp6_cleanup (void );void igmp6_late_cleanup (void ); -int igmp6_event_query (struct sk_buff *skb); +void igmp6_event_query (struct sk_buff *skb); -int igmp6_event_report (struct sk_buff *skb); +void igmp6_event_report (struct sk_buff *skb);#ifdef CONFIG_SYSCTL
net/ipv6/mcast.c +12 -20
@@ -1371,27 +1371,23 @@ static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld, }/* called with rcu_read_lock() */ -int igmp6_event_query (struct sk_buff *skb) +void igmp6_event_query (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); -if (!idev) -return -EINVAL ; - -if (idev->dead) { -kfree_skb (skb); -return -ENODEV ; - } +if (!idev || idev->dead) + goto out;spin_lock_bh (&idev->mc_query_lock);if (skb_queue_len (&idev->mc_query_queue) <MLD_MAX_SKBS ) {__skb_queue_tail (&idev->mc_query_queue, skb);if (!mod_delayed_work (mld_wq, &idev->mc_query_work,0 ))in6_dev_hold (idev); + skb =NULL ; }spin_unlock_bh (&idev->mc_query_lock); - -return 0 ; +out: +kfree_skb (skb); }static void __mld_query_work (struct sk_buff *skb)
@@ -1544,27 +1540,23 @@ static void mld_query_work(struct work_struct *work) }/* called with rcu_read_lock() */ -int igmp6_event_report (struct sk_buff *skb) +void igmp6_event_report (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); -if (!idev) -return -EINVAL ; - -if (idev->dead) { -kfree_skb (skb); -return -ENODEV ; - } +if (!idev || idev->dead) + goto out;spin_lock_bh (&idev->mc_report_lock);if (skb_queue_len (&idev->mc_report_queue) <MLD_MAX_SKBS ) {__skb_queue_tail (&idev->mc_report_queue, skb);if (!mod_delayed_work (mld_wq, &idev->mc_report_work,0 ))in6_dev_hold (idev); + skb =NULL ; }spin_unlock_bh (&idev->mc_report_lock); - -return 0 ; +out: +kfree_skb (skb); }static void __mld_report_work (struct sk_buff *skb)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 418/699 ipv6: mcast: Replace locking comments with lockdep annotations.
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 818ae1a5ecb41d82ad180a99c39111f051894d90 ]
Commit 63ed8de4be81 ("mld: add mc_lock for protecting per-interface mld data") added the same comments regarding locking to many functions.
Let's replace the comments with lockdep annotation, which is more helpful.
Note that we just remove the comment for mld_clear_zeros() and mld_send_cr(), where mc_dereference() is used in the entry of the function.
While at it, a comment for __ipv6_sock_mc_join() is moved back to the correct place.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- net/ipv6/mcast.c | 125 +++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 54 deletions(-)
net/ipv6/mcast.c +71 -54
@@ -108,9 +108,9 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,int sysctl_mld_max_msf__read_mostly =IPV6_MLD_MAX_MSF ;int sysctl_mld_qrv__read_mostly =MLD_QRV_DEFAULT ; -/* -* socket join on multicast group -*/ +#define mc_assert_locked (idev) \ + lockdep_assert_held(&(idev)->mc_lock) +#define mc_dereference (e, idev) \ rcu_dereference_protected(e, lockdep_is_held(&(idev)->mc_lock))
@@ -166,6 +166,9 @@ static int unsolicited_report_interval(struct inet6_dev *idev)return iv >0 ? iv :1 ; } +/* +* socket join on multicast group +*/ static int __ipv6_sock_mc_join (struct sock *sk,int ifindex,const struct in6_addr *addr,unsigned int mode) {
@@ -664,12 +667,13 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,return rv; } -/* called with mc_lock */ static void igmp6_group_added (struct ifmcaddr6 *mc) {struct net_device *dev = mc->idev->dev;char buf[MAX_ADDR_LEN ]; +mc_assert_locked (mc->idev); +if (IPV6_ADDR_MC_SCOPE (&mc->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )return ;
@@ -699,12 +703,13 @@ static void igmp6_group_added(struct ifmcaddr6 *mc)mld_ifc_event (mc->idev); } -/* called with mc_lock */ static void igmp6_group_dropped (struct ifmcaddr6 *mc) {struct net_device *dev = mc->idev->dev;char buf[MAX_ADDR_LEN ]; +mc_assert_locked (mc->idev); +if (IPV6_ADDR_MC_SCOPE (&mc->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )return ;
@@ -725,14 +730,13 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)refcount_dec (&mc->mca_refcnt); } -/* -* deleted ifmcaddr6 manipulation -* called with mc_lock -*/ +/* deleted ifmcaddr6 manipulation */ static void mld_add_delrec (struct inet6_dev *idev,struct ifmcaddr6 *im) {struct ifmcaddr6 *pmc; +mc_assert_locked (idev); +/* this is an "ifmcaddr6" for convenience; only the fields below * are actually used. In particular, the refcnt and users are not * used for management of the delete list. Using the same structure
@@ -766,13 +770,14 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)rcu_assign_pointer (idev->mc_tomb, pmc); } -/* called with mc_lock */ static void mld_del_delrec (struct inet6_dev *idev,struct ifmcaddr6 *im) {struct ip6_sf_list *psf, *sources, *tomb;struct in6_addr *pmca = &im->mca_addr;struct ifmcaddr6 *pmc, *pmc_prev; +mc_assert_locked (idev); + pmc_prev =NULL ;for_each_mc_tomb (idev, pmc) {if (ipv6_addr_equal (&pmc->mca_addr, pmca))
@@ -809,11 +814,12 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) } } -/* called with mc_lock */ static void mld_clear_delrec (struct inet6_dev *idev) {struct ifmcaddr6 *pmc, *nextpmc; +mc_assert_locked (idev); + pmc =mc_dereference (idev->mc_tomb, idev);RCU_INIT_POINTER (idev->mc_tomb,NULL );
@@ -870,13 +876,14 @@ static void ma_put(struct ifmcaddr6 *mc) } } -/* called with mc_lock */ static struct ifmcaddr6 *mca_alloc (struct inet6_dev *idev,const struct in6_addr *addr,unsigned int mode) {struct ifmcaddr6 *mc; +mc_assert_locked (idev); + mc =kzalloc (sizeof (*mc),GFP_KERNEL );if (!mc)return NULL ;
@@ -1047,46 +1054,51 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,return rv; } -/* called with mc_lock */ static void mld_gq_start_work (struct inet6_dev *idev) {unsigned long tv =prandom_u32 () % idev->mc_maxdelay; +mc_assert_locked (idev); + idev->mc_gq_running =1 ;if (!mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 ))in6_dev_hold (idev); } -/* called with mc_lock */ static void mld_gq_stop_work (struct inet6_dev *idev) { +mc_assert_locked (idev); + idev->mc_gq_running =0 ;if (cancel_delayed_work (&idev->mc_gq_work))__in6_dev_put (idev); } -/* called with mc_lock */ static void mld_ifc_start_work (struct inet6_dev *idev,unsigned long delay) {unsigned long tv =prandom_u32 () % delay; +mc_assert_locked (idev); +if (!mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 ))in6_dev_hold (idev); } -/* called with mc_lock */ static void mld_ifc_stop_work (struct inet6_dev *idev) { +mc_assert_locked (idev); + idev->mc_ifc_count =0 ;if (cancel_delayed_work (&idev->mc_ifc_work))__in6_dev_put (idev); } -/* called with mc_lock */ static void mld_dad_start_work (struct inet6_dev *idev,unsigned long delay) {unsigned long tv =prandom_u32 () % delay; +mc_assert_locked (idev); +if (!mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 ))in6_dev_hold (idev); }
@@ -1111,14 +1123,13 @@ static void mld_report_stop_work(struct inet6_dev *idev)__in6_dev_put (idev); } -/* -* IGMP handling (alias multicast ICMPv6 messages) -* called with mc_lock -*/ +/* IGMP handling (alias multicast ICMPv6 messages) */ static void igmp6_group_queried (struct ifmcaddr6 *ma,unsigned long resptime) {unsigned long delay = resptime; +mc_assert_locked (ma->idev); +/* Do not start work for these addresses */ if (ipv6_addr_is_ll_all_nodes (&ma->mca_addr) ||IPV6_ADDR_MC_SCOPE (&ma->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )
@@ -1137,15 +1148,15 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) ma->mca_flags |=MAF_TIMER_RUNNING ; } -/* mark EXCLUDE-mode sources -* called with mc_lock -*/ +/* mark EXCLUDE-mode sources */ static bool mld_xmarksources (struct ifmcaddr6 *pmc,int nsrcs,const struct in6_addr *srcs) {struct ip6_sf_list *psf;int i, scount; +mc_assert_locked (pmc->idev); + scount =0 ;for_each_psf_mclock (pmc, psf) {if (scount == nsrcs)
@@ -1168,13 +1179,14 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,return true; } -/* called with mc_lock */ static bool mld_marksources (struct ifmcaddr6 *pmc,int nsrcs,const struct in6_addr *srcs) {struct ip6_sf_list *psf;int i, scount; +mc_assert_locked (pmc->idev); +if (pmc->mca_sfmode ==MCAST_EXCLUDE )return mld_xmarksources (pmc, nsrcs, srcs);
@@ -1862,7 +1874,6 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,#define AVAILABLE (skb) ((skb) ? skb_availroom(skb) : 0) -/* called with mc_lock */ static struct sk_buff *add_grec (struct sk_buff *skb,struct ifmcaddr6 *pmc,int type,int gdeleted,int sdeleted,int crsend)
@@ -1876,6 +1887,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,struct mld2_report *pmr;unsigned int mtu; +mc_assert_locked (idev); +if (pmc->mca_flags &MAF_NOREPORT )return skb;
@@ -1994,12 +2007,13 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,return skb; } -/* called with mc_lock */ static void mld_send_report (struct inet6_dev *idev,struct ifmcaddr6 *pmc) {struct sk_buff *skb =NULL ;int type; +mc_assert_locked (idev); +if (!pmc) {for_each_mc_mclock (idev, pmc) {if (pmc->mca_flags &MAF_NOREPORT )
@@ -2021,10 +2035,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)mld_sendpack (skb); } -/* -* remove zero-count source records from a source filter list -* called with mc_lock -*/ +/* remove zero-count source records from a source filter list */ static void mld_clear_zeros (struct ip6_sf_list __rcu **ppsf,struct inet6_dev *idev) {struct ip6_sf_list *psf_prev, *psf_next, *psf;
@@ -2048,7 +2059,6 @@ static void mld_clear_zeros(struct ip6_sf_list __rcu **ppsf, struct inet6_dev *i } } -/* called with mc_lock */ static void mld_send_cr (struct inet6_dev *idev) {struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next;
@@ -2214,13 +2224,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) goto out; } -/* called with mc_lock */ static void mld_send_initial_cr (struct inet6_dev *idev) { -struct sk_buff *skb;struct ifmcaddr6 *pmc; +struct sk_buff *skb;int type; +mc_assert_locked (idev); +if (mld_in_v1_mode (idev))return ;
@@ -2267,13 +2278,14 @@ static void mld_dad_work(struct work_struct *work)in6_dev_put (idev); } -/* called with mc_lock */ static int ip6_mc_del1_src (struct ifmcaddr6 *pmc,int sfmode, -const struct in6_addr *psfsrc) +const struct in6_addr *psfsrc) {struct ip6_sf_list *psf, *psf_prev;int rv =0 ; +mc_assert_locked (pmc->idev); + psf_prev =NULL ;for_each_psf_mclock (pmc, psf) {if (ipv6_addr_equal (&psf->sf_addr, psfsrc))
@@ -2310,7 +2322,6 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,return rv; } -/* called with mc_lock */ static int ip6_mc_del_src (struct inet6_dev *idev,const struct in6_addr *pmca,int sfmode,int sfcount,const struct in6_addr *psfsrc,int delta)
@@ -2322,6 +2333,8 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,if (!idev)return -ENODEV ; +mc_assert_locked (idev); +for_each_mc_mclock (idev, pmc) {if (ipv6_addr_equal (pmca, &pmc->mca_addr))break ;
@@ -2363,15 +2376,14 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,return err; } -/* -* Add multicast single-source filter to the interface list -* called with mc_lock -*/ +/* Add multicast single-source filter to the interface list */ static int ip6_mc_add1_src (struct ifmcaddr6 *pmc,int sfmode, -const struct in6_addr *psfsrc) +const struct in6_addr *psfsrc) {struct ip6_sf_list *psf, *psf_prev; +mc_assert_locked (pmc->idev); + psf_prev =NULL ;for_each_psf_mclock (pmc, psf) {if (ipv6_addr_equal (&psf->sf_addr, psfsrc))
@@ -2394,11 +2406,12 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,return 0 ; } -/* called with mc_lock */ static void sf_markstate (struct ifmcaddr6 *pmc) { -struct ip6_sf_list *psf;int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE ]; +struct ip6_sf_list *psf; + +mc_assert_locked (pmc->idev);for_each_psf_mclock (pmc, psf) {if (pmc->mca_sfcount[MCAST_EXCLUDE ]) {
@@ -2411,14 +2424,15 @@ static void sf_markstate(struct ifmcaddr6 *pmc) } } -/* called with mc_lock */ static int sf_setstate (struct ifmcaddr6 *pmc) { -struct ip6_sf_list *psf, *dpsf;int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE ]; +struct ip6_sf_list *psf, *dpsf;int qrv = pmc->idev->mc_qrv;int new_in, rv; +mc_assert_locked (pmc->idev); + rv =0 ;for_each_psf_mclock (pmc, psf) {if (pmc->mca_sfcount[MCAST_EXCLUDE ]) {
@@ -2477,10 +2491,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)return rv; } -/* -* Add multicast source filter list to the interface list -* called with mc_lock -*/ +/* Add multicast source filter list to the interface list */ static int ip6_mc_add_src (struct inet6_dev *idev,const struct in6_addr *pmca,int sfmode,int sfcount,const struct in6_addr *psfsrc,int delta)
@@ -2492,6 +2503,8 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,if (!idev)return -ENODEV ; +mc_assert_locked (idev); +for_each_mc_mclock (idev, pmc) {if (ipv6_addr_equal (pmca, &pmc->mca_addr))break ;
@@ -2537,11 +2550,12 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,return err; } -/* called with mc_lock */ static void ip6_mc_clear_src (struct ifmcaddr6 *pmc) {struct ip6_sf_list *psf, *nextpsf; +mc_assert_locked (pmc->idev); +for (psf =mc_dereference (pmc->mca_tomb, pmc->idev); psf; psf = nextpsf) {
@@ -2561,11 +2575,12 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) pmc->mca_sfcount[MCAST_EXCLUDE ] =1 ; } -/* called with mc_lock */ static void igmp6_join_group (struct ifmcaddr6 *ma) {unsigned long delay; +mc_assert_locked (ma->idev); +if (ma->mca_flags &MAF_NOREPORT )return ;
@@ -2611,9 +2626,10 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,return err; } -/* called with mc_lock */ static void igmp6_leave_group (struct ifmcaddr6 *ma) { +mc_assert_locked (ma->idev); +if (mld_in_v1_mode (ma->idev)) {if (ma->mca_flags &MAF_LAST_REPORTER ) { igmp6_send(&ma->mca_addr, ma->idev->dev,
@@ -2658,9 +2674,10 @@ static void mld_ifc_work(struct work_struct *work)in6_dev_put (idev); } -/* called with mc_lock */ static void mld_ifc_event (struct inet6_dev *idev) { +mc_assert_locked (idev); +if (mld_in_v1_mode (idev))return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 419/699 ipv6: mcast: Fix potential UAF in MLD delayed work
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9b26518b6896a16b809b1e42986f4ebac7bccc1e ]
A race condition exists between device teardown and incoming MLD query processing, leading to a Use-After-Free in the MLD delayed work.
During device destruction, the primary reference to inet6_dev is dropped, which can drop its refcount to 0. The actual freeing of inet6_dev memory is deferred via RCU.
Concurrently, the packet receive path runs under RCU read lock and obtains the inet6_dev pointer. Because the memory is RCU-protected, CPU-0 can safely dereference inet6_dev even if its refcount has hit 0.
However, if CPU-0 calls igmp6_event_query() and schedules delayed work, it attempts to acquire a reference using in6_dev_hold(). This increments the refcount from 0 to 1, triggering a "refcount_t: addition on 0" warning. Since the inet6_dev memory is still scheduled to be freed after the RCU grace period, the device is freed while the work is still scheduled. When the work runs, it accesses the freed memory, causing a kernel panic.
Fix this by using refcount_inc_not_zero() (via a new helper in6_dev_hold_safe()) to prevent acquiring a reference if the device is already being destroyed. If the refcount is 0, we do not schedule the work.
--- include/net/addrconf.h | 5 +++++ net/ipv6/mcast.c | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 12 deletions(-)
include/net/addrconf.h +5 -0
@@ -411,6 +411,11 @@ static inline void in6_dev_hold(struct inet6_dev *idev)refcount_inc (&idev->refcnt); } +static inline bool in6_dev_hold_safe (struct inet6_dev *idev) +{ +return refcount_inc_not_zero (&idev->refcnt); +} +/* called with rcu_read_lock held */ static inline bool ip6_ignore_linkdown (const struct net_device *dev) {
net/ipv6/mcast.c +28 -12
@@ -1061,8 +1061,10 @@ static void mld_gq_start_work(struct inet6_dev *idev)mc_assert_locked (idev); idev->mc_gq_running =1 ; -if (!mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_gq_stop_work (struct inet6_dev *idev)
@@ -1080,8 +1082,10 @@ static void mld_ifc_start_work(struct inet6_dev *idev, unsigned long delay)mc_assert_locked (idev); -if (!mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_ifc_stop_work (struct inet6_dev *idev)
@@ -1099,8 +1103,10 @@ static void mld_dad_start_work(struct inet6_dev *idev, unsigned long delay)mc_assert_locked (idev); -if (!mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_dad_stop_work (struct inet6_dev *idev)
@@ -1386,18 +1392,23 @@ static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,void igmp6_event_query (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); +bool put = false;if (!idev || idev->dead) goto out;spin_lock_bh (&idev->mc_query_lock); -if (skb_queue_len (&idev->mc_query_queue) <MLD_MAX_SKBS ) { +if (skb_queue_len (&idev->mc_query_queue) <MLD_MAX_SKBS && +in6_dev_hold_safe (idev)) {__skb_queue_tail (&idev->mc_query_queue, skb); -if (!mod_delayed_work (mld_wq, &idev->mc_query_work,0 )) -in6_dev_hold (idev); +if (mod_delayed_work (mld_wq, &idev->mc_query_work,0 )) + put = true; skb =NULL ; }spin_unlock_bh (&idev->mc_query_lock); + +if (put) +in6_dev_put (idev); out:kfree_skb (skb); }
@@ -1555,18 +1566,23 @@ static void mld_query_work(struct work_struct *work)void igmp6_event_report (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); +bool put = false;if (!idev || idev->dead) goto out;spin_lock_bh (&idev->mc_report_lock); -if (skb_queue_len (&idev->mc_report_queue) <MLD_MAX_SKBS ) { +if (skb_queue_len (&idev->mc_report_queue) <MLD_MAX_SKBS && +in6_dev_hold_safe (idev)) {__skb_queue_tail (&idev->mc_report_queue, skb); -if (!mod_delayed_work (mld_wq, &idev->mc_report_work,0 )) -in6_dev_hold (idev); +if (mod_delayed_work (mld_wq, &idev->mc_report_work,0 )) + put = true; skb =NULL ; }spin_unlock_bh (&idev->mc_report_lock); + +if (put) +in6_dev_put (idev); out:kfree_skb (skb); }
Signature · 1 line
2.53.0