Fix out-of-memory condition in conf
authorMatt Caswell <matt@openssl.org>
Fri, 10 Mar 2017 10:51:35 +0000 (10:51 +0000)
committerMatt Caswell <matt@openssl.org>
Sun, 12 Mar 2017 00:19:14 +0000 (00:19 +0000)
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.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2894)

crypto/conf/conf_def.c
crypto/conf/conf_err.c
doc/man5/config.pod
fuzz/corpora/conf/0d7ad6e04c0235cdc590756ceec867a05cff5823 [new file with mode: 0644]
include/openssl/conf.h

index 8861b3a5a062dea83a2c86ab963d636ae2f19c1a..a7b11d1598fde4508eb9fa05d9289a96bce0916c 100644 (file)
 #include <openssl/buffer.h>
 #include <openssl/err.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 char *eat_ws(CONF *conf, char *p);
 static char *eat_alpha_numeric(CONF *conf, char *p);
 static void clear_comments(CONF *conf, char *p);
@@ -457,6 +463,8 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from)
         } else if (IS_EOF(conf, *from))
             break;
         else if (*from == '$') {
+            size_t newsize;
+
             /* try to expand it */
             rrp = NULL;
             s = &(from[1]);
@@ -511,8 +519,12 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from)
                 CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE);
                 goto err;
             }
-            if (!BUF_MEM_grow_clean(buf,
-                        (strlen(p) + buf->length - (e - from)))) {
+            newsize = strlen(p) + buf->length - (e - from);
+            if (newsize > MAX_CONF_VALUE_LENGTH) {
+                CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_EXPANSION_TOO_LONG);
+                goto err;
+            }
+            if (!BUF_MEM_grow_clean(buf, newsize)) {
                 CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE);
                 goto err;
             }
index b583c057cde16df2bbe0d143cd5103c518bbaa42..0863bc4d3616f232afe627408e0f9df04b4c2134 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -60,6 +60,8 @@ static ERR_STRING_DATA CONF_str_reasons[] = {
     {ERR_REASON(CONF_R_UNABLE_TO_CREATE_NEW_SECTION),
      "unable to create new section"},
     {ERR_REASON(CONF_R_UNKNOWN_MODULE_NAME), "unknown module name"},
+    {ERR_REASON(CONF_R_VARIABLE_EXPANSION_TOO_LONG),
+     "variable expansion too long"},
     {ERR_REASON(CONF_R_VARIABLE_HAS_NO_VALUE), "variable has no value"},
     {0, NULL}
 };
index 24ebafb5332eebb0d1112a5800f2d2b59228c650..ba9a8ab1740f14df0c2abbb3b9727b83124bde2d 100644 (file)
@@ -44,7 +44,8 @@ or B<${section::name}>. By using the form B<$ENV::name> environment
 variables can be substituted. It is also possible to assign values to
 environment variables by using the name B<ENV::name>, this will work
 if the program looks up environment variables using the B<CONF> library
-instead of calling getenv() directly.
+instead of calling getenv() directly. The value string must not exceed 64k in
+length after variable expansion. Otherwise an error will occur.
 
 It is possible to escape certain characters by using any kind of quote
 or the B<\> character. By making the last character of a line a B<\>
diff --git a/fuzz/corpora/conf/0d7ad6e04c0235cdc590756ceec867a05cff5823 b/fuzz/corpora/conf/0d7ad6e04c0235cdc590756ceec867a05cff5823
new file mode 100644 (file)
index 0000000..b0ed191
--- /dev/null
@@ -0,0 +1,41 @@
+=;2I8
+=$$$$$$󠁉
+=$$$$$$$
+=$$$
+=$$$󠁷
+=$$$
+=$$$
+=$$$
+=
+=$$$
+=$$$
+=$$$󠁷
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$$$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$$$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$
+=$$$
+=$$$$$$$
+=$$$
+=$󠁝$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$
+=$$$$$
\ No newline at end of file
index 462e3c9d397b8f3dc293c799c514c0a35e8c5440..980a51b157f456688df3d0784b9c388f858f80b2 100644 (file)
@@ -208,6 +208,7 @@ int ERR_load_CONF_strings(void);
 # define CONF_R_NO_VALUE                                  108
 # define CONF_R_UNABLE_TO_CREATE_NEW_SECTION              103
 # define CONF_R_UNKNOWN_MODULE_NAME                       113
+# define CONF_R_VARIABLE_EXPANSION_TOO_LONG               116
 # define CONF_R_VARIABLE_HAS_NO_VALUE                     104
 
 # ifdef  __cplusplus