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

  • 43 participants
  • 24865 discussions
[PATCH openEuler-1.0-LTS] ceph: bound copied dentry name length in NFS export get_name
by Chen Yuxi 17 Sep '26

17 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit eff8013c5a8916613c742ae5a2cc341cb605c0ae category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18968 CVE: CVE-2026-89652 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way. Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS. Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name(). Cc: stable(a)vger.kernel.org Fixes: 19913b4eac4a ("ceph: add get_name() NFS export callback") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Reviewed-by: Viacheslav Dubeyko <slava(a)dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov(a)gmail.com> Conflicts: fs/ceph/export.c [Downstream tree lacks the __get_snap_name() function and fscrypt support, so only the ceph_export_copy_name() helper and the ceph_get_name() change were applied while keeping the tree's simpler (non-encrypted) get_name structure.] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- fs/ceph/export.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 3c59ad180ef0..1d087cf1770c 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -194,6 +194,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, return dentry; } +static int ceph_export_copy_name(char *name, const char *src, u32 len) +{ + if (len > NAME_MAX) + return -ENAMETOOLONG; + + memcpy(name, src, len); + name[len] = '\0'; + return 0; +} + static int ceph_get_name(struct dentry *parent, char *name, struct dentry *child) { @@ -221,10 +231,11 @@ static int ceph_get_name(struct dentry *parent, char *name, if (!err) { struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; - memcpy(name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] = 0; - dout("get_name %p ino %llx.%llx name %s\n", - child, ceph_vinop(d_inode(child)), name); + err = ceph_export_copy_name(name, rinfo->dname, + rinfo->dname_len); + if (!err) + dout("get_name %p ino %llx.%llx name %s\n", + child, ceph_vinop(d_inode(child)), name); } else { dout("get_name %p ino %llx.%llx err %d\n", child, ceph_vinop(d_inode(child)), err); -- 2.34.1
2 1
0 0
[PATCH OLK-6.6 v2] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 17 Sep '26

17 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/stable/linux.git/commit/?id… -------------------------------- 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 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 2a4070d0b594..3dc99abc1d51 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -444,6 +444,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); @@ -453,16 +454,21 @@ 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; ips = trace->ip + skip; + preempt_enable(); if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else -- 2.34.1
2 1
0 0
[PATCH OLK-5.10 v2] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 17 Sep '26

17 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/stable/linux.git/commit/?id… -------------------------------- 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 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 0c3504e598e3..44eccaf13aa0 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -620,6 +620,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, if (sysctl_perf_event_max_stack < max_depth) max_depth = sysctl_perf_event_max_stack; + preempt_disable(); if (trace_in) trace = trace_in; else if (kernel && task) @@ -627,17 +628,22 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, else 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; trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; ips = trace->ip + skip; + preempt_enable(); if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] ceph: bound copied dentry name length in NFS export get_name
by Chen Yuxi 17 Sep '26

