From 7c0e20dc6f11aa506abc99ccc90b3a39c48c3052 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 24 Jul 2019 13:03:32 +0200 Subject: [PATCH] ERR: Add new building blocks for reporting errors The new building block are ERR_new(), ERR_set_debug(), ERR_set_error(), ERR_vset_error(), which allocate a new error record and set the diverse data in them. They are designed in such a way that it's reasonably easy to create macros that use all of them but then rely completely on the function signature of ERR_set_error() or ERR_vset_error(). Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/9452) --- crypto/err/build.info | 2 +- crypto/err/err_blocks.c | 113 ++++++++++++++++++++++++++++++++++++++++ doc/man3/ERR_new.pod | 78 +++++++++++++++++++++++++++ include/openssl/err.h | 9 ++++ util/libcrypto.num | 4 ++ 5 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 crypto/err/err_blocks.c create mode 100644 doc/man3/ERR_new.pod diff --git a/crypto/err/build.info b/crypto/err/build.info index 6163d95b74..c010ea4cb9 100644 --- a/crypto/err/build.info +++ b/crypto/err/build.info @@ -1,3 +1,3 @@ LIBS=../../libcrypto SOURCE[../../libcrypto]=\ - err.c err_all.c err_prn.c + err_blocks.c err.c err_all.c err_prn.c diff --git a/crypto/err/err_blocks.c b/crypto/err/err_blocks.c new file mode 100644 index 0000000000..49086bd0c2 --- /dev/null +++ b/crypto/err/err_blocks.c @@ -0,0 +1,113 @@ +/* + * Copyright 2019 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 + */ + +#include +#include +#include "err_locl.h" + +void ERR_new(void) +{ + ERR_STATE *es; + + es = ERR_get_state(); + if (es == NULL) + return; + + /* Allocate a slot */ + err_get_slot(es); + err_clear(es, es->top, 0); +} + +void ERR_set_debug(const char *file, int line, const char *func) +{ + ERR_STATE *es; + + es = ERR_get_state(); + if (es == NULL) + return; + + err_set_debug(es, es->top, file, line, func); +} + +void ERR_set_error(int lib, int reason, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ERR_vset_error(lib, reason, fmt, args); + va_end(args); +} + +void ERR_vset_error(int lib, int reason, const char *fmt, va_list args) +{ + ERR_STATE *es; + char *buf = NULL; + size_t buf_size = 0; + unsigned long flags = 0; + size_t i; + + es = ERR_get_state(); + if (es == NULL) + return; + i = es->top; + + if (fmt != NULL) { + int printed_len = 0; + char *rbuf = NULL; + + buf = es->err_data[i]; + buf_size = es->err_data_size[i]; + + /* + * To protect the string we just grabbed from tampering by other + * functions we may call, or to protect them from freeing a pointer + * that may no longer be valid at that point, we clear away the + * data pointer and the flags. We will set them again at the end + * of this function. + */ + es->err_data[i] = NULL; + es->err_data_flags[i] = 0; + + /* + * Try to maximize the space available. If that fails, we use what + * we have. + */ + if (buf_size < ERR_MAX_DATA_SIZE + && (rbuf = OPENSSL_realloc(buf, ERR_MAX_DATA_SIZE)) != NULL) { + buf = rbuf; + buf_size = ERR_MAX_DATA_SIZE; + } + + if (buf != NULL) { + printed_len = BIO_vsnprintf(buf, ERR_MAX_DATA_SIZE, fmt, args); + } + if (printed_len < 0) + printed_len = 0; + buf[printed_len] = '\0'; + + /* + * Try to reduce the size, but only if we maximized above. If that + * fails, we keep what we have. + * (According to documentation, realloc leaves the old buffer untouched + * if it fails) + */ + if ((rbuf = OPENSSL_realloc(buf, printed_len + 1)) != NULL) { + buf = rbuf; + buf_size = printed_len + 1; + } + + if (buf != NULL) + flags = ERR_TXT_MALLOCED | ERR_TXT_STRING; + } + + err_clear_data(es, es->top, 0); + err_set_error(es, es->top, lib, reason); + if (fmt != NULL) + err_set_data(es, es->top, buf, buf_size, flags); +} diff --git a/doc/man3/ERR_new.pod b/doc/man3/ERR_new.pod new file mode 100644 index 0000000000..80419da2c4 --- /dev/null +++ b/doc/man3/ERR_new.pod @@ -0,0 +1,78 @@ +=pod + +=head1 NAME + +ERR_new, ERR_set_debug, ERR_set_error, ERR_vset_error +- Error recording building blocks + +=head1 SYNOPSIS + + #include + + void ERR_new(void); + void ERR_set_debug(const char *file, int line, const char *func); + void ERR_set_error(int lib, int reason, const char *fmt, ...); + void ERR_vset_error(int lib, int reason, const char *fmt, va_list args); + +=head1 DESCRIPTION + +The functions described here are generally not used directly, but +rather through macros such as L. +They can still be useful for anyone that wants to make their own +macros. + +ERR_new() allocates a new slot in the thread's error queue. + +ERR_set_debug() sets the debug information related to the current +error in the thread's error queue. +The values that can be given are the file name I, line in the +file I and the name of the function I where the error +occured. +The names must be constant, this function will only save away the +pointers, not copy the strings. + +ERR_set_error() sets the error information, which are the library +number I and the reason code I, and additional data as a +format string I and an arbitrary number of arguments. +The additional data is processed with L to form the +additional data string, which is allocated and store in the error +record. + +ERR_vset_error() works like ERR_set_error(), but takes a B +argument instead of a variable number of arguments. + +=head1 RETURN VALUES + +ERR_new, ERR_set_debug, ERR_set_error and ERR_vset_error +do not return any values. + +=head1 NOTES + +The library number is unique to each unit that records errors. +OpenSSL has a number of pre-allocated ones for its own uses, but +others may allocate their own library number dynamically with +L. + +Reason codes are unique within each library, and may have an +associated set of strings as a short description of the reason. +For dynamically allocated library numbers, reason strings are recorded +with L. + +Provider authors are supplied with core versions of these functions, +see L. + +=head1 SEE ALSO + +L, L, +L, L, L + +=head1 COPYRIGHT + +Copyright 2000-2019 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. + +=cut diff --git a/include/openssl/err.h b/include/openssl/err.h index acecca462b..90e14672a4 100644 --- a/include/openssl/err.h +++ b/include/openssl/err.h @@ -236,6 +236,15 @@ typedef struct ERR_string_data_st { DEFINE_LHASH_OF(ERR_STRING_DATA); +/* 12 lines and some on an 80 column terminal */ +#define ERR_MAX_DATA_SIZE 1024 + +/* Building blocks */ +void ERR_new(void); +void ERR_set_debug(const char *file, int line, const char *func); +void ERR_set_error(int lib, int reason, const char *fmt, ...); +void ERR_vset_error(int lib, int reason, const char *fmt, va_list args); + void ERR_put_error(int lib, int func, int reason, const char *file, int line); void ERR_put_func_error(int lib, const char *func, int reason, const char *file, int line); diff --git a/util/libcrypto.num b/util/libcrypto.num index 81462480ca..da7395c9cb 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4700,3 +4700,7 @@ EVP_CIPHER_do_all_ex 4805 3_0_0 EXIST::FUNCTION: EVP_MD_do_all_ex 4806 3_0_0 EXIST::FUNCTION: EVP_KEYEXCH_provider 4807 3_0_0 EXIST::FUNCTION: OSSL_PROVIDER_available 4808 3_0_0 EXIST::FUNCTION: +ERR_new 4809 3_0_0 EXIST::FUNCTION: +ERR_set_debug 4810 3_0_0 EXIST::FUNCTION: +ERR_set_error 4811 3_0_0 EXIST::FUNCTION: +ERR_vset_error 4812 3_0_0 EXIST::FUNCTION: -- 2.25.1