]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
hv_netvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening
authorAndres Beltran <lkmlabelt@gmail.com>
Mon, 9 Nov 2020 10:04:02 +0000 (11:04 +0100)
committerSasha Levin <sashal@kernel.org>
Fri, 15 Mar 2024 14:48:21 +0000 (10:48 -0400)
[ Upstream commit 4d18fcc95f50950a99bd940d4e61a983f91d267a ]

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.

Signed-off-by: Andres Beltran <lkmlabelt@gmail.com>
Co-developed-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org
Link: https://lore.kernel.org/r/20201109100402.8946-4-parri.andrea@gmail.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Stable-dep-of: 9cae43da9867 ("hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/rndis_filter.c
include/linux/hyperv.h

index 367878493e704227c09a9153e46812ba7d4afb42..15652d7951f9e74448d5495113a9fcec40d2cb65 100644 (file)
@@ -847,6 +847,19 @@ 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
+ */
+static inline u32 netvsc_rqstor_size(unsigned long ringbytes)
+{
+       return ringbytes / NETVSC_MIN_OUT_MSG_SIZE +
+               ringbytes / NETVSC_MIN_IN_MSG_SIZE;
+}
+
 #define NETVSC_XFER_HEADER_SIZE(rng_cnt) \
                (offsetof(struct vmtransfer_page_packet_header, ranges) + \
                (rng_cnt) * sizeof(struct vmtransfer_page_range))
index 3eae31c0f97a6e28e84982bc48746486a9290589..c9b73a044881312be7fd4990966a8bd8e44aefb8 100644 (file)
@@ -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;
@@ -557,7 +557,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;
@@ -614,7 +614,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;
@@ -698,10 +698,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 net_device_context *ndev_ctx = netdev_priv(ndev);
+       struct sk_buff *skb;
        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 *)(unsigned long)cmd_rqst;
 
        /* Notify the layer above us */
        if (likely(skb)) {
@@ -1530,6 +1539,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(netvsc_ring_bytes);
        ret = vmbus_open(device->channel, netvsc_ring_bytes,
                         netvsc_ring_bytes,  NULL, 0,
                         netvsc_channel_cb, net_device->chan_table);
index 90bc0008fa2fd7172b551a8ae704bef1fdcdd61a..13f62950eeb9f52fcd5a7b15d1aafc3bce9ffa9d 100644 (file)
@@ -1170,6 +1170,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(netvsc_ring_bytes);
        ret = vmbus_open(new_sc, netvsc_ring_bytes,
                         netvsc_ring_bytes, NULL, 0,
                         netvsc_channel_cb, nvchan);
index 4cb65a79d92f64357335f6443dc7b89b6df17269..2aaf450c8d800d4ede8d735b745cd031126cdb9a 100644 (file)
@@ -779,6 +779,7 @@ struct vmbus_requestor {
 
 #define VMBUS_NO_RQSTOR U64_MAX
 #define VMBUS_RQST_ERROR (U64_MAX - 1)
+#define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2)
 
 struct vmbus_device {
        u16  dev_type;