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
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"},
}
#endif
-static void ERR_STATE_free(ERR_STATE *state)
+void OSSL_ERR_STATE_free(ERR_STATE *state)
{
int i;
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
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;
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;
}
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,
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
GENERATE[html/man3/OSSL_ENCODER_to_bio.html]=man3/OSSL_ENCODER_to_bio.pod
DEPEND[man/man3/OSSL_ENCODER_to_bio.3]=man3/OSSL_ENCODER_to_bio.pod
GENERATE[man/man3/OSSL_ENCODER_to_bio.3]=man3/OSSL_ENCODER_to_bio.pod
+DEPEND[html/man3/OSSL_ERR_STATE_save.html]=man3/OSSL_ERR_STATE_save.pod
+GENERATE[html/man3/OSSL_ERR_STATE_save.html]=man3/OSSL_ERR_STATE_save.pod
+DEPEND[man/man3/OSSL_ERR_STATE_save.3]=man3/OSSL_ERR_STATE_save.pod
+GENERATE[man/man3/OSSL_ERR_STATE_save.3]=man3/OSSL_ERR_STATE_save.pod
DEPEND[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_certs.pod
GENERATE[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_certs.pod
DEPEND[man/man3/OSSL_ESS_check_signing_certs.3]=man3/OSSL_ESS_check_signing_certs.pod
html/man3/OSSL_ENCODER_CTX.html \
html/man3/OSSL_ENCODER_CTX_new_for_pkey.html \
html/man3/OSSL_ENCODER_to_bio.html \
+html/man3/OSSL_ERR_STATE_save.html \
html/man3/OSSL_ESS_check_signing_certs.html \
html/man3/OSSL_HPKE_CTX_new.html \
html/man3/OSSL_HTTP_REQ_CTX.html \
man/man3/OSSL_ENCODER_CTX.3 \
man/man3/OSSL_ENCODER_CTX_new_for_pkey.3 \
man/man3/OSSL_ENCODER_to_bio.3 \
+man/man3/OSSL_ERR_STATE_save.3 \
man/man3/OSSL_ESS_check_signing_certs.3 \
man/man3/OSSL_HPKE_CTX_new.3 \
man/man3/OSSL_HTTP_REQ_CTX.3 \
--- /dev/null
+=pod
+
+=head1 NAME
+
+OSSL_ERR_STATE_new, OSSL_ERR_STATE_save, OSSL_ERR_STATE_restore,
+OSSL_ERR_STATE_free - saving and restoring error state
+
+=head1 SYNOPSIS
+
+ #include <openssl/err.h>
+
+ ERR_STATE *OSSL_ERR_STATE_new(void);
+ void OSSL_ERR_STATE_save(ERR_STATE *es);
+ void OSSL_ERR_STATE_restore(const ERR_STATE *es);
+ void OSSL_ERR_STATE_free(ERR_STATE *es);
+
+=head1 DESCRIPTION
+
+These functions save and restore the error state from the thread
+local error state to a preallocated error state structure.
+
+OSSL_ERR_STATE_new() allocates an empty error state structure to
+be used when saving and restoring thread error state.
+
+OSSL_ERR_STATE_save() saves the thread error state to I<es>. It
+subsequently clears the thread error state. Any previously saved
+state in I<es> is cleared prior to saving the new state.
+
+OSSL_ERR_STATE_restore() adds all the error entries from the
+saved state I<es> to the thread error state. Existing entries in
+the thread error state are not affected if there is enough space
+for all the added entries. Any allocated data in the saved error
+entries is duplicated on adding to the thread state.
+
+OSSL_ERR_STATE_free() frees the saved error state I<es>.
+
+=head1 RETURN VALUES
+
+OSSL_ERR_STATE_new() returns a pointer to the allocated ERR_STATE
+structure or NULL on error.
+
+OSSL_ERR_STATE_save(), OSSL_ERR_STATE_restore(), OSSL_ERR_STATE_free()
+do not return any values.
+
+=head1 NOTES
+
+OSSL_ERR_STATE_save() cannot fail as it takes over any allocated
+data from the thread error state.
+
+OSSL_ERR_STATE_restore() is a best effort function. The only failure
+that can happen during its operation is when memory allocation fails.
+Because it manipulates the thread error state it avoids raising memory
+errors on such failure. At worst the restored error entries will be
+missing the auxiliary error data.
+
+=head1 SEE ALSO
+
+L<ERR_raise(3)>, L<ERR_get_error(3)>, L<ERR_clear_error(3)>
+
+=head1 COPYRIGHT
+
+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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
*/
int ossl_quic_channel_net_error(QUIC_CHANNEL *ch);
+/* Restore saved error state (best effort) */
+void ossl_quic_channel_restore_err_state(QUIC_CHANNEL *ch);
+
/* For RXDP use. */
void ossl_quic_channel_on_remote_conn_close(QUIC_CHANNEL *ch,
OSSL_QUIC_FRAME_CONN_CLOSE *f);
int ERR_pop_to_mark(void);
int ERR_clear_last_mark(void);
+ERR_STATE *OSSL_ERR_STATE_new(void);
+void OSSL_ERR_STATE_save(ERR_STATE *es);
+void OSSL_ERR_STATE_restore(const ERR_STATE *es);
+void OSSL_ERR_STATE_free(ERR_STATE *es);
+
#ifdef __cplusplus
}
#endif
* https://www.openssl.org/source/license.html
*/
+#include <openssl/rand.h>
+#include <openssl/err.h>
#include "internal/quic_channel.h"
#include "internal/quic_error.h"
#include "internal/quic_rx_depack.h"
#include "../ssl_local.h"
#include "quic_channel_local.h"
-#include <openssl/rand.h>
/*
* NOTE: While this channel implementation currently has basic server support,
ossl_qrx_free(ch->qrx);
ossl_quic_demux_free(ch->demux);
OPENSSL_free(ch->local_transport_params);
+ OSSL_ERR_STATE_free(ch->err_state);
}
QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args)
}
}
+static void ch_save_err_state(QUIC_CHANNEL *ch)
+{
+ if (ch->err_state == NULL)
+ ch->err_state = OSSL_ERR_STATE_new();
+
+ if (ch->err_state == NULL)
+ return;
+
+ OSSL_ERR_STATE_save(ch->err_state);
+}
+
static void ch_raise_net_error(QUIC_CHANNEL *ch)
{
QUIC_TERMINATE_CAUSE tcause = {0};
ch->net_error = 1;
+ ch_save_err_state(ch);
tcause.error_code = QUIC_ERR_INTERNAL_ERROR;
return ch->net_error;
}
+void ossl_quic_channel_restore_err_state(QUIC_CHANNEL *ch)
+{
+ if (ch == NULL)
+ return;
+
+ OSSL_ERR_STATE_restore(ch->err_state);
+}
+
void ossl_quic_channel_raise_protocol_error(QUIC_CHANNEL *ch,
uint64_t error_code,
uint64_t frame_type,
{
QUIC_TERMINATE_CAUSE tcause = {0};
+ if (error_code == QUIC_ERR_INTERNAL_ERROR)
+ /* Internal errors might leave some errors on the stack. */
+ ch_save_err_state(ch);
+
tcause.error_code = error_code;
tcause.frame_type = frame_type;
/* Permanent net error encountered */
unsigned int net_error : 1;
+
+ /* Saved error stack in case permanent error was encountered */
+ ERR_STATE *err_state;
};
# endif
{
va_list args;
- ERR_new();
- ERR_set_debug(file, line, func);
-
- va_start(args, fmt);
- ERR_vset_error(ERR_LIB_SSL, reason, fmt, args);
- va_end(args);
-
if (ctx != NULL) {
if (ctx->is_stream && ctx->xso != NULL)
ctx->xso->last_error = SSL_ERROR_SSL;
else if (!ctx->is_stream && ctx->qc != NULL)
ctx->qc->last_error = SSL_ERROR_SSL;
+
+ if (reason == SSL_R_PROTOCOL_IS_SHUTDOWN && ctx->qc != NULL)
+ ossl_quic_channel_restore_err_state(ctx->qc->ch);
}
+ ERR_new();
+ ERR_set_debug(file, line, func);
+
+ va_start(args, fmt);
+ ERR_vset_error(ERR_LIB_SSL, reason, fmt, args);
+ va_end(args);
+
return 0;
}
X509_STORE_CTX_get0_rpk ? 3_2_0 EXIST::FUNCTION:
X509_STORE_CTX_set0_rpk ? 3_2_0 EXIST::FUNCTION:
CRYPTO_atomic_load_int ? 3_2_0 EXIST::FUNCTION:
+OSSL_ERR_STATE_new ? 3_2_0 EXIST::FUNCTION:
+OSSL_ERR_STATE_save ? 3_2_0 EXIST::FUNCTION:
+OSSL_ERR_STATE_restore ? 3_2_0 EXIST::FUNCTION:
+OSSL_ERR_STATE_free ? 3_2_0 EXIST::FUNCTION: