asn1: Fix leaks in template decoding
This commit is contained in:
@@ -767,22 +767,37 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
if (*pel == NULL)
|
if (*pel == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
el = *pel;
|
el = *pel;
|
||||||
}
|
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
|
||||||
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
|
ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
|
||||||
ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
|
} else {
|
||||||
} else {
|
const struct asn1_type_func *f = t->ptr;
|
||||||
const struct asn1_type_func *f = t->ptr;
|
ret = (f->decode)(p, len, el, &newsize);
|
||||||
ret = (f->decode)(p, len, el, &newsize);
|
}
|
||||||
}
|
if (ret) {
|
||||||
if (ret) {
|
|
||||||
if (t->tt & A1_FLAG_OPTIONAL) {
|
|
||||||
/*
|
/*
|
||||||
* Optional field not present in encoding, presumably,
|
* Optional field not present in encoding, presumably,
|
||||||
* though we should really look more carefully at `ret'.
|
* though we should really look more carefully at `ret'.
|
||||||
*/
|
*/
|
||||||
|
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
|
||||||
|
_asn1_free(t->ptr, el);
|
||||||
|
} else {
|
||||||
|
const struct asn1_type_func *f = t->ptr;
|
||||||
|
f->release(el);
|
||||||
|
}
|
||||||
free(*pel);
|
free(*pel);
|
||||||
*pel = NULL;
|
*pel = NULL;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
|
||||||
|
ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize);
|
||||||
|
} else {
|
||||||
|
const struct asn1_type_func *f = t->ptr;
|
||||||
|
ret = (f->decode)(p, len, el, &newsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
if (t->tt & A1_FLAG_OPTIONAL) {
|
||||||
} else if (t->tt & A1_FLAG_DEFAULT) {
|
} else if (t->tt & A1_FLAG_DEFAULT) {
|
||||||
/*
|
/*
|
||||||
* Defaulted field not present in encoding, presumably,
|
* Defaulted field not present in encoding, presumably,
|
||||||
@@ -829,8 +844,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
int is_indefinite = 0;
|
int is_indefinite = 0;
|
||||||
int subflags = flags;
|
int subflags = flags;
|
||||||
int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr);
|
int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr);
|
||||||
|
void *el = data = DPO(data, t->offset);
|
||||||
data = DPO(data, t->offset);
|
void **pel = (void **)el;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX If this type (chasing t->ptr through IMPLICIT tags, if this
|
* XXX If this type (chasing t->ptr through IMPLICIT tags, if this
|
||||||
@@ -914,13 +929,12 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
return ASN1_OVERRUN;
|
return ASN1_OVERRUN;
|
||||||
|
|
||||||
if (t->tt & A1_FLAG_OPTIONAL) {
|
if (t->tt & A1_FLAG_OPTIONAL) {
|
||||||
void **el = (void **)data;
|
|
||||||
size_t ellen = _asn1_sizeofType(t->ptr);
|
size_t ellen = _asn1_sizeofType(t->ptr);
|
||||||
|
|
||||||
*el = calloc(1, ellen);
|
*pel = calloc(1, ellen);
|
||||||
if (*el == NULL)
|
if (*pel == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
data = *el;
|
data = *pel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replace_tag) {
|
if (replace_tag) {
|
||||||
@@ -953,36 +967,45 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
} else {
|
} else {
|
||||||
ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
|
ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret == 0 && !is_indefinite && newsize != datalen)
|
||||||
|
/* Hidden data */
|
||||||
|
ret = ASN1_EXTRA_DATA;
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (is_indefinite) {
|
||||||
|
/* If we use indefinite encoding, the newsize is the datasize. */
|
||||||
|
datalen = newsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
len -= datalen;
|
||||||
|
p += datalen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indefinite encoding needs a trailing EndOfContent,
|
||||||
|
* check for that.
|
||||||
|
*/
|
||||||
|
if (is_indefinite) {
|
||||||
|
ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
|
||||||
|
&dertype, UT_EndOfContent,
|
||||||
|
&datalen, &l);
|
||||||
|
if (ret == 0 && dertype != PRIM)
|
||||||
|
ret = ASN1_BAD_ID;
|
||||||
|
else if (ret == 0 && datalen != 0)
|
||||||
|
ret = ASN1_INDEF_EXTRA_DATA;
|
||||||
|
if (ret == 0) {
|
||||||
|
p += l; len -= l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
if (!(t->tt & A1_FLAG_OPTIONAL))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
_asn1_free(t->ptr, data);
|
||||||
|
free(data);
|
||||||
|
*pel = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
if (is_indefinite) {
|
|
||||||
/* If we use indefinite encoding, the newsize is the datasize. */
|
|
||||||
datalen = newsize;
|
|
||||||
} else if (newsize != datalen) {
|
|
||||||
/* Check for hidden data that might be after the real tag */
|
|
||||||
return ASN1_EXTRA_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
len -= datalen;
|
|
||||||
p += datalen;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Indefinite encoding needs a trailing EndOfContent,
|
|
||||||
* check for that.
|
|
||||||
*/
|
|
||||||
if (is_indefinite) {
|
|
||||||
ret = der_match_tag_and_length(p, len, ASN1_C_UNIV,
|
|
||||||
&dertype, UT_EndOfContent,
|
|
||||||
&datalen, &l);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
if (dertype != PRIM)
|
|
||||||
return ASN1_BAD_ID;
|
|
||||||
if (datalen != 0)
|
|
||||||
return ASN1_INDEF_EXTRA_DATA;
|
|
||||||
p += l; len -= l;
|
|
||||||
}
|
|
||||||
data = olddata;
|
data = olddata;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1024,6 +1047,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
if (vallength > newlen)
|
if (vallength > newlen)
|
||||||
return ASN1_OVERFLOW;
|
return ASN1_OVERFLOW;
|
||||||
|
|
||||||
|
/* XXX Slow */
|
||||||
tmp = realloc(el->val, newlen);
|
tmp = realloc(el->val, newlen);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
@@ -1033,8 +1057,10 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
|||||||
|
|
||||||
ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
|
ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len,
|
||||||
DPO(el->val, vallength), &newsize);
|
DPO(el->val, vallength), &newsize);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
_asn1_free(t->ptr, DPO(el->val, vallength));
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
vallength = newlen;
|
vallength = newlen;
|
||||||
el->len++;
|
el->len++;
|
||||||
p += newsize; len -= newsize;
|
p += newsize; len -= newsize;
|
||||||
@@ -2193,9 +2219,9 @@ _asn1_free(const struct asn1_template *t, void *data)
|
|||||||
case A1_OP_TYPE:
|
case A1_OP_TYPE:
|
||||||
case A1_OP_TYPE_EXTERN: {
|
case A1_OP_TYPE_EXTERN: {
|
||||||
void *el = DPO(data, t->offset);
|
void *el = DPO(data, t->offset);
|
||||||
|
void **pel = (void **)el;
|
||||||
|
|
||||||
if (t->tt & A1_FLAG_OPTIONAL) {
|
if (t->tt & A1_FLAG_OPTIONAL) {
|
||||||
void **pel = (void **)el;
|
|
||||||
if (*pel == NULL)
|
if (*pel == NULL)
|
||||||
break;
|
break;
|
||||||
el = *pel;
|
el = *pel;
|
||||||
@@ -2207,8 +2233,10 @@ _asn1_free(const struct asn1_template *t, void *data)
|
|||||||
const struct asn1_type_func *f = t->ptr;
|
const struct asn1_type_func *f = t->ptr;
|
||||||
(f->release)(el);
|
(f->release)(el);
|
||||||
}
|
}
|
||||||
if (t->tt & A1_FLAG_OPTIONAL)
|
if (t->tt & A1_FLAG_OPTIONAL) {
|
||||||
free(el);
|
free(el);
|
||||||
|
*pel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2227,16 +2255,16 @@ _asn1_free(const struct asn1_template *t, void *data)
|
|||||||
void *el = DPO(data, t->offset);
|
void *el = DPO(data, t->offset);
|
||||||
|
|
||||||
if (t->tt & A1_FLAG_OPTIONAL) {
|
if (t->tt & A1_FLAG_OPTIONAL) {
|
||||||
void **pel = (void **)el;
|
void **pel = (void **)el;
|
||||||
|
|
||||||
if (*pel == NULL)
|
if (*pel == NULL)
|
||||||
break;
|
break;
|
||||||
el = *pel;
|
_asn1_free(t->ptr, *pel);
|
||||||
}
|
free(*pel);
|
||||||
|
*pel = NULL;
|
||||||
_asn1_free(t->ptr, el);
|
} else {
|
||||||
|
_asn1_free(t->ptr, el);
|
||||||
if (t->tt & A1_FLAG_OPTIONAL)
|
}
|
||||||
free(el);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user