This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] [BZ #19402] Clear list of acquired robust mutexes in the child process after forking.
- From: Torvald Riegel <triegel at redhat dot com>
- To: GLIBC Devel <libc-alpha at sourceware dot org>
- Cc: "Carlos O'Donell" <codonell at redhat dot com>, Florian Weimer <fweimer at redhat dot com>
- Date: Thu, 22 Dec 2016 11:15:52 +0100
- Subject: [PATCH] [BZ #19402] Clear list of acquired robust mutexes in the child process after forking.
- Authentication-results: sourceware.org; auth=none
I've asked for comments on whether mutexes acquired before fork() remain
to be acquired by just the parent process after fork():
https://sourceware.org/ml/libc-alpha/2016-12/msg00772.html
If we can agree on one of the requirements I'm proposing there, this
patch fixes the core problem of bug 19402. (The reproducer of this bug
reveals another issue on x86, for which I'll send a patch next.)
The fix is:
Robust mutexes acquired at the time of a call to fork() do not remain
acquired by the forked child process. We have to clear the list of
acquired robust mutexes before registering this list with the kernel;
otherwise, if some of the robust mutexes are process-shared, the parent
process can alter the child's robust mutex list, which can lead to
deadlocks or even modification of memory that may not be occupied by a
mutex anymore.
Tested on x86_64-linux with glibc's tests and the reproducer from 19402.
commit f5a07a158cfe1f5d6583c25eeb57ebbbe2fbee83
Author: Torvald Riegel <triegel@redhat.com>
Date: Wed Dec 21 13:37:19 2016 +0100
Clear list of acquired robust mutexes in the child process after forking.
Robust mutexes acquired at the time of a call to fork() do not remain
acquired by the forked child process. We have to clear the list of
acquired robust mutexes before registering this list with the kernel;
otherwise, if some of the robust mutexes are process-shared, the parent
process can alter the child's robust mutex list, which can lead to
deadlocks or even modification of memory that may not be occupied by a
mutex anymore.
2016-12-22 Torvald Riegel <triegel@redhat.com>
[BZ #19402]
* sysdeps/nptl/fork.c (__libc_fork): Clear list of acquired robust
mutexes.
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index 32cecce..fd3a82d 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -162,12 +162,20 @@ __libc_fork (void)
#endif
#ifdef __NR_set_robust_list
- /* Initialize the robust mutex list which has been reset during
- the fork. We do not check for errors since if it fails here
- it failed at process start as well and noone could have used
- robust mutexes. We also do not have to set
- self->robust_head.futex_offset since we inherit the correct
- value from the parent. */
+ /* Initialize the robust mutex list setting in the kernel which has
+ been reset during the fork. We do not check for errors because if
+ it fails here, it must have failed at process startup as well and
+ nobody could have used robust mutexes.
+ Before we do that, we have to clear the list of robust mutexes
+ because we do not inherit ownership of mutexes from the parent.
+ We do not have to set self->robust_head.futex_offset since we do
+ inherit the correct value from the parent. We do not need to clear
+ the pending operation because it must have been zero when fork was
+ called. */
+# ifdef __PTHREAD_MUTEX_HAVE_PREV
+ self->robust_prev = &self->robust_head;
+# endif
+ self->robust_head.list = &self->robust_head;
# ifdef SHARED
if (__builtin_expect (__libc_pthread_functions_init, 0))
PTHFCT_CALL (ptr_set_robust, (self));