This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit b71c713c8acd81d78db7566f7cbb57d0bd865dd0
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 19 23:33:40 2026 +0200

    fs/vfs: Read the FIONBIO argument before the file reference is taken.
    
    ioctl(fd, FIONBIO, &value) passes a pointer to an int.  The driver reads
    the int, and file_vioctl() reads it again after the driver ioctl, while
    nx_vioctl() holds a reference to the file.  In a kernel build or a
    protected build the pointer comes from user space, so another thread can
    change the int between the two reads, and then the driver and f_oflags do
    not agree.
    
    Read the int once in nx_vioctl() before file_get2(), and give the driver
    and file_vioctl() a pointer to the kernel copy.  No user memory is read
    with the reference held.  Kernel callers of file_ioctl() do not change.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 fs/vfs/fs_ioctl.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/fs/vfs/fs_ioctl.c b/fs/vfs/fs_ioctl.c
index 0de0de35ba9..5e9b6cb3328 100644
--- a/fs/vfs/fs_ioctl.c
+++ b/fs/vfs/fs_ioctl.c
@@ -165,8 +165,25 @@ static int nx_vioctl(int fd, int req, va_list ap)
 {
   FAR struct file *filep;
   FAR struct fd *fdp;
+  FAR int *nonblockp = NULL;
+  int nonblock;
   int ret;
 
+  /* FIONBIO passes a pointer to an int.  Read the int before file_get2(),
+   * so that a bad pointer faults with no file reference held, and give the
+   * driver a pointer to the copy.
+   */
+
+  if (req == FIONBIO)
+    {
+      nonblockp = va_arg(ap, FAR int *);
+      if (nonblockp != NULL)
+        {
+          nonblock  = *nonblockp;
+          nonblockp = &nonblock;
+        }
+    }
+
   ret = file_get2(fd, &filep, &fdp);
   if (ret < 0)
     {
@@ -207,6 +224,10 @@ static int nx_vioctl(int fd, int req, va_list ap)
         break;
 #endif
 
+      case FIONBIO:
+        ret = file_ioctl(filep, req, (unsigned long)(uintptr_t)nonblockp);
+        break;
+
       default:
         ret = file_vioctl(filep, req, ap);
         break;

Reply via email to