This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

SPARC64 dynamic linker crash undoing prelinking


In various circumstances the dynamic linker needs to undo prelinking
of prelinked shared libraries; in particular, if they were loaded at
an address other than that assigned by the prelinker.

On SPARC64, undoing prelinking involves rewriting the PLT.  The code
in question writes various values at address rela->r_offset, where
rela is a relocation from .rela.plt.  This address, however, has not
been adjusted for the library possibly having been loaded at an
address other than that assigned by the prelinker, leading to a
segfault in that case.

This patch changes the code to add l->l_addr, the offset of the
address at which the library was loaded compared to that the prelinker
assigned, when computing the addresses of PLT entries to rewrite.  It
looks like the sparc32 version has the same issue, but not having
observed this issue there I have not prepared the corresponding patch.

2009-02-12  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/sparc/sparc64/dl-machine.h (elf_machine_runtime_setup):
	Adjust rela->r_offset by l->l_addr when rewriting PLT.

Index: sysdeps/sparc/sparc64/dl-machine.h
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/sparc/sparc64/dl-machine.h,v
retrieving revision 1.52
diff -u -p -r1.52 dl-machine.h
--- sysdeps/sparc/sparc64/dl-machine.h	27 Oct 2006 23:11:47 -0000	1.52
+++ sysdeps/sparc/sparc64/dl-machine.h	12 Feb 2009 20:50:40 -0000
@@ -1,6 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  Sparc64 version.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-	Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+	2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -352,7 +352,7 @@ elf_machine_runtime_setup (struct link_m
 	    {
 	      if (__builtin_expect (rela->r_addend, 0) != 0)
 		{
-                  Elf64_Addr slot = ((rela->r_offset + 0x400
+		  Elf64_Addr slot = ((rela->r_offset + l->l_addr + 0x400
 				      - (Elf64_Addr) plt)
 				     / 0x1400) * 0x1400
 				    + (Elf64_Addr) plt - 0x400;
@@ -360,20 +360,23 @@ elf_machine_runtime_setup (struct link_m
 		  unsigned int first_ldx = *(unsigned int *)(slot + 12);
 		  Elf64_Addr ptr = slot + (first_ldx & 0xfff) + 4;
 
-		  *(Elf64_Addr *) rela->r_offset
+		  *(Elf64_Addr *) (rela->r_offset + l->l_addr)
 		    = (Elf64_Addr) plt
-		      - (slot + ((rela->r_offset - ptr) / 8) * 24 + 4);
+		      - (slot + ((rela->r_offset + l->l_addr - ptr) / 8) * 24
+			 + 4);
 		  ++rela;
 		  continue;
 		}
 
-	      *(unsigned int *) rela->r_offset
-		= 0x03000000 | (rela->r_offset - (Elf64_Addr) plt);
-	      *(unsigned int *) (rela->r_offset + 4)
-		= 0x30680000 | ((((Elf64_Addr) plt + 32
-				  - rela->r_offset - 4) >> 2) & 0x7ffff);
-	      __asm __volatile ("flush %0" : : "r" (rela->r_offset));
-	      __asm __volatile ("flush %0+4" : : "r" (rela->r_offset));
+	      *(unsigned int *) (rela->r_offset + l->l_addr)
+		= 0x03000000 | (rela->r_offset + l->l_addr - (Elf64_Addr) plt);
+	      *(unsigned int *) (rela->r_offset + l->l_addr + 4)
+		= 0x30680000 | ((((Elf64_Addr) plt + 32 - rela->r_offset
+				  - l->l_addr - 4) >> 2) & 0x7ffff);
+	      __asm __volatile ("flush %0" : : "r" (rela->r_offset
+						    + l->l_addr));
+	      __asm __volatile ("flush %0+4" : : "r" (rela->r_offset
+						      + l->l_addr));
 	      ++rela;
 	    }
 	}

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]