diff options
| author | Haiyang Zhang <haiyangz@microsoft.com> | 2013-04-05 07:44:40 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-04-08 12:15:17 -0400 |
| commit | f1ea3cd70110d482ef1ce6ef158df113aa366f43 (patch) | |
| tree | ead600ab71402db00476255f4ed7f1d723eacdd3 /drivers/net/hyperv | |
| parent | fd5c07a8d6a10c7112b19f3b0d428627c62b06ab (diff) | |
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>
Diffstat (limited to 'drivers/net/hyperv')
| -rw-r--r-- | drivers/net/hyperv/netvsc.c | 17 | ||||
| -rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 14 |
2 files changed, 13 insertions, 18 deletions
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 1cd77483da50..f5f0f09e4cc5 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
| @@ -470,8 +470,10 @@ static void netvsc_send_completion(struct hv_device *device, | |||
| 470 | packet->trans_id; | 470 | packet->trans_id; |
| 471 | 471 | ||
| 472 | /* Notify the layer above us */ | 472 | /* Notify the layer above us */ |
| 473 | nvsc_packet->completion.send.send_completion( | 473 | if (nvsc_packet) |
| 474 | nvsc_packet->completion.send.send_completion_ctx); | 474 | nvsc_packet->completion.send.send_completion( |
| 475 | nvsc_packet->completion.send. | ||
| 476 | send_completion_ctx); | ||
| 475 | 477 | ||
| 476 | num_outstanding_sends = | 478 | num_outstanding_sends = |
| 477 | atomic_dec_return(&net_device->num_outstanding_sends); | 479 | atomic_dec_return(&net_device->num_outstanding_sends); |
| @@ -498,6 +500,7 @@ int netvsc_send(struct hv_device *device, | |||
| 498 | int ret = 0; | 500 | int ret = 0; |
| 499 | struct nvsp_message sendMessage; | 501 | struct nvsp_message sendMessage; |
| 500 | struct net_device *ndev; | 502 | struct net_device *ndev; |
| 503 | u64 req_id; | ||
| 501 | 504 | ||
| 502 | net_device = get_outbound_net_device(device); | 505 | net_device = get_outbound_net_device(device); |
| 503 | if (!net_device) | 506 | if (!net_device) |
| @@ -518,20 +521,24 @@ int netvsc_send(struct hv_device *device, | |||
| 518 | 0xFFFFFFFF; | 521 | 0xFFFFFFFF; |
| 519 | sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; | 522 | sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; |
| 520 | 523 | ||
| 524 | if (packet->completion.send.send_completion) | ||
| 525 | req_id = (u64)packet; | ||
| 526 | else | ||
| 527 | req_id = 0; | ||
| 528 | |||
| 521 | if (packet->page_buf_cnt) { | 529 | if (packet->page_buf_cnt) { |
| 522 | ret = vmbus_sendpacket_pagebuffer(device->channel, | 530 | ret = vmbus_sendpacket_pagebuffer(device->channel, |
| 523 | packet->page_buf, | 531 | packet->page_buf, |
| 524 | packet->page_buf_cnt, | 532 | packet->page_buf_cnt, |
| 525 | &sendMessage, | 533 | &sendMessage, |
| 526 | sizeof(struct nvsp_message), | 534 | sizeof(struct nvsp_message), |
| 527 | (unsigned long)packet); | 535 | req_id); |
| 528 | } else { | 536 | } else { |
| 529 | ret = vmbus_sendpacket(device->channel, &sendMessage, | 537 | ret = vmbus_sendpacket(device->channel, &sendMessage, |
| 530 | sizeof(struct nvsp_message), | 538 | sizeof(struct nvsp_message), |
| 531 | (unsigned long)packet, | 539 | req_id, |
| 532 | VM_PKT_DATA_INBAND, | 540 | VM_PKT_DATA_INBAND, |
| 533 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | 541 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
| 534 | |||
| 535 | } | 542 | } |
| 536 | 543 | ||
| 537 | if (ret == 0) { | 544 | if (ret == 0) { |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 2b657d4d63a8..0775f0aefd1e 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
| @@ -61,9 +61,6 @@ struct rndis_request { | |||
| 61 | 61 | ||
| 62 | static void rndis_filter_send_completion(void *ctx); | 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 | static struct rndis_device *get_rndis_device(void) | 65 | static struct rndis_device *get_rndis_device(void) |
| 69 | { | 66 | { |
| @@ -241,10 +238,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, | |||
| 241 | packet->page_buf[0].len; | 238 | packet->page_buf[0].len; |
| 242 | } | 239 | } |
| 243 | 240 | ||
| 244 | packet->completion.send.send_completion_ctx = req;/* packet; */ | 241 | packet->completion.send.send_completion = NULL; |
| 245 | packet->completion.send.send_completion = | ||
| 246 | rndis_filter_send_request_completion; | ||
| 247 | packet->completion.send.send_completion_tid = (unsigned long)dev; | ||
| 248 | 242 | ||
| 249 | ret = netvsc_send(dev->net_dev->dev, packet); | 243 | ret = netvsc_send(dev->net_dev->dev, packet); |
| 250 | return ret; | 244 | return ret; |
| @@ -999,9 +993,3 @@ static void rndis_filter_send_completion(void *ctx) | |||
| 999 | /* Pass it back to the original handler */ | 993 | /* Pass it back to the original handler */ |
| 1000 | filter_pkt->completion(filter_pkt->completion_ctx); | 994 | filter_pkt->completion(filter_pkt->completion_ctx); |
| 1001 | } | 995 | } |
| 1002 | |||
| 1003 | |||
| 1004 | static void rndis_filter_send_request_completion(void *ctx) | ||
| 1005 | { | ||
| 1006 | /* Noop */ | ||
| 1007 | } | ||
