From: Arran Cudbard-Bell Date: Tue, 21 Feb 2023 23:27:14 +0000 (-0600) Subject: dl: Fix access check so real errors are not obscured X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e79e1064963d98fde87604740a66c20782382e2;p=thirdparty%2Ffreeradius-server.git dl: Fix access check so real errors are not obscured --- diff --git a/src/lib/util/dl.c b/src/lib/util/dl.c index cfeba90cf54..80892cb0909 100644 --- a/src/lib/util/dl.c +++ b/src/lib/util/dl.c @@ -576,18 +576,30 @@ dl_t *dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx * Yes, this really is the only way of getting the errno * from the dlopen API. */ - if (!strstr(dlerror_txt, fr_syserror(ENOENT))) { + if (strstr(dlerror_txt, fr_syserror_simple(ENOENT)) != NULL) { #ifndef __linux__ int access_mode = R_OK | X_OK; -#ifdef AT_ACCESS +# ifdef AT_ACCESS access_mode |= AT_ACCESS; -#endif +# endif if (access(path, access_mode) < 0 && errno == ENOENT) continue; #endif - fr_strerror_printf("Access check failed: %s", dlerror_txt); + fr_strerror_printf_push("Access check failed: %s", dlerror_txt); break; } + + /* + * We're reliant on dlerror_txt from the loop, + * because once dlerror() is called the error + * is cleared. + * + * We need to push every error because we + * don't know which one would be useful + * in diagnosing the underlying cause of the + * load failure. + */ + fr_strerror_printf_push("%s", dlerror_txt ? dlerror_txt : "unknown dlopen error"); } /* @@ -596,15 +608,11 @@ dl_t *dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx */ if (!handle) { talloc_free(ctx); - /* - * We're reliant on dlerror_txt from the loop, - * because once dlerror() is called the error - * is cleared. - */ - fr_strerror_printf("%s", dlerror_txt ? dlerror_txt : "unknown dlopen error"); return NULL; } + fr_strerror_clear(); /* Don't leave spurious errors in the buffer */ + talloc_free(ctx); } else { char buffer[2048]; @@ -622,7 +630,7 @@ dl_t *dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx /* * Append the error */ - fr_strerror_printf("%s", error); + fr_strerror_printf_push("%s", error); return NULL; } } diff --git a/src/lib/util/syserror.c b/src/lib/util/syserror.c index 3250133195f..d5f2686944a 100644 --- a/src/lib/util/syserror.c +++ b/src/lib/util/syserror.c @@ -159,52 +159,9 @@ static char const *fr_syserror_macro_names[] = { [EXDEV] = "EXDEV" }; -/** Guaranteed to be thread-safe version of strerror - * - * @param num errno as returned by function or from global errno. - * @return local specific error string relating to errno. - * - * @hidecallergraph - */ -char const *fr_syserror(int num) +static inline CC_HINT(always_inline) +ssize_t _fr_syserror(int num, char *buffer, size_t buff_len) { - char *buffer, *p, *end; - - buffer = fr_syserror_buffer; - if (!buffer) { - /* - * Try and produce something useful, - * even if the thread is exiting. - */ - if (logging_stop) { - if (HAVE_DEFINITION(num)) return fr_syserror_macro_names[num]; - return ""; - } - - buffer = talloc_array(NULL, char, FR_SYSERROR_BUFSIZE); - if (!buffer) { - fr_perror("Failed allocating memory for system error buffer"); - return NULL; - } - fr_atexit_thread_local(fr_syserror_buffer, _fr_logging_free, buffer); - } - - if (num == 0) return "No additional error information"; - - p = buffer; - end = p + FR_SYSERROR_BUFSIZE; - - /* - * Prefix system errors with the macro name and number - * if we're debugging. - */ - if (HAVE_DEFINITION(num)) { - p += snprintf(p, end - p, "%s: ", fr_syserror_macro_names[num]); - } else { - p += snprintf(p, end - p, "errno %i: ", num); - } - if (p >= end) return p; - /* * XSI-Compliant version */ @@ -212,49 +169,135 @@ char const *fr_syserror(int num) { int ret; - ret = strerror_r(num, p, end - p); + ret = strerror_r(num, buffer, buff_len); if (ret != 0) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), " "returned %i: %s\n", num, buffer, (size_t)FR_SYSERROR_BUFSIZE, ret, strerror(ret)); # endif buffer[0] = '\0'; + return -1; } } - return buffer; + return strlen(buffer); +#else /* * GNU Specific version * * The GNU Specific version returns a char pointer. That pointer may point * the buffer you just passed in, or to an immutable static string. */ -#else { char *q; - q = strerror_r(num, p, end - p); + q = strerror_r(num, buffer, buff_len); if (!q) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p " "(%zu bytes): %s\n", num, buffer, (size_t)FR_SYSERROR_BUFSIZE, strerror(errno)); # endif buffer[0] = '\0'; - return buffer; + return -1; } /* * If strerror_r used a static string, copy it to the buffer */ - if (q != p) { + if (q != buffer) { size_t len; len = strlen(q) + 1; - if (len >= (size_t)(end - p)) len = end - p; - - strlcpy(p, q, len); + if (len >= buff_len) len = buff_len; /* Truncate */ + return strlcpy(buffer, q, len); } - return buffer; + return strlen(q); } #endif } + +static inline CC_HINT(always_inline) +char *_fr_syserror_buffer(void) +{ + char *buffer; + + buffer = fr_syserror_buffer; + if (!buffer) { + buffer = talloc_array(NULL, char, FR_SYSERROR_BUFSIZE); + if (!buffer) { + fr_perror("Failed allocating memory for system error buffer"); + return NULL; + } + fr_atexit_thread_local(fr_syserror_buffer, _fr_logging_free, buffer); + } + return buffer; +} + +/** Guaranteed to be thread-safe version of strerror + * + * @param num errno as returned by function or from global errno. + * @return Error string relating to errno, with the macro name added as a prefix. + * + * @hidecallergraph + */ +char const *fr_syserror(int num) +{ + char *buffer, *p, *end; + + /* + * Try and produce something useful, + * even if the thread is exiting. + */ + if (logging_stop) { + error: + if (HAVE_DEFINITION(num)) return fr_syserror_macro_names[num]; + return ""; + } + + if (num == 0) return "No additional error information"; + + /* + * Grab our thread local buffer + */ + buffer = _fr_syserror_buffer(); + + p = buffer; + end = p + FR_SYSERROR_BUFSIZE; + + /* + * Prefix system errors with the macro name and number + * if we're debugging. + */ + if (HAVE_DEFINITION(num)) { + p += snprintf(p, end - p, "%s: ", fr_syserror_macro_names[num]); + } else { + p += snprintf(p, end - p, "errno %i: ", num); + } + if (p >= end) return p; + + if (_fr_syserror(num, p, end - p) < 0) goto error; + + return buffer; +} + +/** Guaranteed to be thread-safe version of strerror + * + * @param num errno as returned by function or from global errno. + * @return Error string relating to errno with no decoration. + * + * @hidecallergraph + */ +char const *fr_syserror_simple(int num) +{ + char *buffer; + + if (logging_stop) return ""; + + /* + * Grab our thread local buffer + */ + buffer = _fr_syserror_buffer(); + if (_fr_syserror(num, buffer, FR_SYSERROR_BUFSIZE) < 0) return "Failed retrieving error"; + + return buffer; +} diff --git a/src/lib/util/syserror.h b/src/lib/util/syserror.h index 908d1b43935..76225ddb490 100644 --- a/src/lib/util/syserror.h +++ b/src/lib/util/syserror.h @@ -38,6 +38,9 @@ extern "C" { /** @hidecallergraph */ char const *fr_syserror(int num); +/** @hidecallergraph */ +char const *fr_syserror_simple(int num); + #ifdef __cplusplus } #endif