NCONF_get_number refix.
authorPauli <paul.dale@oracle.com>
Tue, 3 Jul 2018 23:30:43 +0000 (09:30 +1000)
committerPauli <paul.dale@oracle.com>
Tue, 10 Jul 2018 23:03:22 +0000 (09:03 +1000)
Fix the NULL check lack in a different way that is more compatible with
non-NULL branch.  Refer #6632

Also mark and pop the error stack instead of clearing all errors when something
goes awry in CONF_get_number.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Andy Polyakov <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6643)

crypto/conf/conf_err.c
crypto/conf/conf_lib.c
crypto/err/openssl.txt
include/openssl/conferr.h
test/conf_include_test.c

index 01f98da87ac2f65019dac1b882ab9cac3a33af22..f7613584ec3e43b250a80ebabf093360570694bb 100644 (file)
@@ -60,6 +60,7 @@ static const ERR_STRING_DATA CONF_str_reasons[] = {
     {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_NO_SECTION), "no section"},
     {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_NO_SUCH_FILE), "no such file"},
     {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_NO_VALUE), "no value"},
+    {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_NUMBER_TOO_LARGE), "number too large"},
     {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_RECURSIVE_DIRECTORY_INCLUDE),
     "recursive directory include"},
     {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_SSL_COMMAND_SECTION_EMPTY),
index 5f976f35c428639fdde436c0e370d3dbfb499f93..1833b15ebea2929179dac0f360e95c06e0af0268 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <string.h>
 #include "internal/conf.h"
+#include "internal/ctype.h"
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/conf.h>
@@ -123,6 +124,7 @@ long CONF_get_number(LHASH_OF(CONF_VALUE) *conf, const char *group,
     int status;
     long result = 0;
 
+    ERR_set_mark();
     if (conf == NULL) {
         status = NCONF_get_number_e(NULL, group, name, &result);
     } else {
@@ -130,12 +132,8 @@ long CONF_get_number(LHASH_OF(CONF_VALUE) *conf, const char *group,
         CONF_set_nconf(&ctmp, conf);
         status = NCONF_get_number_e(&ctmp, group, name, &result);
     }
-
-    if (status == 0) {
-        /* This function does not believe in errors... */
-        ERR_clear_error();
-    }
-    return result;
+    ERR_pop_to_mark();
+    return status == 0 ? 0L : result;
 }
 
 void CONF_free(LHASH_OF(CONF_VALUE) *conf)
@@ -277,10 +275,23 @@ char *NCONF_get_string(const CONF *conf, const char *group, const char *name)
     return NULL;
 }
 
+static int default_is_number(const CONF *conf, char c)
+{
+    return ossl_isdigit(c);
+}
+
+static int default_to_int(const CONF *conf, char c)
+{
+    return (int)(c - '0');
+}
+
 int NCONF_get_number_e(const CONF *conf, const char *group, const char *name,
                        long *result)
 {
     char *str;
+    long res;
+    int (*is_number)(const CONF *, char) = &default_is_number;
+    int (*to_int)(const CONF *, char) = &default_to_int;
 
     if (result == NULL) {
         CONFerr(CONF_F_NCONF_GET_NUMBER_E, ERR_R_PASSED_NULL_PARAMETER);
@@ -292,14 +303,23 @@ int NCONF_get_number_e(const CONF *conf, const char *group, const char *name,
     if (str == NULL)
         return 0;
 
-    if (conf == NULL)
-        *result = strtol(str, &str, 10);
-    else
-        for (*result = 0; conf->meth->is_number(conf, *str);) {
-            *result = (*result) * 10 + conf->meth->to_int(conf, *str);
-            str++;
+    if (conf != NULL) {
+        if (conf->meth->is_number != NULL)
+            is_number = conf->meth->is_number;
+        if (conf->meth->to_int != NULL)
+            to_int = conf->meth->to_int;
+    }
+    for (res = 0; is_number(conf, *str); str++) {
+        const int d = to_int(conf, *str);
+
+        if (res > (LONG_MAX - d) / 10L) {
+            CONFerr(CONF_F_NCONF_GET_NUMBER_E, CONF_R_NUMBER_TOO_LARGE);
+            return 0;
         }
+        res = res * 10 + d;
+    }
 
+    *result = res;
     return 1;
 }
 
index ee68388b505c5594e43277e89764d5da54af6c13..007560a171965fcd9ab4cd341b46621f4f665f75 100644 (file)
@@ -2012,6 +2012,7 @@ CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE:106:no conf or environment variable
 CONF_R_NO_SECTION:107:no section
 CONF_R_NO_SUCH_FILE:114:no such file
 CONF_R_NO_VALUE:108:no value
+CONF_R_NUMBER_TOO_LARGE:121:number too large
 CONF_R_RECURSIVE_DIRECTORY_INCLUDE:111:recursive directory include
 CONF_R_SSL_COMMAND_SECTION_EMPTY:117:ssl command section empty
 CONF_R_SSL_COMMAND_SECTION_NOT_FOUND:118:ssl command section not found
index 4574636b017646ce01856506f9bdd67aa6ffaa30..d1c92f45d82dbbacc8d0041464fccedd4975c4e3 100644 (file)
@@ -58,6 +58,7 @@ int ERR_load_CONF_strings(void);
 # define CONF_R_NO_SECTION                                107
 # define CONF_R_NO_SUCH_FILE                              114
 # define CONF_R_NO_VALUE                                  108
+# define CONF_R_NUMBER_TOO_LARGE                          121
 # define CONF_R_RECURSIVE_DIRECTORY_INCLUDE               111
 # define CONF_R_SSL_COMMAND_SECTION_EMPTY                 117
 # define CONF_R_SSL_COMMAND_SECTION_NOT_FOUND             118
index ba79d2c208a46604296e619dc9e2b4dff373e5cd..ee02d9b3fb4f638f8501555b75e291551875edfb 100644 (file)
@@ -153,6 +153,31 @@ static int test_check_null_numbers(void)
     return 1;
 }
 
+static int test_check_overflow(void)
+{
+#if defined(_BSD_SOURCE) \
+        || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
+        || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
+    long val = 0;
+    char max[(sizeof(long) * 8) / 3 + 3];
+    char *p;
+
+    p = max + sprintf(max, "0%ld", LONG_MAX) - 1;
+    setenv("FNORD", max, 1);
+    if (!TEST_true(NCONF_get_number(NULL, "missing", "FNORD", &val))
+            || !TEST_long_eq(val, LONG_MAX))
+        return 0;
+
+    while (++*p > '9')
+        *p-- = '0';
+
+    setenv("FNORD", max, 1);
+    if (!TEST_false(NCONF_get_number(NULL, "missing", "FNORD", &val)))
+        return 0;
+#endif
+    return 1;
+}
+
 int setup_tests(void)
 {
     const char *conf_file;
@@ -181,6 +206,7 @@ int setup_tests(void)
 
     ADD_TEST(test_load_config);
     ADD_TEST(test_check_null_numbers);
+    ADD_TEST(test_check_overflow);
     return 1;
 }