mailweb.openeuler.org
Manage this list

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

Kernel

Threads by month
  • ----- 2026 -----
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
kernel@openeuler.org

  • 4 participants
  • 25070 discussions
[PATCH OLK-5.10 v5] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 23 Sep '26

23 Sep '26
From: Daniel Borkmann <borkmann(a)iogearbox.net> mainline inclusion from mainline-v7.3-rc1 commit b1a47b2708d4e95dbd23aee2ec83752190897b3f category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18901 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- get_perf_callchain() returns a per-CPU perf_callchain_entry buffer and releases its recursion slot via put_callchain_entry() before returning, so nothing keeps the entry reserved while __bpf_get_stack() consumes it below. A preemptible BPF program (e.g. a non-sleepable raw tracepoint program on a PREEMPT kernel, which runs under migrate_disable() but not preempt_disable()) can be scheduled out between obtaining the entry and the copy. Another task scheduled on the same CPU then reuses the same per-CPU buffer and overwrites trace->nr with a larger value. copy_len is then computed from the inflated trace->nr and can exceed the caller's buffer, causing an out-of-bounds write in the memcpy() and in the build_id path. The rcu_read_lock() taken here alone does not prevent this. It is only taken on the may_fault path, and under CONFIG_PREEMPT_RCU it does not disable preemption; it merely keeps perf's callchain buffer array alive (freed via call_rcu()) and does nothing to stop another task from reusing the entry. Disable preemption around obtaining the callchain entry and copying it into the caller's buffer, so the entry cannot be reused underneath us and trace->nr stays bounded by max_depth. Build ID resolution may fault and is therefore deferred until after preemption is re-enabled; by then the instruction pointers have already been copied into buf, so it operates only on that private copy. Note, preempt_disable() also subsumes the buffer-lifetime guarantee the rcu_read_lock() provided, since a preempt-disabled section is an RCU read-side critical section for the callchain buffers' call_rcu() reclaim. Fixes: c195651e565a ("bpf: add bpf_get_stack helper") Reported-by: Tao Chen <chen.dylane(a)linux.dev> Reported-by: STAR Labs SG <info(a)starlabs.sg> Signed-off-by: Daniel Borkmann <borkmann(a)iogearbox.net> Signed-off-by: Jiri Olsa <jolsa(a)kernel.org> Signed-off-by: Andrii Nakryiko <andrii(a)kernel.org> Cc: stable(a)vger.kernel.org Link: https://lore.kernel.org/bpf/20260803210149.296496-11-jolsa@kernel.org Closes: https://lore.kernel.org/bpf/20260206090653.1336687-1-chen.dylane@linux.dev/ [ changed Fixes: commit ] Conflicts: kernel/bpf/stackmap.c [not refactor to callchain_store and callchain_finalize] Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- kernel/bpf/stackmap.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 623d50bda9c1..86ab80a2fb23 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -716,6 +716,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, max_depth = stack_map_calculate_max_depth(size, elem_size, flags); + preempt_disable(); if (trace_in) { trace = trace_in; trace->nr = min_t(u32, trace->nr, max_depth); @@ -725,11 +726,15 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, trace = get_perf_callchain(regs, 0, kernel, user, max_depth, crosstask, false); } - if (unlikely(!trace)) + if (unlikely(!trace)) { + preempt_enable(); goto err_fault; + } - if (trace->nr < skip) + if (trace->nr < skip) { + preempt_enable(); goto err_fault; + } trace_nr = trace->nr - skip; copy_len = trace_nr * elem_size; @@ -741,11 +746,15 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, for (i = 0; i < trace_nr; i++) id_offs[i].ip = ips[i]; - stack_map_get_build_id_offset(buf, trace_nr, user); } else { memcpy(buf, ips, copy_len); } + preempt_enable(); + + if (user && user_build_id) + stack_map_get_build_id_offset(buf, trace_nr, user); + if (size > copy_len) memset(buf + copy_len, 0, size - copy_len); return copy_len; -- 2.34.1
2 1
0 0
[PATCH OLK-6.6 v5] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 23 Sep '26

