From: Denis Ovsienko Date: Sat, 3 Oct 2020 14:29:02 +0000 (+0100) Subject: UDLD: Refine and modernize the code. X-Git-Tag: tcpdump-4.99-bp~152 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/44a89a1d70ed0459556ea1a2b09b5848b4fc793c UDLD: Refine and modernize the code. Enable ND_LONGJMP_FROM_TCHECK. Lose a local variable, instead modify the provided pointer and length in sync and always fetch one field at a time. When the packet is declard too short, report it as invalid, not truncated (it may turn out truncated soon thereafter though). Use a named constant. When not decoding the packet completely (whether invalid or not), still check that it is fully within the snapshot. When decoding it completely, add checks at the beginng of the iteration to test that both the TL and the V fit into the remaining part of the declared packet. Move an ND_TCHECK_LEN() into the default case to let the string printing functions guard the snapshot end. Do not declare the remainder of the packet invalid on TLV type 0, as RFC 5171 Section 6 says: "If an implementation does not understand a Type value, it should skip over it using the length field." --- diff --git a/print-udld.c b/print-udld.c index d17e660b..37e36d6b 100644 --- a/print-udld.c +++ b/print-udld.c @@ -25,11 +25,13 @@ #include "netdissect-stdinc.h" +#define ND_LONGJMP_FROM_TCHECK #include "netdissect.h" #include "extract.h" #define UDLD_HEADER_LEN 4 +#define UDLD_TLV_HEADER_LEN 4 #define UDLD_DEVICE_ID_TLV 0x0001 #define UDLD_PORT_ID_TLV 0x0002 #define UDLD_ECHO_TLV 0x0003 @@ -99,60 +101,68 @@ static const struct tok udld_flags_bitmap_str[] = { #define UDLD_EXTRACT_OPCODE(x) ((x)&0x1f) void -udld_print(netdissect_options *ndo, const u_char *pptr, u_int length) +udld_print(netdissect_options *ndo, + const u_char *tptr, u_int length) { - int code, type, len; - const u_char *tptr; + uint8_t ver, code, flags; ndo->ndo_protocol = "udld"; if (length < UDLD_HEADER_LEN) - goto trunc; - - tptr = pptr; - - ND_TCHECK_LEN(tptr, UDLD_HEADER_LEN); + goto invalid; + ver = UDLD_EXTRACT_VERSION(GET_U_1(tptr)); code = UDLD_EXTRACT_OPCODE(GET_U_1(tptr)); + tptr += 1; + length -= 1; + + flags = GET_U_1(tptr); + tptr += 1; + length -= 1; ND_PRINT("UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u", - UDLD_EXTRACT_VERSION(GET_U_1(tptr)), + ver, tok2str(udld_code_values, "Reserved", code), code, - bittok2str(udld_flags_bitmap_str, "none", GET_U_1((tptr + 1))), - GET_U_1((tptr + 1)), - length); + bittok2str(udld_flags_bitmap_str, "none", flags), + flags, + length + 2); /* * In non-verbose mode, just print version and opcode type */ if (ndo->ndo_vflag < 1) { - return; + goto tcheck_remainder; } - ND_PRINT("\n\tChecksum 0x%04x (unverified)", GET_BE_U_2(tptr + 2)); + ND_PRINT("\n\tChecksum 0x%04x (unverified)", GET_BE_U_2(tptr)); + tptr += 2; + length -= 2; - tptr += UDLD_HEADER_LEN; + while (length) { + uint16_t type, len; - while (tptr < (pptr+length)) { + if (length < UDLD_TLV_HEADER_LEN) + goto invalid; type = GET_BE_U_2(tptr); - len = GET_BE_U_2(tptr + 2); + tptr += 2; + length -= 2; + + len = GET_BE_U_2(tptr); + tptr += 2; + length -= 2; ND_PRINT("\n\t%s (0x%04x) TLV, length %u", tok2str(udld_tlv_values, "Unknown", type), type, len); - if (type == 0) - goto invalid; - /* infinite loop check */ - if (len <= 4) + if (len <= UDLD_TLV_HEADER_LEN) goto invalid; - len -= 4; - tptr += 4; - - ND_TCHECK_LEN(tptr, len); + len -= UDLD_TLV_HEADER_LEN; + if (length < len) + goto invalid; switch (type) { case UDLD_DEVICE_ID_TLV: @@ -181,16 +191,17 @@ udld_print(netdissect_options *ndo, const u_char *pptr, u_int length) break; default: + ND_TCHECK_LEN(tptr, len); break; } tptr += len; + length -= len; } return; invalid: nd_print_invalid(ndo); - return; -trunc: - nd_print_trunc(ndo); +tcheck_remainder: + ND_TCHECK_LEN(tptr, length); }