aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ber.c
diff options
context:
space:
mode:
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>2010-07-09 17:07:34 +0000
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>2010-07-09 17:07:34 +0000
commit251351304f964d9d70da6d1ecc49984fd2ed6f84 (patch)
treef1c95378a82f52a59444c0dbd173475382f365bc /epan/dissectors/packet-ber.c
parent864d75be5dd1c9f5f01cb4588a2b5b47b9d2bea4 (diff)
Assume that if we have more than 500 levels of nested indefinite lengths
we have a malformed packet. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@33480 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors/packet-ber.c')
-rw-r--r--epan/dissectors/packet-ber.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/epan/dissectors/packet-ber.c b/epan/dissectors/packet-ber.c
index 1dabbb9507..8ac09506e6 100644
--- a/epan/dissectors/packet-ber.c
+++ b/epan/dissectors/packet-ber.c
@@ -948,8 +948,16 @@ int dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *t
* an indefinite length and haven't reached EOC.
*/
/* 8.1.3 Length octets */
+
+/*
+ * Set a limit on recursion so we don't blow away the stack. Another approach
+ * would be to remove recursion completely but then we'd exhaust CPU+memory
+ * trying to read a hellabyte of nested indefinite lengths.
+ * XXX - Max nesting in the ASN.1 plugin is 32.
+ */
+#define BER_MAX_INDEFINITE_NESTING 500
static gboolean
-try_get_ber_length(tvbuff_t *tvb, int *bl_offset, gboolean pc, guint32 *length, gboolean *ind) {
+try_get_ber_length(tvbuff_t *tvb, int *bl_offset, gboolean pc, guint32 *length, gboolean *ind, gint nest_level) {
int offset = *bl_offset;
guint8 oct, len;
guint32 tmp_len;
@@ -961,6 +969,11 @@ try_get_ber_length(tvbuff_t *tvb, int *bl_offset, gboolean pc, guint32 *length,
int tmp_offset;
tmp_length = 0;
tmp_ind = FALSE;
+
+ if (nest_level > BER_MAX_INDEFINITE_NESTING) {
+ /* Assume that we have a malformed packet. */
+ THROW(ReportedBoundsError);
+ }
oct = tvb_get_guint8(tvb, offset);
offset += 1;
@@ -990,7 +1003,7 @@ try_get_ber_length(tvbuff_t *tvb, int *bl_offset, gboolean pc, guint32 *length,
tmp_offset = get_ber_identifier(tvb, tmp_offset, &tclass, &tpc, &ttag);
/* Make sure we move forward */
- if(tmp_offset > offset && try_get_ber_length(tvb, &tmp_offset, tpc, &tmp_len, &tmp_ind)) {
+ if(tmp_offset > offset && try_get_ber_length(tvb, &tmp_offset, tpc, &tmp_len, &tmp_ind, nest_level+1)) {
if (tmp_len > 0) {
tmp_offset += tmp_len;
continue;
@@ -1034,7 +1047,7 @@ get_ber_length(tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind)
save_pc = last_pc;
save_tag = last_tag;
- if(!try_get_ber_length(tvb, &bl_offset, last_pc, &bl_length, ind)) {
+ if(!try_get_ber_length(tvb, &bl_offset, last_pc, &bl_length, ind, 0)) {
/* we couldn't get a length */
bl_offset = offset;
}