Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137401530
D7782.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D7782.id.diff
View Options
Index: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
===================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
@@ -159,39 +159,22 @@
}
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;
+ const struct rndis_pktinfo *pi = info_data;
+ uint32_t mask = 0;
- 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);
-
- 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);
@@ -249,43 +232,183 @@
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;
+ }
+
+#undef IS_OFFSET_INVALID
+
+ 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;
+ }
+ }
- dlen = rndis_pkt->data_length;
- data = (const uint8_t *)data + data_offset;
+ /*
+ * 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 (hv_rf_find_recvinfo(rndis_pkt, &info)) {
- if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
+ 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);
}
/*
@@ -565,7 +688,7 @@
* 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);
Index: head/sys/net/rndis.h
===================================================================
--- head/sys/net/rndis.h
+++ head/sys/net/rndis.h
@@ -127,6 +127,14 @@
(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 @@
#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 @@
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. */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 24, 2:45 AM (20 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26045502
Default Alt Text
D7782.id.diff (9 KB)
Attached To
Mode
D7782: hyperv/hn: Stringent RNDIS packet message length/offset check.
Attached
Detach File
Event Timeline
Log In to Comment