Skip to content

Commit 571b12d

Browse files
committed
Merge tag 'hyperv-next-signed-20201214' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V updates from Wei Liu: - harden VMBus (Andres Beltran) - clean up VMBus driver (Matheus Castello) - fix hv_balloon reporting (Vitaly Kuznetsov) - fix a potential OOB issue (Andrea Parri) - remove an obsolete TODO item (Stefan Eschenbacher) * tag 'hyperv-next-signed-20201214' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: hv_balloon: do adjust_managed_page_count() when ballooning/un-ballooning hv_balloon: simplify math in alloc_balloon_pages() drivers/hv: remove obsolete TODO and fix misleading typo in comment drivers: hv: vmbus: Fix checkpatch SPLIT_STRING hv_netvsc: Validate number of allocated sub-channels drivers: hv: vmbus: Fix call msleep using < 20ms drivers: hv: vmbus: Fix checkpatch LINE_SPACING drivers: hv: vmbus: Replace symbolic permissions by octal permissions drivers: hv: Fix hyperv_record_panic_msg path on comment hv_netvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening scsi: storvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening Drivers: hv: vmbus: Add vmbus_requestor data structure for VMBus hardening
2 parents e994cc2 + d1df458 commit 571b12d

File tree

10 files changed

+313
-43
lines changed

10 files changed

+313
-43
lines changed

drivers/hv/channel.c

Lines changed: 168 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,70 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
503503
}
504504
EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
505505

506+
/**
507+
* request_arr_init - Allocates memory for the requestor array. Each slot
508+
* keeps track of the next available slot in the array. Initially, each
509+
* slot points to the next one (as in a Linked List). The last slot
510+
* does not point to anything, so its value is U64_MAX by default.
511+
* @size The size of the array
512+
*/
513+
static u64 *request_arr_init(u32 size)
514+
{
515+
int i;
516+
u64 *req_arr;
517+
518+
req_arr = kcalloc(size, sizeof(u64), GFP_KERNEL);
519+
if (!req_arr)
520+
return NULL;
521+
522+
for (i = 0; i < size - 1; i++)
523+
req_arr[i] = i + 1;
524+
525+
/* Last slot (no more available slots) */
526+
req_arr[i] = U64_MAX;
527+
528+
return req_arr;
529+
}
530+
531+
/*
532+
* vmbus_alloc_requestor - Initializes @rqstor's fields.
533+
* Index 0 is the first free slot
534+
* @size: Size of the requestor array
535+
*/
536+
static int vmbus_alloc_requestor(struct vmbus_requestor *rqstor, u32 size)
537+
{
538+
u64 *rqst_arr;
539+
unsigned long *bitmap;
540+
541+
rqst_arr = request_arr_init(size);
542+
if (!rqst_arr)
543+
return -ENOMEM;
544+
545+
bitmap = bitmap_zalloc(size, GFP_KERNEL);
546+
if (!bitmap) {
547+
kfree(rqst_arr);
548+
return -ENOMEM;
549+
}
550+
551+
rqstor->req_arr = rqst_arr;
552+
rqstor->req_bitmap = bitmap;
553+
rqstor->size = size;
554+
rqstor->next_request_id = 0;
555+
spin_lock_init(&rqstor->req_lock);
556+
557+
return 0;
558+
}
559+
560+
/*
561+
* vmbus_free_requestor - Frees memory allocated for @rqstor
562+
* @rqstor: Pointer to the requestor struct
563+
*/
564+
static void vmbus_free_requestor(struct vmbus_requestor *rqstor)
565+
{
566+
kfree(rqstor->req_arr);
567+
bitmap_free(rqstor->req_bitmap);
568+
}
569+
506570
static int __vmbus_open(struct vmbus_channel *newchannel,
507571
void *userdata, u32 userdatalen,
508572
void (*onchannelcallback)(void *context), void *context)
@@ -523,6 +587,12 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
523587
if (newchannel->state != CHANNEL_OPEN_STATE)
524588
return -EINVAL;
525589

590+
/* Create and init requestor */
591+
if (newchannel->rqstor_size) {
592+
if (vmbus_alloc_requestor(&newchannel->requestor, newchannel->rqstor_size))
593+
return -ENOMEM;
594+
}
595+
526596
newchannel->state = CHANNEL_OPENING_STATE;
527597
newchannel->onchannel_callback = onchannelcallback;
528598
newchannel->channel_callback_context = context;
@@ -626,6 +696,7 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
626696
error_clean_ring:
627697
hv_ringbuffer_cleanup(&newchannel->outbound);
628698
hv_ringbuffer_cleanup(&newchannel->inbound);
699+
vmbus_free_requestor(&newchannel->requestor);
629700
newchannel->state = CHANNEL_OPEN_STATE;
630701
return err;
631702
}
@@ -808,6 +879,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
808879
channel->ringbuffer_gpadlhandle = 0;
809880
}
810881

882+
if (!ret)
883+
vmbus_free_requestor(&channel->requestor);
884+
811885
return ret;
812886
}
813887

