Skip to content

Commit 3587403

Browse files
Adam Vartanianandi34
authored andcommitted
CVE 2016-2109 fix
Read ASN.1 data in chunks to prevent invalid inputs from allocating excessive amounts of data. Bug: 35443725 Test: run cts -m CtsLibcoreTestCases Test: manually ran testcase from OpenSSL Change-Id: Ia9d6aa40726c0cba26e2060108112f33e00e8270 Merged-In: Ie00536d7ad815464b2b031f7bcd1b683e12c1623 Merged-In: If087a69ee075b3c5323abb8d7d740e92bd703bb1 Merged-In: If77e23607fc77f724f50ad0e0b94eef4beae57ea Merged-In: Ia8d0370ece1d5c1750a4331810c610ed5c813224 Merged-In: Ia945d5ce50335919b0783fe909892703213454ef (cherry picked from commit ea156ae109eac7b7cf7d4f6a76f3c4590734789b)
1 parent 42437d1 commit 3587403

File tree

1 file changed

+29
-14
lines changed

1 file changed

+29
-14
lines changed

crypto/asn1/a_d2i_fp.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
139139
#endif
140140

141141
#define HEADER_SIZE 8
142+
#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
142143
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
143144
{
144145
BUF_MEM *b;
@@ -230,31 +231,45 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
230231
want=c.slen;
231232
if (want > (len-off))
232233
{
234+
size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
233235
want-=(len-off);
234236
if (want > INT_MAX /* BIO_read takes an int length */ ||
235237
len+want < len)
236238
{
237239
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
238240
goto err;
239241
}
240-
if (!BUF_MEM_grow_clean(b,len+want))
241-
{
242-
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
243-
goto err;
244-
}
245242
while (want > 0)
246243
{
247-
i=BIO_read(in,&(b->data[len]),want);
248-
if (i <= 0)
249-
{
250-
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
251-
ASN1_R_NOT_ENOUGH_DATA);
244+
245+
/*
246+
* Read content in chunks of increasing size
247+
* so we can return an error for EOF without
248+
* having to allocate the entire content length
249+
* in one go.
250+
*/
251+
size_t chunk = want > chunk_max ? chunk_max : want;
252+
253+
if (!BUF_MEM_grow_clean(b, len + chunk)) {
254+
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
252255
goto err;
256+
}
257+
want -= chunk;
258+
while (chunk > 0) {
259+
i = BIO_read(in, &(b->data[len]), chunk);
260+
if (i <= 0) {
261+
ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA);
262+
goto err;
253263
}
254-
/* This can't overflow because
255-
* |len+want| didn't overflow. */
256-
len+=i;
257-
want-=i;
264+
/*
265+
* This can't overflow because |len+want| didn't
266+
* overflow.
267+
*/
268+
len += i;
269+
chunk -= i;
270+
}
271+
if (chunk_max < INT_MAX/2)
272+
chunk_max *= 2;
258273
}
259274
}
260275
if (off + c.slen < off)

0 commit comments

Comments
 (0)