From a41ce5f64640dfe3f697d2ff1f3c86ec91b5c5b0 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Thu, 20 Nov 2014 09:47:49 +0100 Subject: [PATCH] Fix for CVE-2014-8769 Resolves: #1165162 --- ...l-bounds-check-get-rid-of-union-aodv.patch | 516 +++++++++++++++++ 0012-Clean-up-error-message-printing.patch | 190 +++++++ 0013-Further-cleanups.patch | 524 ++++++++++++++++++ ...tof-any-more-so-no-need-for-stddef.h.patch | 26 + ...oo-long-unreachable-destination-list.patch | 81 +++ tcpdump.spec | 10 +- 6 files changed, 1345 insertions(+), 2 deletions(-) create mode 100644 0011-Add-initial-bounds-check-get-rid-of-union-aodv.patch create mode 100644 0012-Clean-up-error-message-printing.patch create mode 100644 0013-Further-cleanups.patch create mode 100644 0014-Not-using-offsetof-any-more-so-no-need-for-stddef.h.patch create mode 100644 0015-Report-a-too-long-unreachable-destination-list.patch diff --git a/0011-Add-initial-bounds-check-get-rid-of-union-aodv.patch b/0011-Add-initial-bounds-check-get-rid-of-union-aodv.patch new file mode 100644 index 0000000..a7ce9e4 --- /dev/null +++ b/0011-Add-initial-bounds-check-get-rid-of-union-aodv.patch @@ -0,0 +1,516 @@ +From ab4e52b94aac6cb729a5a695aa612d5ebda2ec3a Mon Sep 17 00:00:00 2001 +From: Guy Harris +Date: Tue, 11 Nov 2014 17:24:12 -0800 +Subject: [PATCH] Add initial bounds check, get rid of union aodv. + +Fetch the type field without using a structure, and check to make sure +it's not past the end of the packet. + +Pass to each dissection routine a pointer to the appropriate message +type structure, rather than a pointer to a union of all the message type +structures. +--- + print-aodv.c | 274 ++++++++++++++++++++++++++++------------------------------- + 1 file changed, 130 insertions(+), 144 deletions(-) + +diff --git a/print-aodv.c b/print-aodv.c +index 093e174..da5b169 100644 +--- a/print-aodv.c ++++ b/print-aodv.c +@@ -163,19 +163,6 @@ struct aodv_rrep_ack { + uint8_t ra_zero0; + }; + +-union aodv { +- struct aodv_rreq rreq; +- struct aodv_rrep rrep; +- struct aodv_rerr rerr; +- struct aodv_rrep_ack rrep_ack; +-#ifdef INET6 +- struct aodv_rreq6 rreq6; +- struct aodv_rreq6_draft_01 rreq6_draft_01; +- struct aodv_rrep6 rrep6; +- struct aodv_rrep6_draft_01 rrep6_draft_01; +-#endif +-}; +- + #define AODV_RREQ 1 /* route request */ + #define AODV_RREP 2 /* route response */ + #define AODV_RERR 3 /* error report */ +@@ -232,7 +219,7 @@ aodv_extension(netdissect_options *ndo, + + static void + aodv_rreq(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rreq *ap, const u_char *dat, u_int length) + { + u_int i; + +@@ -241,31 +228,31 @@ aodv_rreq(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rreq)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rreq]")); + return; + } +- i -= sizeof(ap->rreq); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, +- ap->rreq.rreq_type & RREQ_JOIN ? "[J]" : "", +- ap->rreq.rreq_type & RREQ_REPAIR ? "[R]" : "", +- ap->rreq.rreq_type & RREQ_GRAT ? "[G]" : "", +- ap->rreq.rreq_type & RREQ_DEST ? "[D]" : "", +- ap->rreq.rreq_type & RREQ_UNKNOWN ? "[U] " : " ", +- ap->rreq.rreq_hops, +- (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_id), +- ipaddr_string(ndo, &ap->rreq.rreq_da), +- (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_ds), +- ipaddr_string(ndo, &ap->rreq.rreq_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_os))); ++ ap->rreq_type & RREQ_JOIN ? "[J]" : "", ++ ap->rreq_type & RREQ_REPAIR ? "[R]" : "", ++ ap->rreq_type & RREQ_GRAT ? "[G]" : "", ++ ap->rreq_type & RREQ_DEST ? "[D]" : "", ++ ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", ++ ap->rreq_hops, ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_id), ++ ipaddr_string(ndo, &ap->rreq_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), ++ ipaddr_string(ndo, &ap->rreq_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rreq + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + } + + static void + aodv_rrep(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rrep *ap, const u_char *dat, u_int length) + { + u_int i; + +@@ -274,28 +261,28 @@ aodv_rrep(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rrep)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rrep]")); + return; + } +- i -= sizeof(ap->rrep); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, +- ap->rrep.rrep_type & RREP_REPAIR ? "[R]" : "", +- ap->rrep.rrep_type & RREP_ACK ? "[A] " : " ", +- ap->rrep.rrep_ps & RREP_PREFIX_MASK, +- ap->rrep.rrep_hops, +- ipaddr_string(ndo, &ap->rrep.rrep_da), +- (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_ds), +- ipaddr_string(ndo, &ap->rrep.rrep_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_life))); ++ ap->rrep_type & RREP_REPAIR ? "[R]" : "", ++ ap->rrep_type & RREP_ACK ? "[A] " : " ", ++ ap->rrep_ps & RREP_PREFIX_MASK, ++ ap->rrep_hops, ++ ipaddr_string(ndo, &ap->rrep_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), ++ ipaddr_string(ndo, &ap->rrep_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rrep + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + } + + static void + aodv_rerr(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rerr *ap, const u_char *dat, u_int length) + { + u_int i; + const struct rerr_unreach *dp = NULL; +@@ -311,14 +298,14 @@ aodv_rerr(netdissect_options *ndo, + return; + } + i -= offsetof(struct aodv_rerr, r); +- dp = &ap->rerr.r.dest[0]; +- n = ap->rerr.rerr_dc * sizeof(ap->rerr.r.dest[0]); ++ dp = &ap->r.dest[0]; ++ n = ap->rerr_dc * sizeof(ap->r.dest[0]); + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", +- ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "", +- ap->rerr.rerr_dc, length)); +- trunc = n - (i/sizeof(ap->rerr.r.dest[0])); +- for (; i >= sizeof(ap->rerr.r.dest[0]); +- ++dp, i -= sizeof(ap->rerr.r.dest[0])) { ++ ap->rerr_flags & RERR_NODELETE ? "[D]" : "", ++ ap->rerr_dc, length)); ++ trunc = n - (i/sizeof(ap->r.dest[0])); ++ for (; i >= sizeof(ap->r.dest[0]); ++ ++dp, i -= sizeof(ap->r.dest[0])) { + ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), + (unsigned long)EXTRACT_32BITS(&dp->u_ds))); + } +@@ -329,10 +316,10 @@ aodv_rerr(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_rreq(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rreq6 *ap, const u_char *dat, u_int length) + #else + aodv_v6_rreq(netdissect_options *ndo, +- const union aodv *ap _U_, const u_char *dat _U_, u_int length) ++ const struct aodv_rreq6 *ap _U_, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -343,26 +330,26 @@ aodv_v6_rreq(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rreq6)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rreq6]")); + return; + } +- i -= sizeof(ap->rreq6); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, +- ap->rreq6.rreq_type & RREQ_JOIN ? "[J]" : "", +- ap->rreq6.rreq_type & RREQ_REPAIR ? "[R]" : "", +- ap->rreq6.rreq_type & RREQ_GRAT ? "[G]" : "", +- ap->rreq6.rreq_type & RREQ_DEST ? "[D]" : "", +- ap->rreq6.rreq_type & RREQ_UNKNOWN ? "[U] " : " ", +- ap->rreq6.rreq_hops, +- (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_id), +- ip6addr_string(ndo, &ap->rreq6.rreq_da), +- (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_ds), +- ip6addr_string(ndo, &ap->rreq6.rreq_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_os))); ++ ap->rreq_type & RREQ_JOIN ? "[J]" : "", ++ ap->rreq_type & RREQ_REPAIR ? "[R]" : "", ++ ap->rreq_type & RREQ_GRAT ? "[G]" : "", ++ ap->rreq_type & RREQ_DEST ? "[D]" : "", ++ ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", ++ ap->rreq_hops, ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_id), ++ ip6addr_string(ndo, &ap->rreq_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), ++ ip6addr_string(ndo, &ap->rreq_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rreq6 + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + #else + ND_PRINT((ndo, " v6 rreq %u", length)); + #endif +@@ -371,10 +358,10 @@ aodv_v6_rreq(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_rrep(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rrep6 *ap, const u_char *dat, u_int length) + #else + aodv_v6_rrep(netdissect_options *ndo, +- const union aodv *ap _U_, const u_char *dat _U_, u_int length) ++ const struct aodv_rrep6 *ap _U_, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -385,23 +372,23 @@ aodv_v6_rrep(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rrep6)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rrep6]")); + return; + } +- i -= sizeof(ap->rrep6); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, +- ap->rrep6.rrep_type & RREP_REPAIR ? "[R]" : "", +- ap->rrep6.rrep_type & RREP_ACK ? "[A] " : " ", +- ap->rrep6.rrep_ps & RREP_PREFIX_MASK, +- ap->rrep6.rrep_hops, +- ip6addr_string(ndo, &ap->rrep6.rrep_da), +- (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_ds), +- ip6addr_string(ndo, &ap->rrep6.rrep_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_life))); ++ ap->rrep_type & RREP_REPAIR ? "[R]" : "", ++ ap->rrep_type & RREP_ACK ? "[A] " : " ", ++ ap->rrep_ps & RREP_PREFIX_MASK, ++ ap->rrep_hops, ++ ip6addr_string(ndo, &ap->rrep_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), ++ ip6addr_string(ndo, &ap->rrep_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rrep6 + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + #else + ND_PRINT((ndo, " rrep %u", length)); + #endif +@@ -410,10 +397,10 @@ aodv_v6_rrep(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_rerr(netdissect_options *ndo, +- const union aodv *ap, u_int length) ++ const struct aodv_rerr *ap, u_int length) + #else + aodv_v6_rerr(netdissect_options *ndo, +- const union aodv *ap _U_, u_int length) ++ const struct aodv_rerr *ap _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -421,12 +408,12 @@ aodv_v6_rerr(netdissect_options *ndo, + int i, j, n, trunc; + + i = length - offsetof(struct aodv_rerr, r); +- j = sizeof(ap->rerr.r.dest6[0]); +- dp6 = &ap->rerr.r.dest6[0]; +- n = ap->rerr.rerr_dc * j; ++ j = sizeof(ap->r.dest6[0]); ++ dp6 = &ap->r.dest6[0]; ++ n = ap->rerr_dc * j; + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", +- ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "", +- ap->rerr.rerr_dc, length)); ++ ap->rerr_flags & RERR_NODELETE ? "[D]" : "", ++ ap->rerr_dc, length)); + trunc = n - (i/j); + for (; i -= j >= 0; ++dp6) { + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), +@@ -442,11 +429,10 @@ aodv_v6_rerr(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_draft_01_rreq(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rreq6_draft_01 *ap, const u_char *dat, u_int length) + #else + aodv_v6_draft_01_rreq(netdissect_options *ndo, +- const union aodv *ap _U_, const u_char *dat _U_, +- u_int length) ++ const struct aodv_rreq6_draft_01 *ap _U_, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -457,26 +443,26 @@ aodv_v6_draft_01_rreq(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rreq6_draft_01)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rreq6]")); + return; + } +- i -= sizeof(ap->rreq6_draft_01); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, +- ap->rreq6_draft_01.rreq_type & RREQ_JOIN ? "[J]" : "", +- ap->rreq6_draft_01.rreq_type & RREQ_REPAIR ? "[R]" : "", +- ap->rreq6_draft_01.rreq_type & RREQ_GRAT ? "[G]" : "", +- ap->rreq6_draft_01.rreq_type & RREQ_DEST ? "[D]" : "", +- ap->rreq6_draft_01.rreq_type & RREQ_UNKNOWN ? "[U] " : " ", +- ap->rreq6_draft_01.rreq_hops, +- (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_id), +- ip6addr_string(ndo, &ap->rreq6_draft_01.rreq_da), +- (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_ds), +- ip6addr_string(ndo, &ap->rreq6_draft_01.rreq_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_os))); ++ ap->rreq_type & RREQ_JOIN ? "[J]" : "", ++ ap->rreq_type & RREQ_REPAIR ? "[R]" : "", ++ ap->rreq_type & RREQ_GRAT ? "[G]" : "", ++ ap->rreq_type & RREQ_DEST ? "[D]" : "", ++ ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ", ++ ap->rreq_hops, ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_id), ++ ip6addr_string(ndo, &ap->rreq_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), ++ ip6addr_string(ndo, &ap->rreq_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rreq6_draft_01 + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + #else + ND_PRINT((ndo, " rreq %u", length)); + #endif +@@ -485,11 +471,10 @@ aodv_v6_draft_01_rreq(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_draft_01_rrep(netdissect_options *ndo, +- const union aodv *ap, const u_char *dat, u_int length) ++ const struct aodv_rrep6_draft_01 *ap, const u_char *dat, u_int length) + #else + aodv_v6_draft_01_rrep(netdissect_options *ndo, +- const union aodv *ap _U_, const u_char *dat _U_, +- u_int length) ++ const struct aodv_rrep6_draft_01 *ap _U_, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -500,23 +485,23 @@ aodv_v6_draft_01_rrep(netdissect_options *ndo, + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(ap->rrep6_draft_01)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rrep6]")); + return; + } +- i -= sizeof(ap->rrep6_draft_01); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, +- ap->rrep6_draft_01.rrep_type & RREP_REPAIR ? "[R]" : "", +- ap->rrep6_draft_01.rrep_type & RREP_ACK ? "[A] " : " ", +- ap->rrep6_draft_01.rrep_ps & RREP_PREFIX_MASK, +- ap->rrep6_draft_01.rrep_hops, +- ip6addr_string(ndo, &ap->rrep6_draft_01.rrep_da), +- (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_ds), +- ip6addr_string(ndo, &ap->rrep6_draft_01.rrep_oa), +- (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_life))); ++ ap->rrep_type & RREP_REPAIR ? "[R]" : "", ++ ap->rrep_type & RREP_ACK ? "[A] " : " ", ++ ap->rrep_ps & RREP_PREFIX_MASK, ++ ap->rrep_hops, ++ ip6addr_string(ndo, &ap->rrep_da), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), ++ ip6addr_string(ndo, &ap->rrep_oa), ++ (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(&ap->rrep6_draft_01 + 1), i); ++ aodv_extension(ndo, (void *)(ap + 1), i); + #else + ND_PRINT((ndo, " rrep %u", length)); + #endif +@@ -525,10 +510,10 @@ aodv_v6_draft_01_rrep(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const union aodv *ap, u_int length) ++ const struct aodv_rerr *ap, u_int length) + #else + aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const union aodv *ap _U_, u_int length) ++ const struct aodv_rerr *ap _U_, u_int length) + #endif + { + #ifdef INET6 +@@ -536,12 +521,12 @@ aodv_v6_draft_01_rerr(netdissect_options *ndo, + int i, j, n, trunc; + + i = length - offsetof(struct aodv_rerr, r); +- j = sizeof(ap->rerr.r.dest6_draft_01[0]); +- dp6 = &ap->rerr.r.dest6_draft_01[0]; +- n = ap->rerr.rerr_dc * j; ++ j = sizeof(ap->r.dest6_draft_01[0]); ++ dp6 = &ap->r.dest6_draft_01[0]; ++ n = ap->rerr_dc * j; + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", +- ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "", +- ap->rerr.rerr_dc, length)); ++ ap->rerr_flags & RERR_NODELETE ? "[D]" : "", ++ ap->rerr_dc, length)); + trunc = n - (i/j); + for (; i -= j >= 0; ++dp6) { + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), +@@ -558,40 +543,37 @@ void + aodv_print(netdissect_options *ndo, + const u_char *dat, u_int length, int is_ip6) + { +- const union aodv *ap; +- +- ap = (union aodv *)dat; +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- if (min(length, (u_int)(ndo->ndo_snapend - dat)) < sizeof(ap->rrep_ack)) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } ++ uint8_t msg_type; ++ ++ /* ++ * The message type is the first byte; make sure we have it ++ * and then fetch it. ++ */ ++ ND_TCHECK(*dat); ++ msg_type = *dat; + ND_PRINT((ndo, " aodv")); + +- switch (ap->rerr.rerr_type) { ++ switch (msg_type) { + + case AODV_RREQ: + if (is_ip6) +- aodv_v6_rreq(ndo, ap, dat, length); ++ aodv_v6_rreq(ndo, (const struct aodv_rreq6 *)dat, dat, length); + else +- aodv_rreq(ndo, ap, dat, length); ++ aodv_rreq(ndo, (const struct aodv_rreq *)dat, dat, length); + break; + + case AODV_RREP: + if (is_ip6) +- aodv_v6_rrep(ndo, ap, dat, length); ++ aodv_v6_rrep(ndo, (const struct aodv_rrep6 *)dat, dat, length); + else +- aodv_rrep(ndo, ap, dat, length); ++ aodv_rrep(ndo, (const struct aodv_rrep *)dat, dat, length); + break; + + case AODV_RERR: + if (is_ip6) +- aodv_v6_rerr(ndo, ap, length); ++ aodv_v6_rerr(ndo, (const struct aodv_rerr *)dat, length); + else +- aodv_rerr(ndo, ap, dat, length); ++ aodv_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); + break; + + case AODV_RREP_ACK: +@@ -599,15 +581,15 @@ aodv_print(netdissect_options *ndo, + break; + + case AODV_V6_DRAFT_01_RREQ: +- aodv_v6_draft_01_rreq(ndo, ap, dat, length); ++ aodv_v6_draft_01_rreq(ndo, (const struct aodv_rreq6_draft_01 *)dat, dat, length); + break; + + case AODV_V6_DRAFT_01_RREP: +- aodv_v6_draft_01_rrep(ndo, ap, dat, length); ++ aodv_v6_draft_01_rrep(ndo, (const struct aodv_rrep6_draft_01 *)dat, dat, length); + break; + + case AODV_V6_DRAFT_01_RERR: +- aodv_v6_draft_01_rerr(ndo, ap, length); ++ aodv_v6_draft_01_rerr(ndo, (const struct aodv_rerr *)dat, length); + break; + + case AODV_V6_DRAFT_01_RREP_ACK: +@@ -615,6 +597,10 @@ aodv_print(netdissect_options *ndo, + break; + + default: +- ND_PRINT((ndo, " %u %u", ap->rreq.rreq_type, length)); ++ ND_PRINT((ndo, " type %u %u", msg_type, length)); + } ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|aodv]")); + } +-- +1.8.3.1 + diff --git a/0012-Clean-up-error-message-printing.patch b/0012-Clean-up-error-message-printing.patch new file mode 100644 index 0000000..02d8958 --- /dev/null +++ b/0012-Clean-up-error-message-printing.patch @@ -0,0 +1,190 @@ +From 3e8a443c3671baa37ae7870f08fb9b4bf386fd24 Mon Sep 17 00:00:00 2001 +From: Guy Harris +Date: Tue, 11 Nov 2014 18:37:35 -0800 +Subject: [PATCH 1/4] Clean up error message printing. + +Have "struct aodv_rerr" just be the header, not including the actual +destinations. + +Simplify the logic somewhat, and make it similar in the print routines +for the three types of error messages. +--- + print-aodv.c | 88 +++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 46 insertions(+), 42 deletions(-) + +diff --git a/print-aodv.c b/print-aodv.c +index da5b169..da26473 100644 +--- a/print-aodv.c ++++ b/print-aodv.c +@@ -146,13 +146,6 @@ struct aodv_rerr { + uint8_t rerr_flags; /* various flags */ + uint8_t rerr_zero0; /* reserved, set to zero */ + uint8_t rerr_dc; /* destination count */ +- union { +- struct rerr_unreach dest[1]; +-#ifdef INET6 +- struct rerr_unreach6 dest6[1]; +- struct rerr_unreach6_draft_01 dest6_draft_01[1]; +-#endif +- } r; + }; + + #define RERR_NODELETE 0x80 /* don't delete the link */ +@@ -284,32 +277,29 @@ static void + aodv_rerr(netdissect_options *ndo, + const struct aodv_rerr *ap, const u_char *dat, u_int length) + { +- u_int i; +- const struct rerr_unreach *dp = NULL; +- int n, trunc; ++ u_int i, dc; ++ const struct rerr_unreach *dp; + + if (ndo->ndo_snapend < dat) { + ND_PRINT((ndo, " [|aodv]")); + return; + } + i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < offsetof(struct aodv_rerr, r)) { ++ if (i < sizeof(*ap)) { + ND_PRINT((ndo, " [|rerr]")); + return; + } +- i -= offsetof(struct aodv_rerr, r); +- dp = &ap->r.dest[0]; +- n = ap->rerr_dc * sizeof(ap->r.dest[0]); ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); +- trunc = n - (i/sizeof(ap->r.dest[0])); +- for (; i >= sizeof(ap->r.dest[0]); +- ++dp, i -= sizeof(ap->r.dest[0])) { ++ dp = (struct rerr_unreach *)(void *)(ap + 1); ++ for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp); ++ ++dp, --dc, i -= sizeof(*dp)) { + ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), + (unsigned long)EXTRACT_32BITS(&dp->u_ds))); + } +- if (trunc) ++ if ((i % sizeof(*dp)) != 0) + ND_PRINT((ndo, "[|rerr]")); + } + +@@ -397,29 +387,36 @@ aodv_v6_rrep(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap, u_int length) ++ const struct aodv_rerr *ap, const u_char *dat, u_int length) + #else + aodv_v6_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap _U_, u_int length) ++ const struct aodv_rerr *ap _U_, const u_char *dat, u_int length) + #endif + { + #ifdef INET6 +- const struct rerr_unreach6 *dp6 = NULL; +- int i, j, n, trunc; ++ u_int i, dc; ++ const struct rerr_unreach6 *dp6; + +- i = length - offsetof(struct aodv_rerr, r); +- j = sizeof(ap->r.dest6[0]); +- dp6 = &ap->r.dest6[0]; +- n = ap->rerr_dc * j; ++ if (ndo->ndo_snapend < dat) { ++ ND_PRINT((ndo, " [|aodv]")); ++ return; ++ } ++ i = min(length, (u_int)(ndo->ndo_snapend - dat)); ++ if (i < sizeof(*ap)) { ++ ND_PRINT((ndo, " [|rerr]")); ++ return; ++ } ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); +- trunc = n - (i/j); +- for (; i -= j >= 0; ++dp6) { ++ dp6 = (struct rerr_unreach6 *)(void *)(ap + 1); ++ for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); ++ ++dp6, --dc, i -= sizeof(*dp6)) { + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); + } +- if (trunc) ++ if ((i % sizeof(*dp6)) != 0) + ND_PRINT((ndo, "[|rerr]")); + #else + ND_PRINT((ndo, " rerr %u", length)); +@@ -510,29 +507,36 @@ aodv_v6_draft_01_rrep(netdissect_options *ndo, + static void + #ifdef INET6 + aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap, u_int length) ++ const struct aodv_rerr *ap, const u_char *dat, u_int length) + #else + aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap _U_, u_int length) ++ const struct aodv_rerr *ap _U_, const u_char *dat, u_int length) + #endif + { + #ifdef INET6 +- const struct rerr_unreach6_draft_01 *dp6 = NULL; +- int i, j, n, trunc; ++ u_int i, dc; ++ const struct rerr_unreach6_draft_01 *dp6; + +- i = length - offsetof(struct aodv_rerr, r); +- j = sizeof(ap->r.dest6_draft_01[0]); +- dp6 = &ap->r.dest6_draft_01[0]; +- n = ap->rerr_dc * j; ++ if (ndo->ndo_snapend < dat) { ++ ND_PRINT((ndo, " [|aodv]")); ++ return; ++ } ++ i = min(length, (u_int)(ndo->ndo_snapend - dat)); ++ if (i < sizeof(*ap)) { ++ ND_PRINT((ndo, " [|rerr]")); ++ return; ++ } ++ i -= sizeof(*ap); + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); +- trunc = n - (i/j); +- for (; i -= j >= 0; ++dp6) { ++ dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1); ++ for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); ++ ++dp6, --dc, i -= sizeof(*dp6)) { + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); + } +- if (trunc) ++ if ((i % sizeof(*dp6)) != 0) + ND_PRINT((ndo, "[|rerr]")); + #else + ND_PRINT((ndo, " rerr %u", length)); +@@ -571,7 +575,7 @@ aodv_print(netdissect_options *ndo, + + case AODV_RERR: + if (is_ip6) +- aodv_v6_rerr(ndo, (const struct aodv_rerr *)dat, length); ++ aodv_v6_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); + else + aodv_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); + break; +@@ -589,7 +593,7 @@ aodv_print(netdissect_options *ndo, + break; + + case AODV_V6_DRAFT_01_RERR: +- aodv_v6_draft_01_rerr(ndo, (const struct aodv_rerr *)dat, length); ++ aodv_v6_draft_01_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); + break; + + case AODV_V6_DRAFT_01_RREP_ACK: +-- +1.8.3.1 + diff --git a/0013-Further-cleanups.patch b/0013-Further-cleanups.patch new file mode 100644 index 0000000..1b8c653 --- /dev/null +++ b/0013-Further-cleanups.patch @@ -0,0 +1,524 @@ +From e302ff0e4a6bde6915bee1c89373aa14c823dd60 Mon Sep 17 00:00:00 2001 +From: Guy Harris +Date: Tue, 11 Nov 2014 19:05:48 -0800 +Subject: [PATCH 2/4] Further cleanups. + +Use ND_TCHECK() rather than home-brew bounds checks. Do simpler length +checks. + +Let i be the length of the actual remaining packet data; use ND_TCHECK() +inside loops that iterate over the remaining data. + +Let the printers for particular message types cast the raw data pointer +to a pointer of the appropriate type, rather than passing two pointers, +with different types, to the same data. +--- + print-aodv.c | 277 +++++++++++++++++++++++++++-------------------------------- + 1 file changed, 126 insertions(+), 151 deletions(-) + +diff --git a/print-aodv.c b/print-aodv.c +index da26473..2649936 100644 +--- a/print-aodv.c ++++ b/print-aodv.c +@@ -184,22 +184,14 @@ static void + aodv_extension(netdissect_options *ndo, + const struct aodv_ext *ep, u_int length) + { +- u_int i; + const struct aodv_hello *ah; + + switch (ep->type) { + case AODV_EXT_HELLO: +- if (ndo->ndo_snapend < (u_char *) ep) { +- ND_PRINT((ndo, " [|hello]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - (u_char *)ep)); +- if (i < sizeof(struct aodv_hello)) { +- ND_PRINT((ndo, " [|hello]")); +- return; +- } +- i -= sizeof(struct aodv_hello); +- ah = (void *)ep; ++ ah = (const struct aodv_hello *)(const void *)ep; ++ ND_TCHECK(*ah); ++ if (length < sizeof(struct aodv_hello)) ++ goto trunc; + ND_PRINT((ndo, "\n\text HELLO %ld ms", + (unsigned long)EXTRACT_32BITS(&ah->interval))); + break; +@@ -208,24 +200,21 @@ aodv_extension(netdissect_options *ndo, + ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length)); + break; + } ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|hello]")); + } + + static void +-aodv_rreq(netdissect_options *ndo, +- const struct aodv_rreq *ap, const u_char *dat, u_int length) ++aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length) + { + u_int i; ++ const struct aodv_rreq *ap = (const struct aodv_rreq *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rreq]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, + ap->rreq_type & RREQ_JOIN ? "[J]" : "", +@@ -239,26 +228,24 @@ aodv_rreq(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), + ipaddr_string(ndo, &ap->rreq_oa), + (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + } + + static void +-aodv_rrep(netdissect_options *ndo, +- const struct aodv_rrep *ap, const u_char *dat, u_int length) ++aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length) + { + u_int i; ++ const struct aodv_rrep *ap = (const struct aodv_rrep *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rrep]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, + ap->rrep_type & RREP_REPAIR ? "[R]" : "", +@@ -269,62 +256,58 @@ aodv_rrep(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), + ipaddr_string(ndo, &ap->rrep_oa), + (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + } + + static void +-aodv_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap, const u_char *dat, u_int length) ++aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) + { + u_int i, dc; ++ const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; + const struct rerr_unreach *dp; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rerr]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); +- dp = (struct rerr_unreach *)(void *)(ap + 1); ++ dp = (struct rerr_unreach *)(dat + sizeof(*ap)); ++ i = length - sizeof(*ap); + for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp); + ++dp, --dc, i -= sizeof(*dp)) { ++ ND_TCHECK(*dp); + ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), + (unsigned long)EXTRACT_32BITS(&dp->u_ds))); + } + if ((i % sizeof(*dp)) != 0) +- ND_PRINT((ndo, "[|rerr]")); ++ goto trunc; ++ return; ++ ++trunc: ++ ND_PRINT((ndo, "[|rerr]")); + } + + static void + #ifdef INET6 +-aodv_v6_rreq(netdissect_options *ndo, +- const struct aodv_rreq6 *ap, const u_char *dat, u_int length) ++aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_rreq(netdissect_options *ndo, +- const struct aodv_rreq6 *ap _U_, const u_char *dat _U_, u_int length) ++aodv_v6_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i; ++ const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rreq6]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, + ap->rreq_type & RREQ_JOIN ? "[J]" : "", +@@ -338,8 +321,13 @@ aodv_v6_rreq(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), + ip6addr_string(ndo, &ap->rreq_oa), + (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + #else + ND_PRINT((ndo, " v6 rreq %u", length)); + #endif +@@ -347,26 +335,18 @@ aodv_v6_rreq(netdissect_options *ndo, + + static void + #ifdef INET6 +-aodv_v6_rrep(netdissect_options *ndo, +- const struct aodv_rrep6 *ap, const u_char *dat, u_int length) ++aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_rrep(netdissect_options *ndo, +- const struct aodv_rrep6 *ap _U_, const u_char *dat _U_, u_int length) ++aodv_v6_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i; ++ const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rrep6]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, + ap->rrep_type & RREP_REPAIR ? "[R]" : "", +@@ -377,8 +357,13 @@ aodv_v6_rrep(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), + ip6addr_string(ndo, &ap->rrep_oa), + (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + #else + ND_PRINT((ndo, " rrep %u", length)); + #endif +@@ -386,38 +371,36 @@ aodv_v6_rrep(netdissect_options *ndo, + + static void + #ifdef INET6 +-aodv_v6_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap, const u_char *dat, u_int length) ++aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap _U_, const u_char *dat, u_int length) ++aodv_v6_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i, dc; ++ const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; + const struct rerr_unreach6 *dp6; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rerr]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); + dp6 = (struct rerr_unreach6 *)(void *)(ap + 1); ++ i = length - sizeof(*ap); + for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); + ++dp6, --dc, i -= sizeof(*dp6)) { ++ ND_TCHECK(*dp6); + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); + } + if ((i % sizeof(*dp6)) != 0) +- ND_PRINT((ndo, "[|rerr]")); ++ goto trunc; ++ return; ++ ++trunc: ++ ND_PRINT((ndo, "[|rerr]")); + #else + ND_PRINT((ndo, " rerr %u", length)); + #endif +@@ -425,26 +408,18 @@ aodv_v6_rerr(netdissect_options *ndo, + + static void + #ifdef INET6 +-aodv_v6_draft_01_rreq(netdissect_options *ndo, +- const struct aodv_rreq6_draft_01 *ap, const u_char *dat, u_int length) ++aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_draft_01_rreq(netdissect_options *ndo, +- const struct aodv_rreq6_draft_01 *ap _U_, const u_char *dat _U_, u_int length) ++aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i; ++ const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rreq6]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n" + "\tdst %s seq %lu src %s seq %lu", length, + ap->rreq_type & RREQ_JOIN ? "[J]" : "", +@@ -458,8 +433,13 @@ aodv_v6_draft_01_rreq(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rreq_ds), + ip6addr_string(ndo, &ap->rreq_oa), + (unsigned long)EXTRACT_32BITS(&ap->rreq_os))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + #else + ND_PRINT((ndo, " rreq %u", length)); + #endif +@@ -467,26 +447,18 @@ aodv_v6_draft_01_rreq(netdissect_options *ndo, + + static void + #ifdef INET6 +-aodv_v6_draft_01_rrep(netdissect_options *ndo, +- const struct aodv_rrep6_draft_01 *ap, const u_char *dat, u_int length) ++aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_draft_01_rrep(netdissect_options *ndo, +- const struct aodv_rrep6_draft_01 *ap _U_, const u_char *dat _U_, u_int length) ++aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i; ++ const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rrep6]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n" + "\tdst %s dseq %lu src %s %lu ms", length, + ap->rrep_type & RREP_REPAIR ? "[R]" : "", +@@ -497,8 +469,13 @@ aodv_v6_draft_01_rrep(netdissect_options *ndo, + (unsigned long)EXTRACT_32BITS(&ap->rrep_ds), + ip6addr_string(ndo, &ap->rrep_oa), + (unsigned long)EXTRACT_32BITS(&ap->rrep_life))); ++ i = length - sizeof(*ap); + if (i >= sizeof(struct aodv_ext)) +- aodv_extension(ndo, (void *)(ap + 1), i); ++ aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i); ++ return; ++ ++trunc: ++ ND_PRINT((ndo, " [|rreq")); + #else + ND_PRINT((ndo, " rrep %u", length)); + #endif +@@ -506,38 +483,36 @@ aodv_v6_draft_01_rrep(netdissect_options *ndo, + + static void + #ifdef INET6 +-aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap, const u_char *dat, u_int length) ++aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length) + #else +-aodv_v6_draft_01_rerr(netdissect_options *ndo, +- const struct aodv_rerr *ap _U_, const u_char *dat, u_int length) ++aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length) + #endif + { + #ifdef INET6 + u_int i, dc; ++ const struct aodv_rerr *ap = (const struct aodv_rerr *)dat; + const struct rerr_unreach6_draft_01 *dp6; + +- if (ndo->ndo_snapend < dat) { +- ND_PRINT((ndo, " [|aodv]")); +- return; +- } +- i = min(length, (u_int)(ndo->ndo_snapend - dat)); +- if (i < sizeof(*ap)) { +- ND_PRINT((ndo, " [|rerr]")); +- return; +- } +- i -= sizeof(*ap); ++ ND_TCHECK(*ap); ++ if (length < sizeof(*ap)) ++ goto trunc; + ND_PRINT((ndo, " rerr %s [items %u] [%u]:", + ap->rerr_flags & RERR_NODELETE ? "[D]" : "", + ap->rerr_dc, length)); + dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1); ++ i = length - sizeof(*ap); + for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); + ++dp6, --dc, i -= sizeof(*dp6)) { ++ ND_TCHECK(*dp6); + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); + } + if ((i % sizeof(*dp6)) != 0) +- ND_PRINT((ndo, "[|rerr]")); ++ goto trunc; ++ return; ++ ++trunc: ++ ND_PRINT((ndo, "[|rerr]")); + #else + ND_PRINT((ndo, " rerr %u", length)); + #endif +@@ -561,23 +536,23 @@ aodv_print(netdissect_options *ndo, + + case AODV_RREQ: + if (is_ip6) +- aodv_v6_rreq(ndo, (const struct aodv_rreq6 *)dat, dat, length); ++ aodv_v6_rreq(ndo, dat, length); + else +- aodv_rreq(ndo, (const struct aodv_rreq *)dat, dat, length); ++ aodv_rreq(ndo, dat, length); + break; + + case AODV_RREP: + if (is_ip6) +- aodv_v6_rrep(ndo, (const struct aodv_rrep6 *)dat, dat, length); ++ aodv_v6_rrep(ndo, dat, length); + else +- aodv_rrep(ndo, (const struct aodv_rrep *)dat, dat, length); ++ aodv_rrep(ndo, dat, length); + break; + + case AODV_RERR: + if (is_ip6) +- aodv_v6_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); ++ aodv_v6_rerr(ndo, dat, length); + else +- aodv_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); ++ aodv_rerr(ndo, dat, length); + break; + + case AODV_RREP_ACK: +@@ -585,15 +560,15 @@ aodv_print(netdissect_options *ndo, + break; + + case AODV_V6_DRAFT_01_RREQ: +- aodv_v6_draft_01_rreq(ndo, (const struct aodv_rreq6_draft_01 *)dat, dat, length); ++ aodv_v6_draft_01_rreq(ndo, dat, length); + break; + + case AODV_V6_DRAFT_01_RREP: +- aodv_v6_draft_01_rrep(ndo, (const struct aodv_rrep6_draft_01 *)dat, dat, length); ++ aodv_v6_draft_01_rrep(ndo, dat, length); + break; + + case AODV_V6_DRAFT_01_RERR: +- aodv_v6_draft_01_rerr(ndo, (const struct aodv_rerr *)dat, dat, length); ++ aodv_v6_draft_01_rerr(ndo, dat, length); + break; + + case AODV_V6_DRAFT_01_RREP_ACK: +-- +1.8.3.1 + diff --git a/0014-Not-using-offsetof-any-more-so-no-need-for-stddef.h.patch b/0014-Not-using-offsetof-any-more-so-no-need-for-stddef.h.patch new file mode 100644 index 0000000..3a33914 --- /dev/null +++ b/0014-Not-using-offsetof-any-more-so-no-need-for-stddef.h.patch @@ -0,0 +1,26 @@ +From 54d2912c19240a1a1866ba1519889086868038c4 Mon Sep 17 00:00:00 2001 +From: Guy Harris +Date: Tue, 11 Nov 2014 19:18:12 -0800 +Subject: [PATCH 3/4] Not using offsetof() any more, so no need for . + +--- + print-aodv.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/print-aodv.c b/print-aodv.c +index 2649936..9b3523a 100644 +--- a/print-aodv.c ++++ b/print-aodv.c +@@ -37,9 +37,6 @@ + + #include + +-/* for offsetof */ +-#include +- + #include "interface.h" + #include "addrtoname.h" + #include "extract.h" /* must come after interface.h */ +-- +1.8.3.1 + diff --git a/0015-Report-a-too-long-unreachable-destination-list.patch b/0015-Report-a-too-long-unreachable-destination-list.patch new file mode 100644 index 0000000..9a24a0b --- /dev/null +++ b/0015-Report-a-too-long-unreachable-destination-list.patch @@ -0,0 +1,81 @@ +From 3f5693a2bb783b1caa2a308e64ee34d167f36f05 Mon Sep 17 00:00:00 2001 +From: Guy Harris +Date: Wed, 12 Nov 2014 01:09:27 -0800 +Subject: [PATCH 4/4] Report a too-long unreachable destination list. + +Running out of packet length before running out of unreachable +destinations is an error; report it as such. + +Don't worry about leftover data past the end of the list of unreachable +destinations. +--- + print-aodv.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/print-aodv.c b/print-aodv.c +index 9b3523a..ef27eee 100644 +--- a/print-aodv.c ++++ b/print-aodv.c +@@ -277,14 +277,15 @@ aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length) + ap->rerr_dc, length)); + dp = (struct rerr_unreach *)(dat + sizeof(*ap)); + i = length - sizeof(*ap); +- for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp); +- ++dp, --dc, i -= sizeof(*dp)) { ++ for (dc = ap->rerr_dc; dc != 0; dc--) { + ND_TCHECK(*dp); ++ if (i < sizeof(*dp)) ++ goto trunc; + ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da), + (unsigned long)EXTRACT_32BITS(&dp->u_ds))); ++ dp++; ++ i -= sizeof(*dp); + } +- if ((i % sizeof(*dp)) != 0) +- goto trunc; + return; + + trunc: +@@ -386,14 +387,15 @@ aodv_v6_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length) + ap->rerr_dc, length)); + dp6 = (struct rerr_unreach6 *)(void *)(ap + 1); + i = length - sizeof(*ap); +- for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); +- ++dp6, --dc, i -= sizeof(*dp6)) { ++ for (dc = ap->rerr_dc; dc != 0; dc--) { + ND_TCHECK(*dp6); ++ if (i < sizeof(*dp6)) ++ goto trunc; + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); ++ dp6++; ++ i -= sizeof(*dp6); + } +- if ((i % sizeof(*dp6)) != 0) +- goto trunc; + return; + + trunc: +@@ -498,14 +500,15 @@ aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int leng + ap->rerr_dc, length)); + dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1); + i = length - sizeof(*ap); +- for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6); +- ++dp6, --dc, i -= sizeof(*dp6)) { ++ for (dc = ap->rerr_dc; dc != 0; dc--) { + ND_TCHECK(*dp6); ++ if (i < sizeof(*dp6)) ++ goto trunc; + ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da), + (unsigned long)EXTRACT_32BITS(&dp6->u_ds))); ++ dp6++; ++ i -= sizeof(*dp6); + } +- if ((i % sizeof(*dp6)) != 0) +- goto trunc; + return; + + trunc: +-- +1.8.3.1 + diff --git a/tcpdump.spec b/tcpdump.spec index 6fae5f9..46be859 100644 --- a/tcpdump.spec +++ b/tcpdump.spec @@ -2,7 +2,7 @@ Summary: A network traffic monitoring tool Name: tcpdump Epoch: 14 Version: 4.6.2 -Release: 1%{?dist} +Release: 2%{?dist} License: BSD with advertising URL: http://www.tcpdump.org Group: Applications/Internet @@ -22,6 +22,11 @@ Patch0007: 0007-Introduce-nn-option.patch Patch0008: 0008-Don-t-print-out-we-dropped-root-we-are-always-droppi.patch Patch0009: 0009-Do-more-bounds-checking-and-length-checking.patch Patch0010: 0010-Do-bounds-checking-and-length-checking.patch +Patch0011: 0011-Add-initial-bounds-check-get-rid-of-union-aodv.patch +Patch0012: 0012-Clean-up-error-message-printing.patch +Patch0013: 0013-Further-cleanups.patch +Patch0014: 0014-Not-using-offsetof-any-more-so-no-need-for-stddef.h.patch +Patch0015: 0015-Report-a-too-long-unreachable-destination-list.patch %define tcpslice_dir tcpslice-1.2a3 @@ -84,9 +89,10 @@ exit 0 %{_mandir}/man8/tcpdump.8* %changelog -* Thu Nov 20 2014 Michal Sekletar - 14:4.6.2-1 +* Thu Nov 20 2014 Michal Sekletar - 14:4.6.2-2 - fix for CVE-2014-8767 (#1165160) - fix for CVE-2014-8768 (#1165161) +- fix for CVE-2014-8769 (#1165162) * Mon Oct 20 2014 Michal Sekletar - 14:4.6.2-1 - update to 4.6.2 (#1124289)