diff mbox series

[v8,3/3] hv_netvsc: Use vmbus_requestor to generate transaction IDs for VMBus hardening

Message ID 20201104154027.319432-4-parri.andrea@gmail.com
State New
Headers show
Series None | expand

Commit Message

Andrea Parri Nov. 4, 2020, 3:40 p.m. UTC
From: Andres Beltran <lkmlabelt@gmail.com>

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>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org
---
 drivers/net/hyperv/hyperv_net.h   | 13 +++++++++++++
 drivers/net/hyperv/netvsc.c       | 22 ++++++++++++++++------
 drivers/net/hyperv/rndis_filter.c |  1 +
 include/linux/hyperv.h            |  1 +
 4 files changed, 31 insertions(+), 6 deletions(-)

Comments

Jakub Kicinski Nov. 4, 2020, 9:43 p.m. UTC | #1
On Wed,  4 Nov 2020 16:40:27 +0100 Andrea Parri (Microsoft) wrote:
> From: Andres Beltran <lkmlabelt@gmail.com>

> 

> 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>


I'm assuming this is targeting net-next? If so could you please tag it
as [PATCH net-next vN]?

> @@ -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 sk_buff *skb;

>  	struct net_device_context *ndev_ctx = netdev_priv(ndev);


Swap these two lines please to keep the variables declaration lines
longest to shortest.
Jakub Kicinski Nov. 4, 2020, 9:45 p.m. UTC | #2
On Wed, 4 Nov 2020 13:43:48 -0800 Jakub Kicinski wrote:
> On Wed,  4 Nov 2020 16:40:27 +0100 Andrea Parri (Microsoft) wrote:

> > From: Andres Beltran <lkmlabelt@gmail.com>

> > 

> > 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>  

> 

> I'm assuming this is targeting net-next? If so could you please tag it

> as [PATCH net-next vN]?


Ah, you don't 'cause you only sent us the third patch. In that case with
the nit below addressed:

Acked-by: Jakub Kicinski <kuba@kernel.org>


> > @@ -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 sk_buff *skb;

> >  	struct net_device_context *ndev_ctx = netdev_priv(ndev);  

> 

> Swap these two lines please to keep the variables declaration lines

> longest to shortest.
Andrea Parri Nov. 5, 2020, 3:32 a.m. UTC | #3
On Wed, Nov 04, 2020 at 01:45:05PM -0800, Jakub Kicinski wrote:
> On Wed, 4 Nov 2020 13:43:48 -0800 Jakub Kicinski wrote:
> > On Wed,  4 Nov 2020 16:40:27 +0100 Andrea Parri (Microsoft) wrote:
> > > From: Andres Beltran <lkmlabelt@gmail.com>
> > > 
> > > 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>  
> > 
> > I'm assuming this is targeting net-next? If so could you please tag it
> > as [PATCH net-next vN]?
> 
> Ah, you don't 'cause you only sent us the third patch. In that case with
> the nit below addressed:
> 
> Acked-by: Jakub Kicinski <kuba@kernel.org>

I fixed the declarations locally.  Thank you for the review, Jakub.

(Yes, FWIW, I was imaging the series to go via hyperv-next...)

Thanks,
  Andrea


> 
> > > @@ -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 sk_buff *skb;
> > >  	struct net_device_context *ndev_ctx = netdev_priv(ndev);  
> > 
> > Swap these two lines please to keep the variables declaration lines
> > longest to shortest.
>
diff mbox series

Patch

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index a0f338cf14247..2a87cfa27ac02 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -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))
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 0c3de94b51787..f74ee8b90b84d 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;
@@ -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 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 *)(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);
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index b22e47bcfeca1..6ae43319ece68 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -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);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 5b6d5c4e37110..5ddb479c4d4cb 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -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;