Author: sephe
Date: Thu Oct 13 07:42:44 2016
New Revision: 307198
URL: https://svnweb.freebsd.org/changeset/base/307198

Log:
  MFC 305405,305407,305408,305410,305411,305453
  
  305405
      hyperv/vmbus: Stringent header length and total length check.
  
      While I'm here, minor style changes.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7752
  
  305407
      hyperv/hn: Stringent NVS notification length check.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7753
  
  305408
      hyperv/hn: Stringent NVS RNDIS packets length checks.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7755
  
  305410
      net/rndis: Define RNDIS status message, which could be sent by device.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7757
  
  305411
      hyperv/hn: Stringent RNDIS control message length check.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7758
  
  305453
      hyperv/hn: Stringent RNDIS packet message length/offset check.
  
      While I'm here, use definition in net/rndis.h
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7782

Modified:
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
  stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h
  stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
  stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h
  stable/10/sys/net/rndis.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c        Thu Oct 13 07:35:19 
2016        (r307197)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c        Thu Oct 13 07:42:44 
2016        (r307198)
@@ -741,32 +741,53 @@ hv_nv_on_receive(struct hn_softc *sc, st
 {
        const struct vmbus_chanpkt_rxbuf *pkt;
        const struct hn_nvs_hdr *nvs_hdr;
-       int count = 0;
-       int i = 0;
+       int count, i, hlen;
 
-       /* Make sure that this is a RNDIS message. */
+       if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
+               if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
+               return;
+       }
        nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
+
+       /* Make sure that this is a RNDIS message. */
        if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
                if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
                    nvs_hdr->nvs_type);
                return;
        }
-       
+
+       hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
+       if (__predict_false(hlen < sizeof(*pkt))) {
+               if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
+               return;
+       }
        pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
 
-       if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) {
-               if_printf(rxr->hn_ifp, "rxbuf_id %d is invalid!\n",
+       if (__predict_false(pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID)) {
+               if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
                    pkt->cp_rxbuf_id);
                return;
        }
 
        count = pkt->cp_rxbuf_cnt;
+       if (__predict_false(hlen <
+           __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
+               if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
+               return;
+       }
 
        /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
-       for (i = 0; i < count; i++) {
-               hv_rf_on_receive(sc, rxr,
-                   rxr->hn_rxbuf + pkt->cp_rxbuf[i].rb_ofs,
-                   pkt->cp_rxbuf[i].rb_len);
+       for (i = 0; i < count; ++i) {
+               int ofs, len;
+
+               ofs = pkt->cp_rxbuf[i].rb_ofs;
+               len = pkt->cp_rxbuf[i].rb_len;
+               if (__predict_false(ofs + len > NETVSC_RECEIVE_BUFFER_SIZE)) {
+                       if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
+                           "ofs %d, len %d\n", i, ofs, len);
+                       continue;
+               }
+               hv_rf_on_receive(sc, rxr, rxr->hn_rxbuf + ofs, len);
        }
        
        /*
@@ -815,7 +836,12 @@ hn_proc_notify(struct hn_softc *sc, cons
 {
        const struct hn_nvs_hdr *hdr;
 
+       if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
+               if_printf(sc->hn_ifp, "invalid nvs notify\n");
+               return;
+       }
        hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
+
        if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
                /* Useless; ignore */
                return;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Thu Oct 13 07:35:19 
2016        (r307197)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Thu Oct 13 07:42:44 
2016        (r307198)
@@ -73,7 +73,7 @@ __FBSDID("$FreeBSD$");
  * Forward declarations
  */
 static void hv_rf_receive_indicate_status(struct hn_softc *sc,
-    const rndis_msg *response);
+    const void *data, int dlen);
 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
     const void *data, int dlen);
 static int hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr);
