提交 c6298139 编写于 作者: D Dr. Stephen Henson

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: NViktor Dukhovni <viktor@openssl.org>
上级 ddc606c9
...@@ -138,6 +138,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) ...@@ -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) ...@@ -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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册