From: Aaron Merey Date: Mon, 28 Jul 2025 20:32:28 +0000 (-0400) Subject: elf_getdata_rawchunk.c: Fix dummy chunk insertion race condition X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=20b0dae7eb2ce48ee9fb5d4f41352b2c99efd066;p=thirdparty%2Felfutils.git elf_getdata_rawchunk.c: Fix dummy chunk insertion race condition When elf_getdata_rawchunk aquires a new chunk for the first time, it inserts a stack-allocated dummy chunk into a search_tree with a rdlock held. When the real chunk is prepared to replace the dummy chunk, the rdlock is released and a wrlock is then held while replacing the dummy with the real chunk. Before the wrlock is held, other threads could incorrectly acquire the dummy chunk as if it were a real chunk. Fix this by holding a wrlock throughout elf_getdata_rawchunk. Signed-off-by: Aaron Merey --- diff --git a/libelf/elf_getdata_rawchunk.c b/libelf/elf_getdata_rawchunk.c index 010fac90..87da912a 100644 --- a/libelf/elf_getdata_rawchunk.c +++ b/libelf/elf_getdata_rawchunk.c @@ -87,7 +87,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) int flags = 0; Elf_Data *result = NULL; - rwlock_rdlock (elf->lock); + rwlock_wrlock (elf->lock); /* Maybe we already got this chunk? */ Elf_Data_Chunk key; @@ -95,7 +95,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) key.data.d.d_size = size; key.data.d.d_type = type; Elf_Data_Chunk **found - = eu_tsearch (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); + = eu_tsearch_nolock (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); if (found == NULL) goto nomem; @@ -136,7 +136,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) if (rawchunk == NULL) { nomem: - eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); + eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree, + &chunk_compare); __libelf_seterrno (ELF_E_NOMEM); goto out; } @@ -147,7 +148,8 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) != size)) { /* Something went wrong. */ - eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); + eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree, + &chunk_compare); free (rawchunk); __libelf_seterrno (ELF_E_READ_ERROR); goto out; @@ -217,9 +219,6 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) chunk->data.d.d_version = EV_CURRENT; chunk->offset = offset; - rwlock_unlock (elf->lock); - rwlock_wrlock (elf->lock); - *found = chunk; result = &chunk->data.d;