@@ -132,59 +132,50 @@ hv_set_rppi_data(rndis_msg *rndis_mesg, 
  * RNDIS filter receive indicate status
  */
 static void 
-hv_rf_receive_indicate_status(struct hn_softc *sc, const rndis_msg *response)
+hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
 {
-       const rndis_indicate_status *indicate = &response->msg.indicate_status;
-               
-       switch(indicate->status) {
+       const struct rndis_status_msg *msg;
+
+       if (dlen < sizeof(*msg)) {
+               if_printf(sc->hn_ifp, "invalid RNDIS status\n");
+               return;
+       }
+       msg = data;
+
+       switch (msg->rm_status) {
        case RNDIS_STATUS_MEDIA_CONNECT:
                netvsc_linkstatus_callback(sc, 1);
                break;
+
        case RNDIS_STATUS_MEDIA_DISCONNECT:
                netvsc_linkstatus_callback(sc, 0);
                break;
+
        default:
                /* TODO: */
-               if_printf(sc->hn_ifp,
-                   "unknown status %d received\n", indicate->status);
+               if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
+                   msg->rm_status);
                break;
        }
 }
 
 static int
-hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
+hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
 {
-       const struct rndis_pktinfo *pi;
-       uint32_t mask = 0, len;
-
-       info->vlan_info = HN_NDIS_VLAN_INFO_INVALID;
-       info->csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
-       info->hash_info = HN_NDIS_HASH_INFO_INVALID;
-
-       if (rpkt->per_pkt_info_offset == 0)
-               return (0);
-       if (__predict_false(rpkt->per_pkt_info_offset &
-           (RNDIS_PKTINFO_ALIGN - 1)))
-               return (EINVAL);
-       if (__predict_false(rpkt->per_pkt_info_offset <
-           RNDIS_PACKET_MSG_OFFSET_MIN))
-               return (EINVAL);
+       const struct rndis_pktinfo *pi = info_data;
+       uint32_t mask = 0;
 
-       pi = (const struct rndis_pktinfo *)
-           ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
-       len = rpkt->per_pkt_info_length;
-
-       while (len != 0) {
+       while (info_dlen != 0) {
                const void *data;
                uint32_t dlen;
 
-               if (__predict_false(len < sizeof(*pi)))
+               if (__predict_false(info_dlen < sizeof(*pi)))
                        return (EINVAL);
-               if (__predict_false(len < pi->rm_size))
+               if (__predict_false(info_dlen < pi->rm_size))
                        return (EINVAL);
-               len -= pi->rm_size;
+               info_dlen -= pi->rm_size;
 
-               if (__predict_false(pi->rm_size & (RNDIS_PKTINFO_ALIGN - 1)))
+               if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
                        return (EINVAL);
                if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
                        return (EINVAL);
@@ -242,76 +233,223 @@ next:
        return (0);
 }
 
+static __inline bool
+hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
+{
+
+       if (off < check_off) {
+               if (__predict_true(off + len <= check_off))
+                       return (false);
+       } else if (off > check_off) {
+               if (__predict_true(check_off + check_len <= off))
+                       return (false);
+       }
+       return (true);
+}
+
 /*
  * RNDIS filter receive data
  */
 static void
 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
 {
-       const rndis_msg *message = data;
-       const rndis_packet *rndis_pkt;
-       uint32_t data_offset;
+       const struct rndis_packet_msg *pkt;
        struct hn_recvinfo info;
-
-       rndis_pkt = &message->msg.packet;
+       int data_off, pktinfo_off, data_len, pktinfo_len;
 
        /*
-        * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
-        * netvsc packet (ie tot_data_buf_len != message_length)
+        * Check length.
         */
+       if (__predict_false(dlen < sizeof(*pkt))) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
+               return;
+       }
+       pkt = data;
 
-       /* Remove rndis header, then pass data packet up the stack */
-       data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
+       if (__predict_false(dlen < pkt->rm_len)) {
+               if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
+                   "dlen %d, msglen %u\n", dlen, pkt->rm_len);
+               return;
+       }
+       if (__predict_false(pkt->rm_len <
+           pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
+                   "msglen %u, data %u, oob %u, pktinfo %u\n",
+                   pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
+                   pkt->rm_pktinfolen);
+               return;
+       }
+       if (__predict_false(pkt->rm_datalen == 0)) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
+               return;
+       }
 
-       dlen -= data_offset;
-       if (dlen < rndis_pkt->data_length) {
-               if_printf(rxr->hn_ifp,
-                   "total length %u is less than data length %u\n",
-                   dlen, rndis_pkt->data_length);
+       /*
+        * Check offests.
+        */
+#define IS_OFFSET_INVALID(ofs)                 \
+       ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
+        ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
+
+       /* XXX Hyper-V does not meet data offset alignment requirement */
+       if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                   "data offset %u\n", pkt->rm_dataoffset);
+               return;
+       }
+       if (__predict_false(pkt->rm_oobdataoffset > 0 &&
+           IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                   "oob offset %u\n", pkt->rm_oobdataoffset);
+               return;
+       }
+       if (__predict_true(pkt->rm_pktinfooffset > 0) &&
+           __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                   "pktinfo offset %u\n", pkt->rm_pktinfooffset);
                return;
        }
 
