Bug 8211

Summary: pthread_atfork handlers not removed during dlclose
Product: uClibc Reporter: John Ata <john.ata>
Component: ThreadsAssignee: unassigned
Status: NEW ---    
Severity: minor CC: uclibc-cvs
Priority: P5    
Version: 0.9.33.2   
Target Milestone: ---   
Hardware: PC   
OS: Other   
Host: Target:
Build:
Attachments: Invoke pthread_atfork handler cleanup when removing the associated DSO...
Invoke pthread_atfork handler cleanup when removing the associated DSO...

Description John Ata 2015-07-09 23:08:32 UTC
Created attachment 6096 [details]
Invoke pthread_atfork handler cleanup when removing the associated DSO...

If a program loads a DSO (dlopen) that sets up a pthread_atfork handler(s), and then subsequently closes the DSO, the handler(s) are left in place.  If fork() is subsequently called, the handlers are invoked even though the DSO has been removed causing crashes or unpredictable code execution.  This is because the code in __cxa_finalize(atexit.c)to invoke the unregister_atfork() routine is ifdef'd out with the comment that it hasn't been "looked into this yet...".  I have added the code in and it seems to work properly.

--- libc/stdlib/_atexit.c    2015-07-09 13:08:22.080550119 -040
0
+++ libc/stdlib/_atexit.c        2015-07-08 18:12:06.476077
601 -0400
@@ -42,6 +42,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <atomic.h>
+#include <fork.h>

 #include <bits/uClibc_mutex.h>
 __UCLIBC_MUTEX_EXTERN(__atexit_lock);
@@ -207,17 +208,15 @@
         }
     }

-#if 0 /* haven't looked into this yet... */
     /*
      * Remove the registered fork handlers. We do not have to
      * unregister anything if the program is going to terminate anyway.
      */
 #ifdef UNREGISTER_ATFORK
-    if (d != NULL) {
-        UNREGISTER_ATFORK(d);
+    if (dso_handle != NULL) {
+        UNREGISTER_ATFORK(dso_handle);
     }
 #endif
-#endif
 }
 #endif
Comment 1 Leonid 2015-12-22 18:46:11 UTC
Test-case can be taken from
 http://sourceware.org/bugzilla/show_bug.cgi?id=13502
Comment 2 Leonid 2016-01-02 11:56:49 UTC
Proposed patch breaks build both LT.old & LT.new. NPTL is fine.

Jonh, can you fix it?
Comment 3 John Ata 2016-01-05 01:32:35 UTC
Our toolchain was converted to use nptl along with out kernel, I no longer have a convenient way to build with any of the linux_threads versions... :-(

If you post an output script with the errors for the linux_thread.old and linux_thread, I'll take a look but don't think I could test...
Comment 4 Leonid 2016-01-05 07:48:36 UTC
The problem is simple:

1) LT.old hasn't fork.h & __unregister_atfork() at all.

2) in LT.new __register_atfork()/__unregister_atfork() functions resides in libpthread and not accessible from libc directly.

So, my suggestion, since rework LT.old & LT.new is a large separate task, simply to enable pthread_atfork handlers cleanup for NPTL only.

i.e. first hunk of your patch should be changed to:

@@ -42,6 +42,9 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <atomic.h>
+#if defined __UCLIBC_HAS_THREADS__ && defined __UCLIBC_HAS_THREADS_NATIVE__
+# include <fork.h>
+#endif
 
 #include <bits/uClibc_mutex.h>
 __UCLIBC_MUTEX_EXTERN(__atexit_lock) attribute_hidden;
Comment 5 John Ata 2016-01-05 19:53:00 UTC
Created attachment 6276 [details]
Invoke pthread_atfork handler cleanup when removing the associated DSO...

Takes into account both old and new linuxthreads and seems to continue working fine with ntpl.