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

  • 46 participants
  • 24481 discussions
[PATCH OLK-6.6] tracing: Fix race between update_event_fields and, event_define_fields
by Tengda Wu 25 Aug '26

25 Aug '26
From: Michael Wu <michael(a)allwinnertech.com> stable inclusion from stable-v6.6.152 commit e5f1d301b4bdaa4206db251fdc691f623162b0a8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18289 CVE: CVE-2026-74636 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit c3730b8373bb5059d735509b9e6a00d7eb337d7c upstream. The following sequence may leads race between event_define_fields() and update_event_fields(): CPU0 (loads module A) CPU1 (loads module B) =============================== =============================== load_module(A) load_module(B) notifier_call_chain notifier_call_chain trace_module_notify trace_module_notify mutex_lock(&event_mutex) trace_event_update_all() trace_module_add_events(A) down_write(&trace_event_sem) __register_event(call_A) __add_event_to_tracers(call_A) event_define_fields(call_A) for each f: list_for_each_entry(field, list_add(&f->link, &class->fields, link) &class->fields) field = class->fields->next; Where access to the class->fields is not protected by the event_mutex in trace_event_update_all(). This produces the following panic: Unable to handle kernel access ... at virtual address 0000000000000018 pc : update_event_fields+0xf8/0x368 Call trace: update_event_fields+0xf8/0x368 trace_event_update_all+0x7c/0x2b4 trace_module_notify+0x4c/0x1dc notifier_call_chain+0x84/0x168 blocking_notifier_call_chain_robust+0x64/0xd4 load_module+0x10c8/0x123c __arm64_sys_finit_module+0x230/0x31c Fix by taking event_mutex in trace_event_update_all() before trace_event_sem. Cc: stable(a)vger.kernel.org Fixes: b3bc8547d3be ("tracing: Have TRACE_DEFINE_ENUM affect trace event types as well") Link: https://patch.msgid.link/2e5730d2-c631-da41-3a3a-ae35bb4895f3@allwinnertech… Signed-off-by: Michael Wu <michael(a)allwinnertech.com> Signed-off-by: Steven Rostedt <rostedt(a)goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Conflicts: kernel/trace/trace_events.c [Context conflict] Signed-off-by: Tengda Wu <wutengda2(a)huawei.com> --- kernel/trace/trace_events.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index bea0ab4d8d73..7326cfafcc23 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -3035,6 +3035,7 @@ void trace_event_eval_update(struct trace_eval_map **map, int len) int last_i; int i; + mutex_lock(&event_mutex); down_write(&trace_event_sem); list_for_each_entry_safe(call, p, &ftrace_events, list) { /* events are usually grouped together with systems */ @@ -3068,6 +3069,7 @@ void trace_event_eval_update(struct trace_eval_map **map, int len) cond_resched(); } up_write(&trace_event_sem); + mutex_unlock(&event_mutex); } static struct trace_event_file * -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] eventfs: Fix use-after-free in eventfs_remove_rec()
by Tengda Wu 25 Aug '26

25 Aug '26
From: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> stable inclusion from stable-v6.6.152 commit b77581b25e213e83b79ce11eb30024e55ceeb3e9 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18299 CVE: CVE-2026-74606 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit fd73b691702170d37d66f4b0278530cea8ed419a upstream. eventfs_remove_rec() recursively removes the child at the current loop position. After the recursive call returns, list_for_each_entry() advances by reading list.next from the removed child. If free_ei() drops the final reference, release_ei() reuses the list/rcu union to queue an SRCU callback. The child may be freed before that read. The eventfs_mutex serializes list updates, but it does not keep the removed child alive or prevent the SRCU callback from running. Use list_for_each_entry_safe() to save the next sibling before recursively removing the current child. Cc: stable(a)vger.kernel.org Fixes: 43aa6f97c2d0 ("eventfs: Get rid of dentry pointers without refcounts") Link: https://patch.msgid.link/20260806022719.375354-1-shuangpeng.kernel@gmail.com Signed-off-by: Shuangpeng Bai <shuangpeng.kernel(a)gmail.com> Acked-by: Masami Hiramatsu (Google) <mhiramat(a)kernel.org> Signed-off-by: Steven Rostedt <rostedt(a)goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2(a)huawei.com> --- fs/tracefs/event_inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 36257e1092d6..4ac459c7efc3 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -922,7 +922,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry */ static void eventfs_remove_rec(struct eventfs_inode *ei, int level) { - struct eventfs_inode *ei_child; + struct eventfs_inode *ei_child, *tmp; /* * Check recursion depth. It should never be greater than 3: @@ -935,7 +935,7 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, int level) return; /* search for nested folders or files */ - list_for_each_entry(ei_child, &ei->children, list) + list_for_each_entry_safe(ei_child, tmp, &ei->children, list) eventfs_remove_rec(ei_child, level + 1); list_del_rcu(&ei->list); -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] RDMA/rxe: Copy WQE to local buffer in non-SRQ receive path
by Chen Jinghuang 25 Aug '26

