summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Kinsburskii <skinsburskii@linux.microsoft.com>2026-05-07 15:44:32 +0000
committerWei Liu <wei.liu@kernel.org>2026-07-23 06:27:20 +0000
commitb7e92e14744131ca00720837dcdff944fa54fa10 (patch)
treef3ec0f5fa80589f92223582f07a8858a91912e14
parent2225dc7722999c4746dddc1efd7ac0282975fd90 (diff)
downloadlinux-next-b7e92e14744131ca00720837dcdff944fa54fa10.tar.gz
linux-next-b7e92e14744131ca00720837dcdff944fa54fa10.zip
mshv: Publish VP to pt_vp_array before installing the file descriptor
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>
-rw-r--r--drivers/hv/mshv_root_main.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 8a15448e2ace..cc2cfce2aefd 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -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: