Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Oct 2016 08:10:24 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r307498 - in stable/11/sys: dev/hyperv/netvsc dev/hyperv/vmbus net
Message-ID:  <201610170810.u9H8AOHm025384@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Mon Oct 17 08:10:24 2016
New Revision: 307498
URL: https://svnweb.freebsd.org/changeset/base/307498

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/11/sys/dev/hyperv/netvsc/hv_net_vsc.c
  stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.h
  stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c
  stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h
  stable/11/sys/net/rndis.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c	Mon Oct 17 08:10:24 2016	(r307498)
@@ -742,32 +742,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);
 	}
 	
 	/*
@@ -816,7 +837,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/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Mon Oct 17 08:10:24 2016	(r307498)
@@ -72,7 +72,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);
@@ -131,59 +131,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);
@@ -241,76 +232,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:
@@ -321,15 +459,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);
 }
 
 /*
@@ -551,7 +688,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/11/sys/dev/hyperv/netvsc/hv_rndis_filter.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.h	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.h	Mon Oct 17 08:10:24 2016	(r307498)
@@ -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/11/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Mon Oct 17 08:10:24 2016	(r307498)
@@ -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/11/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h	Mon Oct 17 08:10:24 2016	(r307498)
@@ -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/11/sys/net/rndis.h
==============================================================================
--- stable/11/sys/net/rndis.h	Mon Oct 17 08:06:19 2016	(r307497)
+++ stable/11/sys/net/rndis.h	Mon Oct 17 08:10:24 2016	(r307498)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610170810.u9H8AOHm025384>