>Synopsis: display bug and complex length bug in tcpdump/print-icmp.c
>Category: system
>Environment:
System : OpenBSD 7.2
Details : OpenBSD 7.2 (GENERIC.MP) #2: Thu Nov 24 23:53:03 MST 2022
[email protected]:/usr/src/sys/arch/arm64/compile/GENERIC.MP
Architecture: OpenBSD.arm64
Machine : arm64
>Description:
In the print-icmp.c code there is a while() near line 316 that goes
through Router Advertisements (icmp type 9 code 0) but doesn't advance struct
idp. My patch adds this, yet I was unable to test it.
Also I'm not satisfied with the -vv option and printing the IP packet and
it's payload the way it is done. Basically it passes print_ip() length
parameter with what's given on the wire (as payload of the icmp) which will
run through so many length checks in print_ip() it's not funny. In fact
you could use this similar to a GRE specially crafted packet to increase
some length that may point beyond snaplen. I'm thinking of some high length
like 0xffff being put in there. I have done a calculation on what length it
should be instead only it looks ugly but is more correct. Let me show you
the captured tcpdumps next section.
>How-To-Repeat:
Normal before:
root@echo# tcpdump -vv -n -i bse0 -s 1500 ip and icmp
tcpdump: listening on bse0, link-type EN10MB
17:51:32.250143 192.168.177.14 > 192.168.177.13: icmp: 192.168.177.14 udp port
999 unreachable [icmp cksum ok] for 192.168.177.13.11143 > 192.168.177.14.999:
udp 6 (ttl 64, id 6174, len 34) (ttl 255, id 42263, len 56)
With my patch:
root@echo# obj/tcpdump -vv -n -i bse0 -s 1500 ip and icmp
tcpdump: listening on bse0, link-type EN10MB
17:51:00.810291 192.168.177.14 > 192.168.177.13: icmp: 192.168.177.14 udp port
999 unreachable [icmp cksum ok] for truncated-ip - 6 bytes
missing!192.168.177.13.36685 > 192.168.177.14.999: truncated-udp - 6 bytes
missing![bad udp cksum 5445! -> 3689] udp 0 (ttl 64, id 52444, len 34) (ttl
255, id 58823, len 56)
^C
As seen in the hexdump the packet is really missing data:
Normal before:
17:55:22.936602 192.168.177.14 > 192.168.177.13: icmp: 192.168.177.14 udp port
999 unreachable [icmp cksum ok] for 192.168.177.13.37982 > 192.168.177.14.999:
udp 6 (ttl 64, id 17991, len 34) (ttl 255, id 44077, len 56)
0000: 4500 0038 ac2d 0000 ff01 2c2a c0a8 b10e E..8.-....,*....
0010: c0a8 b10d 0303 2466 0000 0000 4500 0022 ......$f....E.."
0020: 4647 0000 4011 5117 c0a8 b10d c0a8 b10e [email protected].........
0030: 945e 03e7 000e 4043 .^....@C
With my patch:
17:56:09.560294 192.168.177.14 > 192.168.177.13: icmp: 192.168.177.14 udp port
999 unreachable [icmp cksum ok] for truncated-ip - 6 bytes
missing!192.168.177.13.22420 > 192.168.177.14.999: truncated-udp - 6 bytes
missing![bad udp cksum 0d7d! -> efc0] udp 0 (ttl 64, id 316, len 34) (ttl 255,
id 20015, len 56)
0000: 4500 0038 4e2f 0000 ff01 8a28 c0a8 b10e E..8N/.....(....
0010: c0a8 b10d 0303 2466 0000 0000 4500 0022 ......$f....E.."
0020: 013c 0000 4011 9622 c0a8 b10d c0a8 b10e .<..@.."........
0030: 5794 03e7 000e 7d0d W.....}.
>Fix:
The patch:
Index: print-icmp.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-icmp.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 print-icmp.c
--- print-icmp.c 1 Dec 2021 18:28:46 -0000 1.27
+++ print-icmp.c 1 Mar 2023 16:49:55 -0000
@@ -319,6 +319,7 @@ icmp_print(const u_char *bp, u_int lengt
ipaddr_string(&idp->ird_addr),
EXTRACT_32BITS(&idp->ird_pref));
strlcat(buf, buf2, sizeof(buf));
+ idp++;
}
}
break;
@@ -385,9 +386,13 @@ icmp_print(const u_char *bp, u_int lengt
}
if (vflag > 1 && !ICMP_INFOTYPE(dp->icmp_type) &&
TTEST(dp->icmp_ip)) {
+ int ilen;
printf(" for ");
oip = &dp->icmp_ip;
- ip_print((u_char *)oip, ntohs(oip->ip_len));
+ ilen = length - ((u_char *)oip - (u_char *)bp);
+ if (ilen <= 0 || ilen > length)
+ goto trunc;
+ ip_print((u_char *)oip, ilen);
}
return;
trunc:
dmesg:
My host hasn't changed.