Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp1556623ybt; Thu, 25 Jun 2020 08:41:40 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzaO95kXVVDD5oBzcH4gxmRrcvckm4FCYl+3h8B7AGCOZaNYx5w4W8IPQvZJYD5BfZhsjFx X-Received: by 2002:a17:906:e2ca:: with SMTP id gr10mr19681624ejb.81.1593099700604; Thu, 25 Jun 2020 08:41:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1593099700; cv=none; d=google.com; s=arc-20160816; b=o5hH4K2x7qai4V8QKLdMlJ3XoPJSrEfGltYy1GLYnc/jazYOOUncZwiW3jmMI0cqXr 5RRLe9pFXl97MKsOlzY1U9yj690ea7AhAYKtMhswdJnW7aiwl87Svf6PxKznA/2/ngvc x4GY83zbP8tAodk3INF8FPEv4LiFASRwqylnKJVYtflZSCP9854ruaIpz2LcYH79BL9F epVUUrjLwfWJAIJYx8synTbnYI4miFookP+H83Rn3LqIQYfjtVjlhKqidmR/N97hTLWR mskGIGh6arGsuKQS31jJPZHJPEu1wDGvUTota/CHZU+TOs+N9UqVl3bWU/QKPZUxtV8O EsLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=g2cgJ+7MczxOg79OI1tbP0EQA/VC0sOGt1JvuGb7PFI=; b=V7cnjVNV9rKYpXAjfoOJ67BhnhNEwx8ruTV/v0cyThNcB781OW1npkxvTZWqglcDjU gpk1Z888iLRAA6YI/Exdz+7k8n4xGfG/taxBokVRraMNB1/jcGSkyBXKgTT5DOZpk1zm 6KgmCf7h+yqN/+wGnGGVFyVRB/Zt6afo9N+tEsZHw4FfsMVEcw+M9HR/6T0hgyykkIjD fpId0b7OIS2ddfHdQDtG5hRSSfy72+YM91rNjJyBwWpWj0PcEauuS4mkNa2HDtJ/nQDz u7hcHr0C+DmgJ9mBHu5qm7EGwOJX0rYNA2S2j7lBlXvM5sVSTZ4YZd5PO/oeu/JxNp4K InOg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=YhaHMbjL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id ca5si3470570edb.511.2020.06.25.08.41.16; Thu, 25 Jun 2020 08:41:40 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=YhaHMbjL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2405929AbgFYPh6 (ORCPT + 99 others); Thu, 25 Jun 2020 11:37:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57568 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2405159AbgFYPh4 (ORCPT ); Thu, 25 Jun 2020 11:37:56 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD715C08C5C1; Thu, 25 Jun 2020 08:37:56 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id d12so2963616ply.1; Thu, 25 Jun 2020 08:37:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=g2cgJ+7MczxOg79OI1tbP0EQA/VC0sOGt1JvuGb7PFI=; b=YhaHMbjL5wdH5svKnqpdMZpz0w+1a/tROAOKzZS9qY+Av6wCXr7BEBYuWWqzbCUmHw /8tsVoAw8ljcouhEpcHhruD8gOGuP6QXE7Tl+SEB0bAKzv8U0wJhG+bcayvSAgAz8bcf YVAHT/k5R9KXTUrsDyxGyx3ryJIsXmzGfkrdeJ5FVAcYywMoF834NLcWVVteNU5tCsZO pAfL050Uclh8XTqJd64N0ZbaE6M/0v/UuoGWnFpfL25UK8Ug9dmMjwMZrRTyTEji4mq5 eskM0aiCV8iI5MOdfnmjS/P3fHm81NdnH+N41mgEqFaSQk+7eMX9DRbuF6lZDvFiXaiP Daaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=g2cgJ+7MczxOg79OI1tbP0EQA/VC0sOGt1JvuGb7PFI=; b=M+p++rcHXM2M6bWRtZi8LZjNvhTJcJkpbFCjBce8e2H95ReXPEyvFgr559HD56vYSh f8YgXpSgektG773YIiOIjxa+otnttuweE5a7v9Mhp6Anu+20zr4yODr6DmJ2m4Qu7zJF zzl9dioUF70zFtPUw9NjnXuFkENPI1dBA8DDQCvRx+6RjSRARlFOF4vH6WYyBb6Eoeaq 3Lqmv37yK/11cM9QgN59VNi8lA1MHMrXu68t3UT+S2eNSpboPcKdHAkhSwgnqq4rc03K JQ9aQtBuA3aO/FuupSBOrIKTQGkHUp5MGkh9YX19JcHg05Vs1zOZD558vJtHXbw93EhM K8aw== X-Gm-Message-State: AOAM533/gqJzvBvUZe7FTMAV8j+sW7Zt7gYmwVThk7OZ3exDYIR8uwAo JDy/QByy0UKbjXvtZlSHPOM= X-Received: by 2002:a17:90a:cd01:: with SMTP id d1mr3955729pju.212.1593099476337; Thu, 25 Jun 2020 08:37:56 -0700 (PDT) Received: from localhost.localdomain ([131.107.147.194]) by smtp.gmail.com with ESMTPSA id i14sm22980813pfo.14.2020.06.25.08.37.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 08:37:56 -0700 (PDT) From: Andres Beltran To: kys@microsoft.com, haiyangz@microsoft.com, sthemmin@microsoft.com, wei.liu@kernel.org Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, mikelley@microsoft.com, parri.andrea@gmail.com, Andres Beltran , "David S. Miller" , Jakub Kicinski , netdev@vger.kernel.org Subject: [PATCH 3/3] hv_netvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening Date: Thu, 25 Jun 2020 11:37:23 -0400 Message-Id: <20200625153723.8428-4-lkmlabelt@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200625153723.8428-1-lkmlabelt@gmail.com> References: <20200625153723.8428-1-lkmlabelt@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently, pointers to guest memory are passed to Hyper-V as transaction IDs in netvsc. In the face of errors or malicious behavior in Hyper-V, netvsc should not expose or trust the transaction IDs returned by Hyper-V to be valid guest memory addresses. Instead, use small integers generated by vmbus_requestor as requests (transaction) IDs. Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev@vger.kernel.org Signed-off-by: Andres Beltran --- drivers/net/hyperv/hyperv_net.h | 10 +++++ drivers/net/hyperv/netvsc.c | 75 +++++++++++++++++++++++++------ drivers/net/hyperv/rndis_filter.c | 1 + include/linux/hyperv.h | 1 + 4 files changed, 73 insertions(+), 14 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index abda736e7c7d..14735c98e798 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -847,6 +847,16 @@ struct nvsp_message { #define NETVSC_XDP_HDRM 256 +#define NETVSC_MIN_OUT_MSG_SIZE (sizeof(struct vmpacket_descriptor) + \ + sizeof(struct nvsp_message)) +#define NETVSC_MIN_IN_MSG_SIZE sizeof(struct vmpacket_descriptor) + +/* Estimated requestor size: + * out_ring_size/min_out_msg_size + in_ring_size/min_in_msg_size + */ +#define NETVSC_RQSTOR_SIZE (netvsc_ring_bytes / NETVSC_MIN_OUT_MSG_SIZE + \ + netvsc_ring_bytes / NETVSC_MIN_IN_MSG_SIZE) + struct multi_send_data { struct sk_buff *skb; /* skb containing the pkt */ struct hv_netvsc_packet *pkt; /* netvsc pkt pending */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 41f5cf0bb997..c73d5aef4436 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -50,7 +50,7 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) vmbus_sendpacket(dev->channel, init_pkt, sizeof(struct nvsp_message), - (unsigned long)init_pkt, + VMBUS_RQST_ID_NO_RESPONSE, VM_PKT_DATA_INBAND, 0); } @@ -163,7 +163,7 @@ static void netvsc_revoke_recv_buf(struct hv_device *device, ret = vmbus_sendpacket(device->channel, revoke_packet, sizeof(struct nvsp_message), - (unsigned long)revoke_packet, + VMBUS_RQST_ID_NO_RESPONSE, VM_PKT_DATA_INBAND, 0); /* If the failure is because the channel is rescinded; * ignore the failure since we cannot send on a rescinded @@ -213,7 +213,7 @@ static void netvsc_revoke_send_buf(struct hv_device *device, ret = vmbus_sendpacket(device->channel, revoke_packet, sizeof(struct nvsp_message), - (unsigned long)revoke_packet, + VMBUS_RQST_ID_NO_RESPONSE, VM_PKT_DATA_INBAND, 0); /* If the failure is because the channel is rescinded; @@ -304,6 +304,7 @@ static int netvsc_init_buf(struct hv_device *device, unsigned int buf_size; size_t map_words; int ret = 0; + u64 rqst_id; /* Get receive buffer area. */ buf_size = device_info->recv_sections * device_info->recv_section_size; @@ -350,13 +351,21 @@ static int netvsc_init_buf(struct hv_device *device, trace_nvsp_send(ndev, init_packet); + rqst_id = vmbus_next_request_id(&device->channel->requestor, (u64)init_packet); + if (rqst_id == VMBUS_RQST_ERROR) { + netdev_err(ndev, "No request id available\n"); + goto cleanup; + } + /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)init_packet, + rqst_id, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&device->channel->requestor, rqst_id); netdev_err(ndev, "unable to send receive buffer's gpadl to netvsp\n"); goto cleanup; @@ -432,13 +441,21 @@ static int netvsc_init_buf(struct hv_device *device, trace_nvsp_send(ndev, init_packet); + rqst_id = vmbus_next_request_id(&device->channel->requestor, (u64)init_packet); + if (rqst_id == VMBUS_RQST_ERROR) { + netdev_err(ndev, "No request id available\n"); + goto cleanup; + } + /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)init_packet, + rqst_id, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&device->channel->requestor, rqst_id); netdev_err(ndev, "unable to send send buffer's gpadl to netvsp\n"); goto cleanup; @@ -496,6 +513,7 @@ static int negotiate_nvsp_ver(struct hv_device *device, { struct net_device *ndev = hv_get_drvdata(device); int ret; + u64 rqst_id; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; @@ -503,15 +521,24 @@ static int negotiate_nvsp_ver(struct hv_device *device, init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver; trace_nvsp_send(ndev, init_packet); + rqst_id = vmbus_next_request_id(&device->channel->requestor, (u64)init_packet); + if (rqst_id == VMBUS_RQST_ERROR) { + netdev_err(ndev, "No request id available\n"); + return -EAGAIN; + } + /* Send the init request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)init_packet, + rqst_id, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) + if (ret != 0) { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&device->channel->requestor, rqst_id); return ret; + } wait_for_completion(&net_device->channel_init_wait); @@ -542,7 +569,7 @@ static int negotiate_nvsp_ver(struct hv_device *device, ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)init_packet, + VMBUS_RQST_ID_NO_RESPONSE, VM_PKT_DATA_INBAND, 0); return ret; @@ -599,7 +626,7 @@ static int netvsc_connect_vsp(struct hv_device *device, /* Send the init request */ ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)init_packet, + VMBUS_RQST_ID_NO_RESPONSE, VM_PKT_DATA_INBAND, 0); if (ret != 0) goto cleanup; @@ -680,10 +707,19 @@ static void netvsc_send_tx_complete(struct net_device *ndev, const struct vmpacket_descriptor *desc, int budget) { - struct sk_buff *skb = (struct sk_buff *)(unsigned long)desc->trans_id; + struct sk_buff *skb; struct net_device_context *ndev_ctx = netdev_priv(ndev); u16 q_idx = 0; int queue_sends; + u64 cmd_rqst; + + cmd_rqst = vmbus_request_addr(&channel->requestor, (u64)desc->trans_id); + if (cmd_rqst == VMBUS_RQST_ERROR) { + netdev_err(ndev, "Incorrect transaction id\n"); + return; + } + + skb = (struct sk_buff *)cmd_rqst; /* Notify the layer above us */ if (likely(skb)) { @@ -822,7 +858,7 @@ static inline int netvsc_send_pkt( struct net_device *ndev = hv_get_drvdata(device); struct net_device_context *ndev_ctx = netdev_priv(ndev); struct netdev_queue *txq = netdev_get_tx_queue(ndev, packet->q_idx); - u64 req_id; + u64 rqst_id; int ret; u32 ring_avail = hv_get_avail_to_write_percent(&out_channel->outbound); @@ -838,13 +874,18 @@ static inline int netvsc_send_pkt( else rpkt->send_buf_section_size = packet->total_data_buflen; - req_id = (ulong)skb; if (out_channel->rescind) return -ENODEV; trace_nvsp_send_pkt(ndev, out_channel, rpkt); + rqst_id = vmbus_next_request_id(&out_channel->requestor, (u64)skb); + if (rqst_id == VMBUS_RQST_ERROR) { + ret = -EAGAIN; + goto ret_check; + } + if (packet->page_buf_cnt) { if (packet->cp_partial) pb += packet->rmsg_pgcnt; @@ -852,14 +893,15 @@ static inline int netvsc_send_pkt( ret = vmbus_sendpacket_pagebuffer(out_channel, pb, packet->page_buf_cnt, &nvmsg, sizeof(nvmsg), - req_id); + rqst_id); } else { ret = vmbus_sendpacket(out_channel, &nvmsg, sizeof(nvmsg), - req_id, VM_PKT_DATA_INBAND, + rqst_id, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); } +ret_check: if (ret == 0) { atomic_inc_return(&nvchan->queue_sends); @@ -868,9 +910,13 @@ static inline int netvsc_send_pkt( ndev_ctx->eth_stats.stop_queue++; } } else if (ret == -EAGAIN) { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&out_channel->requestor, rqst_id); netif_tx_stop_queue(txq); ndev_ctx->eth_stats.stop_queue++; } else { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&out_channel->requestor, rqst_id); netdev_err(ndev, "Unable to send packet pages %u len %u, ret %d\n", packet->page_buf_cnt, packet->total_data_buflen, @@ -1422,6 +1468,7 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, netvsc_poll, NAPI_POLL_WEIGHT); /* Open the channel */ + device->channel->rqstor_size = NETVSC_RQSTOR_SIZE; ret = vmbus_open(device->channel, netvsc_ring_bytes, netvsc_ring_bytes, NULL, 0, netvsc_channel_cb, net_device->chan_table); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index b81ceba38218..4d96e8e5ea24 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1114,6 +1114,7 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) /* Set the channel before opening.*/ nvchan->channel = new_sc; + new_sc->rqstor_size = NETVSC_RQSTOR_SIZE; ret = vmbus_open(new_sc, netvsc_ring_bytes, netvsc_ring_bytes, NULL, 0, netvsc_channel_cb, nvchan); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index c509d20ab7db..d8194924983d 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -730,6 +730,7 @@ struct vmbus_requestor { }; #define VMBUS_RQST_ERROR U64_MAX +#define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 1) struct vmbus_device { u16 dev_type; -- 2.25.1