Skip to content

Commit 1cc5fd9

Browse files
Implement fork handling for keysinuse context management (#154)
* Implement fork handling for keysinuse context management * Refactor keysinuse context management for fork handling * Fix fork safety in keysinuse by recreating locks * Revert "Fix fork safety in keysinuse by recreating locks" This reverts commit 0a6a3ea.
1 parent 5f0a841 commit 1cc5fd9

File tree

1 file changed

+82
-59
lines changed

1 file changed

+82
-59
lines changed

KeysInUse/keysinuse.c

Lines changed: 82 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,16 @@ static BOOL is_keysinuse_enabled();
132132
static void keysinuse_init_internal();
133133
static void keysinuse_cleanup_internal();
134134
static void keysinuse_teardown();
135-
static void keysinuse_atfork_reinit();
135+
136+
static void keysinuse_atfork_prepare();
137+
static void keysinuse_atfork_parent();
138+
static void keysinuse_atfork_child();
139+
140+
static void keysinuse_lock_key_ctx(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx);
141+
static void keysinuse_unlock_key_ctx(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx);
136142

137143
static void keysinuse_free_key_ctx(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx);
138-
static void keysinuse_reset_key_ctx(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx);
144+
static void keysinuse_atfork_reset_key_ctx(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx);
139145
static void keysinuse_ctx_log(_Inout_ SCOSSL_KEYSINUSE_CTX_IMP *ctx, _In_ PVOID doallArg);
140146

141147
static void keysinuse_log_common(int level, _In_ const char *message, va_list args);
@@ -280,7 +286,9 @@ static void keysinuse_init_internal()
280286
goto cleanup;
281287
}
282288

283-
if ((pthreadErr = pthread_atfork(NULL, NULL, keysinuse_atfork_reinit)) != 0)
289+
if ((pthreadErr = pthread_atfork(keysinuse_atfork_prepare,
290+
keysinuse_atfork_parent,
291+
keysinuse_atfork_child)) != 0)
284292
{
285293
keysinuse_log_error("Failed to register logging fork handler,SYS_%d", pthreadErr);
286294
goto cleanup;
@@ -339,63 +347,68 @@ void keysinuse_init()
339347
CRYPTO_THREAD_run_once(&keysinuse_init_once, keysinuse_init_internal);
340348
}
341349