25 Aug '26
From: Tristan Madani <tristmd(a)gmail.com> mainline inclusion from mainline-v7.2-rc1 commit d6ab440240a04b8737ee4c7bb21af9182e451733 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17929 CVE: CVE-2026-74377 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- For non-SRQ QPs, the responder reads WQE fields directly from the shared queue buffer mapped into userspace. This allows a malicious user to modify fields like num_sge or sge entries while the kernel is processing the WQE, leading to out-of-bounds reads in rxe_resp_check_length() and copy_data(). Introduce get_recv_wqe() that validates num_sge and copies the WQE to a kernel-local buffer before processing, matching the approach already used for SRQ WQEs in get_srq_wqe(). The srq_wqe buffer is reused since SRQ and non-SRQ paths are mutually exclusive per QP. Fixes: 8700e3e7c485 ("Soft RoCE driver") Link: https://patch.msgid.link/r/20260518215040.1598586-3-tristan@talencesecurity… Signed-off-by: Tristan Madani <tristan(a)talencesecurity.com> Reviewed-by: Zhu Yanjun <yanjun.zhu(a)linux.dev> Signed-off-by: Jason Gunthorpe <jgg(a)nvidia.com> Conflicts: drivers/infiniband/sw/rxe/rxe_resp.c [The target tree has an older rxe_queue API without a queue type argument and lacks the rxe_dbg_qp() logging macro. Adapted rxe_get_recv_wqe() to call queue_head(q) with the single argument signature and to log via pr_debug()/qp_num() instead of rxe_dbg_qp().] Signed-off-by: Chen Jinghuang <chenjinghuang2(a)huawei.com> --- drivers/infiniband/sw/rxe/rxe_resp.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 83c03212099a..8626cd280ebb 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -328,6 +328,29 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp) return RESPST_CHK_LENGTH; } +static enum resp_states rxe_get_recv_wqe(struct rxe_qp *qp) +{ + struct rxe_queue *q = qp->rq.queue; + struct rxe_recv_wqe *wqe; + unsigned int num_sge; + size_t size; + + wqe = queue_head(q); + if (!wqe) + return RESPST_ERR_RNR; + + num_sge = wqe->dma.num_sge; + if (unlikely(num_sge > qp->rq.max_sge)) { + pr_debug("qp#%d invalid num_sge in recv WQE\n", qp_num(qp)); + return RESPST_ERR_MALFORMED_WQE; + } + size = sizeof(*wqe) + num_sge * sizeof(struct rxe_sge); + memcpy(&qp->resp.srq_wqe, wqe, size); + + qp->resp.wqe = &qp->resp.srq_wqe.wqe; + return RESPST_CHK_LENGTH; +} + static enum resp_states check_resource(struct rxe_qp *qp, struct rxe_pkt_info *pkt) { @@ -365,8 +388,7 @@ static enum resp_states check_resource(struct rxe_qp *qp, if (srq) return get_srq_wqe(qp); - qp->resp.wqe = queue_head(qp->rq.queue); - return (qp->resp.wqe) ? RESPST_CHK_LENGTH : RESPST_ERR_RNR; + return rxe_get_recv_wqe(qp); } return RESPST_CHK_LENGTH; -- 2.34.1
2 1
0 0
[PTACH openEuler-1.0-LTS] RDMA/mlx5: Release the HW‑provided UAR index rather than the SW one
by Chen Jinghuang 25 Aug '26

25 Aug '26
From: Leon Romanovsky <leonro(a)nvidia.com> mainline inclusion from mainline-v7.2-rc1 commit 449ae7927152e46acbe5f19f97eafdae6d3a96b1 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18162 CVE: CVE-2026-74296 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- Free the UAR index returned by the hardware. Fixes: 4ed131d0bb15 ("IB/mlx5: Expose dynamic mmap allocation") Link: https://patch.msgid.link/r/20260611-fix-uar-release-v1-1-f5464d845dbf@nvidi… Signed-off-by: Leon Romanovsky <leonro(a)nvidia.com> Signed-off-by: Jason Gunthorpe <jgg(a)nvidia.com> Conflicts: drivers/infiniband/hw/mlx5/main.c [ Context conflict ] Signed-off-by: Chen jinghuang <chenjinghuang2(a)huawei.com> --- drivers/infiniband/hw/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 4f340d6db582..051de9f3ed82 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2148,7 +2148,7 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd, if (!dyn_uar) return err; - mlx5_cmd_free_uar(dev->mdev, idx); + mlx5_cmd_free_uar(dev->mdev, uar_index); free_bfreg: mlx5_ib_free_bfreg(dev, bfregi, bfreg_dyn_idx); -- 2.34.1
1 0
0 0
[PATCH OLK-6.6] bpf: Avoid lockup of bpf_lru_list in NMI by using trylock
by Chen Yuxi 25 Aug '26

