From e5dcc435cc1ae3fa5f93a3b2e840e678acdf0d1d Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 28 Sep 2024 06:57:42 -0400 Subject: [PATCH] Fix: racy init_done initialization If init_done is set while another thread is loading its value, the other thread can erroneously expect initialization to be complete while the initialization is still in progress. Set init_done after initialization with a store-release, and load it with load-acquire outside of the mutex critical section. Signed-off-by: Mathieu Desnoyers Change-Id: Idb1345c6dcf3da7d711937bd5072527c0bf1d33a --- src/rseq.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/rseq.c b/src/rseq.c index 7ee3616..9b5470e 100644 --- a/src/rseq.c +++ b/src/rseq.c @@ -209,8 +209,12 @@ int rseq_unregister_current_thread(void) static void rseq_init(void) { - /* Ensure initialization is only done once. */ - if (RSEQ_READ_ONCE(init_done)) + /* + * Ensure initialization is only done once. Use load-acquire to + * observe the initialization performed by a concurrently + * running thread. + */ + if (rseq_smp_load_acquire(&init_done)) return; /* @@ -220,7 +224,6 @@ void rseq_init(void) pthread_mutex_lock(&init_lock); if (init_done) goto unlock; - RSEQ_WRITE_ONCE(init_done, 1); /* * Check for glibc rseq support, if the 3 public symbols are found and @@ -286,6 +289,11 @@ void rseq_init(void) * libc behavior. */ rseq_size = 0; + /* + * Set init_done with store-release, to make sure concurrently + * running threads observe the initialized state. + */ + rseq_smp_store_release(&init_done, 1); unlock: pthread_mutex_unlock(&init_lock); } -- 2.34.1