diff options
author | Richard Levitte <levitte@openssl.org> | 2020-06-29 12:18:24 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-07-05 21:13:03 +0200 |
commit | 71f2994b151f5de0c7bc14592c84795ff98256c1 (patch) | |
tree | d5a18c747afd3fd36924d439d0a1786e1f5acf35 /crypto/err | |
parent | 163b2bcd8b2e5cd149dfc8dce1ca096805559379 (diff) |
ERR: special case system errors
Because system errors can be any positive number that fits in an 'int'
according to POSIX, we can't reasonably expect them to be in the 1..127
range, even though that's the most usual.
Instead of packing them into the OpenSSL error code structure, we
recognise them as a special case and mark them as such by storing them
in our error queue with the highest bit set. We make OpenSSL specific
error records have their highest bit cleared, and in doing so, we
shift down the library section of the code by one bit. This still
leaves a very large section for the reason codes.
Of course, we must adapt the error code and reason string extraction
and printing functions accordingly.
With this, we also thrown away the pre-loaded array of system error
strings, and extract them from the system when needed instead, i.e.
when we create error strings.
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/12343)
Diffstat (limited to 'crypto/err')
-rw-r--r-- | crypto/err/err.c | 104 | ||||
-rw-r--r-- | crypto/err/err_local.h | 5 | ||||
-rw-r--r-- | crypto/err/err_prn.c | 26 |
3 files changed, 49 insertions, 86 deletions
diff --git a/crypto/err/err.c b/crypto/err/err.c index 9a37c42625..26cf2b0b9d 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -173,84 +173,6 @@ static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d) 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; @@ -322,7 +244,6 @@ int ERR_load_ERR_strings(void) err_load_strings(ERR_str_libraries); err_load_strings(ERR_str_reasons); - build_SYS_str_reasons(); #endif return 1; } @@ -569,8 +490,8 @@ static unsigned long get_error_values(ERR_GET_ACTION g, 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) @@ -583,8 +504,19 @@ void ERR_error_string_n(unsigned long e, char *buf, size_t len) 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; @@ -642,6 +574,14 @@ const char *ERR_reason_error_string(unsigned long e) 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); diff --git a/crypto/err/err_local.h b/crypto/err/err_local.h index 0374bf6a6f..add49af44c 100644 --- a/crypto/err/err_local.h +++ b/crypto/err/err_local.h @@ -38,7 +38,10 @@ static ossl_inline void err_clear_data(ERR_STATE *es, size_t i, int deall) 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, diff --git a/crypto/err/err_prn.c b/crypto/err/err_prn.c index 80cc0ecf1a..f67cf2e32b 100644 --- a/crypto/err/err_prn.c +++ b/crypto/err/err_prn.c @@ -23,16 +23,36 @@ void ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u), { 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), |