return p;
}
-#ifndef OPENSSL_NO_ERR
-/* 2019-05-21: Russian and Ukrainian locales on Linux require more than 6,5 kB */
-# define SPACE_SYS_STR_REASONS 8 * 1024
-# define NUM_SYS_STR_REASONS 127
-
-static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1];
-/*
- * SYS_str_reasons is filled with copies of strerror() results at
- * initialization. 'errno' values up to 127 should cover all usual errors,
- * others will be displayed numerically by ERR_error_string. It is crucial
- * that we have something for each reason code that occurs in
- * ERR_str_reasons, or bogus reason strings will be returned for SYSerr(),
- * which always gets an errno value and never one of those 'standard' reason
- * codes.
- */
-
-static void build_SYS_str_reasons(void)
-{
- /* OPENSSL_malloc cannot be used here, use static storage instead */
- static char strerror_pool[SPACE_SYS_STR_REASONS];
- char *cur = strerror_pool;
- size_t cnt = 0;
- static int init = 1;
- int i;
- int saveerrno = get_last_sys_error();
-
- CRYPTO_THREAD_write_lock(err_string_lock);
- if (!init) {
- CRYPTO_THREAD_unlock(err_string_lock);
- return;
- }
-
- for (i = 1; i <= NUM_SYS_STR_REASONS; i++) {
- ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
-
- str->error = ERR_PACK(ERR_LIB_SYS, 0, i);
- /*
- * If we have used up all the space in strerror_pool,
- * there's no point in calling openssl_strerror_r()
- */
- if (str->string == NULL && cnt < sizeof(strerror_pool)) {
- if (openssl_strerror_r(i, cur, sizeof(strerror_pool) - cnt)) {
- size_t l = strlen(cur);
-
- str->string = cur;
- cnt += l;
- cur += l;
-
- /*
- * VMS has an unusual quirk of adding spaces at the end of
- * some (most? all?) messages. Lets trim them off.
- */
- while (cur > strerror_pool && ossl_isspace(cur[-1])) {
- cur--;
- cnt--;
- }
- *cur++ = '\0';
- cnt++;
- }
- }
- if (str->string == NULL)
- str->string = "unknown";
- }
-
- /*
- * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as
- * required by ERR_load_strings.
- */
-
- init = 0;
-
- CRYPTO_THREAD_unlock(err_string_lock);
- /* openssl_strerror_r could change errno, but we want to preserve it */
- set_sys_error(saveerrno);
- err_load_strings(SYS_str_reasons);
-}
-#endif
-
static void ERR_STATE_free(ERR_STATE *s)
{
int i;
err_load_strings(ERR_str_libraries);
err_load_strings(ERR_str_reasons);
- build_SYS_str_reasons();
#endif
return 1;
}
void ERR_error_string_n(unsigned long e, char *buf, size_t len)
{
- char lsbuf[64], rsbuf[64];
- const char *ls, *rs;
+ char lsbuf[64], rsbuf[256];
+ const char *ls, *rs = NULL;
unsigned long f = 0, l, r;
if (len == 0)
ls = lsbuf;
}
- rs = ERR_reason_error_string(e);
+ /*
+ * ERR_reason_error_string() can't safely return system error strings,
+ * since it would call openssl_strerror_r(), which needs a buffer for
+ * thread safety. So for system errors, we call openssl_strerror_r()
+ * directly instead.
+ */
r = ERR_GET_REASON(e);
+ if (ERR_SYSTEM_ERROR(e)) {
+ if (openssl_strerror_r(r, rsbuf, sizeof(rsbuf)))
+ rs = rsbuf;
+ } else {
+ rs = ERR_reason_error_string(e);
+ }
if (rs == NULL) {
BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
rs = rsbuf;
return NULL;
}
+ /*
+ * ERR_reason_error_string() can't safely return system error strings,
+ * since openssl_strerror_r() needs a buffer for thread safety, and we
+ * haven't got one that would serve any sensible purpose.
+ */
+ if (ERR_SYSTEM_ERROR(e))
+ return NULL;
+
l = ERR_GET_LIB(e);
r = ERR_GET_REASON(e);
d.error = ERR_PACK(l, 0, r);
static ossl_inline void err_set_error(ERR_STATE *es, size_t i,
int lib, int reason)
{
- es->err_buffer[i] = ERR_PACK(lib, 0, reason);
+ es->err_buffer[i] =
+ lib == ERR_LIB_SYS
+ ? (unsigned int)(ERR_SYSTEM_FLAG | reason)
+ : ERR_PACK(lib, 0, reason);
}
static ossl_inline void err_set_debug(ERR_STATE *es, size_t i,
{
CRYPTO_THREAD_ID tid = CRYPTO_THREAD_get_current_id();
unsigned long l;
- char buf[ERR_PRINT_BUF_SIZE], *hex;
- const char *lib, *reason;
const char *file, *data, *func;
int line, flags;
while ((l = ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) {
+ char buf[ERR_PRINT_BUF_SIZE], *hex;
+ const char *lib, *reason = NULL;
+ char rsbuf[256];
+ unsigned long r = ERR_GET_REASON(l);
+
lib = ERR_lib_error_string(l);
- reason = ERR_reason_error_string(l);
+
+ /*
+ * ERR_reason_error_string() can't safely return system error strings,
+ * since it would call openssl_strerror_r(), which needs a buffer for
+ * thread safety. So for system errors, we call openssl_strerror_r()
+ * directly instead.
+ */
+ if (ERR_SYSTEM_ERROR(l)) {
+ if (openssl_strerror_r(r, rsbuf, sizeof(rsbuf)))
+ reason = rsbuf;
+ } else {
+ reason = ERR_reason_error_string(l);
+ }
+
if (func == NULL)
func = "unknown function";
+ if (reason == NULL) {
+ BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
+ reason = rsbuf;
+ }
if ((flags & ERR_TXT_STRING) == 0)
data = "";
hex = openssl_buf2hexstr_sep((const unsigned char *)&tid, sizeof(tid),
# endif
# endif
+# include <limits.h>
# include <errno.h>
# define ERR_TXT_MALLOCED 0x01
# define X509err(f, r) ERR_raise_data(ERR_LIB_X509, (r), NULL)
# endif
-/*
- * The error code currently packs as follows (viewed as hex nibbles):
+/*-
+ * The error code packs differently depending on if it records a system
+ * error or an OpenSSL error.
*
- * LL rRRRRR
+ * A system error packs like this (we follow POSIX and only allow positive
+ * numbers that fit in an |int|):
*
- * Where LL is the library code, r is the reason flags, and rRRRRR is the
- * reason code.
- * Do note that the reason flags is part of the reason code, and could as
- * well be seen as a section of all possible reason codes. We do this for
- * backward compatibility reasons, i.e. how ERR_R_FATAL was implemented.
+ * +-+-------------------------------------------------------------+
+ * |1| system error number |
+ * +-+-------------------------------------------------------------+
+ *
+ * An OpenSSL error packs like this:
*
- * System errors (ERR_LIB_SYS) are structured the same way, except they
- * don't have any reason flag.
+ * <---------------------------- 32 bits -------------------------->
+ * <--- 8 bits ---><------------------ 23 bits ----------------->
+ * +-+---------------+---------------------------------------------+
+ * |0| library | reason |
+ * +-+---------------+---------------------------------------------+
*
- * LL RRRRRR
+ * A few of the reason bits are reserved as flags with special meaning:
+ *
+ * <4 bits><-------------- 19 bits ------------->
+ * +-------+-------------------------------------+
+ * | rflags| reason |
+ * +-------+-------------------------------------+
+ *
+ * We have the reason flags being part of the overall reason code for
+ * backward compatibility reasons, i.e. how ERR_R_FATAL was implemented.
*/
-# define ERR_LIB_OFFSET 24L
-# define ERR_LIB_MASK 0xFF
-# define ERR_RFLAGS_OFFSET 20L
-# define ERR_RFLAGS_MASK 0xF
-# define ERR_REASON_MASK 0XFFFFFF
+
+/* Macros to help decode recorded system errors */
+# define ERR_SYSTEM_FLAG ((unsigned int)INT_MAX + 1)
+# define ERR_SYSTEM_MASK ((unsigned int)INT_MAX)
+
+/* Macros to help decode recorded OpenSSL errors */
+# define ERR_LIB_OFFSET 23L
+# define ERR_LIB_MASK 0xFF
+# define ERR_RFLAGS_OFFSET 19L
+# define ERR_RFLAGS_MASK 0xF
+# define ERR_REASON_MASK 0X7FFFFF
/*
* Reason flags are defined pre-shifted to easily combine with the reason
* number.
*/
-# define ERR_RFLAG_FATAL (0x1 << ERR_RFLAGS_OFFSET)
-
-/* ERR_PACK takes reason flags and reason code combined in |r| */
-# define ERR_PACK(l,f,r) \
- ( (((unsigned int)(l) & ERR_LIB_MASK) << ERR_LIB_OFFSET) | \
- (((unsigned int)(r) & ERR_REASON_MASK)) )
-# define ERR_GET_LIB(l) (int)(((l) >> ERR_LIB_OFFSET) & ERR_LIB_MASK)
-# define ERR_GET_FUNC(l) 0
-# define ERR_GET_RFLAGS(l) (int)((l) & (ERR_RFLAGS_MASK << ERR_RFLAGS_OFFSET))
-# define ERR_GET_REASON(l) (int)((l) & ERR_REASON_MASK)
-# define ERR_FATAL_ERROR(l) (int)((l) & ERR_RFLAG_FATAL)
+# define ERR_RFLAG_FATAL (0x1 << ERR_RFLAGS_OFFSET)
+
+# define ERR_SYSTEM_ERROR(errcode) (((errcode) & ERR_SYSTEM_FLAG) != 0)
+
+static ossl_inline int ERR_GET_LIB(unsigned long errcode)
+{
+ if (ERR_SYSTEM_ERROR(errcode))
+ return ERR_LIB_SYS;
+ return (errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK;
+}
+
+static ossl_inline int ERR_GET_FUNC(unsigned long errcode)
+{
+ return 0;
+}
+
+static ossl_inline int ERR_GET_RFLAGS(unsigned long errcode)
+{
+ if (ERR_SYSTEM_ERROR(errcode))
+ return 0;
+ return errcode & (ERR_RFLAGS_MASK << ERR_RFLAGS_OFFSET);
+}
+
+static ossl_inline int ERR_GET_REASON(unsigned long errcode)
+{
+ if (ERR_SYSTEM_ERROR(errcode))
+ return errcode & ERR_SYSTEM_MASK;
+ return errcode & ERR_REASON_MASK;
+}
+
+static ossl_inline int ERR_FATAL_ERROR(unsigned long errcode)
+{
+ return (ERR_GET_RFLAGS(errcode) & ERR_RFLAG_FATAL) != 0;
+}
+
+/*
+ * ERR_PACK is a helper macro to properly pack OpenSSL error codes and may
+ * only be used for that purpose. System errors are packed internally.
+ * ERR_PACK takes reason flags and reason code combined in |reason|.
+ * ERR_PACK ignores |func|, that parameter is just legacy from pre-3.0 OpenSSL.
+ */
+# define ERR_PACK(lib,func,reason) \
+ ( (((unsigned long)(lib) & ERR_LIB_MASK ) << ERR_LIB_OFFSET) | \
+ (((unsigned long)(reason) & ERR_REASON_MASK)) )
# ifndef OPENSSL_NO_DEPRECATED_3_0
# define SYS_F_FOPEN 0