This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 80bf4835e80 fs/vfs: hold the inode lock in read_pseudodir()
80bf4835e80 is described below
commit 80bf4835e800ec45b6a5df7404a5ee8cbe88c393
Author: dengwenqi <[email protected]>
AuthorDate: Wed Nov 11 16:17:56 2026 +0800
fs/vfs: hold the inode lock in read_pseudodir()
read_pseudodir() reads pdir->next and its name, operations and child
pointers without the inode lock, and takes the lock only to advance to
the next peer. If another thread unregisters a driver in between, the
peer can be unlinked and freed, and readdir() then dereferences freed
memory.
Take the inode lock at the start of read_pseudodir(), as
seek_pseudodir() already does, and release it on both return paths.
Signed-off-by: dengwenqi <[email protected]>
Signed-off-by: jingfei <[email protected]>
---
fs/vfs/fs_dir.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/fs/vfs/fs_dir.c b/fs/vfs/fs_dir.c
index 156abe15550..1e0d1753a00 100644
--- a/fs/vfs/fs_dir.c
+++ b/fs/vfs/fs_dir.c
@@ -299,9 +299,17 @@ static int read_pseudodir(FAR struct fs_dirent_s *dir,
FAR struct dirent *entry)
{
FAR struct fs_pseudodir_s *pdir = (FAR struct fs_pseudodir_s *)dir;
- FAR struct inode *next = pdir->next;
+ FAR struct inode *next;
FAR struct inode *prev;
+ /* Hold the lock while the entry is used: a concurrent unregister may
+ * unlink and free it.
+ */
+
+ inode_lock();
+
+ next = pdir->next;
+
/* Check if we are at the end of the list */
if (next == NULL)
@@ -310,6 +318,7 @@ static int read_pseudodir(FAR struct fs_dirent_s *dir,
* readdir. Here we return -ENOENT to signal the end of the directory.
*/
+ inode_unlock();
return -ENOENT;
}
@@ -394,8 +403,6 @@ static int read_pseudodir(FAR struct fs_dirent_s *dir,
/* Now get the inode to visit next time that readdir() is called */
- inode_lock();
-
prev = pdir->next;
pdir->next = prev->i_peer; /* The next node to visit */