Duplicate the file and func error strings
authorMatt Caswell <matt@openssl.org>
Mon, 15 Feb 2021 16:59:43 +0000 (16:59 +0000)
committerMatt Caswell <matt@openssl.org>
Wed, 24 Feb 2021 12:13:38 +0000 (12:13 +0000)
Errors raised from a provider that is subsequently unloaded from memory
may have references to strings representing the file and function that
are no longer present because the provider is no longer in memory. This
can cause crashes. To avoid this we duplicate the file and func strings.

Fixes #13623

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14213)

crypto/err/err.c
crypto/err/err_local.h
include/openssl/err.h.in

index fe91ca7b5d75219837f1d51ba0b54e9e26a7b6be..e5f98668131aff3c00d6c796c0c8f42509d48762 100644 (file)
@@ -190,7 +190,7 @@ static void ERR_STATE_free(ERR_STATE *s)
     if (s == NULL)
         return;
     for (i = 0; i < ERR_NUM_ERRORS; i++) {
-        err_clear_data(s, i, 1);
+        err_clear(s, i, 1);
     }
     OPENSSL_free(s);
 }
index 03e05b7a1cf47d88de2deb0f5e3734dd3f72f2e4..abb6996e138de650da443f51d06ed2e5d88c3fbf 100644 (file)
@@ -48,9 +48,21 @@ static ossl_inline void err_set_debug(ERR_STATE *es, size_t i,
                                       const char *file, int line,
                                       const char *fn)
 {
-    es->err_file[i] = file;
+    /*
+     * We dup the file and fn strings because they may be provider owned. If the
+     * provider gets unloaded, they may not be valid anymore.
+     */
+    OPENSSL_free(es->err_file[i]);
+    if (file == NULL || file[0] == '\0')
+        es->err_file[i] = NULL;
+    else
+        es->err_file[i] = OPENSSL_strdup(file);
     es->err_line[i] = line;
-    es->err_func[i] = fn;
+    OPENSSL_free(es->err_func[i]);
+    if (fn == NULL || fn[0] == '\0')
+        es->err_func[i] = NULL;
+    else
+        es->err_func[i] = OPENSSL_strdup(fn);
 }
 
 static ossl_inline void err_set_data(ERR_STATE *es, size_t i,
@@ -67,8 +79,11 @@ static ossl_inline void err_clear(ERR_STATE *es, size_t i, int deall)
     es->err_marks[i] = 0;
     es->err_flags[i] = 0;
     es->err_buffer[i] = 0;
-    es->err_file[i] = NULL;
     es->err_line[i] = -1;
+    OPENSSL_free(es->err_file[i]);
+    es->err_file[i] = NULL;
+    OPENSSL_free(es->err_func[i]);
+    es->err_func[i] = NULL;
 }
 
 ERR_STATE *err_get_state_int(void);
index c012f65d08bfe353106a85a30828d4e806c69814..f7d5c174a17da1e0d4e4cc88a386d603f0818097 100644 (file)
@@ -62,9 +62,9 @@ struct err_state_st {
     char *err_data[ERR_NUM_ERRORS];
     size_t err_data_size[ERR_NUM_ERRORS];
     int err_data_flags[ERR_NUM_ERRORS];
-    const char *err_file[ERR_NUM_ERRORS];
+    char *err_file[ERR_NUM_ERRORS];
     int err_line[ERR_NUM_ERRORS];
-    const char *err_func[ERR_NUM_ERRORS];
+    char *err_func[ERR_NUM_ERRORS];
     int top, bottom;
 };
 # endif