X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Ferr%2Ferr.c;h=9eb477ccda38ca42b617cc6a53b82112c455f9d2;hp=44e7115f9c1041be2d3123563a02807bc642f115;hb=8908d18cb1020f225170dd9090206842dbb6bbe6;hpb=df1f538f28c10f2954757164b17781040d2355ef diff --git a/crypto/err/err.c b/crypto/err/err.c index 44e7115f9c..9eb477ccda 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -58,12 +58,16 @@ static ERR_STRING_DATA ERR_str_libraries[] = { {ERR_PACK(ERR_LIB_UI, 0, 0), "UI routines"}, {ERR_PACK(ERR_LIB_FIPS, 0, 0), "FIPS routines"}, {ERR_PACK(ERR_LIB_CMS, 0, 0), "CMS routines"}, + {ERR_PACK(ERR_LIB_CRMF, 0, 0), "CRMF routines"}, + {ERR_PACK(ERR_LIB_CMP, 0, 0), "CMP routines"}, {ERR_PACK(ERR_LIB_HMAC, 0, 0), "HMAC routines"}, {ERR_PACK(ERR_LIB_CT, 0, 0), "CT routines"}, {ERR_PACK(ERR_LIB_ASYNC, 0, 0), "ASYNC routines"}, {ERR_PACK(ERR_LIB_KDF, 0, 0), "KDF routines"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, 0), "STORE routines"}, {ERR_PACK(ERR_LIB_SM2, 0, 0), "SM2 routines"}, + {ERR_PACK(ERR_LIB_ESS, 0, 0), "ESS routines"}, + {ERR_PACK(ERR_LIB_PROV, 0, 0), "Provider routines"}, {0, NULL}, }; @@ -184,8 +188,8 @@ static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d) } #ifndef OPENSSL_NO_ERR -/* A measurement on Linux 2018-11-21 showed about 3.5kib */ -# define SPACE_SYS_STR_REASONS 4 * 1024 +/* 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]; @@ -219,21 +223,23 @@ static void build_SYS_str_reasons(void) ERR_STRING_DATA *str = &SYS_str_reasons[i - 1]; str->error = ERR_PACK(ERR_LIB_SYS, 0, i); - if (str->string == NULL) { + /* + * 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; - if (cnt > sizeof(strerror_pool)) - cnt = sizeof(strerror_pool); cur += l; /* * VMS has an unusual quirk of adding spaces at the end of - * some (most? all?) messages. Lets trim them off. + * some (most? all?) messages. Lets trim them off. */ - while (ossl_isspace(cur[-1])) { + while (cur > strerror_pool && ossl_isspace(cur[-1])) { cur--; cnt--; } @@ -523,8 +529,24 @@ static unsigned long get_error_values(int inc, int top, const char **file, return ERR_R_INTERNAL_ERROR; } + while (es->bottom != es->top) { + if (es->err_flags[es->top] & ERR_FLAG_CLEAR) { + err_clear(es, es->top); + es->top = es->top > 0 ? es->top - 1 : ERR_NUM_ERRORS - 1; + continue; + } + i = (es->bottom + 1) % ERR_NUM_ERRORS; + if (es->err_flags[i] & ERR_FLAG_CLEAR) { + es->bottom = i; + err_clear(es, es->bottom); + continue; + } + break; + } + if (es->bottom == es->top) return 0; + if (top) i = es->top; /* last error */ else @@ -666,7 +688,8 @@ const char *ERR_reason_error_string(unsigned long e) return ((p == NULL) ? NULL : p->string); } -void err_delete_thread_state(void) +/* TODO(3.0): arg ignored for now */ +static void err_delete_thread_state(void *arg) { ERR_STATE *state = CRYPTO_THREAD_get_local(&err_thread_local); if (state == NULL) @@ -718,7 +741,7 @@ ERR_STATE *ERR_get_state(void) return NULL; } - if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_ERR_STATE) + if (!ossl_init_thread_start(NULL, err_delete_thread_state) || !CRYPTO_THREAD_set_local(&err_thread_local, state)) { ERR_STATE_free(state); CRYPTO_THREAD_set_local(&err_thread_local, NULL); @@ -790,20 +813,31 @@ int ERR_get_next_error_library(void) return ret; } -void ERR_set_error_data(char *data, int flags) +static int err_set_error_data_int(char *data, int flags) { ERR_STATE *es; int i; es = ERR_get_state(); if (es == NULL) - return; + return 0; i = es->top; err_clear_data(es, i); es->err_data[i] = data; es->err_data_flags[i] = flags; + + return 1; +} + +void ERR_set_error_data(char *data, int flags) +{ + /* + * This function is void so we cannot propagate the error return. Since it + * is also in the public API we can't change the return type. + */ + err_set_error_data_int(data, flags); } void ERR_add_error_data(int num, ...) @@ -816,34 +850,44 @@ void ERR_add_error_data(int num, ...) void ERR_add_error_vdata(int num, va_list args) { - int i, n, s; - char *str, *p, *a; + int i, len, size; + char *str, *p, *arg; + ERR_STATE *es; + + /* Get the current error data; if an allocated string get it. */ + es = ERR_get_state(); + if (es == NULL) + return; + i = es->top; + p = es->err_data_flags[i] == (ERR_TXT_MALLOCED | ERR_TXT_STRING) + ? es->err_data[i] : ""; - s = 80; - if ((str = OPENSSL_malloc(s + 1)) == NULL) { + /* Start with initial (or empty) string and allocate a new buffer */ + size = 80 + strlen(p); + if ((str = OPENSSL_malloc(size + 1)) == NULL) { /* ERRerr(ERR_F_ERR_ADD_ERROR_VDATA, ERR_R_MALLOC_FAILURE); */ return; } - str[0] = '\0'; - - n = 0; - for (i = 0; i < num; i++) { - a = va_arg(args, char *); - if (a == NULL) - a = ""; - n += strlen(a); - if (n > s) { - s = n + 20; - p = OPENSSL_realloc(str, s + 1); + strcpy(str, p); + + for (len = 0; --num >= 0; ) { + arg = va_arg(args, char *); + if (arg == NULL) + arg = ""; + len += strlen(arg); + if (len > size) { + size = len + 20; + p = OPENSSL_realloc(str, size + 1); if (p == NULL) { OPENSSL_free(str); return; } str = p; } - OPENSSL_strlcat(str, a, (size_t)s + 1); + OPENSSL_strlcat(str, arg, (size_t)size + 1); } - ERR_set_error_data(str, ERR_TXT_MALLOCED | ERR_TXT_STRING); + if (!err_set_error_data_int(str, ERR_TXT_MALLOCED | ERR_TXT_STRING)) + OPENSSL_free(str); } int ERR_set_mark(void) @@ -901,25 +945,6 @@ int ERR_clear_last_mark(void) return 1; } -#ifdef UINTPTR_T -# undef UINTPTR_T -#endif -/* - * uintptr_t is the answer, but unfortunately C89, current "least common - * denominator" doesn't define it. Most legacy platforms typedef it anyway, - * so that attempt to fill the gaps means that one would have to identify - * that track these gaps, which would be undesirable. Macro it is... - */ -#if defined(__VMS) && __INITIAL_POINTER_SIZE==64 -/* - * But we can't use size_t on VMS, because it adheres to sizeof(size_t)==4 - * even in 64-bit builds, which means that it won't work as mask. - */ -# define UINTPTR_T unsigned long long -#else -# define UINTPTR_T size_t -#endif - void err_clear_last_constant_time(int clear) { ERR_STATE *es; @@ -931,11 +956,11 @@ void err_clear_last_constant_time(int clear) top = es->top; - es->err_flags[top] &= ~(0 - clear); - es->err_buffer[top] &= ~(0UL - clear); - es->err_file[top] = (const char *)((UINTPTR_T)es->err_file[top] & - ~((UINTPTR_T)0 - clear)); - es->err_line[top] |= 0 - clear; - - es->top = (top + ERR_NUM_ERRORS - clear) % ERR_NUM_ERRORS; + /* + * Flag error as cleared but remove it elsewhere to avoid two errors + * accessing the same error stack location, revealing timing information. + */ + clear = constant_time_select_int(constant_time_eq_int(clear, 0), + 0, ERR_FLAG_CLEAR); + es->err_flags[top] |= clear; }