23 Sep '26
From: Daniel Borkmann <borkmann(a)iogearbox.net> mainline inclusion from mainline-v7.3-rc1 commit b1a47b2708d4e95dbd23aee2ec83752190897b3f category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18901 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- get_perf_callchain() returns a per-CPU perf_callchain_entry buffer and releases its recursion slot via put_callchain_entry() before returning, so nothing keeps the entry reserved while __bpf_get_stack() consumes it below. A preemptible BPF program (e.g. a non-sleepable raw tracepoint program on a PREEMPT kernel, which runs under migrate_disable() but not preempt_disable()) can be scheduled out between obtaining the entry and the copy. Another task scheduled on the same CPU then reuses the same per-CPU buffer and overwrites trace->nr with a larger value. copy_len is then computed from the inflated trace->nr and can exceed the caller's buffer, causing an out-of-bounds write in the memcpy() and in the build_id path. The rcu_read_lock() taken here alone does not prevent this. It is only taken on the may_fault path, and under CONFIG_PREEMPT_RCU it does not disable preemption; it merely keeps perf's callchain buffer array alive (freed via call_rcu()) and does nothing to stop another task from reusing the entry. Disable preemption around obtaining the callchain entry and copying it into the caller's buffer, so the entry cannot be reused underneath us and trace->nr stays bounded by max_depth. Build ID resolution may fault and is therefore deferred until after preemption is re-enabled; by then the instruction pointers have already been copied into buf, so it operates only on that private copy. Note, preempt_disable() also subsumes the buffer-lifetime guarantee the rcu_read_lock() provided, since a preempt-disabled section is an RCU read-side critical section for the callchain buffers' call_rcu() reclaim. Fixes: c195651e565a ("bpf: add bpf_get_stack helper") Reported-by: Tao Chen <chen.dylane(a)linux.dev> Reported-by: STAR Labs SG <info(a)starlabs.sg> Signed-off-by: Daniel Borkmann <borkmann(a)iogearbox.net> Signed-off-by: Jiri Olsa <jolsa(a)kernel.org> Signed-off-by: Andrii Nakryiko <andrii(a)kernel.org> Cc: stable(a)vger.kernel.org Link: https://lore.kernel.org/bpf/20260803210149.296496-11-jolsa@kernel.org Closes: https://lore.kernel.org/bpf/20260206090653.1336687-1-chen.dylane@linux.dev/ [ changed Fixes: commit ] Conflicts: kernel/bpf/stackmap.c [not refactor to callchain_store and callchain_finalize] Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- kernel/bpf/stackmap.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 12bb2f66f03a..d2ec9758b4d5 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -516,6 +516,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, max_depth = stack_map_calculate_max_depth(size, elem_size, flags); + preempt_disable(); if (trace_in) { trace = trace_in; trace->nr = min_t(u32, trace->nr, max_depth); @@ -525,11 +526,15 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, trace = get_perf_callchain(regs, 0, kernel, user, max_depth, crosstask, false); } - if (unlikely(!trace)) + if (unlikely(!trace)) { + preempt_enable(); goto err_fault; + } - if (trace->nr < skip) + if (trace->nr < skip) { + preempt_enable(); goto err_fault; + } trace_nr = trace->nr - skip; copy_len = trace_nr * elem_size; @@ -541,11 +546,15 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, for (i = 0; i < trace_nr; i++) id_offs[i].ip = ips[i]; - stack_map_get_build_id_offset(buf, trace_nr, user); } else { memcpy(buf, ips, copy_len); } + preempt_enable(); + + if (user && user_build_id) + stack_map_get_build_id_offset(buf, trace_nr, user); + if (size > copy_len) memset(buf + copy_len, 0, size - copy_len); return copy_len; -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] ring-buffer: Acquire the lock with irqsave in rb_wake_up_waiters()
by Tengda Wu 23 Sep '26