-       dlen = rndis_pkt->data_length;
-       data = (const uint8_t *)data + data_offset;
+#undef IS_OFFSET_INVALID
 
-       if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
-               if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
+       data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
+       data_len = pkt->rm_datalen;
+       pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
+       pktinfo_len = pkt->rm_pktinfolen;
+
+       /*
+        * Check OOB coverage.
+        */
+       if (__predict_false(pkt->rm_oobdatalen != 0)) {
+               int oob_off, oob_len;
+
+               if_printf(rxr->hn_ifp, "got oobdata\n");
+               oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
+               oob_len = pkt->rm_oobdatalen;
+
+               if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                           "oob overflow, msglen %u, oob abs %d len %d\n",
+                           pkt->rm_len, oob_off, oob_len);
+                       return;
+               }
+
+               /*
+                * Check against data.
+                */
+               if (hn_rndis_check_overlap(oob_off, oob_len,
+                   data_off, data_len)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                           "oob overlaps data, oob abs %d len %d, "
+                           "data abs %d len %d\n",
+                           oob_off, oob_len, data_off, data_len);
+                       return;
+               }
+
+               /*
+                * Check against pktinfo.
+                */
+               if (pktinfo_len != 0 &&
+                   hn_rndis_check_overlap(oob_off, oob_len,
+                   pktinfo_off, pktinfo_len)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                           "oob overlaps pktinfo, oob abs %d len %d, "
+                           "pktinfo abs %d len %d\n",
+                           oob_off, oob_len, pktinfo_off, pktinfo_len);
+                       return;
+               }
+       }
+
+       /*
+        * Check per-packet-info coverage and find useful per-packet-info.
+        */
+       info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
+       info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
+       info.hash_info = HN_NDIS_HASH_INFO_INVALID;
+       if (__predict_true(pktinfo_len != 0)) {
+               bool overlap;
+               int error;
+
+               if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                           "pktinfo overflow, msglen %u, "
+                           "pktinfo abs %d len %d\n",
+                           pkt->rm_len, pktinfo_off, pktinfo_len);
+                       return;
+               }
+
+               /*
+                * Check packet info coverage.
+                */
+               overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
+                   data_off, data_len);
+               if (__predict_false(overlap)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                           "pktinfo overlap data, pktinfo abs %d len %d, "
+                           "data abs %d len %d\n",
+                           pktinfo_off, pktinfo_len, data_off, data_len);
+                       return;
+               }
+
+               /*
+                * Find useful per-packet-info.
+                */
+               error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
+                   pktinfo_len, &info);
+               if (__predict_false(error)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
+                           "pktinfo\n");
+                       return;
+               }
+       }
+
+       if (__predict_false(data_off + data_len > pkt->rm_len)) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+                   "data overflow, msglen %u, data abs %d len %d\n",
+                   pkt->rm_len, data_off, data_len);
                return;
        }
-       netvsc_recv(rxr, data, dlen, &info);
+       netvsc_recv(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
 }
 
 /*
  * RNDIS filter on receive
  */
-int
+void
 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
     const void *data, int dlen)
 {
-       const rndis_msg *rndis_hdr;
        const struct rndis_comp_hdr *comp;
+       const struct rndis_msghdr *hdr;
+
+       if (__predict_false(dlen < sizeof(*hdr))) {
+               if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
+               return;
+       }
+       hdr = data;
 
-       rndis_hdr = data;
-       switch (rndis_hdr->ndis_msg_type) {
-       /* data message */
+       switch (hdr->rm_type) {
        case REMOTE_NDIS_PACKET_MSG:
                hv_rf_receive_data(rxr, data, dlen);
                break;
 
-       /* completion messages */
        case REMOTE_NDIS_INITIALIZE_CMPLT:
        case REMOTE_NDIS_QUERY_CMPLT:
        case REMOTE_NDIS_SET_CMPLT:
-       case REMOTE_NDIS_KEEPALIVE_CMPLT:
+       case REMOTE_NDIS_KEEPALIVE_CMPLT:       /* unused */
+               if (dlen < sizeof(*comp)) {
+                       if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
+                       return;
+               }
                comp = data;
+
                KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
-                   ("invalid rid 0x%08x\n", comp->rm_rid));
+                   ("invalid RNDIS rid 0x%08x\n", comp->rm_rid));
                vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
                break;
 
-       /* notification message */
        case REMOTE_NDIS_INDICATE_STATUS_MSG:
-               hv_rf_receive_indicate_status(sc, rndis_hdr);
+               hv_rf_receive_indicate_status(sc, data, dlen);
                break;
 
        case REMOTE_NDIS_RESET_CMPLT:
@@ -322,15 +460,14 @@ hv_rf_on_receive(struct hn_softc *sc, st
                 * RESET is not issued by hn(4), so this message should
                 * _not_ be observed.
                 */
-               if_printf(sc->hn_ifp, "RESET CMPLT received\n");
+               if_printf(rxr->hn_ifp, "RESET cmplt received\n");
                break;
 
        default:
-               if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
-                       rndis_hdr->ndis_msg_type);
+               if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
+                   hdr->rm_type);
                break;
        }
