fix deadlock in synccall after threaded fork
authorSamuel Holland <samuel@sholland.org>
Mon, 1 Jul 2019 03:44:28 +0000 (22:44 -0500)
committerRich Felker <dalias@aerifal.cx>
Mon, 1 Jul 2019 14:10:52 +0000 (10:10 -0400)
synccall may be called by AS-safe functions such as setuid/setgid after
fork. although fork() resets libc.threads_minus_one, causing synccall to
take the single-threaded path, synccall still takes the thread list
lock. This lock may be held by another thread if for example fork()
races with pthread_create(). After fork(), the value of the lock is
meaningless, so clear it.

maintainer's note: commit 8f11e6127fe93093f81a52b15bb1537edc3fc8af and
e4235d70672d9751d7718ddc2b52d0b426430768 introduced this regression.
the state protected by this lock is the linked list, which is entirely
replaced in the child path of fork (next=prev=self), so resetting it
is semantically sound.

src/process/fork.c

index 11286ef44e3bd5fd1069087f8741e5e0ff3fdcf0..fb42478ae709a3e11619740a11b7a344cb63655a 100644 (file)
@@ -28,6 +28,7 @@ pid_t fork(void)
                self->robust_list.off = 0;
                self->robust_list.pending = 0;
                self->next = self->prev = self;
+               __thread_list_lock = 0;
                libc.threads_minus_1 = 0;
        }
        __restore_sigs(&set);