summaryrefslogtreecommitdiffstats
path: root/crypto/err
diff options
context:
space:
mode:
authorTomas Mraz <tomas@openssl.org>2023-05-30 22:14:58 +0200
committerTomas Mraz <tomas@openssl.org>2023-07-07 15:13:29 +0200
commit9c3ea4e1d7580fc061dfb754b620adb3439e683f (patch)
treee87832dee0de7a0e5a1f0da4a71e59ac89f3345d /crypto/err
parent5c3474ea563ed95bb7c86c08867139613655276b (diff)
QUIC err handling: Save and restore error state
We save the error state from the thread that encountered a permanent error condition caused by system or internal error to the QUIC_CHANNEL. Then we restore it whenever we are returning to a user call when protocol is shutdown. Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21087)
Diffstat (limited to 'crypto/err')
-rw-r--r--crypto/err/build.info2
-rw-r--r--crypto/err/err.c10
-rw-r--r--crypto/err/err_local.h5
-rw-r--r--crypto/err/err_save.c89
4 files changed, 97 insertions, 9 deletions
diff --git a/crypto/err/build.info b/crypto/err/build.info
index ee37938418..8552d7c393 100644
--- a/crypto/err/build.info
+++ b/crypto/err/build.info
@@ -1,3 +1,3 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
- err_blocks.c err_mark.c err.c err_all.c err_all_legacy.c err_prn.c
+ err_blocks.c err_mark.c err.c err_all.c err_all_legacy.c err_prn.c err_save.c
diff --git a/crypto/err/err.c b/crypto/err/err.c
index a6c5ff6132..972856ad23 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -33,7 +33,6 @@ ERR_STATE *ERR_get_state(void);
static int err_load_strings(const ERR_STRING_DATA *str);
#endif
-static void ERR_STATE_free(ERR_STATE *s);
#ifndef OPENSSL_NO_ERR
static ERR_STRING_DATA ERR_str_libraries[] = {
{ERR_PACK(ERR_LIB_NONE, 0, 0), "unknown library"},
@@ -199,7 +198,7 @@ static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
}
#endif
-static void ERR_STATE_free(ERR_STATE *state)
+void OSSL_ERR_STATE_free(ERR_STATE *state)
{
int i;
@@ -649,7 +648,7 @@ static void err_delete_thread_state(void *unused)
return;
CRYPTO_THREAD_set_local(&err_thread_local, NULL);
- ERR_STATE_free(state);
+ OSSL_ERR_STATE_free(state);
}
#ifndef OPENSSL_NO_DEPRECATED_1_1_0
@@ -689,8 +688,7 @@ ERR_STATE *ossl_err_get_state_int(void)
if (!CRYPTO_THREAD_set_local(&err_thread_local, (ERR_STATE*)-1))
return NULL;
- /* calling CRYPTO_zalloc(.., NULL, 0) prevents mem alloc error loop */
- state = CRYPTO_zalloc(sizeof(*state), NULL, 0);
+ state = OSSL_ERR_STATE_new();
if (state == NULL) {
CRYPTO_THREAD_set_local(&err_thread_local, NULL);
return NULL;
@@ -698,7 +696,7 @@ ERR_STATE *ossl_err_get_state_int(void)
if (!ossl_init_thread_start(NULL, NULL, err_delete_thread_state)
|| !CRYPTO_THREAD_set_local(&err_thread_local, state)) {
- ERR_STATE_free(state);
+ OSSL_ERR_STATE_free(state);
CRYPTO_THREAD_set_local(&err_thread_local, NULL);
return NULL;
}
diff --git a/crypto/err/err_local.h b/crypto/err/err_local.h
index 7d785ab618..202ac35ad4 100644
--- a/crypto/err/err_local.h
+++ b/crypto/err/err_local.h
@@ -66,8 +66,9 @@ static ossl_inline void err_set_debug(ERR_STATE *es, size_t i,
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);
+ else if ((es->err_func[i] = CRYPTO_malloc(strlen(fn) + 1,
+ NULL, 0)) != NULL)
+ strcpy(es->err_func[i], fn);
}
static ossl_inline void err_set_data(ERR_STATE *es, size_t i,
diff --git a/crypto/err/err_save.c b/crypto/err/err_save.c
new file mode 100644
index 0000000000..a471b22682
--- /dev/null
+++ b/crypto/err/err_save.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#define OSSL_FORCE_ERR_STATE
+
+#include <openssl/err.h>
+#include "err_local.h"
+
+/*
+ * Save and restore error state.
+ * We are using CRYPTO_zalloc(.., NULL, 0) instead of OPENSSL_malloc() in
+ * these functions to prevent mem alloc error loop.
+ */
+
+ERR_STATE *OSSL_ERR_STATE_new(void)
+{
+ return CRYPTO_zalloc(sizeof(ERR_STATE), NULL, 0);
+}
+
+void OSSL_ERR_STATE_save(ERR_STATE *es)
+{
+ size_t i;
+ ERR_STATE *thread_es;
+
+ if (es == NULL)
+ return;
+
+ for (i = 0; i < ERR_NUM_ERRORS; i++)
+ err_clear(es, i, 1);
+
+ thread_es = ossl_err_get_state_int();
+ if (thread_es == NULL)
+ return;
+
+ memcpy(es, thread_es, sizeof(*es));
+ /* Taking over the pointers, just clear the thread state. */
+ memset(thread_es, 0, sizeof(*thread_es));
+}
+
+void OSSL_ERR_STATE_restore(const ERR_STATE *es)
+{
+ size_t i;
+ ERR_STATE *thread_es;
+
+ if (es == NULL || es->bottom == es->top)
+ return;
+
+ thread_es = ossl_err_get_state_int();
+ if (thread_es == NULL)
+ return;
+
+ for (i = (size_t)es->bottom; i != (size_t)es->top;) {
+ size_t top;
+
+ i = (i + 1) % ERR_NUM_ERRORS;
+ if ((es->err_flags[i] & ERR_FLAG_CLEAR) != 0)
+ continue;
+
+ err_get_slot(thread_es);
+ top = thread_es->top;
+ err_clear(thread_es, top, 0);
+
+ thread_es->err_flags[top] = es->err_flags[i];
+ thread_es->err_buffer[top] = es->err_buffer[i];
+
+ err_set_debug(thread_es, top, es->err_file[i], es->err_line[i],
+ es->err_func[i]);
+
+ if (es->err_data[i] != NULL && es->err_data_size[i] != 0) {
+ void *data;
+ size_t data_sz = es->err_data_size[i];
+
+ data = CRYPTO_malloc(data_sz, NULL, 0);
+ if (data != NULL) {
+ memcpy(data, es->err_data[i], data_sz);
+ err_set_data(thread_es, top, data, data_sz,
+ es->err_data_flags[i] | ERR_TXT_MALLOCED);
+ }
+ } else {
+ err_clear_data(thread_es, top, 0);
+ }
+ }
+}