X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/f72772154caa9c3851f91954c2a43dc2b653f637..refs/pull/1034/head:/print-tcp.c diff --git a/print-tcp.c b/print-tcp.c index 595515c4..d9ca4a34 100644 --- a/print-tcp.c +++ b/print-tcp.c @@ -39,10 +39,13 @@ __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $"); #include #include +#define ND_LONGJMP_FROM_TCHECK #include "netdissect.h" #include "addrtoname.h" #include "extract.h" +#include "diag-control.h" + #include "tcp.h" #include "ip.h" @@ -62,7 +65,7 @@ static int tcp_verify_signature(netdissect_options *ndo, static void print_tcp_rst_data(netdissect_options *, const u_char *sp, u_int length); static void print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp, - u_int datalen, int exp); + u_int datalen); #define MAX_RST_DATA_LEN 30 @@ -172,6 +175,7 @@ tcp_print(netdissect_options *ndo, uint16_t magic; int rev; const struct ip6_hdr *ip6; + u_int header_len; /* Header length in bytes */ ndo->ndo_protocol = "tcp"; tp = (const struct tcphdr *)bp; @@ -191,8 +195,7 @@ tcp_print(netdissect_options *ndo, GET_IPADDR_STRING(ip->ip_src), GET_IPADDR_STRING(ip->ip_dst)); } - nd_print_trunc(ndo); - return; + nd_trunc_longjmp(ndo); } sport = GET_BE_U_2(tp->th_sport); @@ -222,14 +225,12 @@ tcp_print(netdissect_options *ndo, } } - ND_TCHECK_SIZE(tp); - hlen = TH_OFF(tp) * 4; if (hlen < sizeof(*tp)) { ND_PRINT(" tcp %u [bad hdr length %u - too short, < %zu]", length - hlen, hlen, sizeof(*tp)); - return; + goto invalid; } seq = GET_BE_U_4(tp->th_seq); @@ -242,6 +243,7 @@ tcp_print(netdissect_options *ndo, if (hlen > length) { ND_PRINT(" [bad hdr length %u - too long, > %u]", hlen, length); + goto invalid; } return; } @@ -380,7 +382,7 @@ tcp_print(netdissect_options *ndo, if (hlen > length) { ND_PRINT(" [bad hdr length %u - too long, > %u]", hlen, length); - return; + goto invalid; } if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) { @@ -461,7 +463,7 @@ tcp_print(netdissect_options *ndo, datalen = 0; /* Bail if "l" bytes of data are not left or were not captured */ -#define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); } +#define LENCHECK(l) { if ((l) > hlen) goto bad; } ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt)); @@ -531,6 +533,7 @@ tcp_print(netdissect_options *ndo, case TCPOPT_SIGNATURE: datalen = TCP_SIGLEN; LENCHECK(datalen); + ND_TCHECK_LEN(cp, datalen); ND_PRINT(" "); #ifdef HAVE_LIBCRYPTO switch (tcp_verify_signature(ndo, ip, tp, @@ -612,22 +615,46 @@ tcp_print(netdissect_options *ndo, break; case TCPOPT_MPTCP: + { + const u_char *snapend_save; + int ret; + datalen = len - 2; LENCHECK(datalen); - if (!mptcp_print(ndo, cp-2, len, flags)) + /* FIXME: Proof-read mptcp_print() and if it + * always covers all bytes when it returns 1, + * only do ND_TCHECK_LEN() if it returned 0. + */ + ND_TCHECK_LEN(cp, datalen); + /* Update the snapend to the end of the option + * before calling mptcp_print(). Some options + * (MPTCP or others) may be present after a + * MPTCP option. This prevents that, in + * mptcp_print(), the remaining length < the + * remaining caplen. + */ + snapend_save = ndo->ndo_snapend; + ndo->ndo_snapend = ND_MIN(cp - 2 + len, + ndo->ndo_snapend); + ret = mptcp_print(ndo, cp - 2, len, flags); + ndo->ndo_snapend = snapend_save; + if (!ret) goto bad; break; + } case TCPOPT_FASTOPEN: datalen = len - 2; LENCHECK(datalen); + ND_TCHECK_LEN(cp, datalen); ND_PRINT(" "); - print_tcp_fastopen_option(ndo, cp, datalen, FALSE); + print_tcp_fastopen_option(ndo, cp, datalen); break; case TCPOPT_EXPERIMENT2: datalen = len - 2; LENCHECK(datalen); + ND_TCHECK_LEN(cp, datalen); if (datalen < 2) goto bad; /* RFC6994 */ @@ -637,7 +664,8 @@ tcp_print(netdissect_options *ndo, switch(magic) { case 0xf989: /* TCP Fast Open RFC 7413 */ - print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE); + ND_PRINT("tfo"); + print_tcp_fastopen_option(ndo, cp + 2, datalen - 2); break; default: @@ -680,13 +708,23 @@ tcp_print(netdissect_options *ndo, */ ND_PRINT(", length %u", length); - if (length <= 0) + if (length == 0) return; /* * Decode payload if necessary. */ - bp += TH_OFF(tp) * 4; + header_len = TH_OFF(tp) * 4; + /* + * Do a bounds check before decoding the payload. + * At least the header data is required. + */ + if (!ND_TTEST_LEN(bp, header_len)) { + ND_PRINT(" [remaining caplen(%u) < header length(%u)]", + ND_BYTES_AVAILABLE_AFTER(bp), header_len); + nd_trunc_longjmp(ndo); + } + bp += header_len; if ((flags & TH_RST) && ndo->ndo_vflag) { print_tcp_rst_data(ndo, bp, length); return; @@ -715,8 +753,7 @@ tcp_print(netdissect_options *ndo, smtp_print(ndo, bp, length); } else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) { ND_PRINT(": "); - ndo->ndo_protocol = "whois"; /* needed by txtproto_print() */ - txtproto_print(ndo, bp, length, NULL, 0); /* RFC 3912 */ + whois_print(ndo, bp, length); } else if (IS_SRC_OR_DST_PORT(BGP_PORT)) bgp_print(ndo, bp, length); else if (IS_SRC_OR_DST_PORT(PPTP_PORT)) @@ -754,7 +791,7 @@ tcp_print(netdissect_options *ndo, } else if (IS_SRC_OR_DST_PORT(LDP_PORT)) { ldp_print(ndo, bp, length); } else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) && - length >= 4 && ND_TTEST_4(bp)) { + length >= 4) { /* * If data present, header length valid, and NFS port used, * assume NFS. @@ -792,10 +829,8 @@ bad: if (ch != '\0') ND_PRINT("]"); return; -trunc: - nd_print_trunc(ndo); - if (ch != '\0') - ND_PRINT(">"); +invalid: + nd_print_invalid(ndo); } /* @@ -817,32 +852,22 @@ static void print_tcp_rst_data(netdissect_options *ndo, const u_char *sp, u_int length) { - u_char c; - ND_PRINT(ND_TTEST_LEN(sp, length) ? " [RST" : " [!RST"); if (length > MAX_RST_DATA_LEN) { length = MAX_RST_DATA_LEN; /* can use -X for longer */ ND_PRINT("+"); /* indicate we truncate */ } ND_PRINT(" "); - while (length && sp < ndo->ndo_snapend) { - c = GET_U_1(sp); - sp++; - fn_print_char(ndo, c); - length--; - } + (void)nd_printn(ndo, sp, length, ndo->ndo_snapend); ND_PRINT("]"); } static void print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp, - u_int datalen, int exp) + u_int datalen) { u_int i; - if (exp) - ND_PRINT("tfo"); - if (datalen == 0) { /* Fast Open Cookie Request */ ND_PRINT(" cookiereq"); @@ -859,7 +884,7 @@ print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp, } #ifdef HAVE_LIBCRYPTO -USES_APPLE_DEPRECATED_API +DIAG_OFF_DEPRECATION static int tcp_verify_signature(netdissect_options *ndo, const struct ip *ip, const struct tcphdr *tp, @@ -874,7 +899,7 @@ tcp_verify_signature(netdissect_options *ndo, uint32_t len32; uint8_t nxt; - if (data + length > ndo->ndo_snapend) { + if (!ND_TTEST_LEN(data, length)) { ND_PRINT("snaplen too short, "); return (CANT_CHECK_SIGNATURE); } @@ -939,5 +964,5 @@ tcp_verify_signature(netdissect_options *ndo, else return (SIGNATURE_INVALID); } -USES_APPLE_RST +DIAG_ON_DEPRECATION #endif /* HAVE_LIBCRYPTO */