23 Sep '26
From: Sebastian Andrzej Siewior <bigeasy(a)linutronix.de> mainline inclusion from mainline-v7.3-rc3 commit 815e07c8fe885a87751c2496a30ae0dcd4118210 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9956 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- rb_wake_up_waiters() is a irq_work callback which is initialized with init_irq_work(). As such it will be invoked in thread context on PREEMPT_RT. Invoking the callback in IRQ context on PREEMPT_RT is not an option due its usage of wake_up_all(). Since this callback may run in thread context, it needs to acquire ring_buffer_per_cpu::reader_lock with disabling interrupts and may not assume that they are disabled. Use raw_spinlock_irqsave() to acquire ring_buffer_per_cpu::reader_lock. Cc: stable(a)vger.kernel.org Link: https://patch.msgid.link/20260911102152.YEtwkBj9@linutronix.de Fixes: 68282dd930ea3 ("ring-buffer: Fix resetting of shortest_full") Reviewed-by: Vincent Donnefort <vdonnefort(a)google.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy(a)linutronix.de> Signed-off-by: Steven Rostedt <rostedt(a)goodmis.org> Conflicts: kernel/trace/ring_buffer.c [scope_guard is not widely used in this version, so use original raw_spin_lock_irqsave/irqrestore instead.] Signed-off-by: Tengda Wu <wutengda2(a)huawei.com> --- kernel/trace/ring_buffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 9a2c8727b033..91346d3a0f96 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -828,6 +828,7 @@ static __always_inline bool full_hit(struct trace_buffer *buffer, int cpu, int f static void rb_wake_up_waiters(struct irq_work *work) { struct rb_irq_work *rbwork = container_of(work, struct rb_irq_work, work); + unsigned long flags; wake_up_all(&rbwork->waiters); if (rbwork->full_waiters_pending || rbwork->wakeup_full) { @@ -835,14 +836,13 @@ static void rb_wake_up_waiters(struct irq_work *work) struct ring_buffer_per_cpu *cpu_buffer = container_of(rbwork, struct ring_buffer_per_cpu, irq_work); - /* Called from interrupt context */ - raw_spin_lock(&cpu_buffer->reader_lock); + raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); rbwork->wakeup_full = false; rbwork->full_waiters_pending = false; /* Waking up all waiters, they will reset the shortest full */ cpu_buffer->shortest_full = 0; - raw_spin_unlock(&cpu_buffer->reader_lock); + raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); wake_up_all(&rbwork->full_waiters); } -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] lockd: fix NULL dereference on lockowner allocation failure
by Pu Lehui 23 Sep '26

23 Sep '26
From: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit 4c7fc129db061c7daab841c4f3c342d894832362 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18849 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- nlmclnt_locks_init_private() installs NLM file lock operations even when nlmclnt_find_lockowner() fails to allocate a lockowner. nlmclnt_proc() then returns -ENOMEM, but the VFS still tears down the partially initialized file_lock and calls locks_release_private(). That invokes nlmclnt_locks_release_private(), which dereferences fl->fl_u.nfs_fl.owner and crashes because the owner was never installed. Clear fl_ops before attempting to initialize the NLM private state, and install the NLM lock operations only after a lockowner has been allocated successfully. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable(a)vger.kernel.org Signed-off-by: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust(a)hammerspace.com> Conflicts: fs/lockd/clntproc.c [ctx conflicts] Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- fs/lockd/clntproc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index fba6c7fa7474..bbaa8c2d8877 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -485,8 +485,11 @@ static const struct file_lock_operations nlmclnt_lock_ops = { static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) { fl->fl_u.nfs_fl.state = 0; + fl->fl_ops = NULL; fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host, fl->fl_owner); INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); + if (!fl->fl_u.nfs_fl.owner) + return; fl->fl_ops = &nlmclnt_lock_ops; } -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] ring-buffer: Acquire the lock with irqsave in rb_wake_up_waiters()
by Tengda Wu 23 Sep '26

