Commit 4d18fcc9 authored by Andres Beltran's avatar Andres Beltran Committed by Wei Liu
Browse files

hv_netvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening



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: default avatarAndres Beltran <lkmlabelt@gmail.com>
Co-developed-by: default avatarAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Signed-off-by: default avatarAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Reviewed-by: default avatarWei 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: default avatarWei Liu <wei.liu@kernel.org>
parent 453de21c
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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))
+16 −6
Original line number Diff line number Diff line
@@ -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;
@@ -695,10 +695,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)) {
@@ -1520,6 +1529,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);
+1 −0
Original line number Diff line number Diff line
@@ -1172,6 +1172,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);
+1 −0
Original line number Diff line number Diff line
@@ -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;