From: Arran Cudbard-Bell Date: Thu, 24 Feb 2022 18:13:25 +0000 (-0500) Subject: async_posix: Allow custom stack allocation functions to be specified for POSIX contexts X-Git-Tag: openssl-3.2.0-alpha1~2872 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f6f56f4776727e18d4dd5490e3b507bae068013a;p=thirdparty%2Fopenssl.git async_posix: Allow custom stack allocation functions to be specified for POSIX contexts Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/17762) --- diff --git a/crypto/async/arch/async_null.c b/crypto/async/arch/async_null.c index 675c1d35bf0..85268b32351 100644 --- a/crypto/async/arch/async_null.c +++ b/crypto/async/arch/async_null.c @@ -16,6 +16,21 @@ int ASYNC_is_capable(void) return 0; } +int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, + ASYNC_stack_free_fn free_fn) +{ + return 0; +} + +void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, + ASYNC_stack_free_fn *free_fn) +{ + if (alloc_fn != NULL) + *alloc_fn = NULL; + if (free_fn != NULL) + *free_fn = NULL; +} + void async_local_cleanup(void) { } diff --git a/crypto/async/arch/async_posix.c b/crypto/async/arch/async_posix.c index a0ac97783fa..0a1ffbf8d06 100644 --- a/crypto/async/arch/async_posix.c +++ b/crypto/async/arch/async_posix.c @@ -18,6 +18,13 @@ #define STACKSIZE 32768 +static void *async_stack_alloc(size_t *num); +static void async_stack_free(void *addr); + +static int allow_customize = 1; +static ASYNC_stack_alloc_fn stack_alloc_impl = async_stack_alloc; +static ASYNC_stack_free_fn stack_free_impl = async_stack_free; + int ASYNC_is_capable(void) { ucontext_t ctx; @@ -29,6 +36,37 @@ int ASYNC_is_capable(void) return getcontext(&ctx) == 0; } +int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, + ASYNC_stack_free_fn free_fn) +{ + if (!allow_customize) + return 0; + if (alloc_fn != NULL) + stack_alloc_impl = alloc_fn; + if (free_fn != NULL) + stack_free_impl = free_fn; + return 1; +} + +void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, + ASYNC_stack_free_fn *free_fn) +{ + if (alloc_fn != NULL) + *alloc_fn = stack_alloc_impl; + if (free_fn != NULL) + *free_fn = stack_free_impl; +} + +static void *async_stack_alloc(size_t *num) +{ + return OPENSSL_malloc(*num); +} + +static void async_stack_free(void *addr) +{ + OPENSSL_free(addr); +} + void async_local_cleanup(void) { } @@ -39,9 +77,18 @@ int async_fibre_makecontext(async_fibre *fibre) fibre->env_init = 0; #endif if (getcontext(&fibre->fibre) == 0) { - fibre->fibre.uc_stack.ss_sp = OPENSSL_malloc(STACKSIZE); + size_t num = STACKSIZE; + + /* + * Disallow customisation after the first + * stack is allocated. + */ + if (allow_customize) + allow_customize = 0; + + fibre->fibre.uc_stack.ss_sp = stack_alloc_impl(&num); if (fibre->fibre.uc_stack.ss_sp != NULL) { - fibre->fibre.uc_stack.ss_size = STACKSIZE; + fibre->fibre.uc_stack.ss_size = num; fibre->fibre.uc_link = NULL; makecontext(&fibre->fibre, async_start_func, 0); return 1; @@ -55,7 +102,7 @@ int async_fibre_makecontext(async_fibre *fibre) void async_fibre_free(async_fibre *fibre) { - OPENSSL_free(fibre->fibre.uc_stack.ss_sp); + stack_free_impl(fibre->fibre.uc_stack.ss_sp); fibre->fibre.uc_stack.ss_sp = NULL; } diff --git a/crypto/async/arch/async_win.c b/crypto/async/arch/async_win.c index 0b276fd504d..1d0d9fa0284 100644 --- a/crypto/async/arch/async_win.c +++ b/crypto/async/arch/async_win.c @@ -20,6 +20,21 @@ int ASYNC_is_capable(void) return 1; } +int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, + ASYNC_stack_free_fn free_fn) +{ + return 0; +} + +void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, + ASYNC_stack_free_fn *free_fn) +{ + if (alloc_fn != NULL) + *alloc_fn = NULL; + if (free_fn != NULL) + *free_fn = NULL; +} + void async_local_cleanup(void) { async_ctx *ctx = async_get_ctx(); diff --git a/doc/man3/ASYNC_start_job.pod b/doc/man3/ASYNC_start_job.pod index b2e7a583d4e..9cf34f65ce1 100644 --- a/doc/man3/ASYNC_start_job.pod +++ b/doc/man3/ASYNC_start_job.pod @@ -4,7 +4,8 @@ ASYNC_get_wait_ctx, ASYNC_init_thread, ASYNC_cleanup_thread, ASYNC_start_job, ASYNC_pause_job, -ASYNC_get_current_job, ASYNC_block_pause, ASYNC_unblock_pause, ASYNC_is_capable +ASYNC_get_current_job, ASYNC_block_pause, ASYNC_unblock_pause, ASYNC_is_capable, +ASYNC_stack_alloc_fn, ASYNC_stack_free_fn, ASYNC_set_mem_functions, ASYNC_get_mem_functions - asynchronous job management functions =head1 SYNOPSIS @@ -25,6 +26,13 @@ ASYNC_get_current_job, ASYNC_block_pause, ASYNC_unblock_pause, ASYNC_is_capable int ASYNC_is_capable(void); + typedef void *(*ASYNC_stack_alloc_fn)(size_t *num); + typedef void (*ASYNC_stack_free_fn)(void *addr); + int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, + ASYNC_stack_free_fn free_fn); + void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, + ASYNC_stack_free_fn *free_fn); + =head1 DESCRIPTION OpenSSL implements asynchronous capabilities through an B. This @@ -146,6 +154,15 @@ occur. Some platforms cannot support async operations. The ASYNC_is_capable() function can be used to detect whether the current platform is async capable or not. +Custom memory allocation functions are supported for the POSIX platform. +Custom memory allocation functions allow alternative methods of allocating +stack memory such as mmap, or using stack memory from the current thread. +Using an ASYNC_stack_alloc_fn callback also allows manipulation of the stack +size, which defaults to 32k. +The stack size can be altered by allocating a stack of a size different to +the requested size, and passing back the new stack size in the callback's I<*num> +parameter. + =head1 RETURN VALUES ASYNC_init_thread returns 1 on success or 0 otherwise. @@ -165,6 +182,9 @@ ASYNC_get_wait_ctx() returns a pointer to the B for the job. ASYNC_is_capable() returns 1 if the current platform is async capable or 0 otherwise. +ASYNC_set_mem_functions returns 1 if custom stack allocators are supported by +the current platform and no allocations have already occurred or 0 otherwise. + =head1 NOTES On Windows platforms the F<< >> header is dependent on some diff --git a/include/openssl/async.h b/include/openssl/async.h index bc27d5db06a..94429a0009e 100644 --- a/include/openssl/async.h +++ b/include/openssl/async.h @@ -80,6 +80,14 @@ int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key); int ASYNC_is_capable(void); +typedef void *(*ASYNC_stack_alloc_fn)(size_t *num); +typedef void (*ASYNC_stack_free_fn)(void *addr); + +int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn, + ASYNC_stack_free_fn free_fn); +void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn, + ASYNC_stack_free_fn *free_fn); + int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret, int (*func)(void *), void *args, size_t size); int ASYNC_pause_job(void); diff --git a/test/asynctest.c b/test/asynctest.c index 6502ee98454..0e2e012403f 100644 --- a/test/asynctest.c +++ b/test/asynctest.c @@ -18,6 +18,8 @@ static int ctr = 0; static ASYNC_JOB *currjob = NULL; +static int custom_alloc_used = 0; +static int custom_free_used = 0; static int only_pause(void *args) { @@ -413,6 +415,51 @@ static int test_ASYNC_start_job_ex(void) return ret; } +static void *test_alloc_stack(size_t *num) +{ + custom_alloc_used = 1; + return OPENSSL_malloc(*num); +} + +static void test_free_stack(void *addr) +{ + custom_free_used = 1; + OPENSSL_free(addr); +} + +static int test_ASYNC_set_mem_functions(void) +{ + ASYNC_stack_alloc_fn alloc_fn; + ASYNC_stack_free_fn free_fn; + + /* Not all platforms support this */ + if (ASYNC_set_mem_functions(test_alloc_stack, test_free_stack) == 0) return 1; + + ASYNC_get_mem_functions(&alloc_fn, &free_fn); + + if ((alloc_fn != test_alloc_stack) || (free_fn != test_free_stack)) { + fprintf(stderr, + "test_ASYNC_set_mem_functions() - setting and retrieving custom allocators failed\n"); + return 0; + } + + if (!ASYNC_init_thread(1, 1)) { + fprintf(stderr, + "test_ASYNC_set_mem_functions() - failed initialising ctx pool\n"); + return 0; + } + ASYNC_cleanup_thread(); + + if (!custom_alloc_used || !custom_free_used) { + fprintf(stderr, + "test_ASYNC_set_mem_functions() - custom allocation functions not used\n"); + + return 0; + } + + return 1; +} + int main(int argc, char **argv) { if (!ASYNC_is_capable()) { @@ -425,7 +472,8 @@ int main(int argc, char **argv) || !test_ASYNC_get_current_job() || !test_ASYNC_WAIT_CTX_get_all_fds() || !test_ASYNC_block_pause() - || !test_ASYNC_start_job_ex()) { + || !test_ASYNC_start_job_ex() + || !test_ASYNC_set_mem_functions()) { return 1; } } diff --git a/util/libcrypto.num b/util/libcrypto.num index 7b63154b552..0549b870250 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5434,3 +5434,5 @@ BN_signed_lebin2bn ? 3_1_0 EXIST::FUNCTION: BN_signed_bn2lebin ? 3_1_0 EXIST::FUNCTION: BN_signed_native2bn ? 3_1_0 EXIST::FUNCTION: BN_signed_bn2native ? 3_1_0 EXIST::FUNCTION: +ASYNC_set_mem_functions ? 3_1_0 EXIST::FUNCTION: +ASYNC_get_mem_functions ? 3_1_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index 974fe62f6a4..7635854b195 100644 --- a/util/other.syms +++ b/util/other.syms @@ -137,6 +137,8 @@ custom_ext_free_cb datatype custom_ext_parse_cb datatype pem_password_cb datatype ssl_ct_validation_cb datatype +ASYNC_stack_alloc_fn datatype +ASYNC_stack_free_fn datatype # ASN1_BIT_STRING_digest define BIO_append_filename define