mirror of https://gerrit.osmocom.org/asn1c
Fix UPER string decoding constrained only by lower bound > 0
This commit is contained in:
parent
ce6b0a66de
commit
9d1b45f8ac
|
@ -10,6 +10,8 @@
|
|||
(Severity: medium; Security impact: medium)
|
||||
* Fix REAL type overwrite conversion memory leak.
|
||||
(Severity: low; Security impact: medium)
|
||||
* Fix UPER string decoding constrained only by lower bound > 0
|
||||
(Severity: low; Security impact: none)
|
||||
|
||||
0.9.28: 2017-03-26
|
||||
* PER decoding: avoid memory leak on error. By github.com/simo5
|
||||
|
|
|
@ -216,7 +216,7 @@ ANY_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
|
|||
int ret;
|
||||
|
||||
/* Get the PER length */
|
||||
raw_len = uper_get_length(pd, -1, &repeat);
|
||||
raw_len = uper_get_length(pd, -1, 0, &repeat);
|
||||
if(raw_len < 0) RETURN(RC_WMORE);
|
||||
|
||||
ASN_DEBUG("Got PER length len %zu, %s (%s)", raw_len,
|
||||
|
|
|
@ -656,7 +656,7 @@ INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t
|
|||
int ret = 0;
|
||||
|
||||
/* Get the PER length */
|
||||
len = uper_get_length(pd, -1, &repeat);
|
||||
len = uper_get_length(pd, -1, 0, &repeat);
|
||||
if(len < 0) ASN__DECODE_STARVED;
|
||||
|
||||
p = REALLOC(st->buf, st->size + len + 1);
|
||||
|
|
|
@ -1424,7 +1424,6 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
|
|||
if(inext < 0) RETURN(RC_WMORE);
|
||||
if(inext) {
|
||||
csiz = &asn_DEF_OCTET_STRING_constraints.size;
|
||||
cval = &asn_DEF_OCTET_STRING_constraints.value;
|
||||
unit_bits = canonical_unit_bits;
|
||||
}
|
||||
}
|
||||
|
@ -1477,9 +1476,9 @@ OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
|
|||
int ret;
|
||||
|
||||
/* Get the PER length */
|
||||
raw_len = uper_get_length(pd, csiz->effective_bits, &repeat);
|
||||
raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
|
||||
&repeat);
|
||||
if(raw_len < 0) RETURN(RC_WMORE);
|
||||
raw_len += csiz->lower_bound;
|
||||
|
||||
ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
|
||||
(long)csiz->effective_bits, (long)raw_len,
|
||||
|
@ -1531,7 +1530,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
|
|||
int inext = 0; /* Lies not within extension root */
|
||||
unsigned int unit_bits;
|
||||
unsigned int canonical_unit_bits;
|
||||
unsigned int sizeinunits;
|
||||
size_t size_in_units;
|
||||
const uint8_t *buf;
|
||||
int ret;
|
||||
enum {
|
||||
|
@ -1561,23 +1560,23 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
|
|||
case ASN_OSUBV_BIT:
|
||||
canonical_unit_bits = unit_bits = 1;
|
||||
bpc = OS__BPC_BIT;
|
||||
sizeinunits = st->size * 8 - (st->bits_unused & 0x07);
|
||||
ASN_DEBUG("BIT STRING of %d bytes, %d bits unused",
|
||||
sizeinunits, st->bits_unused);
|
||||
size_in_units = st->size * 8 - (st->bits_unused & 0x07);
|
||||
ASN_DEBUG("BIT STRING of %zu bytes, %d bits unused",
|
||||
size_in_units, st->bits_unused);
|
||||
break;
|
||||
case ASN_OSUBV_STR:
|
||||
canonical_unit_bits = unit_bits = 8;
|
||||
if(cval->flags & APC_CONSTRAINED)
|
||||
unit_bits = cval->range_bits;
|
||||
bpc = OS__BPC_CHAR;
|
||||
sizeinunits = st->size;
|
||||
size_in_units = st->size;
|
||||
break;
|
||||
case ASN_OSUBV_U16:
|
||||
canonical_unit_bits = unit_bits = 16;
|
||||
if(cval->flags & APC_CONSTRAINED)
|
||||
unit_bits = cval->range_bits;
|
||||
bpc = OS__BPC_U16;
|
||||
sizeinunits = st->size >> 1;
|
||||
size_in_units = st->size >> 1;
|
||||
if(st->size & 1) {
|
||||
ASN_DEBUG("%s string size is not modulo 2", td->name);
|
||||
ASN__ENCODE_FAILED;
|
||||
|
@ -1588,7 +1587,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
|
|||
if(cval->flags & APC_CONSTRAINED)
|
||||
unit_bits = cval->range_bits;
|
||||
bpc = OS__BPC_U32;
|
||||
sizeinunits = st->size >> 2;
|
||||
size_in_units = st->size >> 2;
|
||||
if(st->size & 3) {
|
||||
ASN_DEBUG("%s string size is not modulo 4", td->name);
|
||||
ASN__ENCODE_FAILED;
|
||||
|
@ -1596,92 +1595,85 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
|
|||
break;
|
||||
}
|
||||
|
||||
ASN_DEBUG("Encoding %s into %d units of %d bits"
|
||||
ASN_DEBUG("Encoding %s into %zu units of %d bits"
|
||||
" (%ld..%ld, effective %d)%s",
|
||||
td->name, sizeinunits, unit_bits,
|
||||
td->name, size_in_units, unit_bits,
|
||||
csiz->lower_bound, csiz->upper_bound,
|
||||
csiz->effective_bits, ct_extensible ? " EXT" : "");
|
||||
|
||||
/* Figure out whether size lies within PER visible constraint */
|
||||
|
||||
if(csiz->effective_bits >= 0) {
|
||||
if((int)sizeinunits < csiz->lower_bound
|
||||
|| (int)sizeinunits > csiz->upper_bound) {
|
||||
if(ct_extensible) {
|
||||
cval = &asn_DEF_OCTET_STRING_constraints.value;
|
||||
csiz = &asn_DEF_OCTET_STRING_constraints.size;
|
||||
unit_bits = canonical_unit_bits;
|
||||
inext = 1;
|
||||
} else {
|
||||
ASN__ENCODE_FAILED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inext = 0;
|
||||
}
|
||||
if(csiz->effective_bits >= 0) {
|
||||
if((ssize_t)size_in_units < csiz->lower_bound
|
||||
|| (ssize_t)size_in_units > csiz->upper_bound) {
|
||||
if(ct_extensible) {
|
||||
csiz = &asn_DEF_OCTET_STRING_constraints.size;
|
||||
unit_bits = canonical_unit_bits;
|
||||
inext = 1;
|
||||
} else {
|
||||
ASN__ENCODE_FAILED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inext = 0;
|
||||
}
|
||||
|
||||
if(ct_extensible) {
|
||||
if(ct_extensible) {
|
||||
/* Declare whether length is [not] within extension root */
|
||||
if(per_put_few_bits(po, inext, 1))
|
||||
ASN__ENCODE_FAILED;
|
||||
}
|
||||
|
||||
/* X.691, #16.5: zero-length encoding */
|
||||
/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
|
||||
/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
|
||||
if(csiz->effective_bits >= 0) {
|
||||
ASN_DEBUG("Encoding %zu bytes (%ld), length in %d bits",
|
||||
st->size, sizeinunits - csiz->lower_bound,
|
||||
csiz->effective_bits);
|
||||
ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound,
|
||||
csiz->effective_bits);
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
if(bpc) {
|
||||
ret = OCTET_STRING_per_put_characters(po, st->buf,
|
||||
sizeinunits, bpc, unit_bits,
|
||||
cval->lower_bound, cval->upper_bound, pc);
|
||||
} else {
|
||||
ret = per_put_many_bits(po, st->buf,
|
||||
sizeinunits * unit_bits);
|
||||
}
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
ASN__ENCODED_OK(er);
|
||||
}
|
||||
if(csiz->effective_bits >= 0 && !inext) {
|
||||
ASN_DEBUG("Encoding %zu bytes (%ld), length in %d bits", st->size,
|
||||
size_in_units - csiz->lower_bound, csiz->effective_bits);
|
||||
ret = per_put_few_bits(po, size_in_units - csiz->lower_bound,
|
||||
csiz->effective_bits);
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
if(bpc) {
|
||||
ret = OCTET_STRING_per_put_characters(
|
||||
po, st->buf, size_in_units, bpc, unit_bits, cval->lower_bound,
|
||||
cval->upper_bound, pc);
|
||||
} else {
|
||||
assert(unit_bits == 1);
|
||||
ret = per_put_many_bits(po, st->buf, size_in_units);
|
||||
}
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
ASN__ENCODED_OK(er);
|
||||
}
|
||||
|
||||
ASN_DEBUG("Encoding %zu bytes", st->size);
|
||||
ASN_DEBUG("Encoding %zu bytes", st->size);
|
||||
|
||||
if(sizeinunits == 0) {
|
||||
if(uper_put_length(po, 0))
|
||||
ASN__ENCODE_FAILED;
|
||||
ASN__ENCODED_OK(er);
|
||||
}
|
||||
if(size_in_units == 0) {
|
||||
if(uper_put_length(po, 0)) ASN__ENCODE_FAILED;
|
||||
ASN__ENCODED_OK(er);
|
||||
}
|
||||
|
||||
buf = st->buf;
|
||||
while(sizeinunits) {
|
||||
ssize_t maySave = uper_put_length(po, sizeinunits);
|
||||
if(maySave < 0) ASN__ENCODE_FAILED;
|
||||
buf = st->buf;
|
||||
while(size_in_units) {
|
||||
ssize_t maySave = uper_put_length(po, size_in_units);
|
||||
if(maySave < 0) ASN__ENCODE_FAILED;
|
||||
|
||||
ASN_DEBUG("Encoding %ld of %ld",
|
||||
(long)maySave, (long)sizeinunits);
|
||||
ASN_DEBUG("Encoding %ld of %ld", (long)maySave, (long)sizeinunits);
|
||||
|
||||
if(bpc) {
|
||||
ret = OCTET_STRING_per_put_characters(po, buf,
|
||||
maySave, bpc, unit_bits,
|
||||
cval->lower_bound, cval->upper_bound, pc);
|
||||
} else {
|
||||
ret = per_put_many_bits(po, buf, maySave * unit_bits);
|
||||
}
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
if(bpc) {
|
||||
ret = OCTET_STRING_per_put_characters(po, buf, maySave, bpc,
|
||||
unit_bits, cval->lower_bound,
|
||||
cval->upper_bound, pc);
|
||||
} else {
|
||||
ret = per_put_many_bits(po, buf, maySave);
|
||||
}
|
||||
if(ret) ASN__ENCODE_FAILED;
|
||||
|
||||
if(bpc)
|
||||
buf += maySave * bpc;
|
||||
else
|
||||
buf += maySave >> 3;
|
||||
sizeinunits -= maySave;
|
||||
assert(!(maySave & 0x07) || !sizeinunits);
|
||||
}
|
||||
if(bpc)
|
||||
buf += maySave * bpc;
|
||||
else
|
||||
buf += maySave >> 3;
|
||||
size_in_units -= maySave;
|
||||
assert(!(maySave & 0x07) || !size_in_units);
|
||||
}
|
||||
|
||||
ASN__ENCODED_OK(er);
|
||||
ASN__ENCODED_OK(er);
|
||||
}
|
||||
|
||||
#endif /* ASN_DISABLE_PER_SUPPORT */
|
||||
|
@ -1987,10 +1979,36 @@ OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
|
|||
const asn_per_constraint_t *pc =
|
||||
&td->encoding_constraints.per_constraints->size;
|
||||
if(pc->flags & APC_CONSTRAINED) {
|
||||
long suggested_upper_bound =
|
||||
pc->upper_bound < max_length ? pc->upper_bound : max_length;
|
||||
if(max_length < (size_t)pc->lower_bound) {
|
||||
return result_skipped;
|
||||
}
|
||||
rnd_len = asn_random_between(pc->lower_bound, pc->upper_bound);
|
||||
if(pc->flags & APC_EXTENSIBLE) {
|
||||
switch(asn_random_between(0, 5)) {
|
||||
case 0:
|
||||
if(pc->lower_bound > 0) {
|
||||
rnd_len = pc->lower_bound - 1;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case 1:
|
||||
rnd_len = pc->upper_bound + 1;
|
||||
break;
|
||||
case 2:
|
||||
/* Keep rnd_len from the table */
|
||||
if(rnd_len < max_length) {
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
rnd_len = asn_random_between(pc->lower_bound,
|
||||
suggested_upper_bound);
|
||||
}
|
||||
} else {
|
||||
rnd_len =
|
||||
asn_random_between(pc->lower_bound, suggested_upper_bound);
|
||||
}
|
||||
} else {
|
||||
rnd_len = asn_random_between(0, max_length - 1);
|
||||
}
|
||||
|
|
|
@ -910,8 +910,7 @@ SET_OF_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *
|
|||
do {
|
||||
int i;
|
||||
if(nelems < 0) {
|
||||
nelems = uper_get_length(pd,
|
||||
ct ? ct->effective_bits : -1, &repeat);
|
||||
nelems = uper_get_length(pd, -1, 0, &repeat);
|
||||
ASN_DEBUG("Got to decode %d elements (eff %d)",
|
||||
(int)nelems, (int)(ct ? ct->effective_bits : -1));
|
||||
if(nelems < 0) ASN__DECODE_STARVED;
|
||||
|
|
|
@ -73,10 +73,10 @@ oer_decoder.h oer_decoder.c OPEN_TYPE.h # OER decoding support
|
|||
oer_encoder.h oer_encoder.c # OER encoding support
|
||||
oer_support.h oer_support.c # OER support
|
||||
OPEN_TYPE.h OPEN_TYPE_oer.c constr_CHOICE.h
|
||||
INTEGER_oer.c
|
||||
INTEGER_oer.c INTEGER.h
|
||||
OCTET_STRING_oer.c
|
||||
NativeInteger_oer.c
|
||||
NativeEnumerated_oer.c
|
||||
NativeInteger_oer.c NativeInteger.h
|
||||
NativeEnumerated_oer.c NativeEnumerated.h
|
||||
constr_SEQUENCE_oer.c constr_SEQUENCE.h
|
||||
constr_CHOICE_oer.c
|
||||
constr_SET_OF_oer.c constr_SET_OF.h asn_SET_OF.h asn_SET_OF.c
|
||||
|
|
|
@ -73,7 +73,7 @@ uper_open_type_get_simple(const asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
|
|||
ASN_DEBUG("Getting open type %s...", td->name);
|
||||
|
||||
do {
|
||||
chunk_bytes = uper_get_length(pd, -1, &repeat);
|
||||
chunk_bytes = uper_get_length(pd, -1, 0, &repeat);
|
||||
if(chunk_bytes < 0) {
|
||||
FREEMEM(buf);
|
||||
ASN__DECODE_STARVED;
|
||||
|
@ -329,7 +329,7 @@ uper_ugot_refill(asn_per_data_t *pd) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
|
||||
next_chunk_bytes = uper_get_length(oldpd, -1, 0, &arg->repeat);
|
||||
ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
|
||||
(long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
|
||||
if(next_chunk_bytes < 0) return -1;
|
||||
|
|
|
@ -12,14 +12,17 @@
|
|||
* Get the optionally constrained length "n" from the stream.
|
||||
*/
|
||||
ssize_t
|
||||
uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) {
|
||||
uper_get_length(asn_per_data_t *pd, int ebits, size_t lower_bound,
|
||||
int *repeat) {
|
||||
ssize_t value;
|
||||
|
||||
*repeat = 0;
|
||||
|
||||
/* #11.9.4.1 Encoding if constrained (according to effective bits) */
|
||||
if(ebits >= 0 && ebits <= 16) {
|
||||
return per_get_few_bits(pd, ebits);
|
||||
value = per_get_few_bits(pd, ebits);
|
||||
if(value >= 0) value += lower_bound;
|
||||
return value;
|
||||
}
|
||||
|
||||
value = per_get_few_bits(pd, 8);
|
||||
|
@ -58,7 +61,7 @@ uper_get_nslength(asn_per_data_t *pd) {
|
|||
return length;
|
||||
} else {
|
||||
int repeat;
|
||||
length = uper_get_length(pd, -1, &repeat);
|
||||
length = uper_get_length(pd, -1, 0, &repeat);
|
||||
if(length >= 0 && !repeat) return length;
|
||||
return -1; /* Error, or do not support >16K extensions */
|
||||
}
|
||||
|
@ -170,23 +173,25 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int
|
|||
}
|
||||
|
||||
/*
|
||||
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
|
||||
* Put the length "n" (or part of it) into the stream.
|
||||
*/
|
||||
ssize_t
|
||||
uper_put_length(asn_per_outp_t *po, size_t length) {
|
||||
|
||||
if(length <= 127) /* #10.9.3.6 */
|
||||
return per_put_few_bits(po, length, 8)
|
||||
? -1 : (ssize_t)length;
|
||||
else if(length < 16384) /* #10.9.3.7 */
|
||||
return per_put_few_bits(po, length|0x8000, 16)
|
||||
? -1 : (ssize_t)length;
|
||||
if(length <= 127) /* #11.9.3.6 */
|
||||
return per_put_few_bits(po, length, 8)
|
||||
? -1 : (ssize_t)length;
|
||||
else if(length < 16384) /* #10.9.3.7 */
|
||||
return per_put_few_bits(po, length|0x8000, 16)
|
||||
? -1 : (ssize_t)length;
|
||||
|
||||
length >>= 14;
|
||||
if(length > 4) length = 4;
|
||||
length >>= 14;
|
||||
if(length > 4) length = 4;
|
||||
|
||||
return per_put_few_bits(po, 0xC0 | length, 8)
|
||||
? -1 : (ssize_t)(length << 14);
|
||||
|
||||
return per_put_few_bits(po, 0xC0 | length, 8)
|
||||
? -1 : (ssize_t)(length << 14);
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,7 +204,7 @@ int
|
|||
uper_put_nslength(asn_per_outp_t *po, size_t length) {
|
||||
|
||||
if(length <= 64) {
|
||||
/* #10.9.3.4 */
|
||||
/* #11.9.3.4 */
|
||||
if(length == 0) return -1;
|
||||
return per_put_few_bits(po, length-1, 7) ? -1 : 0;
|
||||
} else {
|
||||
|
|
|
@ -43,11 +43,11 @@ typedef struct asn_bit_data_s asn_per_data_t;
|
|||
asn_get_many_bits(data, dst, align, bits)
|
||||
|
||||
/*
|
||||
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
|
||||
* Get the length "n" from the Unaligned PER stream.
|
||||
*/
|
||||
ssize_t uper_get_length(asn_per_data_t *pd,
|
||||
int effective_bound_bits,
|
||||
int *repeat);
|
||||
ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits,
|
||||
size_t lower_bound, int *repeat);
|
||||
|
||||
/*
|
||||
* Get the normally small length "n".
|
||||
|
@ -74,6 +74,7 @@ int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits);
|
|||
int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits);
|
||||
|
||||
/*
|
||||
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
|
||||
* Put the length "n" to the Unaligned PER stream.
|
||||
* This function returns the number of units which may be flushed
|
||||
* in the next units saving iteration.
|
||||
|
|
Loading…
Reference in New Issue