From owner-svn-src-head@freebsd.org Wed Mar 2 16:36:26 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 6CA43AC1B49; Wed, 2 Mar 2016 16:36:26 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 450281A2B; Wed, 2 Mar 2016 16:36:26 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u22GaPwl072796; Wed, 2 Mar 2016 16:36:25 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u22GaOBc072793; Wed, 2 Mar 2016 16:36:25 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201603021636.u22GaOBc072793@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 2 Mar 2016 16:36:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r296319 - head/libexec/rtld-elf X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Mar 2016 16:36:26 -0000 Author: kib Date: Wed Mar 2 16:36:24 2016 New Revision: 296319 URL: https://svnweb.freebsd.org/changeset/base/296319 Log: Fix handling of DT_TEXTREL for an object with more than one read-only segment. According to gABI spec, presence of the tag indicates that dynamic linker must be prepared to handle relocations against any read-only segment, not only the segment which we, somewhat arbitrary, declared the text. For each read-only segment, add write permission before relocs are processed, and return to the mapping mode requested by the phdr, after relocs are done. Reported, tested, and reviewed by: emaste PR: 207631 Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Modified: head/libexec/rtld-elf/map_object.c head/libexec/rtld-elf/rtld.c head/libexec/rtld-elf/rtld.h Modified: head/libexec/rtld-elf/map_object.c ============================================================================== --- head/libexec/rtld-elf/map_object.c Wed Mar 2 16:14:46 2016 (r296318) +++ head/libexec/rtld-elf/map_object.c Wed Mar 2 16:36:24 2016 (r296319) @@ -39,7 +39,6 @@ #include "rtld.h" static Elf_Ehdr *get_elf_header(int, const char *, const struct stat *); -static int convert_prot(int); /* Elf flags -> mmap protection */ static int convert_flags(int); /* Elf flags -> mmap flags */ /* @@ -445,7 +444,7 @@ obj_new(void) * Given a set of ELF protection flags, return the corresponding protection * flags for MMAP. */ -static int +int convert_prot(int elfflags) { int prot = 0; Modified: head/libexec/rtld-elf/rtld.c ============================================================================== --- head/libexec/rtld-elf/rtld.c Wed Mar 2 16:14:46 2016 (r296318) +++ head/libexec/rtld-elf/rtld.c Wed Mar 2 16:36:24 2016 (r296319) @@ -2627,6 +2627,40 @@ relocate_object_dag(Obj_Entry *root, boo } /* + * Prepare for, or clean after, relocating an object marked with + * DT_TEXTREL or DF_TEXTREL. Before relocating, all read-only + * segments are remapped read-write. After relocations are done, the + * segment's permissions are returned back to the modes specified in + * the phdrs. If any relocation happened, or always for wired + * program, COW is triggered. + */ +static int +reloc_textrel_prot(Obj_Entry *obj, bool before) +{ + const Elf_Phdr *ph; + void *base; + size_t l, sz; + int prot; + + for (l = obj->phsize / sizeof(*ph), ph = obj->phdr; l > 0; + l--, ph++) { + if (ph->p_type != PT_LOAD || (ph->p_flags & PF_W) != 0) + continue; + base = obj->relocbase + trunc_page(ph->p_vaddr); + sz = round_page(ph->p_vaddr + ph->p_filesz) - + trunc_page(ph->p_vaddr); + prot = convert_prot(ph->p_flags) | (before ? PROT_WRITE : 0); + if (mprotect(base, sz, prot) == -1) { + _rtld_error("%s: Cannot write-%sable text segment: %s", + obj->path, before ? "en" : "dis", + rtld_strerror(errno)); + return (-1); + } + } + return (0); +} + +/* * Relocate single object. * Returns 0 on success, or -1 on failure. */ @@ -2648,28 +2682,17 @@ relocate_object(Obj_Entry *obj, bool bin return (-1); } - if (obj->textrel) { - /* There are relocations to the write-protected text segment. */ - if (mprotect(obj->mapbase, obj->textsize, - PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { - _rtld_error("%s: Cannot write-enable text segment: %s", - obj->path, rtld_strerror(errno)); - return (-1); - } - } + /* There are relocations to the write-protected text segment. */ + if (obj->textrel && reloc_textrel_prot(obj, true) != 0) + return (-1); /* Process the non-PLT non-IFUNC relocations. */ if (reloc_non_plt(obj, rtldobj, flags, lockstate)) return (-1); - if (obj->textrel) { /* Re-protected the text segment. */ - if (mprotect(obj->mapbase, obj->textsize, - PROT_READ|PROT_EXEC) == -1) { - _rtld_error("%s: Cannot write-protect text segment: %s", - obj->path, rtld_strerror(errno)); - return (-1); - } - } + /* Re-protected the text segment. */ + if (obj->textrel && reloc_textrel_prot(obj, false) != 0) + return (-1); /* Set the special PLT or GOT entries. */ init_pltgot(obj); Modified: head/libexec/rtld-elf/rtld.h ============================================================================== --- head/libexec/rtld-elf/rtld.h Wed Mar 2 16:14:46 2016 (r296318) +++ head/libexec/rtld-elf/rtld.h Wed Mar 2 16:36:24 2016 (r296319) @@ -385,6 +385,7 @@ void *allocate_module_tls(int index); bool allocate_tls_offset(Obj_Entry *obj); void free_tls_offset(Obj_Entry *obj); const Ver_Entry *fetch_ventry(const Obj_Entry *obj, unsigned long); +int convert_prot(int elfflags); /* * MD function declarations.