about summary refs log tree commit diff
path: root/libio/iopopen.c
diff options
context:
space:
mode:
authorArjun Shankar <arjun@redhat.com>2024-10-18 16:03:25 +0200
committerArjun Shankar <arjun@redhat.com>2024-10-23 13:40:16 +0200
commit9f0d2c0ee6c728643fcf9a4879e9f20f5e45ce5f (patch)
tree86cff8d63944f5a0e573b1d0a72d3a669c4f124d /libio/iopopen.c
parent81439a116cf48583127ddf1f09809440aa40969a (diff)
downloadglibc-9f0d2c0ee6c728643fcf9a4879e9f20f5e45ce5f.tar.gz
glibc-9f0d2c0ee6c728643fcf9a4879e9f20f5e45ce5f.tar.xz
glibc-9f0d2c0ee6c728643fcf9a4879e9f20f5e45ce5f.zip
libio: Fix a deadlock after fork in popen
popen modifies its file handler book-keeping under a lock that wasn't
being taken during fork.  This meant that a concurrent popen and fork
could end up copying the lock in a "locked" state into the fork child,
where subsequently calling popen would lead to a deadlock due to the
already (spuriously) held lock.

This commit fixes the deadlock by appropriately taking the lock before
fork, and releasing/resetting it in the parent/child after the fork.

A new test for concurrent popen and fork is also added.  It consistently
hangs (and therefore fails via timeout) without the fix applied.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
Diffstat (limited to 'libio/iopopen.c')
-rw-r--r--libio/iopopen.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/libio/iopopen.c b/libio/iopopen.c
index d01cb0648e..352513a291 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -57,6 +57,26 @@ unlock (void *not_used)
 }
 #endif
 
+/* These lock/unlock/resetlock functions are used during fork.  */
+
+void
+_IO_proc_file_chain_lock (void)
+{
+  _IO_lock_lock (proc_file_chain_lock);
+}
+
+void
+_IO_proc_file_chain_unlock (void)
+{
+  _IO_lock_unlock (proc_file_chain_lock);
+}
+
+void
+_IO_proc_file_chain_resetlock (void)
+{
+  _IO_lock_init (proc_file_chain_lock);
+}
+
 /* POSIX states popen shall ensure that any streams from previous popen()
    calls that remain open in the parent process should be closed in the new
    child process.