dump_tcp() computes length as (buff_len - ip6_header_len - tcp_header_len),
but the only bounds guard ensures 20 bytes, while doff allows a higher
header length (60 bytes). With a doff of 15 (60 bytes) and only 20 bytes
available in the buffer, the calculation would underflow and show a bugus
length of the TCP payload. For now, set the payload length to zero for such
a packet.

Fixes: 35b37756f4a3 ("add IPv6 support to tcpdump parser")
Signed-off-by: Sven Eckelmann <[email protected]>
---
 tcpdump.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tcpdump.c b/tcpdump.c
index 9c90f36..7769cbf 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -537,18 +537,20 @@ static void dump_tcp(const char ip_string[], unsigned 
char *packet_buff,
 {
        uint16_t tcp_header_len;
        struct tcphdr *tcphdr;
+       size_t tcp_len;
 
        LEN_CHECK((size_t)buff_len - ip6_header_len,
                  sizeof(struct tcphdr), "TCP");
        tcphdr = (struct tcphdr *)(packet_buff + ip6_header_len);
        tcp_header_len = tcphdr->doff * 4;
+       tcp_len = (size_t)buff_len - ip6_header_len;
        printf("%s %s.%i > ", ip_string, src_addr, ntohs(tcphdr->source));
        printf("%s.%i: TCP, Flags [%c%c%c%c%c%c], length %zu\n",
               dst_addr, ntohs(tcphdr->dest),
               (tcphdr->fin ? 'F' : '.'), (tcphdr->syn ? 'S' : '.'),
               (tcphdr->rst ? 'R' : '.'), (tcphdr->psh ? 'P' : '.'),
               (tcphdr->ack ? 'A' : '.'), (tcphdr->urg ? 'U' : '.'),
-              (size_t)buff_len - ip6_header_len - tcp_header_len);
+              tcp_len > tcp_header_len ? tcp_len - tcp_header_len : 0);
 }
 
 static void dump_udp(const char ip_string[], unsigned char *packet_buff,

-- 
2.47.3

Reply via email to