net_device->recv_section_size = resp->sections[0].sub_alloc_size;
        net_device->recv_section_cnt = resp->sections[0].num_sub_allocs;
 
+       /* Ensure buffer will not overflow */
+       if (net_device->recv_section_size < NETVSC_MTU_MIN || (u64)net_device->recv_section_size *
+           (u64)net_device->recv_section_cnt > (u64)buf_size) {
+               netdev_err(ndev, "invalid recv_section_size %u\n",
+                          net_device->recv_section_size);
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
        /* Setup receive completion ring.
         * Add 1 to the recv_section_cnt because at least one entry in a
         * ring buffer has to be empty.
        /* Parse the response */
        net_device->send_section_size = init_packet->msg.
                                v1_msg.send_send_buf_complete.section_size;
+       if (net_device->send_section_size < NETVSC_MTU_MIN) {
+               netdev_err(ndev, "invalid send_section_size %u\n",
+                          net_device->send_section_size);
+               ret = -EINVAL;
+               goto cleanup;
+       }
 
        /* Section count is simply the size divided by the section size. */
        net_device->send_section_cnt = buf_size / net_device->send_section_size;
                                   int budget)
 {
        const struct nvsp_message *nvsp_packet = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
+
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netdev_err(ndev, "nvsp_message length too small: %u\n", msglen);
+               return;
+       }
 
        switch (nvsp_packet->hdr.msg_type) {
        case NVSP_MSG_TYPE_INIT_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_message_init_complete)) {
+                       netdev_err(ndev, "nvsp_msg length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_1_message_send_receive_buffer_complete)) {
+                       netdev_err(ndev, "nvsp_msg1 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_1_message_send_send_buffer_complete)) {
+                       netdev_err(ndev, "nvsp_msg1 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG5_TYPE_SUBCHANNEL:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_5_subchannel_complete)) {
+                       netdev_err(ndev, "nvsp_msg5 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
                /* Copy the response back */
                memcpy(&net_device->channel_init_pkt, nvsp_packet,
                       sizeof(struct nvsp_message));
 static int netvsc_receive(struct net_device *ndev,
                          struct netvsc_device *net_device,
                          struct netvsc_channel *nvchan,
-                         const struct vmpacket_descriptor *desc,
-                         const struct nvsp_message *nvsp)
+                         const struct vmpacket_descriptor *desc)
 {
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
        struct vmbus_channel *channel = nvchan->channel;
        const struct vmtransfer_page_packet_header *vmxferpage_packet
                = container_of(desc, const struct vmtransfer_page_packet_header, d);
+       const struct nvsp_message *nvsp = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
        u16 q_idx = channel->offermsg.offer.sub_channel_index;
        char *recv_buf = net_device->recv_buf;
        u32 status = NVSP_STAT_SUCCESS;
        int i;
        int count = 0;
 
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "invalid nvsp header, length too small: %u\n",
+                         msglen);
+               return 0;
+       }
+
        /* Make sure this is a valid nvsp packet */
        if (unlikely(nvsp->hdr.msg_type != NVSP_MSG1_TYPE_SEND_RNDIS_PKT)) {
                netif_err(net_device_ctx, rx_err, ndev,
                return 0;
        }
 
+       /* Validate xfer page pkt header */
+       if ((desc->offset8 << 3) < sizeof(struct vmtransfer_page_packet_header)) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "Invalid xfer page pkt, offset too small: %u\n",
+                         desc->offset8 << 3);
+               return 0;
+       }
+
        if (unlikely(vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID)) {
                netif_err(net_device_ctx, rx_err, ndev,
                          "Invalid xfer page set id - expecting %x got %x\n",
 
        count = vmxferpage_packet->range_cnt;
 
+       /* Check count for a valid value */
+       if (NETVSC_XFER_HEADER_SIZE(count) > desc->offset8 << 3) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "Range count is not valid: %d\n",
+                         count);
+               return 0;
+       }
+
        /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
        for (i = 0; i < count; i++) {
                u32 offset = vmxferpage_packet->ranges[i].byte_offset;
                void *data;
                int ret;
 
-               if (unlikely(offset + buflen > net_device->recv_buf_size)) {
+               if (unlikely(offset > net_device->recv_buf_size ||
+                            buflen > net_device->recv_buf_size - offset)) {
                        nvchan->rsc.cnt = 0;
                        status = NVSP_STAT_FAIL;
                        netif_err(net_device_ctx, rx_err, ndev,
        u32 count, offset, *tab;
        int i;
 
+       /* Ensure packet is big enough to read send_table fields */
+       if (msglen < sizeof(struct nvsp_message_header) +
+                    sizeof(struct nvsp_5_send_indirect_table)) {
+               netdev_err(ndev, "nvsp_v5_msg length too small: %u\n", msglen);
+               return;
+       }
+
        count = nvmsg->msg.v5_msg.send_table.count;
        offset = nvmsg->msg.v5_msg.send_table.offset;
 
 }
 
 static void netvsc_send_vf(struct net_device *ndev,
-                          const struct nvsp_message *nvmsg)
+                          const struct nvsp_message *nvmsg,
+                          u32 msglen)
 {
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
 
+       /* Ensure packet is big enough to read its fields */
+       if (msglen < sizeof(struct nvsp_message_header) +
+                    sizeof(struct nvsp_4_send_vf_association)) {
+               netdev_err(ndev, "nvsp_v4_msg length too small: %u\n", msglen);
+               return;
+       }
+
        net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
        net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
        netdev_info(ndev, "VF slot %u %s\n",
 
 static void netvsc_receive_inband(struct net_device *ndev,
                                  struct netvsc_device *nvscdev,
-                                 const struct nvsp_message *nvmsg,
-                                 u32 msglen)
+                                 const struct vmpacket_descriptor *desc)
 {
+       const struct nvsp_message *nvmsg = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
+
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netdev_err(ndev, "inband nvsp_message length too small: %u\n", msglen);
+               return;
+       }
+
        switch (nvmsg->hdr.msg_type) {
        case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
                netvsc_send_table(ndev, nvscdev, nvmsg, msglen);
                break;
 
        case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
-               netvsc_send_vf(ndev, nvmsg);
+               netvsc_send_vf(ndev, nvmsg, msglen);
                break;
        }
 }
 {
        struct vmbus_channel *channel = nvchan->channel;
        const struct nvsp_message *nvmsg = hv_pkt_data(desc);
-       u32 msglen = hv_pkt_datalen(desc);
 
        trace_nvsp_recv(ndev, channel, nvmsg);
 
        switch (desc->type) {
        case VM_PKT_COMP:
-               netvsc_send_completion(ndev, net_device, channel,
-                                      desc, budget);
+               netvsc_send_completion(ndev, net_device, channel, desc, budget);
                break;
 
        case VM_PKT_DATA_USING_XFER_PAGES:
-               return netvsc_receive(ndev, net_device, nvchan,
-                                     desc, nvmsg);
+               return netvsc_receive(ndev, net_device, nvchan, desc);
                break;
 
        case VM_PKT_DATA_INBAND:
-               netvsc_receive_inband(ndev, net_device, nvmsg, msglen);
+               netvsc_receive_inband(ndev, net_device, desc);
                break;
 
        default:
 
                return;
        }
 
+       /* Ensure the packet is big enough to read req_id. Req_id is the 1st
+        * field in any request/response message, so the payload should have at
+        * least sizeof(u32) bytes
+        */
+       if (resp->msg_len - RNDIS_HEADER_SIZE < sizeof(u32)) {
+               netdev_err(ndev, "rndis msg_len too small: %u\n",
+                          resp->msg_len);
+               return;
+       }
+
        spin_lock_irqsave(&dev->request_lock, flags);
        list_for_each_entry(request, &dev->req_list, list_ent) {
                /*
  * Get the Per-Packet-Info with the specified type
  * return NULL if not found.
  */
-static inline void *rndis_get_ppi(struct rndis_packet *rpkt,
-                                 u32 type, u8 internal)
+static inline void *rndis_get_ppi(struct net_device *ndev,
+                                 struct rndis_packet *rpkt,
+                                 u32 rpkt_len, u32 type, u8 internal)
 {
        struct rndis_per_packet_info *ppi;
        int len;
        if (rpkt->per_pkt_info_offset == 0)
                return NULL;
 
+       /* Validate info_offset and info_len */
+       if (rpkt->per_pkt_info_offset < sizeof(struct rndis_packet) ||
+           rpkt->per_pkt_info_offset > rpkt_len) {
+               netdev_err(ndev, "Invalid per_pkt_info_offset: %u\n",
+                          rpkt->per_pkt_info_offset);
+               return NULL;
+       }
+
+       if (rpkt->per_pkt_info_len > rpkt_len - rpkt->per_pkt_info_offset) {
+               netdev_err(ndev, "Invalid per_pkt_info_len: %u\n",
+                          rpkt->per_pkt_info_len);
+               return NULL;
+       }
+
        ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
                rpkt->per_pkt_info_offset);
        len = rpkt->per_pkt_info_len;
 
        while (len > 0) {
+               /* Validate ppi_offset and ppi_size */
+               if (ppi->size > len) {
+                       netdev_err(ndev, "Invalid ppi size: %u\n", ppi->size);
+                       continue;
+               }
+
+               if (ppi->ppi_offset >= ppi->size) {
+                       netdev_err(ndev, "Invalid ppi_offset: %u\n", ppi->ppi_offset);
+                       continue;
+               }
+
                if (ppi->type == type && ppi->internal == internal)
                        return (void *)((ulong)ppi + ppi->ppi_offset);
                len -= ppi->size;
        const struct ndis_pkt_8021q_info *vlan;
        const struct rndis_pktinfo_id *pktinfo_id;
        const u32 *hash_info;
-       u32 data_offset;
+       u32 data_offset, rpkt_len;
        void *data;
        bool rsc_more = false;
        int ret;
 
+       /* Ensure data_buflen is big enough to read header fields */
+       if (data_buflen < RNDIS_HEADER_SIZE + sizeof(struct rndis_packet)) {
+               netdev_err(ndev, "invalid rndis pkt, data_buflen too small: %u\n",
+                          data_buflen);
+               return NVSP_STAT_FAIL;
+       }
+
+       /* Validate rndis_pkt offset */
+       if (rndis_pkt->data_offset >= data_buflen - RNDIS_HEADER_SIZE) {
+               netdev_err(ndev, "invalid rndis packet offset: %u\n",
+                          rndis_pkt->data_offset);
+               return NVSP_STAT_FAIL;
+       }
+
        /* Remove the rndis header and pass it back up the stack */
        data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
 
+       rpkt_len = data_buflen - RNDIS_HEADER_SIZE;
        data_buflen -= data_offset;
 
        /*
                return NVSP_STAT_FAIL;
        }
 
-       vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO, 0);
+       vlan = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, IEEE_8021Q_INFO, 0);
 
-       csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO, 0);
+       csum_info = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, TCPIP_CHKSUM_PKTINFO, 0);
 
-       hash_info = rndis_get_ppi(rndis_pkt, NBL_HASH_VALUE, 0);
+       hash_info = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, NBL_HASH_VALUE, 0);
 
-       pktinfo_id = rndis_get_ppi(rndis_pkt, RNDIS_PKTINFO_ID, 1);
+       pktinfo_id = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, RNDIS_PKTINFO_ID, 1);
 
        data = (void *)msg + data_offset;
 
        if (netif_msg_rx_status(net_device_ctx))
                dump_rndis_message(ndev, rndis_msg);
 
+       /* Validate incoming rndis_message packet */
+       if (buflen < RNDIS_HEADER_SIZE || rndis_msg->msg_len < RNDIS_HEADER_SIZE ||
+           buflen < rndis_msg->msg_len) {
+               netdev_err(ndev, "Invalid rndis_msg (buflen: %u, msg_len: %u)\n",
+                          buflen, rndis_msg->msg_len);
+               return NVSP_STAT_FAIL;
+       }
+
        switch (rndis_msg->ndis_msg_type) {
        case RNDIS_MSG_PACKET:
                return rndis_filter_receive_data(ndev, net_dev, nvchan,