-       return (0);
 }
 
 /*
@@ -552,7 +689,7 @@ hn_rndis_query(struct hn_softc *sc, uint
         * Check output data length and offset.
         */
        /* ofs is the offset from the beginning of comp. */
-       ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
+       ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->rm_infobufoffset);
        if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
                if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
                    "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h   Thu Oct 13 07:35:19 
2016        (r307197)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h   Thu Oct 13 07:42:44 
2016        (r307198)
@@ -40,7 +40,7 @@
  */
 struct hn_rx_ring;
 
-int hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
+void hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
     const void *data, int dlen);
 void hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
 int hv_rf_on_device_add(struct hn_softc *sc, void *additl_info, int *nchan,

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c Thu Oct 13 07:35:19 2016        
(r307197)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c Thu Oct 13 07:42:44 2016        
(r307198)
@@ -721,7 +721,20 @@ vmbus_chan_recv(struct vmbus_channel *ch
 
        error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
        if (error)
-               return error;
+               return (error);
+
+       if (__predict_false(pkt.cph_hlen < VMBUS_CHANPKT_HLEN_MIN)) {
+               device_printf(chan->ch_dev, "invalid hlen %u\n",
+                   pkt.cph_hlen);
+               /* XXX this channel is dead actually. */
+               return (EIO);
+       }
+       if (__predict_false(pkt.cph_hlen > pkt.cph_tlen)) {
+               device_printf(chan->ch_dev, "invalid hlen %u and tlen %u\n",
+                   pkt.cph_hlen, pkt.cph_tlen);
+               /* XXX this channel is dead actually. */
+               return (EIO);
+       }
 
        hlen = VMBUS_CHANPKT_GETLEN(pkt.cph_hlen);
        dlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen) - hlen;
@@ -729,7 +742,7 @@ vmbus_chan_recv(struct vmbus_channel *ch
        if (*dlen0 < dlen) {
                /* Return the size of this packet's data. */
                *dlen0 = dlen;
-               return ENOBUFS;
+               return (ENOBUFS);
        }
 
        *xactid = pkt.cph_xactid;
@@ -739,7 +752,7 @@ vmbus_chan_recv(struct vmbus_channel *ch
        error = vmbus_rxbr_read(&chan->ch_rxbr, data, dlen, hlen);
        KASSERT(!error, ("vmbus_rxbr_read failed"));
 
-       return 0;
+       return (0);
 }
 
 int
@@ -751,13 +764,26 @@ vmbus_chan_recv_pkt(struct vmbus_channel
 
        error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
        if (error)
-               return error;
+               return (error);
+
+       if (__predict_false(pkt.cph_hlen < VMBUS_CHANPKT_HLEN_MIN)) {
+               device_printf(chan->ch_dev, "invalid hlen %u\n",
+                   pkt.cph_hlen);
+               /* XXX this channel is dead actually. */
+               return (EIO);
+       }
+       if (__predict_false(pkt.cph_hlen > pkt.cph_tlen)) {
+               device_printf(chan->ch_dev, "invalid hlen %u and tlen %u\n",
+                   pkt.cph_hlen, pkt.cph_tlen);
+               /* XXX this channel is dead actually. */
+               return (EIO);
+       }
 
        pktlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen);
        if (*pktlen0 < pktlen) {
                /* Return the size of this packet. */
                *pktlen0 = pktlen;
-               return ENOBUFS;
+               return (ENOBUFS);
        }
        *pktlen0 = pktlen;
 
@@ -765,7 +791,7 @@ vmbus_chan_recv_pkt(struct vmbus_channel
        error = vmbus_rxbr_read(&chan->ch_rxbr, pkt0, pktlen, 0);
        KASSERT(!error, ("vmbus_rxbr_read failed"));
 
-       return 0;
+       return (0);
 }
 
 static void

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h  Thu Oct 13 07:35:19 2016        
(r307197)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h  Thu Oct 13 07:42:44 2016        
(r307198)
@@ -153,6 +153,9 @@ do {                                                        
\
 #define VMBUS_CHANPKT_TOTLEN(tlen)     \
        roundup2((tlen), VMBUS_CHANPKT_SIZE_ALIGN)
 
+#define VMBUS_CHANPKT_HLEN_MIN         \
+       (sizeof(struct vmbus_chanpkt_hdr) >> VMBUS_CHANPKT_SIZE_SHIFT)
+
 struct vmbus_chanpkt {
        struct vmbus_chanpkt_hdr cp_hdr;
 } __packed;

Modified: stable/10/sys/net/rndis.h
==============================================================================
--- stable/10/sys/net/rndis.h   Thu Oct 13 07:35:19 2016        (r307197)
+++ stable/10/sys/net/rndis.h   Thu Oct 13 07:42:44 2016        (r307198)
@@ -127,6 +127,14 @@ struct rndis_packet_msg {
        (sizeof(struct rndis_packet_msg) -      \
         __offsetof(struct rndis_packet_msg, rm_dataoffset))
 
+/* Offset from the beginning of rndis_packet_msg. */
+#define        RNDIS_PACKET_MSG_OFFSET_ABS(ofs)        \
+       ((ofs) + __offsetof(struct rndis_packet_msg, rm_dataoffset))
+
+#define        RNDIS_PACKET_MSG_OFFSET_ALIGN           4
+#define        RNDIS_PACKET_MSG_OFFSET_ALIGNMASK       \
+       (RNDIS_PACKET_MSG_OFFSET_ALIGN - 1)
+
 /* Per-packet-info for RNDIS data message */
 struct rndis_pktinfo {
        uint32_t rm_size;
@@ -137,7 +145,8 @@ struct rndis_pktinfo {
 
 #define        RNDIS_PKTINFO_OFFSET            \
        __offsetof(struct rndis_pktinfo, rm_data[0])
-#define        RNDIS_PKTINFO_ALIGN             4
+#define        RNDIS_PKTINFO_SIZE_ALIGN        4
+#define        RNDIS_PKTINFO_SIZE_ALIGNMASK    (RNDIS_PKTINFO_SIZE_ALIGN - 1)
 
 #define        NDIS_PKTINFO_TYPE_CSUM          0
 #define        NDIS_PKTINFO_TYPE_IPSEC         1
@@ -236,7 +245,8 @@ struct rndis_query_comp {
        uint32_t rm_infobufoffset;
 };
 
-#define        RNDIS_QUERY_COMP_INFOBUFABS(ofs)        \
+/* infobuf offset from the beginning of rndis_query_comp. */
+#define        RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(ofs) \
        ((ofs) + __offsetof(struct rndis_query_req, rm_rid))
 
 /* Send a set object request. */
@@ -295,9 +305,28 @@ struct rndis_reset_comp {
        uint32_t rm_adrreset;
 };
 
-/* 802.3 link-state or undefined message error. */
+/* 802.3 link-state or undefined message error.  Sent by device. */
 #define        REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007
 
+struct rndis_status_msg {
+       uint32_t rm_type;
+       uint32_t rm_len;
+       uint32_t rm_status;
+       uint32_t rm_stbuflen;
+       uint32_t rm_stbufoffset;
+       /* rndis_diag_info */
+};
+
+/*
+ * Immediately after rndis_status_msg.rm_stbufoffset, if a control
+ * message is malformatted, or a packet message contains inappropriate
+ * content.
+ */
+struct rndis_diag_info {
+       uint32_t rm_diagstatus;
+       uint32_t rm_erroffset;
+};
+
 /* Keepalive messsage.  May be sent by device. */
 #define        REMOTE_NDIS_KEEPALIVE_MSG       0x00000008
 #define        REMOTE_NDIS_KEEPALIVE_CMPLT     0x80000008
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to