25 Aug '26
Offering: HULK hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17962 CVE: CVE-2026-74337 -------------------------------- The upstream fix for this CVE relies on the rqspinlock feature, which hulk has not yet introduced, so it cannot be backported directly. Instead, use raw_spin_trylock instead of the blocking lock, returning immediately when the trylock fails to avoid a deadlock in NMI. Fixes: 3a08c2fd7634 ("bpf: LRU List") Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- kernel/bpf/bpf_lru_list.c | 160 ++++++++++++++++++++++++++------------ kernel/bpf/bpf_lru_list.h | 20 ++++- 2 files changed, 128 insertions(+), 52 deletions(-) diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c index 2d6e1c98d8ad..0884b1b23b10 100644 --- a/kernel/bpf/bpf_lru_list.c +++ b/kernel/bpf/bpf_lru_list.c @@ -13,10 +13,6 @@ #define PERCPU_FREE_TARGET (4) #define PERCPU_NR_SCANS PERCPU_FREE_TARGET -/* Helpers to get the local list index */ -#define LOCAL_LIST_IDX(t) ((t) - BPF_LOCAL_LIST_T_OFFSET) -#define LOCAL_FREE_LIST_IDX LOCAL_LIST_IDX(BPF_LRU_LOCAL_LIST_T_FREE) -#define LOCAL_PENDING_LIST_IDX LOCAL_LIST_IDX(BPF_LRU_LOCAL_LIST_T_PENDING) #define IS_LOCAL_LIST_TYPE(t) ((t) >= BPF_LOCAL_LIST_T_OFFSET) static int get_next_cpu(int cpu) @@ -27,17 +23,6 @@ static int get_next_cpu(int cpu) return cpu; } -/* Local list helpers */ -static struct list_head *local_free_list(struct bpf_lru_locallist *loc_l) -{ - return &loc_l->lists[LOCAL_FREE_LIST_IDX]; -} - -static struct list_head *local_pending_list(struct bpf_lru_locallist *loc_l) -{ - return &loc_l->lists[LOCAL_PENDING_LIST_IDX]; -} - /* bpf_lru_node helpers */ static bool bpf_lru_node_is_ref(const struct bpf_lru_node *node) { @@ -80,6 +65,7 @@ static void __bpf_lru_node_move_to_free(struct bpf_lru_list *l, bpf_lru_list_count_dec(l, node->type); node->type = tgt_free_type; + WRITE_ONCE(node->pending_free, 0); list_move(&node->list, free_list); } @@ -95,6 +81,9 @@ static void __bpf_lru_node_move_in(struct bpf_lru_list *l, bpf_lru_list_count_inc(l, tgt_type); node->type = tgt_type; bpf_lru_node_clear_ref(node); + /* Reset pending_free only when moving to the free list */ + if (tgt_type == BPF_LRU_LIST_T_FREE) + WRITE_ONCE(node->pending_free, 0); list_move(&node->list, &l->lists[tgt_type]); } @@ -220,11 +209,13 @@ __bpf_lru_list_shrink_inactive(struct bpf_lru *lru, unsigned int i = 0; list_for_each_entry_safe_reverse(node, tmp_node, inactive, list) { - if (bpf_lru_node_is_ref(node)) { + if (bpf_lru_node_is_ref(node) && + !READ_ONCE(node->pending_free)) { __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE); - } else if (lru->del_from_htab(lru->del_arg, node)) { + } else if (READ_ONCE(node->pending_free) || + lru->del_from_htab(lru->del_arg, node)) { __bpf_lru_node_move_to_free(l, node, free_list, - tgt_free_type); + tgt_free_type); if (++nshrinked == tgt_nshrink) break; } @@ -281,7 +272,8 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru, list_for_each_entry_safe_reverse(node, tmp_node, force_shrink_list, list) { - if (lru->del_from_htab(lru->del_arg, node)) { + if (READ_ONCE(node->pending_free) || + lru->del_from_htab(lru->del_arg, node)) { __bpf_lru_node_move_to_free(l, node, free_list, tgt_free_type); return 1; @@ -298,8 +290,10 @@ static void __local_list_flush(struct bpf_lru_list *l, struct bpf_lru_node *node, *tmp_node; list_for_each_entry_safe_reverse(node, tmp_node, - local_pending_list(loc_l), list) { - if (bpf_lru_node_is_ref(node)) + &loc_l->pending_list, list) { + if (READ_ONCE(node->pending_free)) + __bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_FREE); + else if (bpf_lru_node_is_ref(node)) __bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_ACTIVE); else __bpf_lru_node_move_in(l, node, @@ -315,7 +309,14 @@ static void bpf_lru_list_push_free(struct bpf_lru_list *l, if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type))) return; - raw_spin_lock_irqsave(&l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&l->lock, flags)) { + WRITE_ONCE(node->pending_free, 1); + return; + } + } else { + raw_spin_lock_irqsave(&l->lock, flags); + } __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE); raw_spin_unlock_irqrestore(&l->lock, flags); } @@ -326,8 +327,14 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru, struct bpf_lru_list *l = &lru->common_lru.lru_list; struct bpf_lru_node *node, *tmp_node; unsigned int nfree = 0; + LIST_HEAD(tmp_free); - raw_spin_lock(&l->lock); + if (in_nmi()) { + if (!raw_spin_trylock(&l->lock)) + return; + } else { + raw_spin_lock(&l->lock); + } __local_list_flush(l, loc_l); @@ -335,7 +342,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru, list_for_each_entry_safe(node, tmp_node, &l->lists[BPF_LRU_LIST_T_FREE], list) { - __bpf_lru_node_move_to_free(l, node, local_free_list(loc_l), + __bpf_lru_node_move_to_free(l, node, &tmp_free, BPF_LRU_LOCAL_LIST_T_FREE); if (++nfree == lru->target_free) break; @@ -343,10 +350,19 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru, if (nfree < lru->target_free) __bpf_lru_list_shrink(lru, l, lru->target_free - nfree, - local_free_list(loc_l), + &tmp_free, BPF_LRU_LOCAL_LIST_T_FREE); raw_spin_unlock(&l->lock); + + /* + * Transfer the harvested nodes from the temporary list_head into + * the lockless per-CPU free llist. + */ + list_for_each_entry_safe(node, tmp_node, &tmp_free, list) { + list_del(&node->list); + llist_add(&node->llist, &loc_l->free_llist); + } } static void __local_list_add_pending(struct bpf_lru *lru, @@ -358,22 +374,21 @@ static void __local_list_add_pending(struct bpf_lru *lru, *(u32 *)((void *)node + lru->hash_offset) = hash; node->cpu = cpu; node->type = BPF_LRU_LOCAL_LIST_T_PENDING; + WRITE_ONCE(node->pending_free, 0); bpf_lru_node_clear_ref(node); - list_add(&node->list, local_pending_list(loc_l)); + list_add(&node->list, &loc_l->pending_list); } static struct bpf_lru_node * __local_list_pop_free(struct bpf_lru_locallist *loc_l) { - struct bpf_lru_node *node; + struct llist_node *llnode; - node = list_first_entry_or_null(local_free_list(loc_l), - struct bpf_lru_node, - list); - if (node) - list_del(&node->list); + llnode = llist_del_first(&loc_l->free_llist); + if (!llnode) + return NULL; - return node; + return container_of(llnode, struct bpf_lru_node, llist); } static struct bpf_lru_node * @@ -384,10 +399,10 @@ __local_list_pop_pending(struct bpf_lru *lru, struct bpf_lru_locallist *loc_l) ignore_ref: /* Get from the tail (i.e. older element) of the pending list. */ - list_for_each_entry_reverse(node, local_pending_list(loc_l), - list) { + list_for_each_entry_reverse(node, &loc_l->pending_list, list) { if ((!bpf_lru_node_is_ref(node) || force) && - lru->del_from_htab(lru->del_arg, node)) { + (READ_ONCE(node->pending_free) || + lru->del_from_htab(lru->del_arg, node))) { list_del(&node->list); return node; } @@ -412,7 +427,12 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(struct bpf_lru *lru, l = per_cpu_ptr(lru->percpu_lru, cpu); - raw_spin_lock_irqsave(&l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&l->lock, flags)) + return NULL; + } else { + raw_spin_lock_irqsave(&l->lock, flags); + } __bpf_lru_list_rotate(lru, l); @@ -445,7 +465,12 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct bpf_lru *lru, loc_l = per_cpu_ptr(clru->local_list, cpu); - raw_spin_lock_irqsave(&loc_l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&loc_l->lock, flags)) + return NULL; + } else { + raw_spin_lock_irqsave(&loc_l->lock, flags); + } node = __local_list_pop_free(loc_l); if (!node) { @@ -474,7 +499,12 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct bpf_lru *lru, do { steal_loc_l = per_cpu_ptr(clru->local_list, steal); - raw_spin_lock_irqsave(&steal_loc_l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&steal_loc_l->lock, flags)) + goto next_steal; + } else { + raw_spin_lock_irqsave(&steal_loc_l->lock, flags); + } node = __local_list_pop_free(steal_loc_l); if (!node) @@ -482,16 +512,33 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct bpf_lru *lru, raw_spin_unlock_irqrestore(&steal_loc_l->lock, flags); +next_steal: steal = get_next_cpu(steal); } while (!node && steal != first_steal); loc_l->next_steal = steal; - if (node) { - raw_spin_lock_irqsave(&loc_l->lock, flags); - __local_list_add_pending(lru, loc_l, cpu, node, hash); + if (!node) + return NULL; + + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&loc_l->lock, flags)) { + /* + * Could not re-acquire the local lock; publish the + * stolen node to the lockless per-CPU free_llist + * instead of orphaning it. + */ + node->type = BPF_LRU_LOCAL_LIST_T_FREE; + bpf_lru_node_clear_ref(node); + WRITE_ONCE(node->pending_free, 0); + llist_add(&node->llist, &loc_l->free_llist); + return NULL; + } + } else { raw_spin_unlock_irqrestore(&loc_l->lock, flags); } + __local_list_add_pending(lru, loc_l, cpu, node, hash); + raw_spin_unlock_irqrestore(&loc_l->lock, flags); return node; } @@ -519,7 +566,14 @@ static void bpf_common_lru_push_free(struct bpf_lru *lru, loc_l = per_cpu_ptr(lru->common_lru.local_list, node->cpu); - raw_spin_lock_irqsave(&loc_l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&loc_l->lock, flags)) { + WRITE_ONCE(node->pending_free, 1); + return; + } + } else { + raw_spin_lock_irqsave(&loc_l->lock, flags); + } if (unlikely(node->type != BPF_LRU_LOCAL_LIST_T_PENDING)) { raw_spin_unlock_irqrestore(&loc_l->lock, flags); @@ -528,9 +582,10 @@ static void bpf_common_lru_push_free(struct bpf_lru *lru, node->type = BPF_LRU_LOCAL_LIST_T_FREE; bpf_lru_node_clear_ref(node); - list_move(&node->list, local_free_list(loc_l)); + list_del(&node->list); raw_spin_unlock_irqrestore(&loc_l->lock, flags); + llist_add(&node->llist, &loc_l->free_llist); return; } @@ -546,7 +601,14 @@ static void bpf_percpu_lru_push_free(struct bpf_lru *lru, l = per_cpu_ptr(lru->percpu_lru, node->cpu); - raw_spin_lock_irqsave(&l->lock, flags); + if (in_nmi()) { + if (!raw_spin_trylock_irqsave(&l->lock, flags)) { + WRITE_ONCE(node->pending_free, 1); + return; + } + } else { + raw_spin_lock_irqsave(&l->lock, flags); + } __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE); @@ -573,6 +635,7 @@ static void bpf_common_lru_populate(struct bpf_lru *lru, void *buf, node = (struct bpf_lru_node *)(buf + node_offset); node->type = BPF_LRU_LIST_T_FREE; + node->pending_free = 0; bpf_lru_node_clear_ref(node); list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]); buf += elem_size; @@ -602,6 +665,7 @@ static void bpf_percpu_lru_populate(struct bpf_lru *lru, void *buf, node = (struct bpf_lru_node *)(buf + node_offset); node->cpu = cpu; node->type = BPF_LRU_LIST_T_FREE; + node->pending_free = 0; bpf_lru_node_clear_ref(node); list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]); i++; @@ -626,10 +690,8 @@ void bpf_lru_populate(struct bpf_lru *lru, void *buf, u32 node_offset, static void bpf_lru_locallist_init(struct bpf_lru_locallist *loc_l, int cpu) { - int i; - - for (i = 0; i < NR_BPF_LRU_LOCAL_LIST_T; i++) - INIT_LIST_HEAD(&loc_l->lists[i]); + INIT_LIST_HEAD(&loc_l->pending_list); + init_llist_head(&loc_l->free_llist); loc_l->next_steal = cpu; diff --git a/kernel/bpf/bpf_lru_list.h b/kernel/bpf/bpf_lru_list.h index fe2661a58ea9..5ed8831528af 100644 --- a/kernel/bpf/bpf_lru_list.h +++ b/kernel/bpf/bpf_lru_list.h @@ -6,11 +6,11 @@ #include <linux/cache.h> #include <linux/list.h> +#include <linux/llist.h> #include <linux/spinlock_types.h> #define NR_BPF_LRU_LIST_T (3) #define NR_BPF_LRU_LIST_COUNT (2) -#define NR_BPF_LRU_LOCAL_LIST_T (2) #define BPF_LOCAL_LIST_T_OFFSET NR_BPF_LRU_LIST_T enum bpf_lru_list_type { @@ -22,10 +22,23 @@ enum bpf_lru_list_type { }; struct bpf_lru_node { - struct list_head list; + /* + * A node is in at most one list at a time. The free path on the + * per-CPU locallist uses an llist, so share storage via a union. + */ + union { + struct list_head list; + struct llist_node llist; + }; u16 cpu; u8 type; u8 ref; + /* + * Marks nodes whose *_push_free() lock acquisition failed; these + * are reclaimed by flush/shrink which honor the flag instead of + * calling del_from_htab(). + */ + u8 pending_free; }; struct bpf_lru_list { @@ -38,7 +51,8 @@ struct bpf_lru_list { }; struct bpf_lru_locallist { - struct list_head lists[NR_BPF_LRU_LOCAL_LIST_T]; + struct list_head pending_list; + struct llist_head free_llist; u16 next_steal; raw_spinlock_t lock; }; -- 2.34.1
2 1
0 0
[PATCH] bpf: Reset register bounds before narrowing retval range in check_mem_access()
by Chen Yuxi 25 Aug '26

