diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-12-23 10:55:49 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-12-23 10:55:49 +0900 |
commit | 9fd74865e44c3af62343386d35d326df9e49161d (patch) | |
tree | 77f3a57dcb1482a5c6e324c0ae62ab20107e45af /src/ber-decoder.c | |
parent | 8f617f621304d77e839de3ff1ef2c09347b612d9 (diff) | |
download | libksba-9fd74865e44c3af62343386d35d326df9e49161d.tar.gz libksba-9fd74865e44c3af62343386d35d326df9e49161d.tar.bz2 libksba-9fd74865e44c3af62343386d35d326df9e49161d.zip |
Imported Upstream version 1.3.3upstream/1.3.3
Diffstat (limited to 'src/ber-decoder.c')
-rw-r--r-- | src/ber-decoder.c | 101 |
1 files changed, 72 insertions, 29 deletions
diff --git a/src/ber-decoder.c b/src/ber-decoder.c index 873f810..9e70d92 100644 --- a/src/ber-decoder.c +++ b/src/ber-decoder.c @@ -1,5 +1,5 @@ /* ber-decoder.c - Basic Encoding Rules Decoder - * Copyright (C) 2001, 2004, 2006, 2012 g10 Code GmbH + * Copyright (C) 2001, 2004, 2006, 2012, 2015 g10 Code GmbH * * This file is part of KSBA. * @@ -100,7 +100,7 @@ struct ber_decoder_s struct { int primitive; /* current value is a primitive one */ - int length; /* length of the primitive one */ + size_t length; /* length of the primitive one */ int nhdr; /* length of the header */ int tag; int is_endtag; @@ -109,6 +109,23 @@ struct ber_decoder_s }; + +/* Evaluate with overflow check: A1 + A2 > B */ +static inline int +sum_a1_a2_gt_b (size_t a1, size_t a2, size_t b) +{ + size_t sum = a1 + a2; + return (sum < a1 || sum > b); +} + +/* Evaluate with overflow check: A1 + A2 >= B */ +static inline int +sum_a1_a2_ge_b (size_t a1, size_t a2, size_t b) +{ + size_t sum = a1 + a2; + return (sum < a1 || sum >= b); +} + static DECODER_STATE @@ -158,26 +175,28 @@ dump_decoder_state (DECODER_STATE ds) } /* Push ITEM onto the stack */ -static void +static gpg_error_t push_decoder_state (DECODER_STATE ds) { if (ds->idx >= ds->stacksize) { - fprintf (stderr, "ERROR: decoder stack overflow!\n"); - abort (); + fprintf (stderr, "ksba: ber-decoder: stack overflow!\n"); + return gpg_error (GPG_ERR_LIMIT_REACHED); } ds->stack[ds->idx++] = ds->cur; + return 0; } -static void +static gpg_error_t pop_decoder_state (DECODER_STATE ds) { if (!ds->idx) { - fprintf (stderr, "ERROR: decoder stack underflow!\n"); - abort (); + fprintf (stderr, "ksba: ber-decoder: stack underflow!\n"); + return gpg_error (GPG_ERR_INTERNAL); } ds->cur = ds->stack[--ds->idx]; + return 0; } @@ -185,7 +204,7 @@ pop_decoder_state (DECODER_STATE ds) static int set_error (BerDecoder d, AsnNode node, const char *text) { - fprintf (stderr,"ber-decoder: node `%s': %s\n", + fprintf (stderr,"ksba: ber-decoder: node `%s': %s\n", node? node->name:"?", text); d->last_errdesc = text; return gpg_error (GPG_ERR_BAD_BER); @@ -839,14 +858,16 @@ decoder_next (BerDecoder d) { /* We need some extra bytes to store the stuff we read ahead at the end of the module which is later pushed back. */ - d->image.length = ti.length + 100; d->image.used = 0; + d->image.length = ti.length + 100; + if (d->image.length < ti.length) + return gpg_error (GPG_ERR_BAD_BER); d->image.buf = xtrymalloc (d->image.length); if (!d->image.buf) return gpg_error (GPG_ERR_ENOMEM); } - if (ti.nhdr + d->image.used >= d->image.length) + if (sum_a1_a2_ge_b (ti.nhdr, d->image.used, d->image.length)) return set_error (d, NULL, "image buffer too short to store the tag"); memcpy (d->image.buf + d->image.used, ti.buf, ti.nhdr); @@ -936,9 +957,9 @@ decoder_next (BerDecoder d) && (ds->cur.nread > ds->stack[ds->idx-1].length)) { - fprintf (stderr, " ERROR: object length field " + fprintf (stderr, "ksba: ERROR: object length field " "%d octects too large\n", - ds->cur.nread > ds->cur.length); + ds->cur.nread - ds->cur.length); ds->cur.nread = ds->cur.length; } if ( ds->idx @@ -948,7 +969,9 @@ decoder_next (BerDecoder d) >= ds->stack[ds->idx-1].length)))) { int n = ds->cur.nread; - pop_decoder_state (ds); + err = pop_decoder_state (ds); + if (err) + return err; ds->cur.nread += n; ds->cur.went_up++; } @@ -964,7 +987,9 @@ decoder_next (BerDecoder d) /* prepare for the next level */ ds->cur.length = ti.length; ds->cur.ndef_length = ti.ndef; - push_decoder_state (ds); + err = push_decoder_state (ds); + if (err) + return err; ds->cur.length = 0; ds->cur.ndef_length = 0; ds->cur.nread = 0; @@ -1041,7 +1066,7 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp) int depth = 0; AsnNode node; unsigned char *buf = NULL; - size_t buflen = 0;; + size_t buflen = 0; if (!d) return gpg_error (GPG_ERR_INV_VALUE); @@ -1063,9 +1088,9 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp) if (node) depth = distance (d->root, node); - fprintf (fp, "%4lu %4u:%*s", + fprintf (fp, "%4lu %4lu:%*s", ksba_reader_tell (d->reader) - d->val.nhdr, - d->val.length, + (unsigned long)d->val.length, depth*2, ""); if (node) _ksba_asn_node_dump (node, fp); @@ -1074,16 +1099,22 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp) if (node && d->val.primitive) { - int i, n, c; + size_t n; + int i, c; char *p; if (!buf || buflen < d->val.length) { xfree (buf); buflen = d->val.length + 100; - buf = xtrymalloc (buflen); - if (!buf) - err = gpg_error (GPG_ERR_ENOMEM); + if (buflen < d->val.length) + err = gpg_error (GPG_ERR_BAD_BER); /* Overflow */ + else + { + buf = xtrymalloc (buflen); + if (!buf) + err = gpg_error_from_syserror (); + } } for (n=0; !err && n < d->val.length; n++) @@ -1171,8 +1202,6 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name, while (!(err = decoder_next (d))) { - int n, c; - node = d->val.node; /* Fixme: USE_IMAGE is only not used with the ber-dump utility and thus of no big use. We should remove the other code @@ -1188,7 +1217,7 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name, if (node->type == TYPE_ANY) node->actual_type = d->val.tag; } - if (d->image.used + d->val.length > d->image.length) + if (sum_a1_a2_gt_b (d->image.used, d->val.length, d->image.length)) err = set_error(d, NULL, "TLV length too large"); else if (d->val.primitive) { @@ -1196,18 +1225,32 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name, d->image.buf + d->image.used, d->val.length)) err = eof_or_error (d, 1); else - d->image.used += d->val.length; + { + size_t sum = d->image.used + d->val.length; + if (sum < d->image.used) + err = gpg_error (GPG_ERR_BAD_BER); + else + d->image.used = sum; + } } } else if (node && d->val.primitive) { + size_t n; + int c; + if (!buf || buflen < d->val.length) { xfree (buf); buflen = d->val.length + 100; - buf = xtrymalloc (buflen); - if (!buf) - err = gpg_error (GPG_ERR_ENOMEM); + if (buflen < d->val.length) + err = gpg_error (GPG_ERR_BAD_BER); + else + { + buf = xtrymalloc (buflen); + if (!buf) + err = gpg_error_from_syserror (); + } } for (n=0; !err && n < d->val.length; n++) |