23 Sep '26
From: Sebastian Andrzej Siewior <bigeasy(a)linutronix.de> mainline inclusion from mainline-v7.3-rc3 commit 815e07c8fe885a87751c2496a30ae0dcd4118210 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9956 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- rb_wake_up_waiters() is a irq_work callback which is initialized with init_irq_work(). As such it will be invoked in thread context on PREEMPT_RT. Invoking the callback in IRQ context on PREEMPT_RT is not an option due its usage of wake_up_all(). Since this callback may run in thread context, it needs to acquire ring_buffer_per_cpu::reader_lock with disabling interrupts and may not assume that they are disabled. Use raw_spinlock_irqsave() to acquire ring_buffer_per_cpu::reader_lock. Cc: stable(a)vger.kernel.org Link: https://patch.msgid.link/20260911102152.YEtwkBj9@linutronix.de Fixes: 68282dd930ea3 ("ring-buffer: Fix resetting of shortest_full") Reviewed-by: Vincent Donnefort <vdonnefort(a)google.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy(a)linutronix.de> Signed-off-by: Steven Rostedt <rostedt(a)goodmis.org> Signed-off-by: Tengda Wu <wutengda2(a)huawei.com> --- kernel/trace/ring_buffer.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 47908a826373..c1800fb607ae 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -918,14 +918,13 @@ static void rb_wake_up_waiters(struct irq_work *work) struct ring_buffer_per_cpu *cpu_buffer = container_of(rbwork, struct ring_buffer_per_cpu, irq_work); - /* Called from interrupt context */ - raw_spin_lock(&cpu_buffer->reader_lock); - rbwork->wakeup_full = false; - rbwork->full_waiters_pending = false; + scoped_guard(raw_spinlock_irqsave, &cpu_buffer->reader_lock) { + rbwork->wakeup_full = false; + rbwork->full_waiters_pending = false; - /* Waking up all waiters, they will reset the shortest full */ - cpu_buffer->shortest_full = 0; - raw_spin_unlock(&cpu_buffer->reader_lock); + /* Waking up all waiters, they will reset the shortest full */ + cpu_buffer->shortest_full = 0; + } wake_up_all(&rbwork->full_waiters); } -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] lockd: fix NULL dereference on lockowner allocation failure
by Pu Lehui 23 Sep '26

23 Sep '26
From: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit 4c7fc129db061c7daab841c4f3c342d894832362 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18849 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- nlmclnt_locks_init_private() installs NLM file lock operations even when nlmclnt_find_lockowner() fails to allocate a lockowner. nlmclnt_proc() then returns -ENOMEM, but the VFS still tears down the partially initialized file_lock and calls locks_release_private(). That invokes nlmclnt_locks_release_private(), which dereferences fl->fl_u.nfs_fl.owner and crashes because the owner was never installed. Clear fl_ops before attempting to initialize the NLM private state, and install the NLM lock operations only after a lockowner has been allocated successfully. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable(a)vger.kernel.org Signed-off-by: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust(a)hammerspace.com> Conflicts: fs/lockd/clntproc.c [ctx conflicts] Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- fs/lockd/clntproc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index fba6c7fa7474..bbaa8c2d8877 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -485,8 +485,11 @@ static const struct file_lock_operations nlmclnt_lock_ops = { static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) { fl->fl_u.nfs_fl.state = 0; + fl->fl_ops = NULL; fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host, fl->fl_owner); INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); + if (!fl->fl_u.nfs_fl.owner) + return; fl->fl_ops = &nlmclnt_lock_ops; } -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] ceph: cap delegated inode count in ceph_parse_deleg_inos()
by Pan Taixi 23 Sep '26