342-
// If the calling process forks, the logging thread needs to be restarted in the
343-
// child process, and any locks should be reinitialized in case the parent
344-
// process held a lock at the time of the fork.
345-
static void keysinuse_atfork_reinit()
350+
351+
// acquire all locks to freeze state before fork
352+
static void keysinuse_atfork_prepare()
353+
{
354+
pthread_mutex_lock(&logging_thread_mutex);
355+
356+
if (lh_keysinuse_ctx_imp_lock != NULL)
357+
{
358+
CRYPTO_THREAD_write_lock(lh_keysinuse_ctx_imp_lock);
359+
}
360+
361+
if (lh_keysinuse_ctx_imp != NULL)
362+
{
363+
lh_SCOSSL_KEYSINUSE_CTX_IMP_doall(lh_keysinuse_ctx_imp, keysinuse_lock_key_ctx);
364+
}
365+
}
366+
367+
// release all locks in reverse order after fork
368+
static void keysinuse_atfork_parent()
369+
{
370+
if (lh_keysinuse_ctx_imp != NULL)
371+
{
372+
lh_SCOSSL_KEYSINUSE_CTX_IMP_doall(lh_keysinuse_ctx_imp, keysinuse_unlock_key_ctx);
373+
}
374+
375+
if (lh_keysinuse_ctx_imp_lock != NULL)
376+
{
377+
CRYPTO_THREAD_unlock(lh_keysinuse_ctx_imp_lock);
378+
}
379+
380+
pthread_mutex_unlock(&logging_thread_mutex);
381+
}
382+
383+
// The logging thread needs to be restarted in the child process.
384+
// Inherited locks are destroyed and recreated to ensure they are in a clean, unlocked state.
385+
static void keysinuse_atfork_child()
346386
{
347387
pthread_condattr_t attr;
348388
int pthreadErr;
349389
SCOSSL_STATUS status = SCOSSL_FAILURE;
350390
int is_parent_logging = is_logging;
351391
int is_parent_running = keysinuse_running;
352-
unsigned long lhDownLoad = 0;
353392

354393
// Reset global state
355394
keysinuse_running = FALSE;
356395
first_use_pending = FALSE;
357396
is_logging = FALSE;
358397
logging_thread_exit_status = SCOSSL_FAILURE;
359398

360-
logging_thread_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
361-
362-
// Recreate global locks in case they were held by the logging
363-
// thread in the parent process at the time of the fork.
364-
CRYPTO_THREAD_lock_free(lh_keysinuse_ctx_imp_lock);
365-
lh_keysinuse_ctx_imp_lock = CRYPTO_THREAD_lock_new();
366-
if (lh_keysinuse_ctx_imp_lock == NULL)
399+
if (lh_keysinuse_ctx_imp != NULL)
367400
{
368-
keysinuse_log_error("Failed to create keysinuse lock in child process");
369-
goto cleanup;
401+
lh_SCOSSL_KEYSINUSE_CTX_IMP_doall(lh_keysinuse_ctx_imp, keysinuse_atfork_reset_key_ctx);
370402
}
371403

372-
if (CRYPTO_THREAD_write_lock(lh_keysinuse_ctx_imp_lock))
404+
if (lh_keysinuse_ctx_imp_lock != NULL)
373405
{
374-
if (lh_keysinuse_ctx_imp != NULL)
375-
{
376-
// Set load factor to 0 during this operation to prevent hash table contraction.
377-
lhDownLoad = lh_SCOSSL_KEYSINUSE_CTX_IMP_get_down_load(lh_keysinuse_ctx_imp);
378-
lh_SCOSSL_KEYSINUSE_CTX_IMP_set_down_load(lh_keysinuse_ctx_imp, 0);
379-
380-
lh_SCOSSL_KEYSINUSE_CTX_IMP_doall(lh_keysinuse_ctx_imp, keysinuse_reset_key_ctx);
381-
382-
// Restore original down_load
383-
lh_SCOSSL_KEYSINUSE_CTX_IMP_set_down_load(lh_keysinuse_ctx_imp, lhDownLoad);
384-
}
385-
386-
CRYPTO_THREAD_unlock(lh_keysinuse_ctx_imp_lock);
387-
388-
if (lh_keysinuse_ctx_imp == NULL)
389-
{
390-
keysinuse_log_error("Keysinuse context hash table is missing in fork handler");
391-
goto cleanup;
392-
}
393-
}
394-
else
395-
{
396-
keysinuse_log_error("Failed to lock keysinuse context hash table in fork handler,OPENSSL_%d", ERR_get_error());
406+
CRYPTO_THREAD_lock_free(lh_keysinuse_ctx_imp_lock);
407+
lh_keysinuse_ctx_imp_lock = CRYPTO_THREAD_lock_new();
397408
}
398409

410+
pthread_mutex_unlock(&logging_thread_mutex);
411+
399412
// Only recreate logging thread if it was running in the parent process and keysinuse is enabled
400413
if (is_parent_logging && is_parent_running && is_keysinuse_enabled())
401414
{
@@ -784,31 +797,41 @@ static void keysinuse_free_key_ctx(SCOSSL_KEYSINUSE_CTX_IMP *ctx)
784797
}
785798

786799
_Use_decl_annotations_
787-
static void keysinuse_reset_key_ctx(SCOSSL_KEYSINUSE_CTX_IMP *ctx)
800+
static void keysinuse_lock_key_ctx(SCOSSL_KEYSINUSE_CTX_IMP *ctx)
788801
{
789-
if (ctx == NULL)
790-
return;
791-
792-
CRYPTO_THREAD_lock_free(ctx->lock);
793-
ctx->lock = CRYPTO_THREAD_lock_new();
794-
if (ctx->lock == NULL)
802+
if (ctx && ctx->lock)
795803
{
796-
keysinuse_enabled = FALSE;
797-
keysinuse_log_error("Failed to create keysinuse context lock in fork handler");
798-
return;
804+
CRYPTO_THREAD_write_lock(ctx->lock);
799805
}
806+
}
800807

801-
if (CRYPTO_THREAD_write_lock(ctx->lock))
808+
_Use_decl_annotations_
809+
static void keysinuse_unlock_key_ctx(SCOSSL_KEYSINUSE_CTX_IMP *ctx)
810+
{
811+
if (ctx && ctx->lock)
802812
{
803-
// Reset counters
804-
ctx->signCounter = 0;
805-
ctx->decryptCounter = 0;
813+
CRYPTO_THREAD_unlock(ctx->lock);
814+
}
815+
}
806816

807-
// Reset timestamps
808-
ctx->firstLogTime = 0;
809-
ctx->lastLogTime = 0;
817+
_Use_decl_annotations_
818+
static void keysinuse_atfork_reset_key_ctx(SCOSSL_KEYSINUSE_CTX_IMP *ctx)
819+
{
820+
if (ctx == NULL)
821+
return;
810822

811-
CRYPTO_THREAD_unlock(ctx->lock);
823+
// Reset counters
824+
ctx->signCounter = 0;
825+
ctx->decryptCounter = 0;
826+
827+
// Reset timestamps
828+
ctx->firstLogTime = 0;
829+
ctx->lastLogTime = 0;
830+
831+
if (ctx->lock)
832+
{
833+
CRYPTO_THREAD_lock_free(ctx->lock);
834+
ctx->lock = CRYPTO_THREAD_lock_new();
812835
}
813836
}
814837

0 commit comments

Comments
 (0)