arnavsharma990 opened a new issue, #20166:
URL: https://github.com/apache/nuttx/issues/20166
### Description / Steps to reproduce the issue
`mtdconfig_unregister_by_path()` in `drivers/mtd/mtd_config.c` frees the
`mtdconfig_struct_s` object before closing the temporary `struct file` opened
by the function.
The relevant sequence is:
```text
file_open()
-> mtdconfig_open()
-> nxmutex_lock(&dev->lock)
-> dev = inode->i_private
-> nxmutex_destroy(&dev->lock)
-> kmm_free(dev)
-> file_close()
-> mtdconfig_close()
-> nxmutex_unlock(&dev->lock)
```
`mtdconfig_close()` obtains `dev` from `inode->i_private` and accesses
`dev->lock`. At that point, `dev` has already been freed by
`mtdconfig_unregister_by_path()`. The mutex has also already been destroyed
while held by the temporary open.
This results in a use-after-free and heap corruption without requiring
concurrency or another open file.
### Steps to reproduce
1. Build the `sim` target with:
* `CONFIG_MTD=y`
* `CONFIG_MTD_CONFIG=y`
* `CONFIG_RAMMTD=y`
* `CONFIG_RAMMTD_FLASHSIM=y`
* `CONFIG_MM_FILL_ALLOCATIONS=y`
2. Create a RAM MTD device and register it with:
`mtdconfig_register_by_path(mtd, "/dev/uafcfg")`
3. Call:
`mtdconfig_unregister_by_path("/dev/uafcfg")`
4. Observe that `mtdconfig_unregister_by_path()` returns `OK`.
5. Perform a subsequent allocation. The heap is corrupted and the simulator
terminates with `SIGSEGV` inside `mm_malloc()` while traversing the corrupted
free list.
### Reproduction result
The issue was reproduced deterministically on 3 consecutive runs.
Representative output:
```text
UAFCHECK: start (mtd_config unregister lifetime probe)
UAFCHECK control[64]-freed: ptr=0x1002ddae8 len=64 bytes:
0000: c0 01 e2 04 01 00 00 00 a0 01 e2 04 01 00 00 00
0010: 55 55 55 55 ... (all 0x55)
UAFCHECK control non-0x55 bytes past offset 16: 0
UAFCHECK: mtdconfig_register_by_path ret=0
UAFCHECK: open /dev/uafcfg fd=3 errno=0
UAFCHECK: calling mtdconfig_unregister_by_path...
UAFCHECK: mtdconfig_unregister_by_path ret=0
<CRASH — nothing further printed>
```
The LLDB backtrace from the final validation was:
```text
stop reason = EXC_BAD_ACCESS
* frame #0: nuttx`mm_malloc + 176
* frame #1: nuttx`malloc + 32
* frame #2: nuttx`uafcheck_main + 668
```
The final probe was a plain `malloc()` performed immediately after
`mtdconfig_unregister_by_path()`, before any VFS reopen operation. Therefore
the observed allocator failure does not depend on subsequent VFS activity.
### Expected behavior
The private `mtdconfig_struct_s` object should remain valid until the
temporary file has been closed and the driver has been successfully
unregistered.
The object should not be destroyed or freed while `file.f_inode->i_private`
can still be accessed by the file close operation.
Additionally, the return value of `unregister_driver()` should be checked
before freeing the private object. In particular, an `-EBUSY` result must not
be ignored while existing inode references may still access `i_private`.
### Current behavior
The current implementation performs:
```c
dev = inode->i_private;
nxmutex_destroy(&dev->lock);
kmm_free(dev);
file_close(&file);
unregister_driver(path);
return OK;
```
while `mtdconfig_close()` performs:
```c
FAR struct inode *inode = filep->f_inode;
FAR struct mtdconfig_struct_s *dev = inode->i_private;
nxmutex_unlock(&dev->lock);
```
Thus `file_close()` accesses the already-freed `dev`.
### Additional validation
The relevant VFS `file_close()`, inode reference, and `unregister_driver()`
paths were inspected. The free-before-close pattern was also searched for in
the repository.
No existing open or closed issue, PR, or fix commit addressing this specific
`mtdconfig_unregister_by_path()` lifetime violation was found.
The production NuttX source was not modified during runtime validation. The
temporary reproduction harness was removed afterward, the original `.config`
was restored, and both `nuttx` and `apps` repositories were left clean.
### On which OS does this issue occur?
[OS: Windows], [OS: Mac]
### What is the version of your OS?
26.6.2
### NuttX Version
Apache NuttX master — commit 89c2392290b296facc358219161831cad5e1bacd
### Issue Architecture
[Arch: all]
### Issue Area
[Area: Drivers]
### Host information
NuttX configuration options:
CONFIG_HOST_MACOS=y
CONFIG_APPS_DIR="../apps"
CONFIG_BASE_DEFCONFIG="sim:configdata"
CONFIG_BUILD_FLAT=y
CONFIG_OUTPUT_STRIP_PATHS=y
CONFIG_ARCH_HAVE_SETJMP=y
CONFIG_ARCH_SETJMP_H=y
CONFIG_ARCH_NONE_DEBUG_H=y
CONFIG_FORTIFY_SOURCE=0
CONFIG_NDEBUG=y
CONFIG_ARCH_HAVE_STACKCHECK=y
CONFIG_STACK_USAGE_WARNING=0
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEBUG_SYMBOLS_LEVEL="-g"
CONFIG_ARCH_HAVE_CUSTOMOPT=y
CONFIG_DEBUG_NOOPT=y
CONFIG_LTO_NONE=y
CONFIG_DEBUG_OPT_UNUSED_SECTIONS=y
CONFIG_DEBUG_LINK_MAP=y
CONFIG_ARCH_SIM=y
CONFIG_ARCH="sim"
CONFIG_ARCH_CHIP="sim"
CONFIG_HOST_ARM64=y
CONFIG_SIM_TOOLCHAIN_GCC=y
CONFIG_SIM_WALLTIME_SLEEP=y
CONFIG_SIM_WALLTIME_RATIO=100
CONFIG_SIM_LOOP_INTERVAL=10
CONFIG_SIM_STACKSIZE_ADJUSTMENT=65536
CONFIG_SIM_OFFLOAD_NUM_BUFFERS=2
CONFIG_SIM_OFFLOAD_BUFFER_NUMBYTES=32767
CONFIG_SIM_UART_DMA=y
CONFIG_SIM_UART_NUMBER=0
CONFIG_SIM_CUSTOM_DATA_SECTION=""
CONFIG_ARCH_TOOLCHAIN_GNU=y
CONFIG_ARCH_TOOLCHAIN_GCC=y
CONFIG_ARCH_64BIT=y
CONFIG_ARCH_HAVE_TEXT_HEAP=y
CONFIG_ARCH_HAVE_MULTICPU=y
CONFIG_ARCH_HAVE_VFORK=y
CONFIG_ARCH_HAVE_POWEROFF=y
CONFIG_ARCH_HAVE_RTC_SUBSECONDS=y
CONFIG_ARCH_HAVE_SYSCALL_HOOKS=y
CONFIG_ARCH_HAVE_BACKTRACE=y
CONFIG_ARCH_HAVE_CPUINFO=y
CONFIG_ARCH_CPUINFO_FREQ_KHZ=0
CONFIG_ARCH_HAVE_TCBINFO=y
CONFIG_NCPUS=1
CONFIG_BOARD_LOOPSPERMSEC=-1
CONFIG_BOOT_RUNFROMFLASH=y
CONFIG_RAM_START=0x0
CONFIG_RAM_SIZE=0
CONFIG_FLASH_START=0x0
CONFIG_FLASH_SIZE=0
CONFIG_ARCH_BOARD_SIM=y
CONFIG_ARCH_BOARD="sim"
CONFIG_ARCH_HAVE_BUTTONS=y
CONFIG_ARCH_HAVE_IRQBUTTONS=y
CONFIG_BOARD_CRASHDUMP_NONE=y
CONFIG_BOARD_MEMORY_RANGE=""
CONFIG_DISABLE_OS_API=y
CONFIG_DISABLE_POSIX_TIMERS=y
CONFIG_DISABLE_PTHREAD=y
CONFIG_DISABLE_MQUEUE=y
CONFIG_DISABLE_MQUEUE_SYSV=y
CONFIG_ARCH_HAVE_TICKLESS=y
CONFIG_USEC_PER_TICK=10000
CONFIG_TIMER_ADJUST_USEC=0
CONFIG_ARCH_HAVE_TIMEKEEPING=y
CONFIG_START_YEAR=2013
CONFIG_START_MONTH=11
CONFIG_START_DAY=4
CONFIG_IRQ_NWORKS=8
CONFIG_IRQ_WORK_SECTION=""
CONFIG_IRQ_WORK_STACKSIZE=2048
CONFIG_INIT_ENTRY=y
CONFIG_INIT_ARGS=""
CONFIG_INIT_STACKSIZE=2048
CONFIG_INIT_PRIORITY=100
CONFIG_INIT_ENTRYPOINT="configdata_main"
CONFIG_INIT_ENTRYNAME="uafcheck_main"
CONFIG_RR_INTERVAL=0
CONFIG_TASK_NAME_SIZE=31
CONFIG_SCHED_CPULOAD_NONE=y
CONFIG_SCHED_CPULOAD_TICKSPERSEC=100
CONFIG_SCHED_PROFILE_TICKSPERSEC=1000
CONFIG_SCHED_STACK_RECORD=0
CONFIG_DEV_CONSOLE=y
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=8
CONFIG_FILE_STREAM=y
CONFIG_BOARD_LATE_INITIALIZE=y
CONFIG_BOARD_INITTHREAD_STACKSIZE=2048
CONFIG_BOARD_INITTHREAD_PRIORITY=240
CONFIG_ENABLE_ALL_SIGNALS=y
CONFIG_SIG_PREALLOC_IRQ_ACTIONS=8
CONFIG_SIG_PREALLOC_ACTIONS=4
CONFIG_SIG_ALLOC_ACTIONS=1
CONFIG_SCHED_WORKQUEUE=y
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPNTHREADS=1
CONFIG_SCHED_HPWORKPRIORITY=224
CONFIG_SCHED_HPWORKSTACKSIZE=2048
CONFIG_SCHED_HPWORKSTACKSECTION=""
CONFIG_DEFAULT_TASK_STACKSIZE=2048
CONFIG_IDLETHREAD_STACKSIZE=4096
CONFIG_PTHREAD_STACK_MIN=256
CONFIG_PTHREAD_STACK_DEFAULT=2048
CONFIG_PTHREAD_GUARDSIZE_DEFAULT=0
CONFIG_PID_INITIAL_COUNT=16
CONFIG_ONESHOT=y
CONFIG_ONESHOT_COUNT=y
CONFIG_ALARM_ARCH=y
CONFIG_BCH=y
CONFIG_BCH_BUFFER_ALIGNMENT=0
CONFIG_DEV_NULL=y
CONFIG_DEV_ZERO=y
CONFIG_DEV_OPTEE_NONE=y
CONFIG_MTD=y
CONFIG_MTD_BYTE_WRITE=y
CONFIG_MTD_CONFIG=y
CONFIG_MTD_CONFIG_BUFFER_SIZE=0
CONFIG_RAMMTD=y
CONFIG_RAMMTD_BLOCKSIZE=256
CONFIG_RAMMTD_ERASESIZE=4096
CONFIG_RAMMTD_ERASESTATE=0xff
CONFIG_RAMMTD_FLASHSIM=y
CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
CONFIG_SERIAL=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_SERIAL_NPOLLWAITERS=4
CONFIG_SERIAL_IFLOWCONTROL=y
CONFIG_SERIAL_TXDMA=y
CONFIG_SERIAL_RXDMA=y
CONFIG_SYSLOG=y
CONFIG_SYSLOG_DEFAULT_MASK=0xff
CONFIG_SYSLOG_CRLF=y
CONFIG_SYSLOG_MAX_CHANNELS=1
CONFIG_SYSLOG_DEVPATH="/dev/ttyS1"
CONFIG_SYSLOG_DEFAULT=y
CONFIG_FS_NEPOLL_DESCRIPTORS=8
CONFIG_FS_LOCK_BUCKET_SIZE=0
CONFIG_SENDFILE_BUFSIZE=512
CONFIG_FS_BACKTRACE=0
CONFIG_FS_ANONMAP=y
CONFIG_FS_FAT=y
CONFIG_FS_NXFFS=y
CONFIG_NXFFS_PREALLOCATED=y
CONFIG_NXFFS_ERASEDSTATE=0xff
CONFIG_NXFFS_PACKTHRESHOLD=32
CONFIG_NXFFS_MAXNAMLEN=255
CONFIG_NXFFS_TAILTHRESHOLD=8192
CONFIG_NXFONTS_PACKEDMSFIRST=y
CONFIG_MM_DEFAULT_MANAGER=y
CONFIG_MM_DEFAULT_ALIGNMENT=8
CONFIG_MM_NODE_GUARDSIZE=0
CONFIG_MM_REGIONS=1
CONFIG_MM_MAP_COUNT_MAX=1024
CONFIG_MM_FILL_ALLOCATIONS=y
CONFIG_MM_BACKTRACE=-1
CONFIG_MM_FREE_DELAYCOUNT_MAX=0
CONFIG_MM_HEAP_BIGGEST_COUNT=30
CONFIG_MM_HEAP_MEMPOOL_THRESHOLD=-1
CONFIG_BINFMT_ELF_RELOCATABLE=y
CONFIG_STDIO_BUFFER_SIZE=64
CONFIG_STDIO_LINEBUFFER=y
CONFIG_NUNGET_CHARS=2
CONFIG_LIBC_ATOMIC_TOOLCHAIN=y
CONFIG_ARCH_LOWPUTC=y
CONFIG_LIBC_HOMEDIR="/"
CONFIG_LIBC_TMPDIR="/tmp"
CONFIG_LIBC_MAX_TMPFILE=32
CONFIG_LIBC_MAX_EXITFUNS=0
CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=2048
CONFIG_LIBC_HOSTNAME=""
CONFIG_LIBC_OPEN_MAX=256
CONFIG_NAME_MAX=32
CONFIG_PATH_MAX=256
CONFIG_LINE_MAX=80
CONFIG_LIBC_STRERROR_ERRNUM=y
CONFIG_LIBC_STRSIGNAL=y
CONFIG_LIBC_STRFTIME_C_STANDARD_FORMATS=y
CONFIG_LIBC_STRFTIME_POSIX_FORMATS=y
CONFIG_LIBC_STRFTIME_NONSTANDARD_FORMATS=y
CONFIG_TLS_TASK_NELEM=0
CONFIG_TLS_NCLEANUP=0
CONFIG_LIBC_GAISTRERROR_ERRNUM=y
CONFIG_LIBC_FTOK_VFS_PATH="/var/ftok"
CONFIG_LIBC_MEMFD_ERROR=y
CONFIG_LIBC_TEMPBUFFER=y
CONFIG_LIBC_MAX_TEMPBUFFER=2
CONFIG_LIBC_TEMPBUFFER_MALLOC=y
CONFIG_LIBC_MUTEX_BACKTRACE=0
CONFIG_STREAM_OUT_BUFFER_SIZE=64
CONFIG_STREAM_HEXDUMP_BUFFER_SIZE=128
CONFIG_STREAM_BASE64_BUFFER_SIZE=128
CONFIG_LIBC_INLINE_QUEUE=y
CONFIG_LIBM_TOOLCHAIN=y
CONFIG_BUILTIN_TOOLCHAIN=y
CONFIG_COVERAGE_NONE=y
CONFIG_COVERAGE_DEFAULT_PREFIX_STRIP="0"
CONFIG_COVERAGE_DEFAULT_PREFIX="/data"
CONFIG_PROFILE_NONE=y
CONFIG_EXAMPLES_CONFIGDATA=y
CONFIG_EXAMPLES_CONFIGDATA_NEBLOCKS=4
CONFIG_EXAMPLES_CONFIGDATA_NLOOPS=10000
CONFIG_EXAMPLES_CONFIGDATA_SILENT=y
CONFIG_FSUTILS_MKFATFS=y
CONFIG_MKFATFS_BUFFER_ALIGNMENT=0
CONFIG_PLATFORM_CONFIGDATA=y
CONFIG_SYSTEM_DD=y
CONFIG_SYSTEM_DD_PROGNAME="dd"
CONFIG_SYSTEM_DD_PRIORITY=100
CONFIG_SYSTEM_DD_STACKSIZE=2048
CONFIG_SYSTEM_DD_STATS=y
CONFIG_TESTING_NXFFS=y
CONFIG_TESTING_NXFFS_NEBLOCKS=32
CONFIG_TESTING_NXFFS_MAXNAME=128
CONFIG_TESTING_NXFFS_MAXFILE=8192
CONFIG_TESTING_NXFFS_MAXIO=347
CONFIG_TESTING_NXFFS_MAXOPEN=512
CONFIG_TESTING_NXFFS_MOUNTPT="/mnt/nxffs"
CONFIG_TESTING_NXFFS_NLOOPS=100
Host system OS:
macOS 26.6.2 Darwin Arnavs-MacBook-Air.local 25.6.0 Darwin Kernel Version
25.6.0: Fri Jul 31 19:17:12 PDT 2026;
root:xnu-12377.161.14~5/RELEASE_ARM64_T8103 arm64 arm
Host system PATH:
/Users/arnavsharma/.local/bin
/Users/arnavsharma/.antigravity/antigravity/bin
/opt/anaconda3/bin
/opt/anaconda3/condabin
/opt/homebrew/bin
/opt/homebrew/sbin
/Users/arnavsharma/.local/bin
/Library/Frameworks/Python.framework/Versions/3.13/bin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
/pkg/env/global/bin
/Library/Apple/usr/bin
### Verification
- [x] I have verified before submitting the report.
--
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]