Check for potentially exploitable overflows in asn1_d2i_read_bio
BUF_mem_grow and BUF_mem_grow_clean. Refuse attempts to shrink buffer in CRYPTO_realloc_clean. Thanks to Tavis Ormandy, Google Security Team, for discovering this issue and to Adam Langley <agl@chromium.org> for fixing it. (CVE-2012-2110)
This commit is contained in:
parent
3dd2eebfbc
commit
5bd4fcc5c2
9
CHANGES
9
CHANGES
@ -4,7 +4,14 @@
|
|||||||
|
|
||||||
Changes between 1.0.0h and 1.0.0i [xx XXX xxxx]
|
Changes between 1.0.0h and 1.0.0i [xx XXX xxxx]
|
||||||
|
|
||||||
*)
|
*) Check for potentially exploitable overflows in asn1_d2i_read_bio
|
||||||
|
BUF_mem_grow and BUF_mem_grow_clean. Refuse attempts to shrink buffer
|
||||||
|
in CRYPTO_realloc_clean.
|
||||||
|
|
||||||
|
Thanks to Tavis Ormandy, Google Security Team, for discovering this
|
||||||
|
issue and to Adam Langley <agl@chromium.org> for fixing it.
|
||||||
|
(CVE-2012-2110)
|
||||||
|
[Adam Langley (Google), Tavis Ormandy, Google Security Team]
|
||||||
|
|
||||||
Changes between 1.0.0g and 1.0.0h [12 Mar 2012]
|
Changes between 1.0.0g and 1.0.0h [12 Mar 2012]
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
#include <openssl/buffer.h>
|
#include <openssl/buffer.h>
|
||||||
#include <openssl/asn1_mac.h>
|
#include <openssl/asn1_mac.h>
|
||||||
@ -143,17 +144,11 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
BUF_MEM *b;
|
BUF_MEM *b;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int i;
|
int i;
|
||||||
int ret=-1;
|
|
||||||
ASN1_const_CTX c;
|
ASN1_const_CTX c;
|
||||||
int want=HEADER_SIZE;
|
size_t want=HEADER_SIZE;
|
||||||
int eos=0;
|
int eos=0;
|
||||||
#if defined(__GNUC__) && defined(__ia64)
|
size_t off=0;
|
||||||
/* pathetic compiler bug in all known versions as of Nov. 2002 */
|
size_t len=0;
|
||||||
long off=0;
|
|
||||||
#else
|
|
||||||
int off=0;
|
|
||||||
#endif
|
|
||||||
int len=0;
|
|
||||||
|
|
||||||
b=BUF_MEM_new();
|
b=BUF_MEM_new();
|
||||||
if (b == NULL)
|
if (b == NULL)
|
||||||
@ -169,7 +164,7 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
{
|
{
|
||||||
want-=(len-off);
|
want-=(len-off);
|
||||||
|
|
||||||
if (!BUF_MEM_grow_clean(b,len+want))
|
if (len + want < len || !BUF_MEM_grow_clean(b,len+want))
|
||||||
{
|
{
|
||||||
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
|
||||||
goto err;
|
goto err;
|
||||||
@ -181,7 +176,14 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
|
{
|
||||||
|
if (len+i < len)
|
||||||
|
{
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
len+=i;
|
len+=i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* else data already loaded */
|
/* else data already loaded */
|
||||||
|
|
||||||
@ -206,6 +208,11 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
{
|
{
|
||||||
/* no data body so go round again */
|
/* no data body so go round again */
|
||||||
eos++;
|
eos++;
|
||||||
|
if (eos < 0)
|
||||||
|
{
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_HEADER_TOO_LONG);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
want=HEADER_SIZE;
|
want=HEADER_SIZE;
|
||||||
}
|
}
|
||||||
else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC))
|
else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC))
|
||||||
@ -220,10 +227,16 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* suck in c.slen bytes of data */
|
/* suck in c.slen bytes of data */
|
||||||
want=(int)c.slen;
|
want=c.slen;
|
||||||
if (want > (len-off))
|
if (want > (len-off))
|
||||||
{
|
{
|
||||||
want-=(len-off);
|
want-=(len-off);
|
||||||
|
if (want > INT_MAX /* BIO_read takes an int length */ ||
|
||||||
|
len+want < len)
|
||||||
|
{
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
if (!BUF_MEM_grow_clean(b,len+want))
|
if (!BUF_MEM_grow_clean(b,len+want))
|
||||||
{
|
{
|
||||||
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
|
||||||
@ -238,11 +251,18 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
ASN1_R_NOT_ENOUGH_DATA);
|
ASN1_R_NOT_ENOUGH_DATA);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
/* This can't overflow because
|
||||||
|
* |len+want| didn't overflow. */
|
||||||
len+=i;
|
len+=i;
|
||||||
want -= i;
|
want-=i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
off+=(int)c.slen;
|
if (off + c.slen < off)
|
||||||
|
{
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
off+=c.slen;
|
||||||
if (eos <= 0)
|
if (eos <= 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -252,9 +272,15 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (off > INT_MAX)
|
||||||
|
{
|
||||||
|
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
*pb = b;
|
*pb = b;
|
||||||
return off;
|
return off;
|
||||||
err:
|
err:
|
||||||
if (b != NULL) BUF_MEM_free(b);
|
if (b != NULL) BUF_MEM_free(b);
|
||||||
return(ret);
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,11 @@
|
|||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
#include <openssl/buffer.h>
|
#include <openssl/buffer.h>
|
||||||
|
|
||||||
|
/* LIMIT_BEFORE_EXPANSION is the maximum n such that (n+3)/3*4 < 2**31. That
|
||||||
|
* function is applied in several functions in this file and this limit ensures
|
||||||
|
* that the result fits in an int. */
|
||||||
|
#define LIMIT_BEFORE_EXPANSION 0x5ffffffc
|
||||||
|
|
||||||
BUF_MEM *BUF_MEM_new(void)
|
BUF_MEM *BUF_MEM_new(void)
|
||||||
{
|
{
|
||||||
BUF_MEM *ret;
|
BUF_MEM *ret;
|
||||||
@ -105,6 +110,12 @@ int BUF_MEM_grow(BUF_MEM *str, size_t len)
|
|||||||
str->length=len;
|
str->length=len;
|
||||||
return(len);
|
return(len);
|
||||||
}
|
}
|
||||||
|
/* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
|
||||||
|
if (len > LIMIT_BEFORE_EXPANSION)
|
||||||
|
{
|
||||||
|
BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
n=(len+3)/3*4;
|
n=(len+3)/3*4;
|
||||||
if (str->data == NULL)
|
if (str->data == NULL)
|
||||||
ret=OPENSSL_malloc(n);
|
ret=OPENSSL_malloc(n);
|
||||||
@ -142,6 +153,12 @@ int BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
|
|||||||
str->length=len;
|
str->length=len;
|
||||||
return(len);
|
return(len);
|
||||||
}
|
}
|
||||||
|
/* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
|
||||||
|
if (len > LIMIT_BEFORE_EXPANSION)
|
||||||
|
{
|
||||||
|
BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
n=(len+3)/3*4;
|
n=(len+3)/3*4;
|
||||||
if (str->data == NULL)
|
if (str->data == NULL)
|
||||||
ret=OPENSSL_malloc(n);
|
ret=OPENSSL_malloc(n);
|
||||||
|
@ -361,6 +361,10 @@ void *CRYPTO_realloc_clean(void *str, int old_len, int num, const char *file,
|
|||||||
|
|
||||||
if (num <= 0) return NULL;
|
if (num <= 0) return NULL;
|
||||||
|
|
||||||
|
/* We don't support shrinking the buffer. Note the memcpy that copies
|
||||||
|
* |old_len| bytes to the new buffer, below. */
|
||||||
|
if (num < old_len) return NULL;
|
||||||
|
|
||||||
if (realloc_debug_func != NULL)
|
if (realloc_debug_func != NULL)
|
||||||
realloc_debug_func(str, NULL, num, file, line, 0);
|
realloc_debug_func(str, NULL, num, file, line, 0);
|
||||||
ret=malloc_ex_func(num,file,line);
|
ret=malloc_ex_func(num,file,line);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user