diff options
author | Andrea Parri (Microsoft) <parri.andrea@gmail.com> | 2021-01-26 19:29:07 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2021-01-30 03:44:07 +0300 |
commit | 0ba35fe91ce34f2d0feff626efd0062dac41781c (patch) | |
tree | d618cfab0efe234b40342d5d913c60f47a703908 /drivers/net/hyperv/netvsc_drv.c | |
parent | 46eb3c108fe1744d0a6abfda69ef8c1d4f0e92d4 (diff) | |
download | linux-0ba35fe91ce34f2d0feff626efd0062dac41781c.tar.xz |
hv_netvsc: Copy packets sent by Hyper-V out of the receive buffer
Pointers to receive-buffer packets sent by Hyper-V are used within the
guest VM. Hyper-V can send packets with erroneous values or modify
packet fields after they are processed by the guest. To defend against
these scenarios, copy (sections of) the incoming packet after validating
their length and offset fields in netvsc_filter_receive(). In this way,
the packet can no longer be modified by the host.
Reported-by: Juan Vazquez <juvazq@microsoft.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Link: https://lore.kernel.org/r/20210126162907.21056-1-parri.andrea@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index ac20c432d4d8..8176fa0c8b16 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -743,7 +743,8 @@ static netdev_tx_t netvsc_start_xmit(struct sk_buff *skb, * netvsc_linkstatus_callback - Link up/down notification */ void netvsc_linkstatus_callback(struct net_device *net, - struct rndis_message *resp) + struct rndis_message *resp, + void *data) { struct rndis_indicate_status *indicate = &resp->msg.indicate_status; struct net_device_context *ndev_ctx = netdev_priv(net); @@ -757,6 +758,9 @@ void netvsc_linkstatus_callback(struct net_device *net, return; } + /* Copy the RNDIS indicate status into nvchan->recv_buf */ + memcpy(indicate, data + RNDIS_HEADER_SIZE, sizeof(*indicate)); + /* Update the physical link speed when changing to another vSwitch */ if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) { u32 speed; @@ -771,8 +775,7 @@ void netvsc_linkstatus_callback(struct net_device *net, return; } - speed = *(u32 *)((void *)indicate - + indicate->status_buf_offset) / 10000; + speed = *(u32 *)(data + RNDIS_HEADER_SIZE + indicate->status_buf_offset) / 10000; ndev_ctx->speed = speed; return; } @@ -827,10 +830,11 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, struct xdp_buff *xdp) { struct napi_struct *napi = &nvchan->napi; - const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan; + const struct ndis_pkt_8021q_info *vlan = &nvchan->rsc.vlan; const struct ndis_tcp_ip_checksum_info *csum_info = - nvchan->rsc.csum_info; - const u32 *hash_info = nvchan->rsc.hash_info; + &nvchan->rsc.csum_info; + const u32 *hash_info = &nvchan->rsc.hash_info; + u8 ppi_flags = nvchan->rsc.ppi_flags; struct sk_buff *skb; void *xbuf = xdp->data_hard_start; int i; @@ -874,7 +878,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, * We compute it here if the flags are set, because on Linux, the IP * checksum is always checked. */ - if (csum_info && csum_info->receive.ip_checksum_value_invalid && + if ((ppi_flags & NVSC_RSC_CSUM_INFO) && csum_info->receive.ip_checksum_value_invalid && csum_info->receive.ip_checksum_succeeded && skb->protocol == htons(ETH_P_IP)) { /* Check that there is enough space to hold the IP header. */ @@ -886,16 +890,16 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, } /* Do L4 checksum offload if enabled and present. */ - if (csum_info && (net->features & NETIF_F_RXCSUM)) { + if ((ppi_flags & NVSC_RSC_CSUM_INFO) && (net->features & NETIF_F_RXCSUM)) { if (csum_info->receive.tcp_checksum_succeeded || csum_info->receive.udp_checksum_succeeded) skb->ip_summed = CHECKSUM_UNNECESSARY; } - if (hash_info && (net->features & NETIF_F_RXHASH)) + if ((ppi_flags & NVSC_RSC_HASH_INFO) && (net->features & NETIF_F_RXHASH)) skb_set_hash(skb, *hash_info, PKT_HASH_TYPE_L4); - if (vlan) { + if (ppi_flags & NVSC_RSC_VLAN) { u16 vlan_tci = vlan->vlanid | (vlan->pri << VLAN_PRIO_SHIFT) | (vlan->cfi ? VLAN_CFI_MASK : 0); |