2026-06-28 内核社区日报
今天,内核社区在内存管理方面有多项进展:针对 AMD 15h 家族的 hugetlb 映射
get_unmapped_arearegression 收到测试反馈,tmpfs 长符号链接的未初始化尾部泄露问题得到修复,shmem_fault数据竞争修复和 numa_memblks 清理系列也已提交。此外,DAMON 的零长度 region 校验和用户空间 autotuner 也值得关注。
🧠 重点 · 内存
1. hugetlb get_unmapped_area 回归修复系列:Andrew Morton 建议重新发送
发生了什么: Oscar Salvador 发布了系列 [PATCH 0/8] 以修复 AMD 15h Family 上 align_va_addr 设置后 hugetlb 映射的回归,并停止在 get_unmapped_area 中对 hugetlb 映射做特殊处理。Andrew Morton 回复指出该系列发送时机不佳(接近 -rc 周期末),导致缺乏反馈,建议刷新/重新测试/重新发送,并考虑提供一个最小化修复用于 stable 内核(定位 Fixes: 提交,该提交距今约 1.5 年)。他建议在系列说明中明确指出该回归会导致运行时 BUG() 以吸引注意。
为什么重要: 该系列旨在统一普通映射和 hugetlb 映射在 get_unmapped_area 中的路径,消除历史上的特殊分支,并修复一个可能引发运行时 BUG() 的回归,使代码更健壮。
2. tmpfs 长符号链接:修正未初始化的 folio tail 导致的信息泄露
发生了什么: shmem_symlink() 在拷贝 NUL 终止的链接目标后直接标记整个 folio 为 uptodate,但新分配的 folio 尾部未被初始化。回收时,未初始化的尾部可能传递给 swap 压缩器(KMSAN 观察到 sw842_compress() 对其计算校验和),写入 swap 设备时也可能泄露内核数据。补丁在标记 uptodate 前调用 folio_zero_range() 清零尾部未使用部分。
为什么重要: 该补丁修复了通过 swap 路径泄露未初始化内核内存的潜在问题,避免由 folio 尾部未清零导致的 kernel memory disclosure,属于内存安全加固。
3. shmem_fault 数据竞争修复
发生了什么: shmem_fault() 在获取 folio 后检查 folio_test_swapbacked(folio),但这与 shmem_writepage() 中设置 swapbacked 的操作存在数据竞争。KCSAN 会报告该 race。补丁通过在 shmem_fault 中正确使用 READ_ONCE/数据依赖屏障来消除竞争。具体地,patch 为 shmem_fault 中读取 shmem_inode_info->swapped 和 folio swapbacked 标志添加了适当的注解,避免编译器或 CPU 重排导致读到 stale 值。
为什么重要: 这是一个经过 KCSAN 确认的真实 data-race,尽管大多数情况下不会导致崩溃,但理论上可能让 fault 路径观察到错误的 folio 状态(如将一个 non-swapbacked folio 误判为 swapbacked),导致错误的分支(如误发 copy_user_highpage 而非 shmem_swapin),进而引发内存内容错误或用户态数据泄漏。KCSAN 报告的修复有助于提高内核数据竞态安全性。
4. DAMON 核心:在 damon_set_regions() 中校验零长度 region
发生了什么: DAMON 核心逻辑假设零长度 region 不存在,但 DAMON_SYSFS、DAMON_RECLAIM、DAMON_LRU_SORT 等调用者允许用户设置空监控目标 region。零长度 region 在启用 CONFIG_DAMON_DEBUG_SANITY 时触发 WARN_ONCE(),并在 damon_merge_two_regions() 中导致除零错误。补丁在 damon_set_regions() 中增加校验:若 region start 按 min_region_sz 对齐后大于等于 end 对齐后的值,则返回 -EINVAL,阻止无效 region 进入后续逻辑。
为什么重要: 此修复消除了 DAMON 核心因零长度 region 产生的 WARN_ONCE 和除零未定义行为,提升了内核内存监控路径的稳健性。
5. numa_memblks: 移除 NUMA 初始化期间的冗余工作
发生了什么: 该系列包含 9 个 patch,清理 numa_memblks。核心改动有:
(1)在 numa_add_memblk() 内部自动将新 node 标记到 numa_nodes_parsed,消除每个调用者额外调用 node_set() 的冗余;
(2)移除 numa_nodemask_from_meminfo() 函数,因为它所做的工作(从 numa_meminfo 中收集 node)现在完全可由 numa_add_memblk() 内的逻辑替代;
(3)在 numa_cleanup_meminfo() 中使用 numa_add_reserved_memblk() 替代直接调用内部函数,使代码接口更统一。涉及 ACPI、of/numa、x86、arch_numa、LoongArch 等调用方。
为什么重要: 这些清理消除了多个架构(如 x86、LoongArch)及通用子系统(ACPI、of/numa、arch_numa)在 NUMA 初始化阶段对 numa_nodes_parsed 的手动维护,移除了隐含依赖调用者正确执行 node_set() 的冗余,使 NUMA 初始化路径更清晰、更健壮。
6. vmstat: 节点上线时 fold 滞留的 per-CPU 统计,消除永久 skew
发生了什么: 当使用 numa_memblks 或类似机制在新节点上线时(如热插拔场景),原有的 per-CPU nodestats 计数器可能还包含之前分配活动留下的差值。现有代码只是简单地清零 per-CPU 计数器,导致永久丢失这些 delta,最终使该节点的全局 vm_stat 偏低。Gregory Price 提交的 v2 patch 改为在节点上线前将所有 per-CPU 的 delta 折叠(fold)到节点级统计中,然后再清零 per-CPU 缓存,确保数据不丢失。
为什么重要: 该问题对内存热插拔和管理员跟踪节点级内存使用统计影响显著。未折叠的 delta 可能导致 vmstat 输出的 node 统计值低于真实值,影响控制组和 NUMA 策略的调度决策。这是一个正确性修复,对使用 CXL 内存池或非对称 NUMA 系统的用户尤其关键。
7. numa_memblks 清理
发生了什么: Sang-Heon Jeon 提交补丁,将 numa_cleanup_meminfo() 中对内部函数 numa_add_memblk_to() 的直接调用替换为封装函数 numa_add_reserved_memblk()。
为什么重要: 该补丁统一了 numa_add_memblk_to() 的调用入口,使其仅通过两个封装函数被调用,提升了 numa_memblks 子系统的代码一致性,无功能变化。
8. 用户空间 DAMON_RECLAIM min_age 自动调谐器
发生了什么: aethernet65535 提交 RFC [PATCH],提出用户空间程序 DAMA(DAMOS Autotuner/Assistant),通过动态调整 DAMON_RECLAIM 的 min_age 参数来减少不必要的主动回收。测试使用 Masim 模拟两种场景:场景一在 30 秒全访问与 10% 访问间切换(理论最优 min_age > 30s),场景二每 30 秒切换访问四个区域之一(理论最优 min_age < 90s)。
为什么重要: 该方案将调谐逻辑从内核移至用户空间,降低了内核复杂度,并允许基于工作负载特征(如访问模式周期)自适应调整回收阈值,有望提升内存回收效率。
🔧 其它子系统
文件系统
- minix 文件系统转用 iomap 并添加 direct I/O:v2 系列共 4 个 patch,将 minix 的 address space 操作从 buffer_head 迁移到 iomap,同时添加 direct I/O 支持。经 syzbot 测试发现 4 个问题已修复(空指针解引用、truncate 页回写错误等)。这是老旧文件系统现代化的重要一步。来源
- NBD
NBD_CLEAR_SOCK与 buffered write 之间的竞态:syzbot 报告在NBD_CLEAR_SOCK与并发 buffered write 之间发生竞态,导致 block_commit_write 中已设置 BH_Uptodate 的 buffer_head 被随后完成的 NBD 请求(因BLK_STS_IOERR)通过end_buffer_async_write清除 BH_Uptodate,进而在mark_buffer_dirty()中触发WARN_ON_ONCE(!buffer_uptodate(bh))。根源在于blkdev_write_iter使用inode_lock_shared(bd_inode)而NBD_CLEAR_SOCK使用nbd->config_lock,两者不互斥。暂无修复 patch。来源 - NTFS(in-kernel)目录索引越界/释放后读:在
ntfs_index_next()和ntfs_index_walk_down()中,遍历器在检查条目是否超出索引块边界之前就解引用entry的flags和子 VCN,导致可能读入相邻已释放的 slab 对象。由 Bakabaka_9 报告并提供 PoC 与根因分析。来源
网络
- ppp stats ioctl UAF:
ppp_get_stats()(SIOCGPPPSTATS)和 SIOCGPPPCSTATS 在不持锁的情况下分别解引用ppp->vj及ppp->xc_state/ppp->rc_state,而 PPPIOCSMAXCID、PPPIOCSCOMPRESS、ppp_ccp_closed()等路径会在持锁时释放这些结构,从而产生 slab-use-after-free 且将已释放内容复制至用户空间。问题由 Doyensec 报告。来源 - sctp
auth_enablesysctl UAF:proc_sctp_do_auth()更新 SCTP 控制套接字时,若并发删除 network namespace,可能访问已释放的net->sctp.ctl_sock。修复方法是在sctp_ctrlsock_exit()中先调用sctp_sysctl_net_unregister()注销 per-net sysctl 表,再销毁控制套接字,并在注销后清除sysctl_header指针。来源 - tcp SYN-ACK 定时器边界检查:
tcp_synack_retries传入请求套接字定时器后,若用户设置过大值可能导致定时器超时过长。新 patch 将定时器值约束在reqsk_timeout范围内。来源 - teql 锁保护:
sch_teql的 master→slaves 链表无锁保护,并发操作(xmit、dequeue、init、destroy)可导致 UAF。引入slaves_lockspinlock 保护。来源 - xdp tracepoint 扩展提议:Masashi Honma 以 RFC 形式提议扩展
bpf_xdp_link_attach_failedtracepoint,在其输出中增加设备 ifindex,从而将 attach 失败与具体网卡设备关联;示例中 TP_printk 改为"ifindex=%d errmsg=%s"。来源
eBPF
- RISC-V BPF exceptions v2:为 riscv64 实现
arch_bpf_stack_walk()并更新 BPF JIT 序言/尾声以支持 BPF 异常,使bpf_jit_supports_exceptions()返回 true。该支持依赖CONFIG_FRAME_POINTER,使用帧指针展开器;除混合尾调用与 bpf-to-bpf 调用的测试外,其余异常测试均通过。来源 - gotox 目标跨 subprog 边界检查 v3:补丁强制
gotox指令的目标不能跳出当前 subprog 的指令范围,避免 CFG 构建时忽略无效 target 导致的 verifier 误判。来源
Rust / DRM
- DRM rust 驱动:引入 Higher-Ranked Lifetime private data v5:该系列(19 patches)通过引入
RegistrationGuard(表示drm_dev_enter/exitSRCU 临界区的守卫)来解决 DRM ioctl 运行在进程上下文且父总线设备可能在 ioctl 处理期间解绑的问题。核心改动:重命名Uninit为Normal,建立Device<T, Registered>到Device<T, Normal>的 Deref 链,新增Ioctl设备上下文类型状态,并在drm::Driver上添加RegistrationData作为 GAT,允许驱动存储生命周期绑定到父总线设备绑定作用域的数据。ioctl 分发宏现在将每个处理程序包装在RegistrationGuard中,若设备已拔出则返回ENODEV,并将注册数据传递给处理程序。该系列已在 nova 驱动中应用,演示了生命周期感知的注册数据(例如&'bound auxiliary::Device<Bound>)的使用。来源
👀 值得追的讨论 / Patch
1. DAMA:用户态 DAMON_RECLAIM min_age 自动调优器
Rui Yan 发布了 DAMA(DAMOS Autotuner/Assistant),一个通过定期监测 DAMON 回收页、系统回收(kswapd + direct)和 refault 的增量来自动调节 DAMON_RECLAIM 的 min_age 参数的用户空间程序。其算法采用累积衰减、阈值门控与迟滞机制,在 DAMON 回收过多时提高 min_age,在系统回收过多时降低 min_age。合成测试结果表明,DAMA 相比固定 min_age 配置能显著降低系统回收、refault 和 major fault 数量,同时保持较低的内存压力。作者希望社区就如何使 benchmark 更具代表性以及该用户态调优方法提供反馈。来源
2. NBD NBD_CLEAR_SOCK 竞态触发 mark_buffer_dirty() WARNING
NBD NBD_CLEAR_SOCK ioctl 与 buffered block-device 写入之间存在竞态:blkdev_write_iter 在 inode_lock_shared(bd_inode) 下运行,而 NBD_CLEAR_SOCK 在 nbd->config_lock 下处理,两者不互斥。竞态使正在写入的 buffer_head 的 BH_Uptodate 位被清除后又被 mark_buffer_dirty() 检测到,触发 WARN_ON_ONCE(!buffer_uptodate(bh)) 警告。来源
⚡ 一句话速览
- slabobj_ext 与 kmalloc cache 大小提升条件细化:Shakeel Butt 在讨论中建议,当内存分配分析(
mem_alloc_profiling_enabled())启用时,若obj_exts_cache->object_size <= s->object_size则返回s->object_size + 1;否则(仅 memcg 场景)仅在两者相等时提升大小。此讨论围绕避免 kmalloc cache 间循环引用及减少内存浪费展开。来源 - zsmalloc lock contention 优化 v6:Andrew Morton 回复 v6 系列表示“现在看起来不错”,可望合并。来源
- page/folio nid/zonenum 独占位断言 v6:Andrew 回复指出 ASSERT_EXCLUSIVE_BITS 在 kcsan-checks.h 中定义,但 mm.h 和 mmzone.h 当前并未可靠包含该头文件,并询问 Sashiko 报告的合法性。来源
- DAMON core 减少 kernel stack 使用:Arnd Bergmann 提交补丁将 kdamond_tune_intervals 标记为 noinline_for_stack,以解决 kdamond_fn 栈帧大小超过警告限制的问题。Andrew 回应无需添加 Fixes: 和 Cc: stable,因内核中此类问题较多。来源
- hugetlb 访问路径使用
huge_ptep_get():Lance Yang 的系列收到 Dev Jain 关于 addr 对齐的评论,继续讨论。来源 - debugobjects:OOM 时跳过 activate fixup:Andrew 回复同意,已合入 mm tree。来源
- cpuset mempolicy rebind 修复:修正
mpol_rebind_mm()在子 cpuset 未设置 mems 时的除零问题。Andrew 回复表示接受。来源 - fork 动态栈:在 unpoupulated stack ptes 中存储 task pointer:Thomas Gleixner 回复指出原补丁的 changelog 未解释为何不能使用
current,并提出使用raw_cpu_write(next_task, next)的简化方案,该方案可在所有架构上正确工作且开销可忽略。来源 - selftests/mm:pagemap_ioctl 使用正确页面大小:修复
transact_test()中硬编码 4K 页的问题。来源 - selftests/mm:hmm-tests 包含 linux/mman.h:修复旧 glibc 下未定义
MADV_COLLAPSE的编译错误。来源