From 20ca3e8fe321bf4aaf5bb085243d63e07ed387d2 Mon Sep 17 00:00:00 2001 From: Aaron Merey Date: Fri, 12 Jul 2024 18:28:13 -0400 Subject: [PATCH] libelf: Fix deadlock in __libelf_readall 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 Signed-off-by: Aaron Merey Signed-off-by: Mark Wielaard --- libelf/common.h | 16 ++++++++-------- libelf/elf_readall.c | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libelf/common.h b/libelf/common.h index 9b2a856d1..b7226ee8d 100644 --- a/libelf/common.h +++ b/libelf/common.h @@ -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); } diff --git a/libelf/elf_readall.c b/libelf/elf_readall.c index d0f9a28cc..4ef8fe97c 100644 --- a/libelf/elf_readall.c +++ b/libelf/elf_readall.c @@ -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); -- 2.47.2