diff options
author | Guy Harris <guy@alum.mit.edu> | 2003-05-15 06:35:02 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2003-05-15 06:35:02 +0000 |
commit | 64840abd9f877dc56d773fc1c3884dc1f171b249 (patch) | |
tree | 62e8683a46c2576f1d0a76fefa928be4923ff125 | |
parent | d4c805ad331e255f3ca267e3ff8b5913854c7de2 (diff) | |
download | wireshark-64840abd9f877dc56d773fc1c3884dc1f171b249.tar.gz wireshark-64840abd9f877dc56d773fc1c3884dc1f171b249.tar.bz2 wireshark-64840abd9f877dc56d773fc1c3884dc1f171b249.zip |
From Laurent Rabret:
fix a bug where bad IPv4 and IPv6 prefix lengths could cause a
buffer overflow;
check the checksum in LSP packets.
svn path=/trunk/; revision=7675
-rw-r--r-- | packet-isis-lsp.c | 58 | ||||
-rw-r--r-- | packet-osi.c | 97 | ||||
-rw-r--r-- | packet-osi.h | 3 |
3 files changed, 143 insertions, 15 deletions
diff --git a/packet-isis-lsp.c b/packet-isis-lsp.c index 4eafc949a9..b75ddf9867 100644 --- a/packet-isis-lsp.c +++ b/packet-isis-lsp.c @@ -1,7 +1,7 @@ /* packet-isis-lsp.c * Routines for decoding isis lsp packets and their CLVs * - * $Id: packet-isis-lsp.c,v 1.42 2003/04/29 16:57:05 guy Exp $ + * $Id: packet-isis-lsp.c,v 1.43 2003/05/15 06:35:02 guy Exp $ * Stuart Stanley <stuarts@mxmail.net> * * Ethereal - Network traffic analyzer @@ -55,6 +55,7 @@ static int hf_isis_lsp_hippity = -1; static int hf_isis_lsp_is_type = -1; static gint ett_isis_lsp = -1; +static gint ett_isis_lsp_checksum = -1; static gint ett_isis_lsp_info = -1; static gint ett_isis_lsp_att = -1; static gint ett_isis_lsp_clv_area_addr = -1; @@ -713,7 +714,12 @@ dissect_lsp_ext_ip_reachability_clv(tvbuff_t *tvb, proto_tree *tree, ctrl_info = tvb_get_guint8(tvb, offset+4); bit_length = ctrl_info & 0x3f; byte_length = (bit_length + 7) / 8; - tvb_memcpy (tvb, prefix, offset+5, byte_length); + if (byte_length > sizeof(prefix)) { + isis_dissect_unknown(tvb, tree, offset, + "IPv4 prefix has an invalid length: %d bytes", byte_length ); + return; + } + tvb_memcpy (tvb, prefix, offset+5, byte_length); metric = tvb_get_ntohl(tvb, offset); subclvs_len = 0; if ((ctrl_info & 0x40) != 0) @@ -806,13 +812,17 @@ dissect_lsp_ipv6_reachability_clv(tvbuff_t *tvb, proto_tree *tree, int offset, if (!tree) return; - memset (prefix.s6_addr, 0, 16); - while (length > 0) { + memset (prefix.s6_addr, 0, 16); ctrl_info = tvb_get_guint8(tvb, offset+4); bit_length = tvb_get_guint8(tvb, offset+5); byte_length = (bit_length + 7) / 8; - tvb_memcpy (tvb, prefix.s6_addr, offset+6, byte_length); + if (byte_length > sizeof(prefix)) { + isis_dissect_unknown(tvb, tree, offset, + "IPv6 prefix has an invalid length: %d bytes", byte_length ); + return; + } + tvb_memcpy (tvb, prefix.s6_addr, offset+6, byte_length); metric = tvb_get_ntohl(tvb, offset); subclvs_len = 0; if ((ctrl_info & 0x20) != 0) @@ -1753,11 +1763,11 @@ void isis_dissect_isis_lsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int lsp_type, int header_length, int id_length) { - proto_item *ti, *to, *ta; - proto_tree *lsp_tree = NULL, *info_tree, *att_tree; - guint16 pdu_length; + proto_item *ti, *to, *ta, *tc; + proto_tree *lsp_tree = NULL, *info_tree, *att_tree, *check_tree; + guint16 pdu_length, checksum, cacl_checksum=0; guint8 lsp_info, lsp_att; - int len; + int len, offset_checksum; if (tree) { ti = proto_tree_add_text(tree, tvb, offset, -1, @@ -1778,6 +1788,7 @@ isis_dissect_isis_lsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o tvb_get_ntohs(tvb, offset)); } offset += 2; + offset_checksum = offset; if (tree) { proto_tree_add_text(lsp_tree, tvb, offset, id_length + 2, @@ -1804,9 +1815,31 @@ isis_dissect_isis_lsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o offset += 4; if (tree) { - /* XXX -> we could validate the cksum here! */ - proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, tvb, - offset, 2, tvb_get_ntohs(tvb, offset)); + checksum = tvb_get_ntohs(tvb, offset); + tc = proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, tvb, offset, 2, tvb_get_ntohs(tvb, offset)); + check_tree = proto_item_add_subtree(tc, ett_isis_lsp_checksum); + + switch (check_and_get_checksum(tvb, offset_checksum, pdu_length-12, checksum, offset, &cacl_checksum)) { + case NO_CKSUM : + proto_tree_add_text(check_tree, tvb, offset, 2, + "Checksum control disabled"); + break; + case DATA_MISSING : + isis_dissect_unknown(tvb, tree, offset, + "packet length %d went beyond packet", + tvb_length_remaining(tvb, offset_checksum)); + break; + case CKSUM_NOT_OK : + proto_tree_add_text(check_tree, tvb, offset, 2, + "Checksum error: 0x%04x expected", cacl_checksum); + break; + case CKSUM_OK : + proto_tree_add_text(check_tree, tvb, offset, 2, + "Checksum OK"); + break; + default : + g_message("'check_and_get_checksum' returned an invalid value"); + } } offset += 2; @@ -1932,6 +1965,7 @@ isis_register_lsp(int proto_isis) { }; static gint *ett[] = { &ett_isis_lsp, + &ett_isis_lsp_checksum, &ett_isis_lsp_info, &ett_isis_lsp_att, &ett_isis_lsp_clv_area_addr, diff --git a/packet-osi.c b/packet-osi.c index c9782714e2..5f1011b824 100644 --- a/packet-osi.c +++ b/packet-osi.c @@ -2,7 +2,7 @@ * Routines for ISO/OSI network and transport protocol packet disassembly * Main entrance point and common functions * - * $Id: packet-osi.c,v 1.60 2003/04/29 17:56:48 guy Exp $ + * $Id: packet-osi.c,v 1.61 2003/05/15 06:35:02 guy Exp $ * Laurent Deniel <laurent.deniel@free.fr> * Ralf Schneider <Ralf.Schneider@t-online.de> * @@ -91,12 +91,105 @@ calc_checksum( tvbuff_t *tvb, int offset, guint len, guint checksum) { len -= seglen; } if (c0 != 0 || c1 != 0) - return( CKSUM_NOT_OK ); /* XXX - what should the checksum be? */ + return( CKSUM_NOT_OK ); /* XXX - what should the checksum field be? */ else return( CKSUM_OK ); } +cksum_status_t +check_and_get_checksum( tvbuff_t *tvb, int offset, guint len, guint checksum, int offset_check, guint16* result) { + const gchar *buffer; + guint available_len; + const guint8 *p; + guint8 discard = 0; + guint32 c0, c1, factor; + guint seglen, initlen = len; + guint i; + int block, x, y; + + if ( 0 == checksum ) + return( NO_CKSUM ); + + available_len = tvb_length_remaining( tvb, offset ); + offset_check -= offset; + if ( ( available_len < len ) || ( offset_check < 0 ) || ( (guint)(offset_check+2) > len ) ) + return( DATA_MISSING ); + + buffer = tvb_get_ptr( tvb, offset, len ); + block = offset_check / 5803; + + /* + * The maximum values of c0 and c1 will occur if all bytes have the + * value 255; if so, then c0 will be len*255 and c1 will be + * (len*255 + (len-1)*255 + ... + 255), which is + * (len + (len - 1) + ... + 1)*255, or 255*(len*(len + 1))/2. + * This means it can overflow if "len" is 5804 or greater. + * + * (A+B) mod 255 = ((A mod 255) + (B mod 255) mod 255, so + * we can solve this by taking c0 and c1 mod 255 every + * 5803 bytes. + */ + p = buffer; + c0 = 0; + c1 = 0; + + while (len != 0) { + seglen = len; + if ( block-- == 0 ) { + seglen = offset_check % 5803; + discard = 1; + } else if ( seglen > 5803 ) + seglen = 5803; + for (i = 0; i < seglen; i++) { + c0 = c0 + *(p++); + c1 += c0; + } + if ( discard ) { + /* + * This works even if (offset_check % 5803) == 5802 + */ + p += 2; + c1 += 2*c0; + len -= 2; + discard = 0; + } + + c0 = c0 % 255; + c1 = c1 % 255; + + len -= seglen; + } + + factor = ( initlen - offset_check ) * c0; + x = factor - c0 - c1; + y = c1 - factor - 1; + + /* + * This algorithm uses the 8 bits one's complement arithmetic. + * Therefore, we must correct an effect produced + * by the "standard" arithmetic (two's complement) + */ + + if (x < 0 ) x--; + if (y > 0 ) y++; + + x %= 255; + y %= 255; + + if (x == 0) x = 0xFF; + if (y == 0) y = 0x01; + + *result = ( x << 8 ) | ( y & 0xFF ); + + if (*result != checksum) + return( CKSUM_NOT_OK ); /* XXX - what should the checksum field be? */ + else + return( CKSUM_OK ); +} + + + /* main entry point */ /* diff --git a/packet-osi.h b/packet-osi.h index 427010b61d..8b389aab9a 100644 --- a/packet-osi.h +++ b/packet-osi.h @@ -1,6 +1,6 @@ /* packet-osi.h * - * $Id: packet-osi.h,v 1.13 2003/04/29 17:56:48 guy Exp $ + * $Id: packet-osi.h,v 1.14 2003/05/15 06:35:02 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -86,5 +86,6 @@ typedef enum { } cksum_status_t; extern cksum_status_t calc_checksum(tvbuff_t *, int, guint, guint); +extern cksum_status_t check_and_get_checksum( tvbuff_t *, int, guint, guint, int, guint16*); #endif /* _PACKET_OSI_H */ |