@@ -888,7 +962,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
888962
/* in 8-bytes granularity */
889963
desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3;
890964
desc.len8 = (u16)(packetlen_aligned >> 3);
891-
desc.trans_id = requestid;
965+
desc.trans_id = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */
892966

893967
bufferlist[0].iov_base = &desc;
894968
bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor);
@@ -897,7 +971,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
897971
bufferlist[2].iov_base = &aligned_data;
898972
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
899973

900-
return hv_ringbuffer_write(channel, bufferlist, num_vecs);
974+
return hv_ringbuffer_write(channel, bufferlist, num_vecs, requestid);
901975
}
902976
EXPORT_SYMBOL(vmbus_sendpacket);
903977

@@ -939,7 +1013,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
9391013
desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
9401014
desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */
9411015
desc.length8 = (u16)(packetlen_aligned >> 3);
942-
desc.transactionid = requestid;
1016+
desc.transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */
9431017
desc.reserved = 0;
9441018
desc.rangecount = pagecount;
9451019

@@ -956,7 +1030,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
9561030
bufferlist[2].iov_base = &aligned_data;
9571031
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
9581032

959-
return hv_ringbuffer_write(channel, bufferlist, 3);
1033+
return hv_ringbuffer_write(channel, bufferlist, 3, requestid);
9601034
}
9611035
EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
9621036

@@ -983,7 +1057,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
9831057
desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
9841058
desc->dataoffset8 = desc_size >> 3; /* in 8-bytes granularity */
9851059
desc->length8 = (u16)(packetlen_aligned >> 3);
986-
desc->transactionid = requestid;
1060+
desc->transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */
9871061
desc->reserved = 0;
9881062
desc->rangecount = 1;
9891063

@@ -994,7 +1068,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
9941068
bufferlist[2].iov_base = &aligned_data;
9951069
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
9961070

997-
return hv_ringbuffer_write(channel, bufferlist, 3);
1071+
return hv_ringbuffer_write(channel, bufferlist, 3, requestid);
9981072
}
9991073
EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
10001074

@@ -1042,3 +1116,91 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
10421116
buffer_actual_len, requestid, true);
10431117
}
10441118
EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
1119+
1120+
/*
1121+
* vmbus_next_request_id - Returns a new request id. It is also
1122+
* the index at which the guest memory address is stored.
1123+
* Uses a spin lock to avoid race conditions.
1124+
* @rqstor: Pointer to the requestor struct
1125+
* @rqst_add: Guest memory address to be stored in the array
1126+
*/
1127+
u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr)
1128+
{
1129+
unsigned long flags;
1130+
u64 current_id;
1131+
const struct vmbus_channel *channel =
1132+
container_of(rqstor, const struct vmbus_channel, requestor);
1133+
1134+
/* Check rqstor has been initialized */
1135+
if (!channel->rqstor_size)
1136+
return VMBUS_NO_RQSTOR;
1137+
1138+
spin_lock_irqsave(&rqstor->req_lock, flags);
1139+
current_id = rqstor->next_request_id;
1140+
1141+
/* Requestor array is full */
1142+
if (current_id >= rqstor->size) {
1143+
spin_unlock_irqrestore(&rqstor->req_lock, flags);
1144+
return VMBUS_RQST_ERROR;
1145+
}
1146+
1147+
rqstor->next_request_id = rqstor->req_arr[current_id];
1148+
rqstor->req_arr[current_id] = rqst_addr;
1149+
1150+
/* The already held spin lock provides atomicity */
1151+
bitmap_set(rqstor->req_bitmap, current_id, 1);
1152+
1153+
spin_unlock_irqrestore(&rqstor->req_lock, flags);
1154+
1155+
/*
1156+
* Cannot return an ID of 0, which is reserved for an unsolicited
1157+
* message from Hyper-V.
1158+
*/
1159+
return current_id + 1;
1160+
}
1161+
EXPORT_SYMBOL_GPL(vmbus_next_request_id);
1162+
1163+
/*
1164+
* vmbus_request_addr - Returns the memory address stored at @trans_id
1165+
* in @rqstor. Uses a spin lock to avoid race conditions.
1166+
* @rqstor: Pointer to the requestor struct
1167+
* @trans_id: Request id sent back from Hyper-V. Becomes the requestor's
1168+
* next request id.
1169+
*/
1170+
u64 vmbus_request_addr(struct vmbus_requestor *rqstor, u64 trans_id)
1171+
{
1172+
unsigned long flags;
1173+
u64 req_addr;
1174+
const struct vmbus_channel *channel =
1175+
container_of(rqstor, const struct vmbus_channel, requestor);
1176+
1177+
/* Check rqstor has been initialized */
1178+
if (!channel->rqstor_size)
1179+
return VMBUS_NO_RQSTOR;
1180+
1181+
/* Hyper-V can send an unsolicited message with ID of 0 */
1182+
if (!trans_id)
1183+
return trans_id;
1184+
1185+
spin_lock_irqsave(&rqstor->req_lock, flags);
1186+
1187+
/* Data corresponding to trans_id is stored at trans_id - 1 */
1188+
trans_id--;
1189+
1190+
/* Invalid trans_id */
1191+
if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap)) {
1192+
spin_unlock_irqrestore(&rqstor->req_lock, flags);
1193+
return VMBUS_RQST_ERROR;
1194+
}
1195+
1196+
req_addr = rqstor->req_arr[trans_id];
1197+
rqstor->req_arr[trans_id] = rqstor->next_request_id;
1198+
rqstor->next_request_id = trans_id;
1199+
1200+
/* The already held spin lock provides atomicity */
1201+
bitmap_clear(rqstor->req_bitmap, trans_id, 1);
1202+
1203+
spin_unlock_irqrestore(&rqstor->req_lock, flags);
1204+
return req_addr;
1205+
}
1206+
EXPORT_SYMBOL_GPL(vmbus_request_addr);

