summary refs log tree commit diff
path: root/elf/dl-load.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2001-03-16 07:40:05 +0000
committerUlrich Drepper <drepper@redhat.com>2001-03-16 07:40:05 +0000
commita986484f67346b28ff09833c1f4fd3505b52138e (patch)
tree598498dabf381610b1d7e27815917d67426bc34a /elf/dl-load.c
parent328c5f650ffcdc8f10e4ebd6f741ad0b8e6ea1c1 (diff)
downloadglibc-a986484f67346b28ff09833c1f4fd3505b52138e.tar.gz
glibc-a986484f67346b28ff09833c1f4fd3505b52138e.tar.xz
glibc-a986484f67346b28ff09833c1f4fd3505b52138e.zip
Update.
2001-03-12  Jakub Jelinek  <jakub@redhat.com>

	* csu/Makefile (abi-tag.h): Define OS and version separately, allow
	version to be overriden from config.h.
	* csu/abi-note.S: Use OS and version separately, include config.h.
	* elf/dl-load.c (_dl_osversion): New.
	(_dl_map_object_from_fd): Kill some warnings.
	(open_verify): Check .note.ABI-tag of the library if present.
	* elf/Makefile (CPPFLAGS-dl-load.c): Add -I$(csu-objpfx).
	* elf/cache.c (struct cache_entry): Add osversion.
	(print_entry): Print osversion.
	(print_cache): Pass osversion to it.
	(compare): Sort according to osversion.
	(save_cache): Set osversion.
	(add_to_cache): Add osversion argument.
	* sysdeps/generic/ldconfig.h (add_to_cache, process_file,
	process_elf_file): Add osversion argument.
	* elf/readlib.c (process_file): Likewise.
	* sysdeps/generic/readelflib.c (process_elf_file): Likewise.
	* sysdeps/unix/sysv/linux/ia64/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* sysdeps/unix/sysv/linux/i386/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* sysdeps/unix/sysv/linux/sparc/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* elf/ldconfig.c (manual_link): Pass it.
	(search_dir): Issue diagnostic if two libs with the same soname in
	the same directory have different .note.ABI-tag.  Record osversion in
	dlib_entry and use it from there.
	(struct lib_entry): Remove.
	(struct dlib_entry): Add osversion.
	* sysdeps/generic/dl-cache.c (_dl_load_cache_lookup): Check
	osversion.
	* sysdeps/generic/dl-cache.h (struct file_entry_new): Replace __unused
	field with osversion.
	* sysdeps/generic/ldsodefs.h (_dl_osversion): Declare.
	* sysdeps/unix/sysv/linux/init-first.c: Include ldsodefs.h.
	* sysdeps/unix/sysv/linux/dl-osinfo.h (DL_SYSDEP_OSCHECK): Save kernel
	version in _dl_osversion.
	* sysdeps/unix/sysv/linux/configure.in: Define __ABI_TAG_VERSION.
	* Makerules (build-shlib-helper, build-module-helper): New.
	(build-shlib, build-module-helper): Make sure .note.ABI-tag comes
	early.
	* config.h.in (__ABI_TAG_VERSION): Add.
	* elf/dl-minimal.c (__strtoul_internal): Set endptr on return.
	* sysdeps/unix/sysv/linux/i386/dl-librecon.h (EXTRA_LD_ENVVARS):
	Handle LD_ASSUME_KERNEL.
	* sysdeps/unix/sysv/linux/dl-librecon.h: New.
Diffstat (limited to 'elf/dl-load.c')
-rw-r--r--elf/dl-load.c75
1 files changed, 63 insertions, 12 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 6e4c972b00..0a5603f092 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -30,6 +30,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include "dynamic-link.h"
+#include <abi-tag.h>
+#include <dl-osinfo.h>
 
 #include <dl-dst.h>
 
@@ -111,6 +113,8 @@ struct filebuf
 
 size_t _dl_pagesize;
 
+unsigned int _dl_osversion;
+
 int _dl_clktck;
 
 extern const char *_dl_platform;