25 Aug '26
From: Tristan Madani <tristan(a)talencesecurity.com> When the BPF verifier processes a context load of an LSM hook return value, it calls __mark_reg_s32_range() to narrow the register to the hook's valid range. However, __mark_reg_s32_range() intersects the new range with the register's existing bounds using max_t()/min_t() rather than replacing them. If the destination register carries stale bounds from a prior instruction (e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than reality. The verifier then believes it knows the register's exact value, while at runtime the actual hook return value is loaded, creating a verifier/runtime mismatch that can be used to bypass BPF memory safety checks. The else branch already calls mark_reg_unknown() to reset register state before any narrowing. Apply the same reset in the is_retval path so stale bounds are cleared before __mark_reg_s32_range() intersects. Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value") Cc: stable(a)vger.kernel.org Signed-off-by: Tristan Madani <tristan(a)talencesecurity.com> Acked-by: Eduard Zingerman <eddyz87(a)gmail.com> Link: https://lore.kernel.org/r/20260622230123.3695446-2-tristmd@gmail.com Signed-off-by: Alexei Starovoitov <ast(a)kernel.org> --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a2b348f98080..21a365d436a5 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6201,6 +6201,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b */ if (info.reg_type == SCALAR_VALUE) { if (info.is_retval && get_func_retval_range(env->prog, &range)) { + mark_reg_unknown(env, regs, value_regno); err = __mark_reg_s32_range(env, regs, value_regno, range.minval, range.maxval); if (err) -- 2.34.1
1 0
0 0
[PATCH openEuler-1.0-LTS] [openEuler-1.0-LTS] smb: client: validate DFS referral PathConsumed
by Lu Chentao 25 Aug '26

25 Aug '26
From: Yichong Chen <chenyichong(a)uniontech.com> mainline inclusion from mainline-v7.2-rc5 commit f6f5ee2aa33b350c671721b965251c42cebb962e category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17157 CVE: CVE-2026-68343 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- parse_dfs_referrals() validates that the response contains the fixed referral entry array and, on for-next, the per-referral string offsets. However, the response also contains a PathConsumed value that is later used for DFS path parsing. If a malformed response provides a PathConsumed value larger than the search name, later DFS parsing can advance beyond the end of the path. Validate PathConsumed against the search name length before storing it in the parsed referral. Fixes: 4ecce920e13a ("CIFS: move DFS response parsing out of SMB1 code") Reviewed-by: Paulo Alcantara (Red Hat) <pc(a)manguebit.org> Signed-off-by: Yichong Chen <chenyichong(a)uniontech.com> Signed-off-by: Steve French <stfrench(a)microsoft.com> Conflicts: fs/cifs/misc.c [fs/cifs/misc.c: resolved via git 3-way merge of upstream f6f5ee2aa33b (clone base/theirs vs local); no overlap with local divergence] Signed-off-by: Lu Chentao <luchentao1(a)huawei.com> --- fs/cifs/misc.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 17bd7901c4b7..ee24b080c41a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -685,10 +685,12 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, const char *searchName, bool is_unicode) { int i, rc = 0; char *data_end; struct dfs_referral_level_3 *ref; + unsigned int path_consumed; + size_t search_name_len; *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); if (*num_of_nodes < 1) { cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", @@ -715,33 +717,47 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, GFP_KERNEL); if (*target_nodes == NULL) { rc = -ENOMEM; goto parse_DFS_referrals_exit; } + search_name_len = strlen(searchName); /* collect necessary data from referrals */ for (i = 0; i < *num_of_nodes; i++) { char *temp; int max_len; struct dfs_info3_param *node = (*target_nodes)+i; node->flags = le32_to_cpu(rsp->DFSFlags); + path_consumed = le16_to_cpu(rsp->PathConsumed); if (is_unicode) { - __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, - GFP_KERNEL); - if (tmp == NULL) { + size_t search_name_utf16_len = search_name_len * 2 + 2; + __le16 *tmp; + + if (path_consumed > search_name_utf16_len) { + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + + tmp = kmalloc(search_name_utf16_len, GFP_KERNEL); + if (!tmp) { rc = -ENOMEM; goto parse_DFS_referrals_exit; } - cifsConvertToUTF16((__le16 *) tmp, searchName, + cifsConvertToUTF16((__le16 *)tmp, searchName, PATH_MAX, nls_codepage, remap); - node->path_consumed = cifs_utf16_bytes(tmp, - le16_to_cpu(rsp->PathConsumed), - nls_codepage); + node->path_consumed = cifs_utf16_bytes(tmp, path_consumed, + nls_codepage); kfree(tmp); - } else - node->path_consumed = le16_to_cpu(rsp->PathConsumed); + } else { + if (path_consumed > search_name_len) { + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + + node->path_consumed = path_consumed; + } node->server_type = le16_to_cpu(ref->ServerType); node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); /* copy DfsPath */ -- 2.52.0
2 1
0 0
[PTACH openEuler-1.0-LTS] RDMA/mlx5: Release the HW‑provided UAR index rather than the SW one
by Chen Jinghuang 25 Aug '26

25 Aug '26
From: Leon Romanovsky <leonro(a)nvidia.com> mainline inclusion from mainline-v7.2-rc1 commit 449ae7927152e46acbe5f19f97eafdae6d3a96b1 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18162 CVE: CVE-2026-74296 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- Free the UAR index returned by the hardware. Fixes: 4ed131d0bb15 ("IB/mlx5: Expose dynamic mmap allocation") Link: https://patch.msgid.link/r/20260611-fix-uar-release-v1-1-f5464d845dbf@nvidi… Signed-off-by: Leon Romanovsky <leonro(a)nvidia.com> Signed-off-by: Jason Gunthorpe <jgg(a)nvidia.com> Conflicts: drivers/infiniband/hw/mlx5/main.c [ Context conflict ] Signed-off-by: Chen jinghuang <chenjinghuang2(a)huawei.com> --- drivers/infiniband/hw/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 4f340d6db582..051de9f3ed82 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2148,7 +2148,7 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd, if (!dyn_uar) return err; - mlx5_cmd_free_uar(dev->mdev, idx); + mlx5_cmd_free_uar(dev->mdev, uar_index); free_bfreg: mlx5_ib_free_bfreg(dev, bfregi, bfreg_dyn_idx); -- 2.34.1
1 0
0 0
[PATCH OLK-6.6] bpf: Reset register bounds before narrowing retval range in check_mem_access()
by Chen Yuxi 25 Aug '26

25 Aug '26
From: Tristan Madani <tristan(a)talencesecurity.com> mainline inclusion from mainline-v7.2-rc1 commit 5e0b273e0a62cc04ec338c7b502797c66c2ed42a category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17522 CVE: CVE-2026-72111 Reference: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/comm… -------------------------------- When the BPF verifier processes a context load of an LSM hook return value, it calls __mark_reg_s32_range() to narrow the register to the hook's valid range. However, __mark_reg_s32_range() intersects the new range with the register's existing bounds using max_t()/min_t() rather than replacing them. If the destination register carries stale bounds from a prior instruction (e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than reality. The verifier then believes it knows the register's exact value, while at runtime the actual hook return value is loaded, creating a verifier/runtime mismatch that can be used to bypass BPF memory safety checks. The else branch already calls mark_reg_unknown() to reset register state before any narrowing. Apply the same reset in the is_retval path so stale bounds are cleared before __mark_reg_s32_range() intersects. Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value") Cc: stable(a)vger.kernel.org Signed-off-by: Tristan Madani <tristan(a)talencesecurity.com> Acked-by: Eduard Zingerman <eddyz87(a)gmail.com> Link: https://lore.kernel.org/r/20260622230123.3695446-2-tristmd@gmail.com Signed-off-by: Alexei Starovoitov <ast(a)kernel.org> Conflicts: kernel/bpf/verifier.c [context conflicts] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0f37807ed0c2..3de3edcb0344 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6985,6 +6985,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn */ if (reg_type == SCALAR_VALUE) { if (is_retval && get_func_retval_range(env->prog, &range)) { + mark_reg_unknown(env, regs, value_regno); err = __mark_reg_s32_range(env, regs, value_regno, range.minval, range.maxval); if (err) -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] [Backport] smb/client: handle overlapping allocated ranges in fallocate
by Lu Chentao 25 Aug '26

25 Aug '26
From: Huiwen He <hehuiwen(a)kylinos.cn> mainline inclusion from mainline-v7.2-rc4 commit b09ae45d85dc816987a71db9eebc54b0ae288e94 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17070 CVE: CVE-2026-68388 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- smb3_simple_fallocate_range() can skip holes when an allocated range returned by the server starts before the current fallocate offset. The skipped hole is not zero-filled, but fallocate still returns success. A later write to that hole may therefore fail with ENOSPC. The function queries allocated ranges so that it can preserve existing contents and write zeroes only into holes. However, the server may return a range that starts before the current fallocate offset. For example, assume the fallocate request is [100, 400) and the only allocated range returned by the server is [0, 200): Request: [100, 400) Server range: [ 0, 200) allocated Correct: [100, 200) allocated data, skip [200, 400) hole, zero-fill Current: [100, 300) skipped [300, 400) zero-filled afterwards The current code adds the full server range length, 200, to the current offset 100 and moves to 300. As a result, the hole in [200, 300) is skipped without being zero-filled. Fix this by advancing only over the part of the allocated range that overlaps the current fallocate offset. Ignore ranges that end before the current offset and reject ranges whose end offset overflows. This also prevents a malformed range length from causing an out-of-bounds zero-buffer read. Fixes: 966a3cb7c7db ("cifs: improve fallocate emulation") Signed-off-by: Huiwen He <hehuiwen(a)kylinos.cn> Reviewed-by: ChenXiaoSong <chenxiaosong(a)kylinos.cn> Signed-off-by: Steve French <stfrench(a)microsoft.com> Signed-off-by: Lu Chentao <luchentao1(a)huawei.com> --- fs/cifs/smb2ops.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f46c99b61c04..dd72160a4bb4 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3561,10 +3561,11 @@ static int smb3_simple_fallocate_range(unsigned int xid, loff_t off, loff_t len) { struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; u32 out_data_len; char *buf = NULL; + u64 range_start, range_len, range_end; loff_t l; int rc; in_data.file_offset = cpu_to_le64(off); in_data.length = cpu_to_le64(len); @@ -3597,17 +3598,25 @@ static int smb3_simple_fallocate_range(unsigned int xid, if (out_data_len < sizeof(struct file_allocated_range_buffer)) { rc = -EINVAL; goto out; } - if (off < le64_to_cpu(tmp_data->file_offset)) { + range_start = le64_to_cpu(tmp_data->file_offset); + range_len = le64_to_cpu(tmp_data->length); + if (check_add_overflow(range_start, range_len, &range_end) || + range_end > S64_MAX) { + rc = -EINVAL; + goto out; + } + + if (off < range_start) { /* * We are at a hole. Write until the end of the region * or until the next allocated data, * whichever comes next. */ - l = le64_to_cpu(tmp_data->file_offset) - off; + l = range_start - off; if (len < l) l = len; rc = smb3_simple_fallocate_write_range(xid, tcon, cfile, off, l, buf); if (rc) @@ -3620,15 +3629,17 @@ static int smb3_simple_fallocate_range(unsigned int xid, /* * We are at a section of allocated data, just skip forward * until the end of the data or the end of the region * we are supposed to fallocate, whichever comes first. */ - l = le64_to_cpu(tmp_data->length); - if (len < l) - l = len; - off += l; - len -= l; + if (off < range_end) { + l = range_end - off; + if (len < l) + l = len; + off += l; + len -= l; + } tmp_data = &tmp_data[1]; out_data_len -= sizeof(struct file_allocated_range_buffer); } -- 2.52.0
2 3
0 0
  • ← Newer
  • 1
  • 2
  • 3
  • 4
  • ...
  • 2449
  • Older →

HyperKitty Powered by HyperKitty