From patchwork Thu Mar 19 23:52:08 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 452403 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A1D3C1400B7 for ; Fri, 20 Mar 2015 10:52:23 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass reason="1024-bit key; unprotected key" header.d=sourceware.org header.i=@sourceware.org header.b=ZKllrluB; dkim-adsp=none (unprotected policy); dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; q=dns; s=default; b=P5dSvo/MBilpcP9kTLJ2yDgL/fQqC rVb4OgbYS2a4V/Ki7/8jD/1HOsg/SMoiwPg1L7iI5ewndYLb53HOCdVZExJw8WHv 8X1j7O9VS8cl3CwzJCB/sRBehWAiL5RYAk+4EODjTpeo57E5i+jxUScP1PmGr4cX Z/d6+Waxl/q12Q= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; s=default; bh=LaH4uZsai/F3tv6VOk02xU9g6Cs=; b=ZKl lrluBE5lJ7GK3jOoZi+tzq7wz0UuJT5Fyx7H023gLtKoJ513VedYz2BIbmYnjpBB V3LfXmsHoouFHuOyux699OFwwGTh5bS+ZZnRjwpEkurPTMfFGnYTaolPzY/HcxLB ET/ObgeuPLw/EXbzquP4oefcDwEIksT5aEroUZjY= Received: (qmail 104900 invoked by alias); 19 Mar 2015 23:52:17 -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 104887 invoked by uid 89); 19 Mar 2015 23:52:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.5 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, KAM_FROM_URIBL_PCCC, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pd0-f181.google.com X-Received: by 10.70.140.99 with SMTP id rf3mr50082441pdb.156.1426809134257; Thu, 19 Mar 2015 16:52:14 -0700 (PDT) Date: Fri, 20 Mar 2015 10:22:08 +1030 From: Alan Modra To: libc-alpha@sourceware.org Subject: Harden powerpc64 elf_machine_fixup_plt Message-ID: <20150319235208.GB26234@bubble.grove.modra.org> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) IFUNC is difficult to correctly implement on any target needing a GOT to support position independent code, due to the dependency on order of dynamic relocations. ld.so should be changed to apply IFUNC relocations last, globally, because without that it is actually impossible to write an IFUNC resolver in C that works in all situations. Case in point, vfork in libpthread.so is an IFUNC with the resolver returning &__libc_vfork. (system and fork are similar.) If another shared library, libA say, uses vfork then it is quite possible that libpthread.so hasn't been dynamically relocated before the unfortunate libA is dynamically relocated. In that case the GOT entry for &__libc_vfork is still zero, so the IFUNC resolver returns NULL. LD_BIND_NOW=1 results in libA PLT dynamic relocations being applied using this NULL value and ld.so segfaults. This patch hardens ld.so to not segfault on a NULL from an IFUNC resolver. It also fixes a problem with undefined weak. If you leave the plt entry as-is for undefined weak then if the entry is ever called it will loop in ld.so rather than segfaulting. Regression tested powerpc64-linux. * sysdeps/powerpc/powerpc64/dl-machine.h (elf_machine_fixup_plt): Don't segfault if ifunc resolver returns a NULL. Do set plt to zero for undefined weak. (elf_machine_plt_conflict): Similarly. diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h index 55ac736..0576781 100644 --- a/sysdeps/powerpc/powerpc64/dl-machine.h +++ b/sysdeps/powerpc/powerpc64/dl-machine.h @@ -472,19 +472,32 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map, Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr; Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr; Elf64_Addr offset = 0; + Elf64_FuncDesc zero_fd = {0, 0, 0}; PPC_DCBT (&plt->fd_aux); PPC_DCBT (&plt->fd_func); - PPC_DCBT (&rel->fd_aux); - PPC_DCBT (&rel->fd_func); - /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */ + /* If sym_map is NULL, it's a weak undefined sym; Set the plt to + zero. finaladdr should be zero already in this case, but guard + against invalid plt relocations with non-zero addends. */ if (sym_map == NULL) - return 0; + finaladdr = 0; + + /* Don't die here if finaladdr is zero, die if this plt entry is + actually called. Makes a difference when LD_BIND_NOW=1. + finaladdr may be zero for a weak undefined symbol, or when an + ifunc resolver returns zero. */ + if (finaladdr == 0) + rel = &zero_fd; + else + { + PPC_DCBT (&rel->fd_aux); + PPC_DCBT (&rel->fd_func); + } /* If the opd entry is not yet relocated (because it's from a shared object that hasn't been processed yet), then manually reloc it. */ - if (map != sym_map && !sym_map->l_relocated + if (finaladdr != 0 && map != sym_map && !sym_map->l_relocated #if !defined RTLD_BOOTSTRAP && defined SHARED /* Bootstrap map doesn't have l_relocated set for it. */ && sym_map != &GL(dl_rtld_map) @@ -522,6 +535,13 @@ elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map, #if _CALL_ELF != 2 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr; Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr; + Elf64_FuncDesc zero_fd = {0, 0, 0}; + + if (sym_map == NULL) + finaladdr = 0; + + if (finaladdr == 0) + rel = &zero_fd; plt->fd_func = rel->fd_func; plt->fd_aux = rel->fd_aux;