When dissecting a sample, or a flow or counter within the sample, make
sure we don't run past the length in the sample/flow/counter header.
This also means we count the sample length down as we process the
contents of the sample, so we only add what, if anything, remains of the
sample to the pointer into the packet, and subtract that from the
remaining data length in the packet, which means we properly handle
packets with multiple samples.
const u_char *tptr;
int tlen;
u_int32_t sflow_sample_type, sflow_sample_len;
const u_char *tptr;
int tlen;
u_int32_t sflow_sample_type, sflow_sample_len;
- int nsamples, nrecords, counter_len, counter_type, flow_len, flow_type;
+ u_int32_t nsamples, nrecords;
+ u_int32_t counter_len, counter_type, flow_len, flow_type;
len);
/* skip Common header */
len);
/* skip Common header */
- tptr+=sizeof(const struct sflow_datagram_t);
- tlen-=sizeof(const struct sflow_datagram_t);
+ tptr += sizeof(const struct sflow_datagram_t);
+ tlen -= sizeof(const struct sflow_datagram_t);
while (nsamples > 0 && tlen > 0) {
sflow_sample = (const struct sflow_sample_header *)tptr;
while (nsamples > 0 && tlen > 0) {
sflow_sample = (const struct sflow_sample_header *)tptr;
+ TCHECK(*sflow_sample);
+
sflow_sample_type = (EXTRACT_32BITS(sflow_sample->format)&0x0FFF);
sflow_sample_len = EXTRACT_32BITS(sflow_sample->len);
sflow_sample_type = (EXTRACT_32BITS(sflow_sample->format)&0x0FFF);
sflow_sample_len = EXTRACT_32BITS(sflow_sample->len);
- tptr+=sizeof(struct sflow_sample_header);
- tlen-=sizeof(struct sflow_sample_header);
+ tptr += sizeof(struct sflow_sample_header);
+ tlen -= sizeof(struct sflow_sample_header);
printf("\n\t%s (%u), length %u,",
tok2str(sflow_format_values, "Unknown", sflow_sample_type),
printf("\n\t%s (%u), length %u,",
tok2str(sflow_format_values, "Unknown", sflow_sample_type),
}
/* did we capture enough for fully decoding the sample ? */
}
/* did we capture enough for fully decoding the sample ? */
- if (!TTEST2(*tptr, sflow_sample_len))
- goto trunc;
+ TCHECK2(*tptr, sflow_sample_len);
switch(sflow_sample_type) {
case SFLOW_FLOW_SAMPLE: /* XXX */
switch(sflow_sample_type) {
case SFLOW_FLOW_SAMPLE: /* XXX */
break;
case SFLOW_EXPANDED_FLOW_SAMPLE:
break;
case SFLOW_EXPANDED_FLOW_SAMPLE:
+ /* does the header run past the end of the sample? */
+ if (sflow_sample_len < sizeof(struct sflow_expanded_flow_sample_t))
+ goto trunc;
+
sflow_expanded_flow_sample = (const struct sflow_expanded_flow_sample_t *)tptr;
nrecords = EXTRACT_32BITS(sflow_expanded_flow_sample->records);
sflow_expanded_flow_sample = (const struct sflow_expanded_flow_sample_t *)tptr;
nrecords = EXTRACT_32BITS(sflow_expanded_flow_sample->records);
EXTRACT_32BITS(sflow_expanded_flow_sample->drops),
EXTRACT_32BITS(sflow_expanded_flow_sample->records));
EXTRACT_32BITS(sflow_expanded_flow_sample->drops),
EXTRACT_32BITS(sflow_expanded_flow_sample->records));
- tptr+= sizeof(struct sflow_expanded_flow_sample_t);
- tlen-= sizeof(struct sflow_expanded_flow_sample_t);
+ tptr += sizeof(struct sflow_expanded_flow_sample_t);
+ tlen -= sizeof(struct sflow_expanded_flow_sample_t);
+ sflow_sample_len-= sizeof(struct sflow_expanded_flow_sample_t);
while ( nrecords > 0 && tlen > 0) {
while ( nrecords > 0 && tlen > 0) {
-
- /* decode Flow record - 2 bytes */
+ if (sflow_sample_len < 8)
+ goto trunc;
+
+ /* decode Flow record */
flow_type = EXTRACT_32BITS(tptr)&0x0FFF;
flow_len = EXTRACT_32BITS(tptr+4);
printf("\n\t %s (%u) length %u",
flow_type = EXTRACT_32BITS(tptr)&0x0FFF;
flow_len = EXTRACT_32BITS(tptr+4);
printf("\n\t %s (%u) length %u",
- /* did we capture enough for fully decoding the flow ? */
- if (!TTEST2(*tptr, flow_len))
+ /* does the flow run past the end of the sample? */
+ if (sflow_sample_len < flow_len)
goto trunc;
switch(flow_type) {
case SFLOW_FLOW_RAW_PACKET:
goto trunc;
switch(flow_type) {
case SFLOW_FLOW_RAW_PACKET:
+ if (flow_len < sizeof (struct sflow_expanded_flow_raw_t))
+ goto trunc;
+
sflow_flow_raw = (const struct sflow_expanded_flow_raw_t *)tptr;
printf("\n\t protocol %s (%u), length %u, stripped bytes %u, header_size %u",
tok2str(sflow_flow_raw_protocol_values,"Unknown",EXTRACT_32BITS(sflow_flow_raw->protocol)),
sflow_flow_raw = (const struct sflow_expanded_flow_raw_t *)tptr;
printf("\n\t protocol %s (%u), length %u, stripped bytes %u, header_size %u",
tok2str(sflow_flow_raw_protocol_values,"Unknown",EXTRACT_32BITS(sflow_flow_raw->protocol)),
case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC:
case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL:
break;
case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC:
case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL:
break;
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t ", flow_len);
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t ", flow_len);
}
tptr += flow_len;
tlen -= flow_len;
}
tptr += flow_len;
tlen -= flow_len;
+ sflow_sample_len -= flow_len;
nrecords--;
}
break;
case SFLOW_EXPANDED_COUNTER_SAMPLE:
nrecords--;
}
break;
case SFLOW_EXPANDED_COUNTER_SAMPLE:
+ /* does the header run past the end of the sample? */
+ if (sflow_sample_len < sizeof(struct sflow_expanded_counter_sample_t))
+ goto trunc;
+
sflow_expanded_counter_sample = (const struct sflow_expanded_counter_sample_t *)tptr;
nrecords = EXTRACT_32BITS(sflow_expanded_counter_sample->records);
sflow_expanded_counter_sample = (const struct sflow_expanded_counter_sample_t *)tptr;
nrecords = EXTRACT_32BITS(sflow_expanded_counter_sample->records);
EXTRACT_32BITS(sflow_expanded_counter_sample->index),
nrecords);
EXTRACT_32BITS(sflow_expanded_counter_sample->index),
nrecords);
- tptr+= sizeof(struct sflow_expanded_counter_sample_t);
- tlen-= sizeof(struct sflow_expanded_counter_sample_t);
+ tptr += sizeof(struct sflow_expanded_counter_sample_t);
+ tlen -= sizeof(struct sflow_expanded_counter_sample_t);
+ sflow_sample_len -= sizeof(struct sflow_expanded_counter_sample_t);
while ( nrecords > 0 && tlen > 0) {
while ( nrecords > 0 && tlen > 0) {
+ if (sflow_sample_len < 8)
+ goto trunc;
- /* decode counter record - 2 bytes */
+ /* decode counter record */
counter_type = EXTRACT_32BITS(tptr)&0x0FFF;
counter_len = EXTRACT_32BITS(tptr+4);
printf("\n\t %s (%u) length %u",
counter_type = EXTRACT_32BITS(tptr)&0x0FFF;
counter_len = EXTRACT_32BITS(tptr+4);
printf("\n\t %s (%u) length %u",
- /* did we capture enough for fully decoding the counter ? */
- if (!TTEST2(*tptr, counter_len))
+ /* does the counter run past the end of the sample? */
+ if (sflow_sample_len < counter_len)
goto trunc;
switch(counter_type) {
case SFLOW_COUNTER_GENERIC:
goto trunc;
switch(counter_type) {
case SFLOW_COUNTER_GENERIC:
+ if (counter_len < sizeof (struct sflow_generic_counter_t))
+ goto trunc;
+
sflow_gen_counter = (const struct sflow_generic_counter_t *)tptr;
printf("\n\t ifindex %u, iftype %u, ifspeed %u, ifdirection %u (%s)",
EXTRACT_32BITS(sflow_gen_counter->ifindex),
sflow_gen_counter = (const struct sflow_generic_counter_t *)tptr;
printf("\n\t ifindex %u, iftype %u, ifspeed %u, ifdirection %u (%s)",
EXTRACT_32BITS(sflow_gen_counter->ifindex),
EXTRACT_32BITS(sflow_gen_counter->ifouterrors),
EXTRACT_32BITS(sflow_gen_counter->ifpromiscmode));
break;
EXTRACT_32BITS(sflow_gen_counter->ifouterrors),
EXTRACT_32BITS(sflow_gen_counter->ifpromiscmode));
break;
case SFLOW_COUNTER_ETHERNET:
case SFLOW_COUNTER_ETHERNET:
+ if (counter_len < sizeof (struct sflow_ethernet_counter_t))
+ goto trunc;
+
sflow_eth_counter = (const struct sflow_ethernet_counter_t *)tptr;
printf("\n\t align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u",
EXTRACT_32BITS(sflow_eth_counter->alignerrors),
sflow_eth_counter = (const struct sflow_ethernet_counter_t *)tptr;
printf("\n\t align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u",
EXTRACT_32BITS(sflow_eth_counter->alignerrors),
EXTRACT_32BITS(sflow_eth_counter->mac_receive_errors),
EXTRACT_32BITS(sflow_eth_counter->symbol_errors));
break;
EXTRACT_32BITS(sflow_eth_counter->mac_receive_errors),
EXTRACT_32BITS(sflow_eth_counter->symbol_errors));
break;
case SFLOW_COUNTER_TOKEN_RING: /* XXX */
break;
case SFLOW_COUNTER_TOKEN_RING: /* XXX */
break;
case SFLOW_COUNTER_BASEVG:
case SFLOW_COUNTER_BASEVG:
+ if (counter_len < sizeof (struct sflow_100basevg_counter_t))
+ goto trunc;
+
sflow_100basevg_counter = (const struct sflow_100basevg_counter_t *)tptr;
printf("\n\t in high prio frames %u, in high prio octets %" PRIu64,
EXTRACT_32BITS(sflow_100basevg_counter->in_highpriority_frames),
sflow_100basevg_counter = (const struct sflow_100basevg_counter_t *)tptr;
printf("\n\t in high prio frames %u, in high prio octets %" PRIu64,
EXTRACT_32BITS(sflow_100basevg_counter->in_highpriority_frames),
EXTRACT_64BITS(sflow_100basevg_counter->hc_in_normpriority_octets),
EXTRACT_64BITS(sflow_100basevg_counter->hc_out_highpriority_octets));
break;
EXTRACT_64BITS(sflow_100basevg_counter->hc_in_normpriority_octets),
EXTRACT_64BITS(sflow_100basevg_counter->hc_out_highpriority_octets));
break;
+ if (counter_len < sizeof (struct sflow_vlan_counter_t))
+ goto trunc;
+
sflow_vlan_counter = (const struct sflow_vlan_counter_t *)tptr;
printf("\n\t vlan_id %u, octets %" PRIu64
", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u",
sflow_vlan_counter = (const struct sflow_vlan_counter_t *)tptr;
printf("\n\t vlan_id %u, octets %" PRIu64
", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u",
EXTRACT_32BITS(sflow_vlan_counter->broadcast_pkt),
EXTRACT_32BITS(sflow_vlan_counter->discards));
break;
EXTRACT_32BITS(sflow_vlan_counter->broadcast_pkt),
EXTRACT_32BITS(sflow_vlan_counter->discards));
break;
case SFLOW_COUNTER_PROCESSOR: /* XXX */
break;
case SFLOW_COUNTER_PROCESSOR: /* XXX */
break;
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t\t", counter_len);
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t\t", counter_len);
}
tptr += counter_len;
tlen -= counter_len;
}
tptr += counter_len;
tlen -= counter_len;
+ sflow_sample_len -= counter_len;
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t ", sflow_sample_len);
default:
if (vflag <= 1)
print_unknown_data(tptr, "\n\t ", sflow_sample_len);