public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Vitaly Buka <vitalybuka@google.com>
To: libc-alpha@sourceware.org
Cc: Vitaly Buka <vitalybuka@google.com>
Subject: [PATCH] stdlib: Fix data race in __run_exit_handlers
Date: Sun, 20 Sep 2020 02:57:50 -0700	[thread overview]
Message-ID: <20200920095750.396908-1-vitalybuka@google.com> (raw)

Read f->func.cxa under the lock.

It's incredible rare so I failed to create a test. However we have
binary which according to logs add __cxa_atexit with unique arg
and then callback is called twice for the same arg.

There is a clear data race:
thread 0: __run_exit_handlers unlock __exit_funcs_lock
thread 1: __internal_atexit locks __exit_funcs_lock
thread 0: f->flavor = ef_free;
thread 1: sees ef_free and use it as new
thread 1: new->func.cxa.fn = (void (*) (void *, int)) func;
thread 1: new->func.cxa.arg = arg;
thread 1: new->flavor = ef_cxa;
thread 0: cxafct = f->func.cxa.fn;  // it's wrong fn!
thread 0: cxafct (f->func.cxa.arg, status);  // it's wrong arg!
thread 0: goto restart;
thread 0: call the same exit_function again as it's ef_cxa
---
 stdlib/exit.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/stdlib/exit.c b/stdlib/exit.c
index 7bca1cdc14..93cdec82f0 100644
--- a/stdlib/exit.c
+++ b/stdlib/exit.c
@@ -72,44 +72,52 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
 	  struct exit_function *const f = &cur->fns[--cur->idx];
 	  const uint64_t new_exitfn_called = __new_exitfn_called;
 
-	  /* Unlock the list while we call a foreign function.  */
-	  __libc_lock_unlock (__exit_funcs_lock);
 	  switch (f->flavor)
 	    {
 	      void (*atfct) (void);
 	      void (*onfct) (int status, void *arg);
 	      void (*cxafct) (void *arg, int status);
+	      void *arg;
 
 	    case ef_free:
 	    case ef_us:
 	      break;
 	    case ef_on:
 	      onfct = f->func.on.fn;
+	      arg =  f->func.on.arg;
+	      /* Unlock the list while we call a foreign function.  */
+	      __libc_lock_unlock (__exit_funcs_lock);
 #ifdef PTR_DEMANGLE
 	      PTR_DEMANGLE (onfct);
 #endif
-	      onfct (status, f->func.on.arg);
+	      onfct (status, arg);
+	      __libc_lock_lock (__exit_funcs_lock);
 	      break;
 	    case ef_at:
 	      atfct = f->func.at;
+	      /* Unlock the list while we call a foreign function.  */
+	      __libc_lock_unlock (__exit_funcs_lock);
 #ifdef PTR_DEMANGLE
 	      PTR_DEMANGLE (atfct);
 #endif
 	      atfct ();
+	      __libc_lock_lock (__exit_funcs_lock);
 	      break;
 	    case ef_cxa:
 	      /* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
 		 we must mark this function as ef_free.  */
 	      f->flavor = ef_free;
 	      cxafct = f->func.cxa.fn;
+	      arg =  f->func.cxa.arg;
+	      /* Unlock the list while we call a foreign function.  */
+	      __libc_lock_unlock (__exit_funcs_lock);
 #ifdef PTR_DEMANGLE
 	      PTR_DEMANGLE (cxafct);
 #endif
-	      cxafct (f->func.cxa.arg, status);
+	      cxafct (arg, status);
+	      __libc_lock_lock (__exit_funcs_lock);
 	      break;
 	    }
-	  /* Re-lock again before looking at global state.  */
-	  __libc_lock_lock (__exit_funcs_lock);
 
 	  if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
 	    /* The last exit function, or another thread, has registered
-- 
2.28.0.681.g6f77f65b4e-goog


             reply	other threads:[~2020-09-20  9:58 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-20  9:57 Vitaly Buka [this message]
2020-09-20 12:09 ` Vitaly Buka
2020-09-20 20:41   ` Paul Pluzhnikov
2020-09-20 21:26     ` Vitaly Buka
2020-09-20 23:36       ` Vitaly Buka
2020-09-20 23:37         ` Vitaly Buka
2020-09-21  8:31           ` Vitaly Buka
2020-09-30 16:01             ` Joseph Myers
2021-04-17 16:16               ` Vitaly Buka
2021-04-17 17:11                 ` Vitaly Buka
2021-04-17 17:13                   ` Vitaly Buka
2021-04-17 17:22                     ` Vitaly Buka
2021-04-17 18:01                       ` Paul Pluzhnikov
2021-04-20 22:51                         ` Vitaly Buka
2021-04-20 23:40                           ` Paul Pluzhnikov
2021-04-26 19:20                             ` Vitaly Buka
2021-04-26 19:23                               ` Vitaly Buka
2021-04-26 19:27                                 ` Vitaly Buka
2021-05-13 13:15                                   ` Adhemerval Zanella
2021-05-14  6:50                                     ` Vitaly Buka
2021-04-17 17:36               ` Paul Pluzhnikov
2021-04-17 20:19                 ` Florian Weimer
2021-04-19  2:48                   ` Vitaly Buka
2021-04-19  2:57                     ` Vitaly Buka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200920095750.396908-1-vitalybuka@google.com \
    --to=vitalybuka@google.com \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).