]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mshv: Publish VP to pt_vp_array before installing the file descriptor
authorStanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Thu, 7 May 2026 15:44:32 +0000 (15:44 +0000)
committerWei Liu <wei.liu@kernel.org>
Fri, 31 Jul 2026 20:02:03 +0000 (20:02 +0000)
mshv_partition_ioctl_create_vp() called anon_inode_getfd() before
publishing the new VP into partition->pt_vp_array.  anon_inode_getfd()
includes fd_install(), so the fd was live in current->files before the
publish ran.

A concurrent MSHV_RUN_VP ioctl on that fd does not serialise against the
in-progress MSHV_CREATE_VP — it takes vp->vp_mutex, not the partition
mutex.  Once the VP starts running and traps, mshv_intercept_isr() can look
up partition->pt_vp_array[vp_index] and observe NULL, silently dropping the
intercept message.

Split the fd creation: reserve an fd with get_unused_fd_flags(), create the
file with anon_inode_getfile(), publish the VP via smp_store_release(), and
finally call fd_install() as the userspace-visibility commit point.

Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
drivers/hv/mshv_root_main.c

index 8a15448e2ace98e4de5bf171d2ad6ca4fbaaae8f..cc2cfce2aefdb57b421aae18dcb412abbc312e60 100644 (file)
@@ -1072,6 +1072,8 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
        struct mshv_vp *vp;
        struct page *intercept_msg_page, *register_page, *ghcb_page;
        struct hv_stats_page *stats_pages[2];
+       struct file *file;
+       int fd;
        long ret;
 
        if (copy_from_user(&args, arg, sizeof(args)))
@@ -1146,14 +1148,18 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
        if (ret)
                goto put_partition;
 
-       /*
-        * Keep anon_inode_getfd last: it installs fd in the file struct and
-        * thus makes the state accessible in user space.
-        */
-       ret = anon_inode_getfd("mshv_vp", &mshv_vp_fops, vp,
-                              O_RDWR | O_CLOEXEC);
-       if (ret < 0)
+       fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+       if (fd < 0) {
+               ret = fd;
                goto remove_debugfs_vp;
+       }
+
+       file = anon_inode_getfile("mshv_vp", &mshv_vp_fops, vp,
+                                 O_RDWR | O_CLOEXEC);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto put_unused_vp_fd;
+       }
 
        /* already exclusive with the partition mutex for all ioctls */
        partition->pt_vp_count++;
@@ -1165,8 +1171,17 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
         */
        smp_store_release(&partition->pt_vp_array[args.vp_index], vp);
 
+       /*
+        * fd_install() is the userspace-visibility commit point.  Must be the
+        * last operation that can fail or be observed.
+        */
+       fd_install(fd, file);
+       ret = fd;
+
        goto out;
 
+put_unused_vp_fd:
+       put_unused_fd(fd);
 remove_debugfs_vp:
        mshv_debugfs_vp_remove(vp);
 put_partition: