Commit message: CVE-2017-13688/OLSR: Do bounds checks before we fetch data.

While we're at it, clean up some other bounds checks, so we check that
we have a complete IPv4 message header if it's IPv4 and a complete IPv6
message header if it's IPv6.

This fixes a buffer over-read discovered by Bhargava Shastry,
SecT/TU Berlin.

Add tests using the capture files supplied by the reporter(s).
CVE: CVE-2017-13688
CWE: CWE-125
Vulnerability description: The OLSR parser in tcpdump before 4.9.2 has a buffer over-read in print-olsr.c:olsr_print().

Project: tcpdump
File: print-olsr.c

static uint32_t deserialize_gw_speed(uint8_t value) {
  uint32_t speed;
  uint32_t exp;

  if (!value) {
    return 0;
  }

  if (value == UINT8_MAX) {
    /* maximum value: also return maximum value */
    return MAX_SMARTGW_SPEED;
  }

  speed = (value >> 3) + 1;
  exp = value & 7;

  while (exp-- > 0) {
    speed *= 10;
  }
  return speed;
}

Project: tcpdump
File: print-olsr.c

olsr_print_lq_neighbor4(netdissect_options *ndo,
                        const u_char *msg_data, u_int hello_len)
{
    const struct olsr_lq_neighbor4 *lq_neighbor;

    while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {

        lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data;
        if (!ND_TTEST(*lq_neighbor))
            return (-1);

        ND_PRINT((ndo, "\n\t      neighbor %s, link-quality %.2f%%"
               ", neighbor-link-quality %.2f%%",
               ipaddr_string(ndo, lq_neighbor->neighbor),
               ((double)lq_neighbor->link_quality/2.55),
               ((double)lq_neighbor->neighbor_link_quality/2.55)));

        msg_data += sizeof(struct olsr_lq_neighbor4);
        hello_len -= sizeof(struct olsr_lq_neighbor4);
    }
    return (0);
}

Project: tcpdump
File: print-olsr.c

olsr_print_lq_neighbor6(netdissect_options *ndo,
                        const u_char *msg_data, u_int hello_len)
{
    const struct olsr_lq_neighbor6 *lq_neighbor;

    while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {

        lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data;
        if (!ND_TTEST(*lq_neighbor))
            return (-1);

        ND_PRINT((ndo, "\n\t      neighbor %s, link-quality %.2f%%"
               ", neighbor-link-quality %.2f%%",
               ip6addr_string(ndo, lq_neighbor->neighbor),
               ((double)lq_neighbor->link_quality/2.55),
               ((double)lq_neighbor->neighbor_link_quality/2.55)));

        msg_data += sizeof(struct olsr_lq_neighbor6);
        hello_len -= sizeof(struct olsr_lq_neighbor6);
    }
    return (0);
}

Project: tcpdump
File: print-olsr.c

olsr_print_neighbor(netdissect_options *ndo,
                    const u_char *msg_data, u_int hello_len)
{
    int neighbor;

    ND_PRINT((ndo, "\n\t      neighbor\n\t\t"));
    neighbor = 1;

    while (hello_len >= sizeof(struct in_addr)) {

        if (!ND_TTEST2(*msg_data, sizeof(struct in_addr)))
            return (-1);
        /* print 4 neighbors per line */

        ND_PRINT((ndo, "%s%s", ipaddr_string(ndo, msg_data),
               neighbor % 4 == 0 ? "\n\t\t" : " "));

        msg_data += sizeof(struct in_addr);
        hello_len -= sizeof(struct in_addr);
    }
    return (0);
}