c25f0b
From fba95ad936f1d8c1052259bae811f1fc07f9a215 Mon Sep 17 00:00:00 2001
c25f0b
From: Petr Machata <pmachata@redhat.com>
c25f0b
Date: Thu, 30 Oct 2014 01:48:17 +0100
c25f0b
Subject: [PATCH] Initialize the PLT slot map correctly on x86 and x86_64
c25f0b
c25f0b
The PLT slot map translates relocation numbers to PLT slot numbers,
c25f0b
but was actually initialized in the opposite direction.  Fix the way
c25f0b
it's initialized.  This bug can be seen on glibc in particular:
c25f0b
c25f0b
  $ ltrace -e free ls
c25f0b
  libc.so.6->free(0x5)           = <void>
c25f0b
  libc.so.6->free(0x78)          = <void>
c25f0b
  libc.so.6->free(0xc)           = <void>
c25f0b
  libc.so.6->free(0x308)         = <void>
c25f0b
c25f0b
Note the nonsense values passed to free.  The problem is that these
c25f0b
are not free calls at all, but malloc calls that are assigned to wrong
c25f0b
PLT slots due to above bug.
c25f0b
---
c25f0b
 sysdeps/linux-gnu/x86/plt.c | 38 +++++++++++++++++++++-----------------
c25f0b
 1 file changed, 21 insertions(+), 17 deletions(-)
c25f0b
c25f0b
diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
c25f0b
index c860af6..97f6c3e 100644
c25f0b
--- a/sysdeps/linux-gnu/x86/plt.c
c25f0b
+++ b/sysdeps/linux-gnu/x86/plt.c
c25f0b
@@ -77,6 +77,18 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
c25f0b
 {
c25f0b
 	VECT_INIT(&lte->arch.plt_map, unsigned int);
c25f0b
 
c25f0b
+	if (vect_reserve(&lte->arch.plt_map, vect_size(&lte->plt_relocs)) < 0) {
c25f0b
+	fail:
c25f0b
+		arch_elf_destroy(lte);
c25f0b
+		return -1;
c25f0b
+	}
c25f0b
+
c25f0b
+	{
c25f0b
+		unsigned int i, sz = vect_size(&lte->plt_relocs);
c25f0b
+		for (i = 0; i < sz; ++i)
c25f0b
+			vect_pushback (&lte->arch.plt_map, &i);
c25f0b
+	}
c25f0b
+
c25f0b
 	/* IRELATIVE slots may make the whole situation a fair deal
c25f0b
 	 * more complex.  On x86{,_64}, the PLT slots are not
c25f0b
 	 * presented in the order of the corresponding relocations,
c25f0b
@@ -114,43 +126,35 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
c25f0b
 	/* Here we scan the PLT table and initialize a map of
c25f0b
 	 * relocation->slot number in lte->arch.plt_map.  */
c25f0b
 
c25f0b
-	size_t i;
c25f0b
-	for (i = 0; i < vect_size(&lte->plt_relocs); ++i) {
c25f0b
+	unsigned int i, sz = vect_size(&lte->plt_relocs);
c25f0b
+	for (i = 0; i < sz; ++i) {
c25f0b
 
c25f0b
 		GElf_Addr offset = x86_plt_offset(i);
c25f0b
-		uint32_t reloc_arg = 0;
c25f0b
 
c25f0b
 		uint8_t byte;
c25f0b
 		if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
c25f0b
 		    || byte != 0xff
c25f0b
 		    || elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
c25f0b
 		    || (byte != 0xa3 && byte != 0x25))
c25f0b
-			goto next;
c25f0b
+			continue;
c25f0b
 
c25f0b
 		/* Skip immediate argument in the instruction.  */
c25f0b
 		offset += 4;
c25f0b
 
c25f0b
+		uint32_t reloc_arg;
c25f0b
 		if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
c25f0b
 		    || byte != 0x68
c25f0b
 		    || elf_read_next_u32(lte->plt_data,
c25f0b
-					 &offset, &reloc_arg) < 0) {
c25f0b
-			reloc_arg = 0;
c25f0b
-			goto next;
c25f0b
-		}
c25f0b
+					 &offset, &reloc_arg) < 0)
c25f0b
+			continue;
c25f0b
 
c25f0b
 		if (lte->ehdr.e_machine == EM_386) {
c25f0b
-			if (reloc_arg % 8 != 0) {
c25f0b
-				reloc_arg = 0;
c25f0b
-				goto next;
c25f0b
-			}
c25f0b
+			if (reloc_arg % 8 != 0)
c25f0b
+				continue;
c25f0b
 			reloc_arg /= 8;
c25f0b
 		}
c25f0b
 
c25f0b
-	next:
c25f0b
-		if (VECT_PUSHBACK(&lte->arch.plt_map, &reloc_arg) < 0) {
c25f0b
-			arch_elf_destroy(lte);
c25f0b
-			return -1;
c25f0b
-		}
c25f0b
+		*VECT_ELEMENT(&lte->arch.plt_map, unsigned int, reloc_arg) = i;
c25f0b
 	}
c25f0b
 
c25f0b
 	return 0;
c25f0b
-- 
c25f0b
2.1.0
c25f0b