mirror of
https://github.com/openssl/openssl.git
synced 2024-11-28 12:35:22 +08:00
Harden ASN.1 BIO handling of large amounts of data.
If the ASN.1 BIO is presented with a large length field read it in chunks of increasing size checking for EOF on each read. This prevents small files allocating excessive amounts of data. CVE-2016-2109 Thanks to Brian Carpenter for reporting this issue. Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
This commit is contained in:
parent
ddc606c914
commit
c62981390d
@ -138,6 +138,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HEADER_SIZE 8
|
#define HEADER_SIZE 8
|
||||||
|
#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
|
||||||
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
||||||
{
|
{
|
||||||
BUF_MEM *b;
|
BUF_MEM *b;
|
||||||
@ -216,29 +217,44 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
/* suck in slen bytes of data */
|
/* suck in slen bytes of data */
|
||||||
want = slen;
|
want = slen;
|
||||||
if (want > (len - off)) {
|
if (want > (len - off)) {
|
||||||
|
size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
|
||||||
|
|
||||||
want -= (len - off);
|
want -= (len - off);
|
||||||
if (want > INT_MAX /* BIO_read takes an int length */ ||
|
if (want > INT_MAX /* BIO_read takes an int length */ ||
|
||||||
len + want < len) {
|
len + want < len) {
|
||||||
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (!BUF_MEM_grow_clean(b, len + want)) {
|
|
||||||
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
while (want > 0) {
|
while (want > 0) {
|
||||||
i = BIO_read(in, &(b->data[len]), want);
|
/*
|
||||||
if (i <= 0) {
|
* Read content in chunks of increasing size
|
||||||
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
|
* so we can return an error for EOF without
|
||||||
ASN1_R_NOT_ENOUGH_DATA);
|
* having to allocate the entire content length
|
||||||
|
* in one go.
|
||||||
|
*/
|
||||||
|
size_t chunk = want > chunk_max ? chunk_max : want;
|
||||||
|
|
||||||
|
if (!BUF_MEM_grow_clean(b, len + chunk)) {
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
want -= chunk;
|
||||||
|
while (chunk > 0) {
|
||||||
|
i = BIO_read(in, &(b->data[len]), chunk);
|
||||||
|
if (i <= 0) {
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
|
||||||
|
ASN1_R_NOT_ENOUGH_DATA);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* This can't overflow because |len+want| didn't
|
* This can't overflow because |len+want| didn't
|
||||||
* overflow.
|
* overflow.
|
||||||
*/
|
*/
|
||||||
len += i;
|
len += i;
|
||||||
want -= i;
|
chunk -= i;
|
||||||
|
}
|
||||||
|
if (chunk_max < INT_MAX/2)
|
||||||
|
chunk_max *= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (off + slen < off) {
|
if (off + slen < off) {
|
||||||
|
Loading…
Reference in New Issue
Block a user