From patchwork Sat Dec 8 19:59:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eamonn Coughlan X-Patchwork-Id: 30592 Received: (qmail 9943 invoked by alias); 8 Dec 2018 19:59:14 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 9902 invoked by uid 89); 8 Dec 2018 19:59:14 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=H*r:4.86_2 X-HELO: aibo.runbox.com From: Eamonn Coughlan To: libc-alpha@sourceware.org Subject: [PATCH] ldconfig: file truncated while reading soname after patchelf [BZ #23964] Message-ID: <76bf070f-8be1-6874-e284-7988505cb261@coughlan.de> Date: Sat, 8 Dec 2018 20:59:25 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.0 MIME-Version: 1.0 The way loadaddr is computed from the first LOAD segment in process_elf_file assumes .dynstr is also contained in that segment. That is not necessarily true, especially for libraries that have been touched by patchelf. With this patch, the address read from the dynamic segment is checked against all applicable segments instead of only the first one. [BZ #23964] * elf/readelflib.c: Fix resolving of loadaddr for .dynstr vaddr. --- elf/readelflib.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) error (0, 0, _("more than one dynamic segment\n")); @@ -176,11 +171,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, } } - if (loadaddr == (ElfW(Addr)) -1) - { - /* Very strange. */ - loadaddr = 0; - } /* Now we can read the dynamic sections. */ if (dynamic_size == 0) @@ -190,22 +180,31 @@ process_elf_file (const char *file_name, const char *lib, int *flag, check_ptr (dynamic_segment); /* Find the string table. */ - dynamic_strings = NULL; for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; ++dyn_entry) { check_ptr (dyn_entry); if (dyn_entry->d_tag == DT_STRTAB) - { - dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); - check_ptr (dynamic_strings); - break; - } + break; } - if (dynamic_strings == NULL) + for (i = 0, segment = elf_pheader;i < elf_header->e_phnum; i++, segment++) + { + ElfW(Addr) vaddr = dyn_entry->d_un.d_ptr; + if (segment->p_type == PT_LOAD && + vaddr >= segment->p_vaddr && + vaddr < segment->p_vaddr + segment->p_filesz) + { + loadaddr = segment->p_vaddr - segment->p_offset; + break; + } + } + if (loadaddr == (ElfW(Addr)) -1) return 1; + dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); + check_ptr (dynamic_strings); + /* Now read the DT_NEEDED and DT_SONAME entries. */ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; ++dyn_entry) diff --git a/elf/readelflib.c b/elf/readelflib.c index 5a1e2dc2df..bc1195c175 100644 --- a/elf/readelflib.c +++ b/elf/readelflib.c @@ -98,11 +98,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag, switch (segment->p_type) { - case PT_LOAD: - if (loadaddr == (ElfW(Addr)) -1) - loadaddr = segment->p_vaddr - segment->p_offset; - break; - case PT_DYNAMIC: if (dynamic_addr)