]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Setup custom fibre allocators for OpenSSL with a guard page
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 16 Apr 2025 17:00:09 +0000 (12:00 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 16 Apr 2025 17:00:15 +0000 (12:00 -0500)
src/lib/tls/base.c

index 46d53538804d9f2827a3fdc4ebc62a1d672341f5..b5a2d81d49462aead2c15a6d9bf0513faa7b58fe 100644 (file)
@@ -33,6 +33,7 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include "log.h"
 #include "bio.h"
 
+#include <sys/mman.h>
 #include <openssl/conf.h>
 #include <openssl/provider.h>
 
@@ -42,6 +43,8 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include <freeradius-devel/tls/engine.h>
 #include <freeradius-devel/util/atexit.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/math.h>
+#include <freeradius-devel/util/syserror.h>
 
 static uint32_t openssl_instance_count = 0;
 
@@ -374,6 +377,52 @@ static int fr_openssl_cleanup(UNUSED void *uctx)
        return 0;
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30400000L
+static void *fr_openssl_stack_alloc(size_t *len)
+{
+       size_t page_size = (size_t)getpagesize();
+       void *stack;
+
+       /*
+        *      OpenSSL uses 32K stacks by default
+        *      Do that here, then add an extra page's worth of
+        *      of memory at the end for poisoning.
+        */
+       size_t stack_size = ROUND_UP_POW2(32768, page_size); /* Ensure this is a multiple of our page size */
+       if (posix_memalign(&stack, page_size, stack_size + page_size) != 0) {
+               fr_tls_log(NULL, "Failed allocating OpenSSL stack: %s", fr_syserror(errno));
+               return NULL;
+       }
+
+       /*
+        *      Catch reads and writes going off the end of the stack.
+        */
+       if (mprotect((uint8_t *)stack + stack_size, page_size, PROT_NONE) < 0) {
+               fr_tls_log(NULL, "Failed adding guard page to OpenSSL stack: %s", fr_syserror(errno));
+               free(stack);
+               return NULL;
+       }
+       *len = stack_size;
+
+       return stack;
+}
+
+static void fr_openssl_stack_free(void *stack)
+{
+       size_t page_size = (size_t)getpagesize();
+
+       /*
+        *      Remove the guard page.  If this failed, we can't continue
+        *      as we'll have random protected memory chunks
+        */
+       if (unlikely(mprotect(stack, page_size, PROT_READ | PROT_WRITE) < 0)) {
+               fr_assert_msg(0, "Uprotecting OpenSSL stack memory failed, can't continue: %s", fr_syserror(errno));
+               fr_exit(1);
+       }
+       free(stack);
+}
+#endif
+
 /** Add all the default ciphers and message digests to our context.
  *
  * This should be called exactly once from main, before reading the main config
@@ -395,6 +444,17 @@ int fr_openssl_init(void)
                return -1;
        }
 
+       /*
+        *      Setup custom memory allocators for allocating greenthread
+        *      stacks, so we can add guard pages.
+        */
+#if OPENSSL_VERSION_NUMBER >= 0x30400000L
+       if (ASYNC_set_mem_functions(fr_openssl_stack_alloc, fr_openssl_stack_free) != 1) {
+               fr_tls_log(NULL, "Failed to set OpenSSL async stack allocation functions");
+               return -1;
+       }
+#endif
+
        /*
         *      NO_ATEXIT has no effect if init is done after
         *      loading providers, and we need to control the