hv_netvsc: Fix send_table offset in case of a host bug
authorHaiyang Zhang <haiyangz@microsoft.com>
Thu, 21 Nov 2019 21:33:41 +0000 (13:33 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 22 Nov 2019 03:32:23 +0000 (19:32 -0800)
If negotiated NVSP version <= NVSP_PROTOCOL_VERSION_6, the offset may
be wrong (too small) due to a host bug. This can cause missing the
end of the send indirection table, and add multiple zero entries from
leading zeros before the data region. This bug adds extra burden on
channel 0.

So fix the offset by computing it from the data structure sizes. This
will ensure netvsc driver runs normally on unfixed hosts, and future
fixed hosts.

Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling (vRSS)")
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/netvsc.c

index 9b0532ec8b8743362180712a3ef5c9939a3c3899..eab83e71567a916c9127b89f46b08d5ba68e482d 100644 (file)
@@ -1178,6 +1178,7 @@ static int netvsc_receive(struct net_device *ndev,
 }
 
 static void netvsc_send_table(struct net_device *ndev,
+                             struct netvsc_device *nvscdev,
                              const struct nvsp_message *nvmsg,
                              u32 msglen)
 {
@@ -1193,6 +1194,16 @@ static void netvsc_send_table(struct net_device *ndev,
                return;
        }
 
+       /* If negotiated version <= NVSP_PROTOCOL_VERSION_6, the offset may be
+        * wrong due to a host bug. So fix the offset here.
+        */
+       if (nvscdev->nvsp_version <= NVSP_PROTOCOL_VERSION_6 &&
+           msglen >= sizeof(struct nvsp_message_header) +
+           sizeof(union nvsp_6_message_uber) + count * sizeof(u32))
+               offset = sizeof(struct nvsp_message_header) +
+                        sizeof(union nvsp_6_message_uber);
+
+       /* Boundary check for all versions */
        if (offset > msglen - count * sizeof(u32)) {
                netdev_err(ndev, "Received send-table offset too big:%u\n",
                           offset);
@@ -1218,12 +1229,13 @@ static void netvsc_send_vf(struct net_device *ndev,
 }
 
 static void netvsc_receive_inband(struct net_device *ndev,
+                                 struct netvsc_device *nvscdev,
                                  const struct nvsp_message *nvmsg,
                                  u32 msglen)
 {
        switch (nvmsg->hdr.msg_type) {
        case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
-               netvsc_send_table(ndev, nvmsg, msglen);
+               netvsc_send_table(ndev, nvscdev, nvmsg, msglen);
                break;
 
        case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
@@ -1257,7 +1269,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
                break;
 
        case VM_PKT_DATA_INBAND:
-               netvsc_receive_inband(ndev, nvmsg, msglen);
+               netvsc_receive_inband(ndev, net_device, nvmsg, msglen);
                break;
 
        default: