Still looking for OK's.
On Wed, Nov 26, 2014 at 17:18 +0100, Mike Belopuhov wrote:
> >
> > better diff. the problem is that dissectors use packetp and
> > snapend pointers themselves therefore they should be pointing
> > to the newly allocated structure. we can restore them once
> > we're done with the inner content and go back to the caller
> > to see if we need to hexdump the contents.
> >
> > i'll see if i can cook and test the ipv6 version.
> >
> > OK?
> >
>
> now with an ip6 version and i've made sure that this fixes
> dumping unaligned ipv6 packets as well. in the meantime
> jsg@ has lured me into looking at the afl crash in the same
> code and it looks like the check from ip6_print is useful
> here: if we haven't got enough data for a header, don't
> bother with anything else and just bail.
>
> ok?
>
> diff --git usr.sbin/tcpdump/print-ip.c usr.sbin/tcpdump/print-ip.c
> index 3f4194c..e9d2185 100644
> --- usr.sbin/tcpdump/print-ip.c
> +++ usr.sbin/tcpdump/print-ip.c
> @@ -351,22 +351,27 @@ in_cksum(const u_short *addr, register int len, int
> csum)
> * print an IP datagram.
> */
> void
> ip_print(register const u_char *bp, register u_int length)
> {
> + static u_char *abuf = NULL;
> register const struct ip *ip;
> register u_int hlen, len, off;
> register const u_char *cp;
> + const u_char *pktp = packetp;
> + const u_char *send = snapend;
>
> ip = (const struct ip *)bp;
> + if ((u_char *)(ip + 1) > snapend) {
> + printf("[|ip]");
> + return;
> + }
> +
> /*
> * If the IP header is not aligned, copy into abuf.
> - * This will never happen with BPF. It does happen with raw packet
> - * dumps from -r.
> */
> if ((intptr_t)ip & (sizeof(long)-1)) {
> - static u_char *abuf = NULL;
> static int didwarn = 0;
> int clen = snapend - bp;
>
> if (clen > snaplen)
> clen = snaplen;
> @@ -387,11 +392,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> }
>
> TCHECK(*ip);
> if (ip->ip_v != IPVERSION) {
> (void)printf("bad-ip-version %u", ip->ip_v);
> - return;
> + goto out;
> }
>
> len = ntohs(ip->ip_len);
> if (length < len) {
> (void)printf("truncated-ip - %d bytes missing!",
> @@ -400,11 +405,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> }
>
> hlen = ip->ip_hl * 4;
> if (hlen < sizeof(struct ip) || hlen > len) {
> (void)printf("bad-hlen %d", hlen);
> - return;
> + goto out;
> }
>
> len -= hlen;
>
> /*
> @@ -465,11 +470,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> ipaddr_string(&ip->ip_src),
> ipaddr_string(&ip->ip_dst));
> ip_print(cp, len);
> if (! vflag) {
> printf(" (encap)");
> - return;
> + goto out;
> }
> break;
>
> #ifdef INET6
> #ifndef IPPROTO_IPV6
> @@ -482,11 +487,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> ipaddr_string(&ip->ip_src),
> ipaddr_string(&ip->ip_dst));
> ip6_print(cp, len);
> if (! vflag) {
> printf(" (encap)");
> - return;
> + goto out;
> }
> break;
> #endif /*INET6*/
>
> #ifndef IPPROTO_GRE
> @@ -499,11 +504,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> ipaddr_string(&ip->ip_dst));
> /* do it */
> gre_print(cp, len);
> if (! vflag) {
> printf(" (gre encap)");
> - return;
> + goto out;
> }
> break;
>
> #ifndef IPPROTO_ESP
> #define IPPROTO_ESP 50
> @@ -528,11 +533,11 @@ ip_print(register const u_char *bp, register u_int
> length)
> ipaddr_string(&ip->ip_src),
> ipaddr_string(&ip->ip_dst));
> mobile_print(cp, len);
> if (! vflag) {
> printf(" (mobile encap)");
> - return;
> + goto out;
> }
> break;
>
> #ifndef IPPROTO_ETHERIP
> #define IPPROTO_ETHERIP 97
> @@ -653,10 +658,13 @@ ip_print(register const u_char *bp, register u_int
> length)
> (void)printf("%soptlen=%d", sep, hlen);
> ip_optprint((u_char *)(ip + 1), hlen);
> }
> printf(")");
> }
> +out:
> + packetp = pktp;
> + snapend = send;
> return;
>
> trunc:
> printf("[|ip]");
> }
> diff --git usr.sbin/tcpdump/print-ip6.c usr.sbin/tcpdump/print-ip6.c
> index 648de8c..03c9c84 100644
> --- usr.sbin/tcpdump/print-ip6.c
> +++ usr.sbin/tcpdump/print-ip6.c
> @@ -50,26 +50,30 @@
> * print an IP6 datagram.
> */
> void
> ip6_print(register const u_char *bp, register u_int length)
> {
> + static u_char *abuf = NULL;
> register const struct ip6_hdr *ip6;
> register int hlen;
> register int len;
> register const u_char *cp;
> + const u_char *pktp = packetp;
> + const u_char *send = snapend;
> int nh;
> u_int flow;
> -
> +
> ip6 = (const struct ip6_hdr *)bp;
> + if ((u_char *)(ip6 + 1) > snapend) {
> + printf("[|ip6]");
> + return;
> + }
>
> /*
> * The IP header is not word aligned, so copy into abuf.
> - * This will never happen with BPF. It does happen with
> - * raw packet dumps from -r.
> */
> if ((intptr_t)ip6 & (sizeof(long)-1)) {
> - static u_char *abuf = NULL;
> static int didwarn = 0;
> int clen = snapend - bp;
> if (clen > snaplen)
> clen = snaplen;
>
> @@ -87,21 +91,17 @@ ip6_print(register const u_char *bp, register u_int
> length)
> warning("compensating for unaligned libpcap packets");
> ++didwarn;
> }
> }
>
> - if ((u_char *)(ip6 + 1) > snapend) {
> - printf("[|ip6]");
> - return;
> - }
> if (length < sizeof (struct ip6_hdr)) {
> (void)printf("truncated-ip6 %d", length);
> - return;
> + goto out;
> }
> if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
> (void)printf("bad-ip6-version %u", ip6->ip6_vfc >> 4);
> - return;
> + goto out;
> }
> hlen = sizeof(struct ip6_hdr);
>
> len = ntohs(ip6->ip6_plen);
> if (length < len + hlen)
> @@ -204,11 +204,11 @@ ip6_print(register const u_char *bp, register u_int
> length)
> if (hlen == 0)
> break;
> }
>
> end:
> -
> +
> flow = ntohl(ip6->ip6_flow);
> #if 0
> /* rfc1883 */
> if (flow & 0x0f000000)
> (void)printf(" [pri 0x%x]", (flow & 0x0f000000) >> 24);
> @@ -230,8 +230,12 @@ ip6_print(register const u_char *bp, register u_int
> length)
> (void)printf("len %d", len);
> if (ip6->ip6_hlim > 1)
> (void)printf(", hlim %d", (int)ip6->ip6_hlim);
> printf(")");
> }
> +
> + out:
> + packetp = pktp;
> + snapend = send;
> }
>
> #endif /* INET6 */