drivers/hv/hv_balloon.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,7 @@ static void free_balloon_pages(struct hv_dynmem_device *dm,
11981198
__ClearPageOffline(pg);
11991199
__free_page(pg);
12001200
dm->num_pages_ballooned--;
1201+
adjust_managed_page_count(pg, 1);
12011202
}
12021203
}
12031204

@@ -1238,8 +1239,10 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
12381239
split_page(pg, get_order(alloc_unit << PAGE_SHIFT));
12391240

12401241
/* mark all pages offline */
1241-
for (j = 0; j < (1 << get_order(alloc_unit << PAGE_SHIFT)); j++)
1242+
for (j = 0; j < alloc_unit; j++) {
12421243
__SetPageOffline(pg + j);
1244+
adjust_managed_page_count(pg + j, -1);
1245+
}
12431246

12441247
bl_resp->range_count++;
12451248
bl_resp->range_array[i].finfo.start_page =

drivers/hv/hyperv_vmbus.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,21 +179,21 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
179179
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
180180

181181
int hv_ringbuffer_write(struct vmbus_channel *channel,
182-
const struct kvec *kv_list, u32 kv_count);
182+
const struct kvec *kv_list, u32 kv_count,
183+
u64 requestid);
183184

184185
int hv_ringbuffer_read(struct vmbus_channel *channel,
185186
void *buffer, u32 buflen, u32 *buffer_actual_len,
186187
u64 *requestid, bool raw);
187188

188189
/*
189-
* The Maximum number of channels (16348) is determined by the size of the
190+
* The Maximum number of channels (16384) is determined by the size of the
190191
* interrupt page, which is HV_HYP_PAGE_SIZE. 1/2 of HV_HYP_PAGE_SIZE is to
191192
* send endpoint interrupts, and the other is to receive endpoint interrupts.
192193
*/
193194
#define MAX_NUM_CHANNELS ((HV_HYP_PAGE_SIZE >> 1) << 3)
194195

195196
/* The value here must be in multiple of 32 */
196-
/* TODO: Need to make this configurable */
197197
#define MAX_NUM_CHANNELS_SUPPORTED 256
198198

199199
#define MAX_CHANNEL_RELIDS \

drivers/hv/ring_buffer.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
248248

249249
/* Write to the ring buffer. */
250250
int hv_ringbuffer_write(struct vmbus_channel *channel,
251-
const struct kvec *kv_list, u32 kv_count)
251+
const struct kvec *kv_list, u32 kv_count,
252+
u64 requestid)
252253
{
253254
int i;
254255
u32 bytes_avail_towrite;
@@ -258,6 +259,8 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
258259
u64 prev_indices;
259260
unsigned long flags;
260261
struct hv_ring_buffer_info *outring_info = &channel->outbound;
262+
struct vmpacket_descriptor *desc = kv_list[0].iov_base;
263+
u64 rqst_id = VMBUS_NO_RQSTOR;
261264

262265
if (channel->rescind)
263266
return -ENODEV;
@@ -300,6 +303,23 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
300303
kv_list[i].iov_len);
301304
}
302305

306+
/*
307+
* Allocate the request ID after the data has been copied into the
308+
* ring buffer. Once this request ID is allocated, the completion
309+
* path could find the data and free it.
310+
*/
311+
312+
if (desc->flags == VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED) {
313+
rqst_id = vmbus_next_request_id(&channel->requestor, requestid);
314+
if (rqst_id == VMBUS_RQST_ERROR) {
315+
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
316+
pr_err("No request id available\n");
317+
return -EAGAIN;
318+
}
319+
}
320+
desc = hv_get_ring_buffer(outring_info) + old_write;
321+
desc->trans_id = (rqst_id == VMBUS_NO_RQSTOR) ? requestid : rqst_id;
322+
303323
/* Set previous packet start */
304324
prev_indices = hv_get_ring_bufferindices(outring_info);
305325

@@ -319,8 +339,13 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
319339

320340
hv_signal_on_write(old_write, channel);
321341

322-
if (channel->rescind)
342+
if (channel->rescind) {
343+
if (rqst_id != VMBUS_NO_RQSTOR) {
344+
/* Reclaim request ID to avoid leak of IDs */
345+
vmbus_request_addr(&channel->requestor, rqst_id);
346+
}
323347
return -ENODEV;
348+
}
324349

325350
return 0;
326351
}

0 commit comments

Comments
 (0)