JianyuWang0623 opened a new pull request, #20118:
URL: https://github.com/apache/nuttx/pull/20118

   ## Summary
   
   Two independent use-after-scope defects surface when 
`CONFIG_LIBC_TEMPBUFFER=n`. In that mode `lib_get_tempbuffer(n)` / 
`lib_get_pathbuffer()` expand to `alloca(n)` (stack valid only until the 
*allocating* function returns) and `lib_put_tempbuffer()` is a no-op 
(`include/nuttx/lib/lib.h`). Both sites let an alloca'd buffer escape the frame 
that allocated it and get read afterwards.
   
   ### 1. `fs/inode/fs_inodesearch.c` — search path buffer
   
   `_inode_search()` normalizes the lookup path into `desc->buffer` and aliases 
`desc->path` / `desc->relpath` into it, exporting them to callers. Callers 
(`inode_reserve`, `inode_remove`, `nx_open`, … ~30 
`SETUP_SEARCH`/`RELEASE_SEARCH` sites) read those fields *after* 
`_inode_search()` returns, then release via `RELEASE_SEARCH()`. Under `=n` the 
buffer is alloca, freed on return, so the exported pointer dangles. When the 
reclaimed stack is reused, path lookups intermittently fail; observed as an 
intermittent zero-byte boot hang on rv-virt:smp with `CONFIG_FS_LINKS=y` 
softlink paths, and as non-deterministic procfs `open()` ENOENT on rv-virt:nsh.
   
   ### 2. `fs/vfs/fs_close.c` — notify path buffer
   
   `file_get_path()` did `lib_get_pathbuffer()` then `return pathbuffer`; 
`file_close()` reads it later via `notify_close()`. Under `=n` the returned 
pointer dangles once `file_get_path()` returns (use-after-scope, 
`CONFIG_FS_NOTIFY=y`). Note: if the compiler inlines the small static 
`file_get_path`, the defect is masked — the fix removes that fragile dependence.
   
   ## Fix
   
   - **fs/inode**: allocate the search buffer from the fs heap 
(`fs_heap_malloc`) and free it in `RELEASE_SEARCH()` (`fs_heap_free`); its 
lifetime now matches the caller-owned `struct inode_search_s`. The ~30 call 
sites are unchanged.
   - **fs/vfs**: move the allocation into `file_close()`'s own frame; 
`file_get_path()` only fills a caller-provided buffer. Behavior unchanged 
(`path` is NULL exactly when allocation or `F_GETPATH` fails; 
`lib_put_pathbuffer()` pairing preserved).
   
   Impact — base `2a6a86cb68`: `fs/inode/fs_inodesearch.c` (+3/-3), 
`fs/inode/inode.h` (+3/-1), `fs/vfs/fs_close.c` (+8/-19).
   
   ## Testing
   
   Config: rv-virt:nsh, `CONFIG_FS_LINKS=y`, `CONFIG_LIBC_TEMPBUFFER=n` (alloca 
mode — the defect mode). Toolchain riscv64-unknown-elf-gcc; qemu-system-riscv32 
`-M virt,aclint=on -cpu rv32 -bios none -nographic`. Commands paced after boot 
to avoid a procfs-mount startup race in the test harness (unrelated to the 
defect).
   
   Deterministic A/B, `cat /proc/version` isolated, 10 runs each:
   
   | image | result |
   |---|---|
   | baseline (unfixed, alloca) | **PASS 4 / FAIL 6** — non-deterministic |
   | fixed (heap) | **PASS 10 / FAIL 0** — deterministic |
   
   Baseline failing run (dangling search buffer → procfs open fails):
   
   ```
   NuttShell (NSH) NuttX-3.6.1
   nsh> cat /proc/version
   nsh: cat: Could not open /proc/version (is procfs mounted?)
   nsh: cat: open failed: 2
   ```
   
   Fixed run (procfs read + softlink-into-mountpoint traversal all clean):
   
   ```
   NuttShell (NSH) NuttX-3.6.1
   nsh> uname -a
   NuttX 3.6.1 545d52a5b0 Sep 11 2026 19:20:23 risc-v rv-virt
   nsh> cat /proc/version
   NuttX version 3.6.1 545d52a5b0 Sep 11 2026 19:20:23 rv-virt:nsh-dirty
   nsh> ln -s /proc /pl
   nsh> ls /pl
   /pl:
    0/  2/  cpuinfo  fs/  memdump  meminfo  self/  tcbinfo  uptime  version
   nsh> readlink /pl
   /proc
   ```
   
   fs/vfs defect: verified structurally (its runtime manifestation depends on 
`CONFIG_FS_NOTIFY=y` and on whether `file_get_path` is inlined). Disassembly of 
the `=n` build confirms `alloca(PATH_MAX)` now lands in `file_close`'s frame 
and stays valid across the `notify_close()` read.
   
   > Draft: fs/inode is validated end-to-end on QEMU; fs/vfs is structurally 
verified only. A full-image regression on rv-virt:smp (the originally-reported 
hang) is still worth a CI pass before merge.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to