@@ -1061,12 +1065,12 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
     _dl_debug_printf ("  dynamic: 0x%0*lx  base: 0x%0*lx   size: 0x%0*Zx\n"
 		      "    entry: 0x%0*lx  phdr: 0x%0*lx  phnum:   %*u\n\n",
-		      sizeof (void *) * 2, (unsigned long int) l->l_ld,
-		      sizeof (void *) * 2, (unsigned long int) l->l_addr,
-		      sizeof (void *) * 2, maplength,
-		      sizeof (void *) * 2, (unsigned long int) l->l_entry,
-		      sizeof (void *) * 2, (unsigned long int) l->l_phdr,
-		      sizeof (void *) * 2, l->l_phnum);
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_ld,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_addr,
+		      (int) sizeof (void *) * 2, maplength,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_entry,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_phdr,
+		      (int) sizeof (void *) * 2, l->l_phnum);
 
   elf_get_dynamic_info (l);
 
@@ -1213,6 +1217,10 @@ open_verify (const char *name, struct filebuf *fbp)
     [EI_OSABI] = ELFOSABI_SYSV,
     [EI_ABIVERSION] = 0
   };
+  static const struct {
+    ElfW(Word) vendorlen, datalen, type;
+    char vendor [4];
+  } expected_note = { 4, 16, 1, "GNU" };
   int fd;
 
   /* Open the file.  We always open files read-only.  */
@@ -1220,6 +1228,10 @@ open_verify (const char *name, struct filebuf *fbp)
   if (fd != -1)
     {
       ElfW(Ehdr) *ehdr;
+      ElfW(Phdr) *phdr, *ph;
+      ElfW(Word) *abi_note, abi_note_buf[8];
+      unsigned int osversion;
+      size_t maplength;
 
       /* We successfully openened the file.  Now verify it is a file
 	 we can use.  */
@@ -1287,12 +1299,7 @@ open_verify (const char *name, struct filebuf *fbp)
 	lose (0, fd, name, NULL, NULL,
 	      N_("ELF file version does not match current one"));
       if (! __builtin_expect (elf_machine_matches_host (ehdr), 1))
-	{
-	close_and_out:
-	  __close (fd);
-	  __set_errno (ENOENT);
-	  fd = -1;
-	}
+	goto close_and_out;
       else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr)))
 	       != sizeof (ElfW(Phdr)))
 	lose (0, fd, name, NULL, NULL,
@@ -1301,6 +1308,50 @@ open_verify (const char *name, struct filebuf *fbp)
 	       && __builtin_expect (ehdr->e_type, ET_EXEC) != ET_EXEC)
 	lose (0, fd, name, NULL, NULL,
 	      N_("only ET_DYN and ET_EXEC can be loaded"));
+
+      maplength = ehdr->e_phnum * sizeof (ElfW(Phdr));
+      if (ehdr->e_phoff + maplength <= fbp->len)
+	phdr = (void *) (fbp->buf + ehdr->e_phoff);
+      else
+	{
+	  phdr = alloca (maplength);
+	  __lseek (fd, SEEK_SET, ehdr->e_phoff);
+	  if (__libc_read (fd, (void *) phdr, maplength) != maplength)
+	    lose (errno, fd, name, NULL, NULL, N_("cannot read file data"));
+	}
+
+      /* Check .note.ABI-tag if present.  */
+      for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
+	if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4)
+	  {
+	    if (ph->p_offset + 32 <= fbp->len)
+	      abi_note = (void *) (fbp->buf + ph->p_offset);
+	    else
+	      {
+		__lseek (fd, SEEK_SET, ph->p_offset);
+		if (__libc_read (fd, (void *) abi_note_buf, 32) != 32)
+		  lose (errno, fd, name, NULL, NULL,
+			N_("cannot read file data"));
+		abi_note = abi_note_buf;
+	      }
+
+	    if (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+	      continue;
+
+	    osversion = (abi_note [5] & 0xff) * 65536
+			+ (abi_note [6] & 0xff) * 256
+			+ (abi_note [7] & 0xff);
+	    if (abi_note [4] != __ABI_TAG_OS
+		|| (_dl_osversion && _dl_osversion < osversion))
+	      {
+	      close_and_out:
+		__close (fd);
+		__set_errno (ENOENT);
+		fd = -1;
+	      }
+
+	    break;
+	  }
     }
 
   return fd;