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: 621191d709 ("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>
This commit is contained in:
Stanislav Kinsburskii
2026-07-23 06:27:20 +00:00
committed by Wei Liu
parent 2225dc7722
commit b7e92e1474
+22 -7
View 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: