Fix integer overflow in ASN.1 parsing functions.
Bug: 6274291
Change-Id: Id0850ce39aebfc9018c0459ec3147e05506a646f
diff --git a/patches/asn1_overflow.patch b/patches/asn1_overflow.patch
new file mode 100644
index 0000000..bb6c379
--- /dev/null
+++ b/patches/asn1_overflow.patch
@@ -0,0 +1,175 @@
+--- openssl/crypto/asn1/a_d2i_fp.c 2011-02-01 06:46:34.000000000 -0800
++++ openssl/crypto/asn1/a_d2i_fp.c 2012-04-02 10:54:56.000000000 -0700
+@@ -57,6 +57,7 @@
+ */
+
+ #include <stdio.h>
++#include <limits.h>
+ #include "cryptlib.h"
+ #include <openssl/buffer.h>
+ #include <openssl/asn1_mac.h>
+@@ -143,17 +144,11 @@
+ BUF_MEM *b;
+ unsigned char *p;
+ int i;
+- int ret=-1;
+ ASN1_const_CTX c;
+- int want=HEADER_SIZE;
++ size_t want=HEADER_SIZE;
+ int eos=0;
+-#if defined(__GNUC__) && defined(__ia64)
+- /* pathetic compiler bug in all known versions as of Nov. 2002 */
+- long off=0;
+-#else
+- int off=0;
+-#endif
+- int len=0;
++ size_t off=0;
++ size_t len=0;
+
+ b=BUF_MEM_new();
+ if (b == NULL)
+@@ -169,7 +164,7 @@
+ {
+ 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);
+ goto err;
+@@ -181,7 +176,14 @@
+ goto err;
+ }
+ if (i > 0)
++ {
++ if (len+i < len)
++ {
++ ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
++ goto err;
++ }
+ len+=i;
++ }
+ }
+ /* else data already loaded */
+
+@@ -206,6 +208,11 @@
+ {
+ /* no data body so go round again */
+ eos++;
++ if (eos < 0)
++ {
++ ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_HEADER_TOO_LONG);
++ goto err;
++ }
+ want=HEADER_SIZE;
+ }
+ else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC))
+@@ -220,10 +227,16 @@
+ else
+ {
+ /* suck in c.slen bytes of data */
+- want=(int)c.slen;
++ want=c.slen;
+ if (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))
+ {
+ ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
+@@ -238,11 +251,18 @@
+ ASN1_R_NOT_ENOUGH_DATA);
+ goto err;
+ }
++ /* This can't overflow because
++ * |len+want| didn't overflow. */
+ 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)
+ {
+ break;
+@@ -252,9 +272,14 @@
+ }
+ }
+
++ if (off > INT_MAX)
++ {
++ ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
++ goto err;
++ }
+ *pb = b;
+ return off;
+ err:
+ if (b != NULL) BUF_MEM_free(b);
+- return(ret);
++ return -1;
+ }
+--- openssl/crypto/buffer/buffer.c 2011-02-01 06:46:34.000000000 -0800
++++ openssl/crypto/buffer/buffer.c 2012-04-02 10:54:56.000000000 -0700
+@@ -60,6 +60,11 @@
+ #include "cryptlib.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 *ret;
+@@ -105,6 +110,12 @@
+ str->length=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;
+ if (str->data == NULL)
+ ret=OPENSSL_malloc(n);
+@@ -142,6 +153,12 @@
+ str->length=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;
+ if (str->data == NULL)
+ ret=OPENSSL_malloc(n);
+--- openssl/crypto/mem.c 2011-02-02 16:53:02.000000000 -0800
++++ openssl/crypto/mem.c 2012-04-02 10:54:56.000000000 -0700
+@@ -334,6 +334,10 @@
+
+ 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)
+ realloc_debug_func(str, NULL, num, file, line, 0);
+ ret=malloc_ex_func(num,file,line);