17 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit eff8013c5a8916613c742ae5a2cc341cb605c0ae category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18968 Reference: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/comm… -------------------------------- ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way. Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS. Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name(). Cc: stable(a)vger.kernel.org Fixes: 19913b4eac4a ("ceph: add get_name() NFS export callback") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Reviewed-by: Viacheslav Dubeyko <slava(a)dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov(a)gmail.com> Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- fs/ceph/export.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 52c4daf2447d..e9cbd08a7dcb 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -434,6 +434,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, return dentry; } +static int ceph_export_copy_name(char *name, const char *src, u32 len) +{ + if (len > NAME_MAX) + return -ENAMETOOLONG; + + memcpy(name, src, len); + name[len] = '\0'; + return 0; +} + static int __get_snap_name(struct dentry *parent, char *name, struct dentry *child) { @@ -499,9 +509,8 @@ static int __get_snap_name(struct dentry *parent, char *name, BUG_ON(!rde->inode.in); if (ceph_snap(inode) == le64_to_cpu(rde->inode.in->snapid)) { - memcpy(name, rde->name, rde->name_len); - name[rde->name_len] = '\0'; - err = 0; + err = ceph_export_copy_name(name, rde->name, + rde->name_len); goto out; } } @@ -566,8 +575,8 @@ static int ceph_get_name(struct dentry *parent, char *name, rinfo = &req->r_reply_info; if (!IS_ENCRYPTED(dir)) { - memcpy(name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] = 0; + err = ceph_export_copy_name(name, rinfo->dname, + rinfo->dname_len); } else { struct fscrypt_str oname = FSTR_INIT(NULL, 0); struct ceph_fname fname = { .dir = dir, @@ -581,10 +590,9 @@ static int ceph_get_name(struct dentry *parent, char *name, goto out; err = ceph_fname_to_usr(&fname, NULL, &oname, NULL); - if (!err) { - memcpy(name, oname.name, oname.len); - name[oname.len] = 0; - } + if (!err) + err = ceph_export_copy_name(name, oname.name, + oname.len); ceph_fname_free_buffer(dir, &oname); } out: -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] ceph: bound copied dentry name length in NFS export get_name
by Chen Yuxi 17 Sep '26

17 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit eff8013c5a8916613c742ae5a2cc341cb605c0ae category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18968 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way. Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS. Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name(). Cc: stable(a)vger.kernel.org Fixes: 19913b4eac4a ("ceph: add get_name() NFS export callback") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Reviewed-by: Viacheslav Dubeyko <slava(a)dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov(a)gmail.com> Conflicts: fs/ceph/export.c [Downstream tree lacks the fscrypt support, so keep the tree's simpler (non-encrypted) get_name structure.] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- fs/ceph/export.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 952a590dd4bc..54efb44fc89b 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -431,6 +431,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, return dentry; } +static int ceph_export_copy_name(char *name, const char *src, u32 len) +{ + if (len > NAME_MAX) + return -ENAMETOOLONG; + + memcpy(name, src, len); + name[len] = '\0'; + return 0; +} + static int __get_snap_name(struct dentry *parent, char *name, struct dentry *child) { @@ -496,9 +506,8 @@ static int __get_snap_name(struct dentry *parent, char *name, BUG_ON(!rde->inode.in); if (ceph_snap(inode) == le64_to_cpu(rde->inode.in->snapid)) { - memcpy(name, rde->name, rde->name_len); - name[rde->name_len] = '\0'; - err = 0; + err = ceph_export_copy_name(name, rde->name, + rde->name_len); goto out; } } @@ -559,10 +568,11 @@ static int ceph_get_name(struct dentry *parent, char *name, if (!err) { struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; - memcpy(name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] = 0; - dout("get_name %p ino %llx.%llx name %s\n", - child, ceph_vinop(inode), name); + err = ceph_export_copy_name(name, rinfo->dname, + rinfo->dname_len); + if (!err) + dout("get_name %p ino %llx.%llx name %s\n", + child, ceph_vinop(d_inode(child)), name); } else { dout("get_name %p ino %llx.%llx err %d\n", child, ceph_vinop(inode), err); -- 2.34.1
2 1
0 0
[PATCH openEuler-1.0-LTS] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 17 Sep '26

17 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/stable/linux.git/commit/?id… -------------------------------- 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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index a41858db1441..beaf63f17d60 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -477,6 +477,7 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size, if (unlikely(size % elem_size)) goto clear; + preempt_disable(); num_elem = size / elem_size; if (sysctl_perf_event_max_stack < num_elem) init_nr = 0; @@ -484,17 +485,23 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size, init_nr = sysctl_perf_event_max_stack - num_elem; trace = get_perf_callchain(regs, init_nr, kernel, user, sysctl_perf_event_max_stack, false, false); - if (unlikely(!trace)) + if (unlikely(!trace)) { + preempt_enable(); goto err_fault; + } trace_nr = trace->nr - init_nr; - if (trace_nr < skip) + if (trace_nr < skip) { + preempt_enable(); goto err_fault; + } trace_nr -= skip; trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; ips = trace->ip + skip + init_nr; + + preempt_enable(); if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] [Backport] ceph: bound copied dentry name length in NFS export get_name
by Chen Yuxi 17 Sep '26

17 Sep '26
From: Michael Bommarito <michael.bommarito(a)gmail.com> mainline inclusion from mainline-v7.3-rc1 commit eff8013c5a8916613c742ae5a2cc341cb605c0ae category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18968 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way. Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS. Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name(). Cc: stable(a)vger.kernel.org Fixes: 19913b4eac4a ("ceph: add get_name() NFS export callback") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito(a)gmail.com> Reviewed-by: Viacheslav Dubeyko <slava(a)dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov(a)gmail.com> Conflicts: fs/ceph/export.c [Downstream tree lacks the fscrypt support, so keep the tree's simpler (non-encrypted) get_name structure.] Signed-off-by: Chen Yuxi <chenyuxi19(a)huawei.com> --- fs/ceph/export.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 952a590dd4bc..54efb44fc89b 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -431,6 +431,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, return dentry; } +static int ceph_export_copy_name(char *name, const char *src, u32 len) +{ + if (len > NAME_MAX) + return -ENAMETOOLONG; + + memcpy(name, src, len); + name[len] = '\0'; + return 0; +} + static int __get_snap_name(struct dentry *parent, char *name, struct dentry *child) { @@ -496,9 +506,8 @@ static int __get_snap_name(struct dentry *parent, char *name, BUG_ON(!rde->inode.in); if (ceph_snap(inode) == le64_to_cpu(rde->inode.in->snapid)) { - memcpy(name, rde->name, rde->name_len); - name[rde->name_len] = '\0'; - err = 0; + err = ceph_export_copy_name(name, rde->name, + rde->name_len); goto out; } } @@ -559,10 +568,11 @@ static int ceph_get_name(struct dentry *parent, char *name, if (!err) { struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; - memcpy(name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] = 0; - dout("get_name %p ino %llx.%llx name %s\n", - child, ceph_vinop(inode), name); + err = ceph_export_copy_name(name, rinfo->dname, + rinfo->dname_len); + if (!err) + dout("get_name %p ino %llx.%llx name %s\n", + child, ceph_vinop(d_inode(child)), name); } else { dout("get_name %p ino %llx.%llx err %d\n", child, ceph_vinop(inode), err); -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 17 Sep '26

17 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/stable/linux.git/commit/?id… -------------------------------- 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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 0c3504e598e3..1f2547acf3d1 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -620,6 +620,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, if (sysctl_perf_event_max_stack < max_depth) max_depth = sysctl_perf_event_max_stack; + preempt_disable(); if (trace_in) trace = trace_in; else if (kernel && task) @@ -627,16 +628,22 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, else 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; trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; + preempt_enable(); + ips = trace->ip + skip; if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] bpf: Disable preemption in __bpf_get_stack
by Pu Lehui 17 Sep '26

17 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/stable/linux.git/commit/?id… -------------------------------- 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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 2a4070d0b594..a30a136ea954 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -444,6 +444,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); @@ -453,15 +454,21 @@ 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; + preempt_enable(); + ips = trace->ip + skip; if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] bpf: Harden bloom filter sizing and indexing on 32-bit kernels
by Pu Lehui 17 Sep '26

17 Sep '26
From: Jérémy Jean <Jeremy.Jean(a)oss.cyber.gouv.fr> stable inclusion from stable-v6.6.157 commit 80551bf8912c42d1e3d55eec6fa3c40f306c3de8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18900 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit 11c1e836710dcba03e50454a4eedfdbaf8d3050e upstream. bloom_map_alloc() has two 32-bit-specific problems when the computed bitmap reaches the U32_MAX fallback case. First, BITS_TO_BYTES(U32_MAX) is evaluated with 32-bit arithmetic. The addition performed by DIV_ROUND_UP wraps, so the map allocates only the fixed-size bloom filter object while keeping bitset_mask == U32_MAX. Subsequent updates can then write past the allocated object. Second, fixing only the allocation size is not sufficient. The bloom hash is a u32, but set_bit() takes a signed long bit number and x86 test_bit() eventually feeds the index to variable_test_bit(long, ...). On 32-bit kernels, hashes in [0x80000000, U32_MAX] therefore become negative bit offsets. x86 bt/bts with a memory operand interpret those offsets relative to the supplied base, so a map with bitset_mask == U32_MAX can read or write before bloom->bitset even after allocating the full 512 MiB bitmap. Keep the U32_MAX fallback, but split each hash into a word pointer and an in-word bit number before calling test_bit() or set_bit(). The bitops argument is then always in [0, BITS_PER_LONG - 1], while BIT_WORD(h) still selects the intended word in the full bitmap. Compute the bitset size from (u64)bitset_mask + 1 before passing the final size to bpf_map_area_alloc(). This fixes the original under-allocation and keeps the allocated storage consistent with the addressable bitset. Exploitation note: local privilege escalation is possible on a 32-bit x86 kernel using the under-allocation bug from a binary with CAP_BPF. Fixes: 9330986c0300 ("bpf: Add bloom filter map implementation") Signed-off-by: Jérémy Jean <Jeremy.Jean(a)oss.cyber.gouv.fr> Signed-off-by: Andrii Nakryiko <andrii(a)kernel.org> Cc: stable(a)vger.kernel.org Link: https://lore.kernel.org/bpf/20260805060228.2703051-1-Jeremy.Jean@oss.cyber.… Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Assisted-by: Codex:gpt-5 Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- kernel/bpf/bloom_filter.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/bloom_filter.c b/kernel/bpf/bloom_filter.c index 35e1ddca74d2..3f55f28fd589 100644 --- a/kernel/bpf/bloom_filter.c +++ b/kernel/bpf/bloom_filter.c @@ -41,7 +41,7 @@ static long bloom_map_peek_elem(struct bpf_map *map, void *value) for (i = 0; i < bloom->nr_hash_funcs; i++) { h = hash(bloom, value, map->value_size, i); - if (!test_bit(h, bloom->bitset)) + if (!test_bit(h % BITS_PER_LONG, bloom->bitset + BIT_WORD(h))) return -ENOENT; } @@ -57,9 +57,13 @@ static long bloom_map_push_elem(struct bpf_map *map, void *value, u64 flags) if (flags != BPF_ANY) return -EINVAL; + /* + * On 32-bit architectures, hashes larger than INT_MAX would be + * treated as negative by set_bit(). + */ for (i = 0; i < bloom->nr_hash_funcs; i++) { h = hash(bloom, value, map->value_size, i); - set_bit(h, bloom->bitset); + set_bit(h % BITS_PER_LONG, bloom->bitset + BIT_WORD(h)); } return 0; @@ -94,9 +98,10 @@ static int bloom_map_alloc_check(union bpf_attr *attr) static struct bpf_map *bloom_map_alloc(union bpf_attr *attr) { - u32 bitset_bytes, bitset_mask, nr_hash_funcs, nr_bits; + u32 bitset_mask, nr_hash_funcs, nr_bits; int numa_node = bpf_map_attr_numa_node(attr); struct bpf_bloom_filter *bloom; + u64 bitset_bytes; if (attr->key_size != 0 || attr->value_size == 0 || attr->max_entries == 0 || @@ -127,22 +132,16 @@ static struct bpf_map *bloom_map_alloc(union bpf_attr *attr) if (check_mul_overflow(attr->max_entries, nr_hash_funcs, &nr_bits) || check_mul_overflow(nr_bits / 5, (u32)7, &nr_bits) || nr_bits > (1UL << 31)) { - /* The bit array size is 2^32 bits but to avoid overflowing the - * u32, we use U32_MAX, which will round up to the equivalent - * number of bytes - */ - bitset_bytes = BITS_TO_BYTES(U32_MAX); bitset_mask = U32_MAX; } else { if (nr_bits <= BITS_PER_LONG) nr_bits = BITS_PER_LONG; else nr_bits = roundup_pow_of_two(nr_bits); - bitset_bytes = BITS_TO_BYTES(nr_bits); bitset_mask = nr_bits - 1; } - bitset_bytes = roundup(bitset_bytes, sizeof(unsigned long)); + bitset_bytes = BITS_TO_LONGS((u64)bitset_mask + 1) * sizeof(unsigned long); bloom = bpf_map_area_alloc(sizeof(*bloom) + bitset_bytes, numa_node); if (!bloom) -- 2.34.1
2 1
0 0
  • ← Newer
  • 1
  • ...
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • ...
  • 2487
  • Older →

HyperKitty Powered by HyperKitty