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