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 -----
  • 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

  • 44 participants
  • 24952 discussions
[PATCH OLK-6.6] nvme-fabrics: fix DHCHAP secret leak on parse failure
by Chen Yuxi 23 Sep '26

23 Sep '26
From: Xu Rao <raoxu(a)uniontech.com> mainline inclusion from mainline-v7.3-rc2 commit afdee49a1b88ed9bb44e2b30e855297c169bcc53 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19103 CVE: CVE-2026-89975 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- nvmf_parse_options() duplicates dhchap_secret and dhchap_ctrl_secret with match_strdup() before validating the DHHC-1: representation. If validation fails, the parser returns -EINVAL before the temporary string in p is assigned to opts->dhchap_secret or opts->dhchap_ctrl_secret. nvmf_create_ctrl() subsequently frees opts, but nvmf_free_options() cannot release the unassigned temporary string. Each rejected option therefore leaks one allocation. This is easy to miss because valid secrets transfer ownership to opts and are freed normally, while the malformed-secret path still returns the expected -EINVAL to userspace. With CONFIG_NVME_HOST_AUTH enabled, the leak is reachable before the required-option checks and transport lookup. No NVMe-oF target or working transport connection is required; for example, repeatedly writing dhchap_secret=BAD or dhchap_ctrl_secret=BAD to /dev/nvme-fabrics deterministically takes the leaking parse path. Free the temporary string before leaving both validation error paths. Use kfree_sensitive() because the copied option may contain secret material even when its representation is rejected, matching the sensitive cleanup used for stored DHCHAP secrets. Fixes: f50fff73d620 ("nvme: implement In-Band authentication") Cc: stable(a)vger.kernel.org Reviewed-by: Christoph Hellwig <hch(a)lst.de> Signed-off-by: Xu Rao <raoxu(a)uniontech.com> Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- drivers/nvme/host/fabrics.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 5119421afd95..6f5a4670c5d8 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -952,6 +952,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, } if (strlen(p) < 11 || strncmp(p, "DHHC-1:", 7)) { pr_err("Invalid DH-CHAP secret %s\n", p); + kfree_sensitive(p); ret = -EINVAL; goto out; } @@ -966,6 +967,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, } if (strlen(p) < 11 || strncmp(p, "DHHC-1:", 7)) { pr_err("Invalid DH-CHAP secret %s\n", p); + kfree_sensitive(p); ret = -EINVAL; goto out; } -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] nvme-tcp: reject a read that transferred too few bytes
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 7fa3f73f6c8ddc5f0425b50fb2a626a782ef7d12 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18845 CVE: CVE-2026-89480 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- nvme_tcp_recv_data() completes a request once the current C2HData PDU has been consumed. Nothing compares the total bytes received against the length the command asked for: struct nvme_tcp_request has no receive-side counter, queue->data_remaining is per queue, and blk_mq_end_request() completes for blk_rq_bytes(rq) unconditionally with no residual concept anywhere above. A controller can therefore answer a 4096-byte read with 512 bytes and have it reported as a complete read; user space then gets 4096 bytes of which 3584 are whatever was already in the page. I reproduced that with a test target. Count the bytes received and refuse to complete a successful read whose count does not match, at the two NVME_TCP_F_DATA_SUCCESS paths and in nvme_tcp_process_nvme_cqe(). The success test shifts req->status right by one, because the driver keeps the wire value there and shifts it on completion, so the check must see what the completion path will see. Only REQ_OP_READ is checked, because there the length comes from the sectors the request covers; a passthrough command is built by its submitter, which picks both command and buffer, so the kernel has nothing to compare against. 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 1ba2e507f55c ("nvme-tcp: Do not reset transport on data digest errors") is not backported, so this tree completes DATA_SUCCESS requests with the hard-coded NVME_SC_SUCCESS and passes cqe->status directly to nvme_try_complete_req(); give nvme_tcp_data_in_short() an explicit status argument and pass le16_to_cpu(cqe->status) or NVME_SC_SUCCESS at the call sites.] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- drivers/nvme/host/tcp.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 89cef71def14..0779596f629b 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -89,6 +89,7 @@ struct nvme_tcp_request { struct bio *curr_bio; struct iov_iter iter; + u32 data_recvd; /* send state */ size_t offset; @@ -534,6 +535,29 @@ static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl) queue_work(nvme_reset_wq, &to_tcp_ctrl(ctrl)->err_work); } +/* + * NVMe has no short read: a read that completes successfully must + * have transferred everything it asked for. + */ +static bool nvme_tcp_data_in_short(struct nvme_tcp_queue *queue, + struct request *rq, u16 status) +{ + struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq); + + if (status >> 1) + return false; + if (req_op(rq) != REQ_OP_READ || !req->data_len) + return false; + if (likely(req->data_recvd == req->data_len)) + return false; + + dev_err(queue->ctrl->ctrl.device, + "queue %d tag %#x short data-in: got %u of %u\n", + nvme_tcp_queue_id(queue), rq->tag, + req->data_recvd, req->data_len); + return true; +} + static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue, struct nvme_completion *cqe) { @@ -548,6 +572,10 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue, return -EINVAL; } + if (unlikely(nvme_tcp_data_in_short(queue, rq, + le16_to_cpu(cqe->status)))) + return -EPROTO; + if (!nvme_try_complete_req(rq, cqe->status, cqe->result)) nvme_complete_rq(rq); queue->nr_cqe++; @@ -815,6 +843,7 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb, *len -= recv_len; *offset += recv_len; queue->data_remaining -= recv_len; + req->data_recvd += recv_len; } if (!queue->data_remaining) { @@ -823,6 +852,9 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb, queue->ddgst_remaining = NVME_TCP_DIGEST_LENGTH; } else { if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) { + if (unlikely(nvme_tcp_data_in_short(queue, rq, + NVME_SC_SUCCESS))) + return -EPROTO; nvme_tcp_end_request(rq, NVME_SC_SUCCESS); queue->nr_cqe++; } @@ -864,6 +896,10 @@ static int nvme_tcp_recv_ddgst(struct nvme_tcp_queue *queue, struct request *rq = nvme_cid_to_rq(nvme_tcp_tagset(queue), pdu->command_id); + if (unlikely(nvme_tcp_data_in_short(queue, rq, + NVME_SC_SUCCESS))) + return -EPROTO; + nvme_tcp_end_request(rq, NVME_SC_SUCCESS); queue->nr_cqe++; } @@ -2394,6 +2430,7 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns, req->state = NVME_TCP_SEND_CMD_PDU; req->offset = 0; req->data_sent = 0; + req->data_recvd = 0; req->pdu_len = 0; req->pdu_sent = 0; req->data_len = blk_rq_nr_phys_segments(rq) ? -- 2.34.1
2 1
0 0
[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
  • ← Newer
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...
  • 2496
  • Older →

HyperKitty Powered by HyperKitty