Browse Source

deps: back-port openssl patch

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.

Taken from OpenSSL CVS. Addresses CVE-2012-2110.
v0.9.1-release
Ben Noordhuis 13 years ago
parent
commit
89e311b1ae
  1. 54
      deps/openssl/openssl/crypto/asn1/a_d2i_fp.c
  2. 17
      deps/openssl/openssl/crypto/buffer/buffer.c
  3. 4
      deps/openssl/openssl/crypto/mem.c

54
deps/openssl/openssl/crypto/asn1/a_d2i_fp.c

@ -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;
} }

17
deps/openssl/openssl/crypto/buffer/buffer.c

@ -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_CLEAN,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);

4
deps/openssl/openssl/crypto/mem.c

@ -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…
Cancel
Save