]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
dl: Fix access check so real errors are not obscured
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 21 Feb 2023 23:27:14 +0000 (17:27 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 22 Feb 2023 02:56:47 +0000 (20:56 -0600)
src/lib/util/dl.c
src/lib/util/syserror.c
src/lib/util/syserror.h

index cfeba90cf542ae684fa7e5728ffd005c1ec31243..80892cb0909f7360b457b38c4637b26cf353c74a 100644 (file)
@@ -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;
                }
        }
index 3250133195fb548dbd04d377f848b46b9933b16b..d5f2686944aa3bcef62da7a7c74a92c6b25a846a 100644 (file)
@@ -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;
+}
index 908d1b439359dbca8db0280720bd60827a90ca6f..76225ddb4909ef96455800c6d937d32494436293 100644 (file)
@@ -38,6 +38,9 @@ extern "C" {
 /** @hidecallergraph */
 char const     *fr_syserror(int num);
 
+/** @hidecallergraph */
+char const     *fr_syserror_simple(int num);
+
 #ifdef __cplusplus
 }
 #endif