Repository navigation
[dfs][tmpfs] fix use-after-free when truncating a file to zero length - #11910
remukisama wants to merge 3 commits into
Conversation
rt_realloc(ptr, 0) is implemented as free(ptr) + return RT_NULL on both heap backends (src/mem.c:429, src/memheap.c:830), so the NULL return cannot be told apart from an allocation failure. dfs_tmpfs_truncate() treated it as -ENOMEM and returned 0 without updating d_file->data or the file size, which left a dangling buffer behind a successful ftruncate(fd, 0). Handle offset == 0 explicitly before calling rt_realloc(): free the buffer, clear the pointer, and fall through so that d_file->size and file->vnode->size are reset to 0. Return -ENOMEM when the allocation really fails, so the error reaches ftruncate() through dfs_file_ftruncate(). Verified on bsp/qemu-vexpress-a9 (small_mem): read() after ftruncate(fd, 0) returns 0 instead of the stale length, and unlink() no longer trips the MEM_ISUSED assertion in rt_smem_free(). Fixes RT-Thread#11902 Signed-off-by: Leng Mengqi <312309080229@home.hpu.edu.cn>
|
👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread! 为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。 🛠 操作步骤 | Steps
完成后,提交将自动更新至 如有问题欢迎联系我们,再次感谢您的贡献!💐 |
📌 Code Review Assignment🏷️ Tag: componentsReviewers: @Maihuanyi Changed Files (Click to expand)
📊 Current Review Status (Last Updated: 2026-10-21 11:23 CST)
📝 Review Instructions
|
Cover zero and repeated truncation, subsequent I/O, non-zero resize, and allocation failure without losing the original file contents. Signed-off-by: Leng Mengqi <312309080229@home.hpu.edu.cn>
Signed-off-by: Leng Mengqi <312309080229@home.hpu.edu.cn>
|
替这个 PR 跑了一遍 utest,通过,并另做了一次"只留用例、回退修复"的对照,确认用例确实能抓到这个 bug。 环境
本 PR(含修复)——通过对照:只保留用例、把
|
拉取/合并请求描述:(PR description)
[
Fixes #11902
为什么提交这份PR (why to submit this PR)
对非空 tmpfs 文件执行
ftruncate(fd, 0)时,rt_realloc()会释放原缓冲区并返回空指针。原代码在这里直接返回成功,没有清空数据指针和更新文件长度,后续读写会访问已释放的内存,删除文件时也可能触发内存断言。另外,非零大小分配失败时也错误地返回了成功。你的解决方案是什么 (what is your solution)
在
dfs_tmpfs_truncate()中单独处理offset == 0:释放缓冲区、清空指针,再执行后面的长度更新。非零大小仍走原来的重分配流程,失败时改为返回-ENOMEM。在现有 tmpfs utest 目录增加截断用例,检查重复清空、截断后的读写与删除、非零缩放,以及内存不足时错误返回和原文件内容是否保留。
请提供验证的bsp和config (provide the config and bsp)
bsp/qemu-vexpress-a9(标准版、small_mem);bsp/qemu-virt64-aarch64(标准版和 RT-Smart,memheap)。RT_USING_DFS_V2、RT_USING_DFS_TMPFS、RT_USING_POSIX_FS、RT_USING_UTESTCASES、RT_UTEST_TMPFS_TRUNCATE。RT-Smart 测试开启RT_USING_SMART和RT_USING_PAGECACHE。运行命令:
utest_run components.dfs.tmpfs_truncate。标准版和 RT-Smart 的回归用例均通过。RT-Smart 还用独立用户进程经系统调用完成写入、截断为 0、从头读取、重新写入、关闭和删除,结果正常。
同一用例在未修复版本上仍能读到旧数据,并触发内存分配器断言,已保存对照日志。
分配失败测试申请整个堆大小的缓冲区,确认
ftruncate()返回-1、errno为-ENOMEM,且原文件长度和内容保留。验证分支中的四个修复及测试文件与本 PR 一致。主仓 CI 目前为
action_required,尚未执行,需维护者批准运行。]
当前拉取/合并请求的状态 Intent for your PR
必须选择一项 Choose one (Mandatory):
代码质量 Code Quality:
我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:
#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up