Fix out-of-memory condition in conf.

conf has the ability to expand variables in config files. Repeatedly doing
this can lead to an exponential increase in the amount of memory required.
This places a limit on the length of a value that can result from an
expansion.

Credit to OSS-Fuzz for finding this problem.

(Imported from upstream's 6a6213556a80ab0a9eb926a1d6023b8bf44f2afd. This
also import's upstream's ee1ccd0a41ad068957fe65ba7521e593b51bbad4 which
we had previously missed.)

Change-Id: I9be06a7e8a062b5adcd00c974a7b245226123563
Reviewed-on: https://boringssl-review.googlesource.com/14316
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/conf/conf.c b/crypto/conf/conf.c
index 5b51d22..00172f5 100644
--- a/crypto/conf/conf.c
+++ b/crypto/conf/conf.c
@@ -69,6 +69,10 @@
 #include "../internal.h"
 
 
+/* The maximum length we can grow a value to after variable expansion. 64k
+ * should be more than enough for all reasonable uses. */
+#define MAX_CONF_VALUE_LENGTH 65536
+
 static uint32_t conf_value_hash(const CONF_VALUE *v) {
   return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name);
 }
@@ -316,7 +320,15 @@
         OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE);
         goto err;
       }
-      BUF_MEM_grow_clean(buf, (strlen(p) + buf->length - (e - from)));
+      size_t newsize = strlen(p) + buf->length - (e - from);
+      if (newsize > MAX_CONF_VALUE_LENGTH) {
+        OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG);
+        goto err;
+      }
+      if (!BUF_MEM_grow_clean(buf, newsize)) {
+        OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
+        goto err;
+      }
       while (*p) {
         buf->data[to++] = *(p++);
       }
diff --git a/crypto/err/conf.errordata b/crypto/err/conf.errordata
index 651fabe..e6226e4 100644
--- a/crypto/err/conf.errordata
+++ b/crypto/err/conf.errordata
@@ -3,4 +3,5 @@
 CONF,102,MISSING_EQUAL_SIGN
 CONF,103,NO_CLOSE_BRACE
 CONF,104,UNABLE_TO_CREATE_NEW_SECTION
+CONF,106,VARIABLE_EXPANSION_TOO_LONG
 CONF,105,VARIABLE_HAS_NO_VALUE
diff --git a/include/openssl/conf.h b/include/openssl/conf.h
index 8b82fd4..b8ec12e 100644
--- a/include/openssl/conf.h
+++ b/include/openssl/conf.h
@@ -180,5 +180,6 @@
 #define CONF_R_NO_CLOSE_BRACE 103
 #define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 104
 #define CONF_R_VARIABLE_HAS_NO_VALUE 105
+#define CONF_R_VARIABLE_EXPANSION_TOO_LONG 106
 
 #endif  /* OPENSSL_HEADER_THREAD_H */