Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hyperv: Fix RNDIS send_completion code path

In some cases, the VM_PKT_COMP message can arrive later than RNDIS completion
message, which will free the packet memory. This may cause panic due to access
to freed memory in netvsc_send_completion().

This patch fixes this problem by removing rndis_filter_send_request_completion()
from the code path. The function was a no-op.

Reported-by: Long Li <longli@microsoft.com>
Tested-by: Long Li <longli@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Haiyang Zhang and committed by
David S. Miller
f1ea3cd7 fd5c07a8

+13 -18
+12 -5
drivers/net/hyperv/netvsc.c
··· 470 470 packet->trans_id; 471 471 472 472 /* Notify the layer above us */ 473 - nvsc_packet->completion.send.send_completion( 474 - nvsc_packet->completion.send.send_completion_ctx); 473 + if (nvsc_packet) 474 + nvsc_packet->completion.send.send_completion( 475 + nvsc_packet->completion.send. 476 + send_completion_ctx); 475 477 476 478 num_outstanding_sends = 477 479 atomic_dec_return(&net_device->num_outstanding_sends); ··· 500 498 int ret = 0; 501 499 struct nvsp_message sendMessage; 502 500 struct net_device *ndev; 501 + u64 req_id; 503 502 504 503 net_device = get_outbound_net_device(device); 505 504 if (!net_device) ··· 521 518 0xFFFFFFFF; 522 519 sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; 523 520 521 + if (packet->completion.send.send_completion) 522 + req_id = (u64)packet; 523 + else 524 + req_id = 0; 525 + 524 526 if (packet->page_buf_cnt) { 525 527 ret = vmbus_sendpacket_pagebuffer(device->channel, 526 528 packet->page_buf, 527 529 packet->page_buf_cnt, 528 530 &sendMessage, 529 531 sizeof(struct nvsp_message), 530 - (unsigned long)packet); 532 + req_id); 531 533 } else { 532 534 ret = vmbus_sendpacket(device->channel, &sendMessage, 533 535 sizeof(struct nvsp_message), 534 - (unsigned long)packet, 536 + req_id, 535 537 VM_PKT_DATA_INBAND, 536 538 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 537 - 538 539 } 539 540 540 541 if (ret == 0) {
+1 -13
drivers/net/hyperv/rndis_filter.c
··· 61 61 62 62 static void rndis_filter_send_completion(void *ctx); 63 63 64 - static void rndis_filter_send_request_completion(void *ctx); 65 - 66 - 67 64 68 65 static struct rndis_device *get_rndis_device(void) 69 66 { ··· 238 241 packet->page_buf[0].len; 239 242 } 240 243 241 - packet->completion.send.send_completion_ctx = req;/* packet; */ 242 - packet->completion.send.send_completion = 243 - rndis_filter_send_request_completion; 244 - packet->completion.send.send_completion_tid = (unsigned long)dev; 244 + packet->completion.send.send_completion = NULL; 245 245 246 246 ret = netvsc_send(dev->net_dev->dev, packet); 247 247 return ret; ··· 992 998 993 999 /* Pass it back to the original handler */ 994 1000 filter_pkt->completion(filter_pkt->completion_ctx); 995 - } 996 - 997 - 998 - static void rndis_filter_send_request_completion(void *ctx) 999 - { 1000 - /* Noop */ 1001 1001 }