23 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit 4bd3158bd62466d57ed72a3f7bc5f205fedd6919 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18927 CVE: CVE-2026-89648 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… --------------------------- ceph_parse_deleg_inos() decodes interval sets of delegated inode numbers from an MDS create-with-delegation reply. For each set it reads a 64-bit start and a 64-bit len with ceph_decode_64_safe(), which only validates that the eight bytes are present in the message, not the value, and then loops over len while inserting entries into s_delegated_inos. len is fully attacker controlled. A malicious or compromised MDS can send one huge interval, many intervals in one reply, duplicate intervals, or repeated replies that accumulate delegated inodes on the same session. The original code bounded none of these and could spin the insert loop or grow the xarray without limit. Bound both dimensions with a single enforcement point. Track the number of delegated inodes held by each MDS session in an atomic counter and grow it only in ceph_insert_deleg_ino(), which uses atomic_add_unless() to refuse to push the count past CEPH_MAX_DELEG_INOS. Because that helper is the only place the counter grows, the per-session population can never exceed the cap, so no separate per-session pre-check is needed. The counter is decremented when async create consumes a delegated inode or when an insert fails, incremented when a delegated inode is restored, initialized with the session xarray, and reset when reconnect destroys the xarray. A per-session cap alone still lets one reply spin the insert loop on duplicate ranges without growing the counter, so also cap the aggregate interval length accepted from a single reply. Together these bound both the loop trip count per reply and the xarray population across replies. The cap is a fixed, client-chosen constant rather than a value derived from the MDS. mds_client_prealloc_inos is a userspace MDS configuration option; it is never sent to the kernel client on the wire, and a server-supplied bound could not be trusted for a defensive limit in any case. The constant is set well above that option's documented default of 1000 (a generous multiple), so legitimate refill behavior is unaffected while the CPU and xarray memory a malformed delegation stream can consume stays bounded. Impact: a malicious or compromised Ceph MDS can no longer make a client spin through an unbounded delegated-inode interval or grow one session's delegated-inode xarray without limit. Cc: stable(a)vger.kernel.org Fixes: d48464878708 ("ceph: decode interval_sets for delegated inos") Suggested-by: Viacheslav Dubeyko <Slava.Dubeyko(a)ibm.com> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko(a)ibm.com> Signed-off-by: Ilya Dryomov <idryomov(a)gmail.com> Conflicts: fs/ceph/mds_client.c [backport to OLK-5.10: context adjusted for this tree: pr_warn_ratelimited_client()/doutc() from 38d46409c4639 are not used here, so the new warnings use plain pr_warn_ratelimited() and the struct ceph_client *cl local is not added. The redundant 'ino' local (2ecd0edd13a8b not applied here) is dropped together with its only user, the open-coded xa_insert() in ceph_parse_deleg_inos(). CEPH_MAX_DELEG_INOS is inserted right after CEPH_INO_SYSTEM_BASE. s_num_deleg_inos is reset next to the existing xa_destroy() in send_mds_reconnect(), which still runs before mutex_lock(&session->s_mutex) in this tree (39fe30315893 not applied); this matches the linux-6.18.y stable backport c040e139f1a62.] Signed-off-by: Pan Taixi <pantaixi1(a)huawei.com> --- fs/ceph/mds_client.c | 58 ++++++++++++++++++++++++++++++++++++++------ fs/ceph/mds_client.h | 1 + fs/ceph/super.h | 9 +++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index aea1b42b9b18..ef39852280c8 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -419,39 +419,80 @@ static int parse_reply_info_filelock(void **p, void *end, #if BITS_PER_LONG == 64 #define DELEGATED_INO_AVAILABLE xa_mk_value(1) +static int ceph_insert_deleg_ino(struct ceph_mds_session *s, u64 ino) +{ + int err; + + /* + * Cap how many delegated inodes a single session may hold. This is + * the only place that grows the count, so atomic_add_unless() bounds + * it at exactly CEPH_MAX_DELEG_INOS; s_num_deleg_inos can never exceed + * that. + */ + if (!atomic_add_unless(&s->s_num_deleg_inos, 1, CEPH_MAX_DELEG_INOS)) { + pr_warn_ratelimited("MDS session already holds %d delegated inodes\n", + CEPH_MAX_DELEG_INOS); + return -EOVERFLOW; + } + + err = xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE, + GFP_KERNEL); + if (err) + atomic_dec(&s->s_num_deleg_inos); + return err; +} + static int ceph_parse_deleg_inos(void **p, void *end, struct ceph_mds_session *s) { + u64 msg_deleg_inos = 0; u32 sets; ceph_decode_32_safe(p, end, sets, bad); dout("got %u sets of delegated inodes\n", sets); while (sets--) { - u64 start, len, ino; + u64 start, len; ceph_decode_64_safe(p, end, start, bad); ceph_decode_64_safe(p, end, len, bad); /* Don't accept a delegation of system inodes */ if (start < CEPH_INO_SYSTEM_BASE) { pr_warn_ratelimited("ceph: ignoring reserved inode range delegation (start=0x%llx len=0x%llx)\n", start, len); continue; } + + /* + * Bound the number of inodes one reply may delegate. + * ceph_insert_deleg_ino() separately caps the per-session + * population, so this only has to stop one reply from spinning + * the insert loop under an attacker-controlled len. + */ + if (len > (u64)CEPH_MAX_DELEG_INOS || + msg_deleg_inos > (u64)CEPH_MAX_DELEG_INOS - len) { + pr_warn_ratelimited("MDS reply delegates too many inodes (have %llu, +%llu, max %d)\n", + msg_deleg_inos, len, CEPH_MAX_DELEG_INOS); + return -EIO; + } + msg_deleg_inos += len; + while (len--) { - int err = xa_insert(&s->s_delegated_inos, ino = start++, - DELEGATED_INO_AVAILABLE, - GFP_KERNEL); + int err = ceph_insert_deleg_ino(s, start++); + if (!err) { dout("added delegated inode 0x%llx\n", start - 1); } else if (err == -EBUSY) { pr_warn("ceph: MDS delegated inode 0x%llx more than once.\n", start - 1); + } else if (err == -EOVERFLOW) { + /* ceph_insert_deleg_ino() already warned. */ + return -EIO; } else { return err; } } } @@ -465,20 +506,21 @@ u64 ceph_get_deleg_ino(struct ceph_mds_session *s) unsigned long ino; void *val; xa_for_each(&s->s_delegated_inos, ino, val) { val = xa_erase(&s->s_delegated_inos, ino); - if (val == DELEGATED_INO_AVAILABLE) + if (val == DELEGATED_INO_AVAILABLE) { + atomic_dec(&s->s_num_deleg_inos); return ino; + } } return 0; } int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino) { - return xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE, - GFP_KERNEL); + return ceph_insert_deleg_ino(s, ino); } #else /* BITS_PER_LONG == 64 */ /* * FIXME: xarrays can't handle 64-bit indexes on a 32-bit arch. For now, just * ignore delegated_inos on 32 bit arch. Maybe eventually add xarrays for top @@ -760,10 +802,11 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_nr_caps = 0; refcount_set(&s->s_ref, 1); INIT_LIST_HEAD(&s->s_waiting); INIT_LIST_HEAD(&s->s_unsafe); xa_init(&s->s_delegated_inos); + atomic_set(&s->s_num_deleg_inos, 0); s->s_num_cap_releases = 0; s->s_cap_reconnect = 0; s->s_cap_iterator = NULL; INIT_LIST_HEAD(&s->s_cap_releases); INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work); @@ -3908,10 +3951,11 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, reply = ceph_msg_new2(CEPH_MSG_CLIENT_RECONNECT, 0, 1, GFP_NOFS, false); if (!reply) goto fail_nomsg; xa_destroy(&session->s_delegated_inos); + atomic_set(&session->s_num_deleg_inos, 0); mutex_lock(&session->s_mutex); session->s_state = CEPH_MDS_SESSION_RECONNECTING; session->s_seq = 0; diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index b1939f916228..847f04424be3 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -208,10 +208,11 @@ struct ceph_mds_session { u64 s_renew_seq; struct list_head s_waiting; /* waiting requests */ struct list_head s_unsafe; /* unsafe requests */ struct xarray s_delegated_inos; + atomic_t s_num_deleg_inos; }; /* * modes of choosing which MDS to send a request to */ diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c0c5ed3e2718..6b2e0cfb9ae3 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -538,10 +538,19 @@ static inline int ceph_ino_compare(struct inode *inode, void *data) #define CEPH_MAX_MDS 0x100 #define CEPH_NUM_STRAY 10 #define CEPH_MDS_INO_MDSDIR_OFFSET (1 * CEPH_MAX_MDS) #define CEPH_INO_SYSTEM_BASE ((6*CEPH_MAX_MDS) + (CEPH_MAX_MDS * CEPH_NUM_STRAY)) +/* + * Upper bound on the number of delegated inodes a single MDS session may + * hold. The MDS normally hands out a small preallocation window (the + * userspace mds_client_prealloc_inos option defaults to 1000) and refills + * it as the client consumes entries. This leaves generous headroom while + * bounding the CPU and memory a malformed delegation interval can consume. + */ +#define CEPH_MAX_DELEG_INOS 8192 + static inline bool ceph_vino_is_reserved(const struct ceph_vino vino) { if (vino.ino < CEPH_INO_SYSTEM_BASE && vino.ino >= CEPH_MDS_INO_MDSDIR_OFFSET) { WARN_RATELIMIT(1, "Attempt to access reserved inode number 0x%llx", vino.ino); -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] nvme-tcp: fix host memory disclosure on R2T for a read command
by Chen Yuxi 23 Sep '26

23 Sep '26
From: Yehyeong Lee <yhlee(a)isslab.korea.ac.kr> mainline inclusion from mainline-v7.3-rc1 commit 6efbc52237facda35d2d874fe1765bb4839275d8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18846 CVE: CVE-2026-89481 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- nvme_tcp_handle_r2t() does not check the direction of the request the R2T refers to. A malicious controller can send an R2T for a READ and the host will answer it: nvme_tcp_setup_h2c_data_pdu() builds the H2CData header and nvme_tcp_try_send_data() sends the request's data buffer. That buffer is the READ destination, so its contents go to the controller. The command then completes normally and nothing is logged. Against a test controller that answers every READ with an R2T, a 4096 byte buffered read returned all 4096 bytes, split over two R2Ts. The pages contained stale kernel data, including an array of struct page pointers. Reject an R2T for a request that is not a write. Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver") Cc: stable(a)vger.kernel.org Signed-off-by: Yehyeong Lee <yhlee(a)isslab.korea.ac.kr> Signed-off-by: Keith Busch <kbusch(a)kernel.org> Conflicts: drivers/nvme/host/tcp.c [Upstream commit 1d3ef9c3a39e ("nvme-tcp: validate R2T PDU in nvme_tcp_handle_r2t()") is not backported, so there is no standalone r2t_length check after req = blk_mq_rq_to_pdu(rq); insert the rq_data_dir() check right after it, before nvme_tcp_setup_h2c_data_pdu().] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- drivers/nvme/host/tcp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 89cef71def14..586f47e47b11 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -680,6 +680,13 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue, } req = blk_mq_rq_to_pdu(rq); + if (unlikely(rq_data_dir(rq) != WRITE)) { + dev_err(queue->ctrl->ctrl.device, + "req %d unexpected r2t for a non-write command\n", + rq->tag); + return -EPROTO; + } + ret = nvme_tcp_setup_h2c_data_pdu(req, pdu); if (unlikely(ret)) return ret; -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] lockd: pin next file across nlm_inspect_file lock-drop
by Pu Lehui 23 Sep '26

23 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> stable inclusion from stable-v5.10.270 commit e3c413f789eaf0170275c7eba523ead73d963f30 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18850 CVE: CVE-2026-89485 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit 526c49cff3f72c3ec74752016380c7567040581b upstream. nlm_traverse_files() pins the current file with f_count++ across a mutex_unlock for nlm_inspect_file(), but nothing pins the saved next pointer. A concurrent nlm_release_file() can kfree the next file during the unlock window, and the iterator dereferences freed memory on the next loop step. Pin both current and next before the lock-drop. Advance by swapping the pinned cursors at the end of each iteration so next is always held alive across the unlock. Always call nlm_file_release() after dropping the iteration pin, regardless of whether the file matched the predicate. Use nlm_file_inuse(), which does a live walk of the inode lock list, rather than the cached f_locks field, so skipped files that never ran nlm_inspect_file() are evaluated correctly. Because every file in a hash bucket is now pinned and released, files skipped by the is_failover_file predicate that have no locks, blocks, shares, or external references are deleted during traversal. The old code never evaluated skipped files for cleanup. The new behavior is intentional: such files are stale and should not persist in the table. Fixes: 01df9c5e918a ("LOCKD: Fix a deadlock in nlm_traverse_files()") Cc: stable(a)vger.kernel.org Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Link: https://patch.msgid.link/20260524115527.1734251-1-michael.bommarito@gmail.c… Signed-off-by: Chuck Lever <chuck.lever(a)oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- fs/lockd/svcsubs.c | 55 ++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index e64e0110f66b..9e2a67bfd070 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -286,12 +286,10 @@ nlm_file_inuse(struct nlm_file *file) return 0; } -static void nlm_close_files(struct nlm_file *file) +static void nlm_file_release(struct nlm_file *file) { - if (file->f_file[O_RDONLY]) - nlmsvc_ops->fclose(file->f_file[O_RDONLY]); - if (file->f_file[O_WRONLY]) - nlmsvc_ops->fclose(file->f_file[O_WRONLY]); + if (!nlm_file_inuse(file)) + nlm_delete_file(file); } /* @@ -301,32 +299,41 @@ static int nlm_traverse_files(void *data, nlm_host_match_fn_t match, int (*is_failover_file)(void *data, struct nlm_file *file)) { - struct hlist_node *next; - struct nlm_file *file; + struct nlm_file *file, *next; int i, ret = 0; mutex_lock(&nlm_file_mutex); for (i = 0; i < FILE_NRHASH; i++) { - hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) { - if (is_failover_file && !is_failover_file(data, file)) - continue; + file = hlist_entry_safe(nlm_files[i].first, + struct nlm_file, f_list); + if (file) file->f_count++; - mutex_unlock(&nlm_file_mutex); - - /* Traverse locks, blocks and shares of this file - * and update file->f_locks count */ - if (nlm_inspect_file(data, file, match)) - ret = 1; + while (file) { + /* + * Pin the next neighbour before we drop the mutex + * for nlm_inspect_file(); a concurrent + * nlm_release_file() under the same mutex would + * otherwise be free to unlink and kfree it during + * the unlock window, leaving us to dereference a + * freed slab when we walked to next afterwards. + */ + next = hlist_entry_safe(file->f_list.next, + struct nlm_file, f_list); + if (next) + next->f_count++; + + if (!is_failover_file || is_failover_file(data, file)) { + mutex_unlock(&nlm_file_mutex); + + if (nlm_inspect_file(data, file, match)) + ret = 1; + + mutex_lock(&nlm_file_mutex); + } - mutex_lock(&nlm_file_mutex); file->f_count--; - /* No more references to this file. Let go of it. */ - if (list_empty(&file->f_blocks) && !file->f_locks - && !file->f_shares && !file->f_count) { - hlist_del(&file->f_list); - nlm_close_files(file); - kfree(file); - } + nlm_file_release(file); + file = next; } } mutex_unlock(&nlm_file_mutex); -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] [Backport] media: cec: disable delayed work before freeing an interrupted transmit
by Chen Jinghuang 23 Sep '26

23 Sep '26
From: Biren Pandya <birenpandya(a)gmail.com> mainline inclusion from mainline-v7.2-rc1 commit 0fbd5c2327020858c45b2d1c65775d64cdeca523 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19090 CVE: CVE-2026-89899 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- cec_transmit_msg_fh() drops adap->lock to wait for a blocking transmit in wait_for_completion_killable(). If that wait is interrupted by a signal, cancel_delayed_work_sync() can run before the CEC kthread arms the reply timeout via schedule_delayed_work(&data->work) in cec_transmit_done_ts(). The work is then armed after the cancel, and the data is freed with its delayed_work still pending: ODEBUG: free active (active state 0) object: ... hint: cec_wait_timeout Use disable_delayed_work_sync(): it cancels the work and disables it, so the later schedule_delayed_work() becomes a no-op and the work cannot be re-armed. The data is freed right after, so it need not be re-enabled. Fixes: 490d84f6d73c ("media: cec: forgot to cancel delayed work") Reported-by: syzbot+051024d603432b4ab395(a)syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=051024d603432b4ab395 Suggested-by: Hillf Danton <hdanton(a)sina.com> Cc: stable(a)vger.kernel.org Signed-off-by: Biren Pandya <birenpandya(a)gmail.com> Signed-off-by: Hans Verkuil <hverkuil+cisco(a)kernel.org> Conflicts: drivers/media/cec/core/cec-adap.c [The 5.10 tree lacks the disable_delayed_work_sync() API (added in v6.9) and uses the older wait/!data->completed structure; keep the original cancel_delayed_work_sync() and, under adap->lock, cancel the reply-timeout work again before freeing, waiting for a running work without the lock (cec_wait_timeout() takes adap->lock) and re-cancelling after re-locking.] Signed-off-by: Chen Jinghuang <chenjinghuang2(a)huawei.com> --- drivers/media/cec/core/cec-adap.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index eed962a9ff01..05329c40a58e 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -918,8 +918,24 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, mutex_lock(&adap->lock); /* Cancel the transmit if it was interrupted */ - if (!data->completed) - cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + if (!data->completed) { + /* + * The reply-timeout delayed work may have been armed by the + * CEC kthread after the cancel above. Cancel it under the lock; + * if it is already running it is blocked on adap->lock (as + * cec_wait_timeout() takes the lock itself), so wait for it + * without the lock like cec_receive_notify() does, then cancel + * again in case the kthread armed it in the meantime. + */ + if (!cancel_delayed_work(&data->work)) { + mutex_unlock(&adap->lock); + cancel_delayed_work_sync(&data->work); + mutex_lock(&adap->lock); + cancel_delayed_work(&data->work); + } + if (!data->completed) + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + } /* The transmit completed (possibly with an error) */ *msg = data->msg; -- 2.34.1
2 1
0 0
  • ← Newer
  • 1
  • ...
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • ...
  • 2507
  • Older →

HyperKitty Powered by HyperKitty