Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Mar 2016 15:34:16 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r296939 - stable/10/libexec/rtld-elf
Message-ID:  <201603161534.u2GFYGTT016779@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Mar 16 15:34:16 2016
New Revision: 296939
URL: https://svnweb.freebsd.org/changeset/base/296939

Log:
  MFC r296319:
  Fix handling of DT_TEXTREL for an object with more than one read-only
  segment.
  
  PR:	207631

Modified:
  stable/10/libexec/rtld-elf/map_object.c
  stable/10/libexec/rtld-elf/rtld.c
  stable/10/libexec/rtld-elf/rtld.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/libexec/rtld-elf/map_object.c
==============================================================================
--- stable/10/libexec/rtld-elf/map_object.c	Wed Mar 16 15:31:09 2016	(r296938)
+++ stable/10/libexec/rtld-elf/map_object.c	Wed Mar 16 15:34:16 2016	(r296939)
@@ -39,7 +39,6 @@
 #include "rtld.h"
 
 static Elf_Ehdr *get_elf_header(int, const char *);
-static int convert_prot(int);	/* Elf flags -> mmap protection */
 static int convert_flags(int); /* Elf flags -> mmap flags */
 
 /*
@@ -439,7 +438,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: stable/10/libexec/rtld-elf/rtld.c
==============================================================================
--- stable/10/libexec/rtld-elf/rtld.c	Wed Mar 16 15:31:09 2016	(r296938)
+++ stable/10/libexec/rtld-elf/rtld.c	Wed Mar 16 15:34:16 2016	(r296939)
@@ -2578,6 +2578,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.
  */
@@ -2599,28 +2633,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: stable/10/libexec/rtld-elf/rtld.h
==============================================================================
--- stable/10/libexec/rtld-elf/rtld.h	Wed Mar 16 15:31:09 2016	(r296938)
+++ stable/10/libexec/rtld-elf/rtld.h	Wed Mar 16 15:34:16 2016	(r296939)
@@ -398,6 +398,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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201603161534.u2GFYGTT016779>