]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libelf: Fix deadlock in __libelf_readall
authorAaron Merey <amerey@redhat.com>
Fri, 12 Jul 2024 22:28:13 +0000 (18:28 -0400)
committerAaron Merey <amerey@redhat.com>
Tue, 16 Jul 2024 16:11:31 +0000 (12:11 -0400)
Apply locking during __libelf_readall.

v2 changes:

Add locking for all early returns in __libelf_readall.

libelf_{acquire,release}_all have been renamed to
libelf_{acquire,release}_all_children.  These functions also no longer
acquire/release the parent's lock.  This is done in order to simplify
lock management in __libelf_readall.

Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
Signed-off-by: Aaron Merey <amerey@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
libelf/common.h
libelf/elf_readall.c

index 9b2a856d118a55c0977bbc8d9978d8f6b42f18b3..b7226ee8dba4a13cc87c98162e0c07ea95e5eee7 100644 (file)
@@ -92,10 +92,8 @@ allocate_elf (int fildes, void *map_address, int64_t offset, size_t maxsize,
 /* Acquire lock for the descriptor and all children.  */
 static void
 __attribute__ ((unused))
-libelf_acquire_all (Elf *elf)
+libelf_acquire_all_children (Elf *elf)
 {
-  rwlock_wrlock (elf->lock);
-
   if (elf->kind == ELF_K_AR)
     {
       Elf *child = elf->state.ar.children;
@@ -103,7 +101,9 @@ libelf_acquire_all (Elf *elf)
       while (child != NULL)
        {
          if (child->ref_count != 0)
-           libelf_acquire_all (child);
+           libelf_acquire_all_children (child);
+
+         rwlock_wrlock(child->lock);
          child = child->next;
        }
     }
@@ -112,7 +112,7 @@ libelf_acquire_all (Elf *elf)
 /* Release own lock and those of the children.  */
 static void
 __attribute__ ((unused))
-libelf_release_all (Elf *elf)
+libelf_release_all_children (Elf *elf)
 {
   if (elf->kind == ELF_K_AR)
     {
@@ -121,12 +121,12 @@ libelf_release_all (Elf *elf)
       while (child != NULL)
        {
          if (child->ref_count != 0)
-           libelf_release_all (child);
+           libelf_release_all_children (child);
+
+         rwlock_unlock (child->lock);
          child = child->next;
        }
     }
-
-  rwlock_unlock (elf->lock);
 }
 
 
index d0f9a28cc59ea192165391babb31eed951a771ed..4ef8fe97c94074be274ea46c393191dc6ee912a8 100644 (file)
@@ -84,7 +84,7 @@ __libelf_readall (Elf *elf)
 
       /* If this is an archive and we have derived descriptors get the
         locks for all of them.  */
-      libelf_acquire_all (elf);
+      libelf_acquire_all_children (elf);
 
       if (elf->maximum_size == ~((size_t) 0))
        {
@@ -141,7 +141,7 @@ __libelf_readall (Elf *elf)
        __libelf_seterrno (ELF_E_NOMEM);
 
       /* Free the locks on the children.  */
-      libelf_release_all (elf);
+      libelf_release_all_children (elf);
     }
 
   rwlock_unlock (elf->lock);