Commit 13322f2e authored by Christian Riesch's avatar Christian Riesch Committed by David S. Miller
Browse files

dp83640: Fix length check for event timestamp status messages



Event timestamp status messages have a variable length, ranging from
1 to 5 words (16 bit words). The current code however requires
a minimum message length of sizeof(*phy_txts). In most cases this
condition is fulfilled due to padding bytes. However, if several events
are signaled in a single message, padding bytes may not be present.
For short event timestamp status messages, the length check will fail,
and the event timestamp will be dropped.

Signed-off-by: default avatarChristian Riesch <christian.riesch@omicron.at>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b4834c86
Loading
Loading
Loading
Loading
+15 −8
Original line number Original line Diff line number Diff line
@@ -721,7 +721,7 @@ static inline u16 exts_chan_to_edata(int ch)
}
}


static int decode_evnt(struct dp83640_private *dp83640,
static int decode_evnt(struct dp83640_private *dp83640,
		       void *data, u16 ests)
		       void *data, int len, u16 ests)
{
{
	struct phy_txts *phy_txts;
	struct phy_txts *phy_txts;
	struct ptp_clock_event event;
	struct ptp_clock_event event;
@@ -729,6 +729,16 @@ static int decode_evnt(struct dp83640_private *dp83640,
	int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
	int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
	u16 ext_status = 0;
	u16 ext_status = 0;


	/* calculate length of the event timestamp status message */
	if (ests & MULT_EVNT)
		parsed = (words + 2) * sizeof(u16);
	else
		parsed = (words + 1) * sizeof(u16);

	/* check if enough data is available */
	if (len < parsed)
		return len;

	if (ests & MULT_EVNT) {
	if (ests & MULT_EVNT) {
		ext_status = *(u16 *) data;
		ext_status = *(u16 *) data;
		data += sizeof(ext_status);
		data += sizeof(ext_status);
@@ -747,10 +757,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
		dp83640->edata.ns_lo = phy_txts->ns_lo;
		dp83640->edata.ns_lo = phy_txts->ns_lo;
	}
	}


	if (ext_status) {
	if (!ext_status) {
		parsed = words + 2;
	} else {
		parsed = words + 1;
		i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
		i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
		ext_status = exts_chan_to_edata(i);
		ext_status = exts_chan_to_edata(i);
	}
	}
@@ -768,7 +775,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
		}
		}
	}
	}


	return parsed * sizeof(u16);
	return parsed;
}
}


static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
@@ -905,9 +912,9 @@ static void decode_status_frame(struct dp83640_private *dp83640,
			decode_txts(dp83640, phy_txts);
			decode_txts(dp83640, phy_txts);
			size = sizeof(*phy_txts);
			size = sizeof(*phy_txts);


		} else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
		} else if (PSF_EVNT == type) {


			size = decode_evnt(dp83640, ptr, ests);
			size = decode_evnt(dp83640, ptr, len, ests);


		} else {
		} else {
			size = 0;
			size = 0;