Make the ASYNC code default libctx aware
authorMatt Caswell <matt@openssl.org>
Fri, 26 Jun 2020 10:00:25 +0000 (11:00 +0100)
committerRichard Levitte <levitte@openssl.org>
Sun, 28 Jun 2020 08:55:52 +0000 (10:55 +0200)
Since the default libctx is now stored in a thread local variable
swapping in and out of fibres in the ASYNC code could mean that the
"current" default libctx can get confused. Therefore we ensure that
everytime we call async_fibre_swapcontext() we always restore the default
libctx to whatever it was the last time the fibre ran. Similarly when
async_fibre_swapcontext() returns we need to restore the current thread's
default libctx.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/12228)

crypto/async/async.c
crypto/async/async_local.h
doc/man3/OPENSSL_CTX.pod

index 312f47325babc2c40f474a9703b7a6b658156815..b985505309c5784e9b46cfb0bef572bfa04f42f5 100644 (file)
@@ -170,6 +170,7 @@ int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
                     int (*func)(void *), void *args, size_t size)
 {
     async_ctx *ctx;
+    OPENSSL_CTX *libctx;
 
     if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
         return ASYNC_ERR;
@@ -203,6 +204,11 @@ int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
 
             if (ctx->currjob->status == ASYNC_JOB_PAUSED) {
                 ctx->currjob = *job;
+                /*
+                 * Restore the default libctx to what it was the last time the
+                 * fibre ran
+                 */
+                libctx = OPENSSL_CTX_set0_default(ctx->currjob->libctx);
                 /* Resume previous job */
                 if (!async_fibre_swapcontext(&ctx->dispatcher,
                         &ctx->currjob->fibrectx, 1)) {
@@ -210,6 +216,12 @@ int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
                              ASYNC_R_FAILED_TO_SWAP_CONTEXT);
                     goto err;
                 }
+                /*
+                 * In case the fibre changed the default libctx we set it back
+                 * again to what it was originally, and remember what it had
+                 * been changed to.
+                 */
+                ctx->currjob->libctx = OPENSSL_CTX_set0_default(libctx);
                 continue;
             }
 
@@ -240,11 +252,17 @@ int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
 
         ctx->currjob->func = func;
         ctx->currjob->waitctx = wctx;
+        libctx = openssl_ctx_get_concrete(NULL);
         if (!async_fibre_swapcontext(&ctx->dispatcher,
                 &ctx->currjob->fibrectx, 1)) {
             ASYNCerr(ASYNC_F_ASYNC_START_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
             goto err;
         }
+        /*
+         * In case the fibre changed the default libctx we set it back again
+         * to what it was, and remember what it had been changed to.
+         */
+        ctx->currjob->libctx = OPENSSL_CTX_set0_default(libctx);
     }
 
 err:
index 549a27e61143328bc599b93df15bfc8b9cf82d1b..f2f0a561867463ca5c1e1e2ceb7510aff7ccdf21 100644 (file)
@@ -43,6 +43,7 @@ struct async_job_st {
     int ret;
     int status;
     ASYNC_WAIT_CTX *waitctx;
+    OPENSSL_CTX *libctx;
 };
 
 struct fd_lookup_st {
index 0a98451f3d7f0ef71522e8150dab822533387496..01737de2ef50fb0a940e571007c47621c0cede76 100644 (file)
@@ -43,6 +43,14 @@ I<ctx> in the current thread.  The previous default library context is
 returned.  Care should be taken by the caller to restore the previous
 default library context with a subsequent call of this function.
 
+Care should be taken when changing the default library context and starting
+async jobs (see L<ASYNC_start_job(3)>), as the default library context when
+the job is started will be used throughout the lifetime of an async job, no
+matter how the calling thread makes further default library context changes
+in the mean time.  This means that the calling thread must not free the
+library context that was the default at the start of the async job before
+that job has finished.
+
 =head1 RETURN VALUES
 
 OPENSSL_CTX_new() and OPENSSL_CTX_set0_default() return a library context