Skip to content

Commit c720e6a

Browse files
Anirudh Rayabharam (Microsoft)liuw
authored andcommitted
mshv: Add ioctl for self targeted passthrough hvcalls
Allow MSHV_ROOT_HVCALL IOCTL on the /dev/mshv fd. This IOCTL would execute a passthrough hypercall targeting the root/parent partition i.e. HV_PARTITION_ID_SELF. This will be useful for the VMM to query things like supported synthetic processor features, supported VMM capabiliites etc. Since hypercalls targeting the host partition could potentially perform privileged operations, allow only a limited set of hypercalls. To begin with, allow only: HVCALL_GET_PARTITION_PROPERTY HVCALL_GET_PARTITION_PROPERTY_EX Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com> Reviewed-by: Nuno Das Neves <nunodasneves@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent 7bfe3b8 commit c720e6a

1 file changed

Lines changed: 38 additions & 9 deletions

File tree

drivers/hv/mshv_root_main.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static struct miscdevice mshv_dev = {
122122
*/
123123
static u16 mshv_passthru_hvcalls[] = {
124124
HVCALL_GET_PARTITION_PROPERTY,
125+
HVCALL_GET_PARTITION_PROPERTY_EX,
125126
HVCALL_SET_PARTITION_PROPERTY,
126127
HVCALL_INSTALL_INTERCEPT,
127128
HVCALL_GET_VP_REGISTERS,
@@ -136,6 +137,16 @@ static u16 mshv_passthru_hvcalls[] = {
136137
HVCALL_GET_VP_CPUID_VALUES,
137138
};
138139

140+
/*
141+
* Only allow hypercalls that are safe to be called by the VMM with the host
142+
* partition as target (i.e. HV_PARTITION_ID_SELF). Carefully audit that a
143+
* hypercall cannot be misused by the VMM before adding it to this list.
144+
*/
145+
static u16 mshv_self_passthru_hvcalls[] = {
146+
HVCALL_GET_PARTITION_PROPERTY,
147+
HVCALL_GET_PARTITION_PROPERTY_EX,
148+
};
149+
139150
static bool mshv_hvcall_is_async(u16 code)
140151
{
141152
switch (code) {
@@ -147,19 +158,38 @@ static bool mshv_hvcall_is_async(u16 code)
147158
return false;
148159
}
149160

161+
static bool mshv_passthru_hvcall_allowed(u16 code, u64 pt_id)
162+
{
163+
int i;
164+
int n = ARRAY_SIZE(mshv_passthru_hvcalls);
165+
u16 *allowed_hvcalls = mshv_passthru_hvcalls;
166+
167+
if (pt_id == HV_PARTITION_ID_SELF) {
168+
n = ARRAY_SIZE(mshv_self_passthru_hvcalls);
169+
allowed_hvcalls = mshv_self_passthru_hvcalls;
170+
}
171+
172+
for (i = 0; i < n; ++i)
173+
if (allowed_hvcalls[i] == code)
174+
return true;
175+
176+
return false;
177+
}
178+
150179
static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
151180
bool partition_locked,
152181
void __user *user_args)
153182
{
154183
u64 status;
155-
int ret = 0, i;
184+
int ret = 0;
156185
bool is_async;
157186
struct mshv_root_hvcall args;
158187
struct page *page;
159188
unsigned int pages_order;
160189
void *input_pg = NULL;
161190
void *output_pg = NULL;
162191
u16 reps_completed;
192+
u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF;
163193

164194
if (copy_from_user(&args, user_args, sizeof(args)))
165195
return -EFAULT;
@@ -171,17 +201,13 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
171201
if (args.out_ptr && (!args.out_sz || args.out_sz > HV_HYP_PAGE_SIZE))
172202
return -EINVAL;
173203

174-
for (i = 0; i < ARRAY_SIZE(mshv_passthru_hvcalls); ++i)
175-
if (args.code == mshv_passthru_hvcalls[i])
176-
break;
177-
178-
if (i >= ARRAY_SIZE(mshv_passthru_hvcalls))
204+
if (!mshv_passthru_hvcall_allowed(args.code, pt_id))
179205
return -EINVAL;
180206

181207
is_async = mshv_hvcall_is_async(args.code);
182208
if (is_async) {
183209
/* async hypercalls can only be called from partition fd */
184-
if (!partition_locked)
210+
if (!partition || !partition_locked)
185211
return -EINVAL;
186212
ret = mshv_init_async_handler(partition);
187213
if (ret)
@@ -209,7 +235,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
209235
* NOTE: This only works because all the allowed hypercalls' input
210236
* structs begin with a u64 partition_id field.
211237
*/
212-
*(u64 *)input_pg = partition->pt_id;
238+
*(u64 *)input_pg = pt_id;
213239

214240
reps_completed = 0;
215241
do {
@@ -238,7 +264,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
238264
ret = hv_result_to_errno(status);
239265
else
240266
ret = hv_call_deposit_pages(NUMA_NO_NODE,
241-
partition->pt_id, 1);
267+
pt_id, 1);
242268
} while (!ret);
243269

244270
args.status = hv_result(status);
@@ -2050,6 +2076,9 @@ static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl,
20502076
case MSHV_CREATE_PARTITION:
20512077
return mshv_ioctl_create_partition((void __user *)arg,
20522078
misc->this_device);
2079+
case MSHV_ROOT_HVCALL:
2080+
return mshv_ioctl_passthru_hvcall(NULL, false,
2081+
(void __user *)arg);
20532082
}
20542083

20552084
return -ENOTTY;

0 commit comments

Comments
 (0)