about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile2
-rw-r--r--elf/cache.c62
-rw-r--r--elf/dl-load.c75
-rw-r--r--elf/dl-minimal.c4
-rw-r--r--elf/ldconfig.c35
-rw-r--r--elf/readlib.c25
6 files changed, 145 insertions, 58 deletions
diff --git a/elf/Makefile b/elf/Makefile
index a4f0a1063e..dff36c9371 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -188,7 +188,7 @@ $(objpfx)trusted-dirs.st: Makefile $(..)Makeconfig
 	| $(AWK) -f gen-trusted-dirs.awk > ${@:st=T};
 	$(move-if-change) ${@:st=T} ${@:st=h}
 	touch $@
-CPPFLAGS-dl-load.c = -I$(objpfx).
+CPPFLAGS-dl-load.c = -I$(objpfx). -I$(csu-objpfx).
 
 ifeq (yes,$(build-shared))
 $(inst_slibdir)/$(rtld-version-installed-name): $(objpfx)ld.so $(+force)
diff --git a/elf/cache.c b/elf/cache.c
index 378ce8f69c..19237bbe79 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -39,6 +39,7 @@ struct cache_entry
   char *lib;			/* Library name.  */
   char *path;			/* Path to find library.  */
   int flags;			/* Flags to indicate kind of library.  */
+  unsigned int osversion;	/* Required OS version.  */
   uint64_t hwcap;		/* Important hardware capabilities.  */
   int bits_hwcap;		/* Number of bits set in hwcap.  */
   struct cache_entry *next;	/* Next entry in list.  */
@@ -52,7 +53,8 @@ static const char *flag_descr[] =
 
 /* Print a single entry.  */
 static void
-print_entry (const char *lib, int flag, uint64_t hwcap, const char *key)
+print_entry (const char *lib, int flag, unsigned int osversion,
+	     uint64_t hwcap, const char *key)
 {
   printf ("\t%s (", lib);
   switch (flag & FLAG_TYPE_MASK)
@@ -61,7 +63,7 @@ print_entry (const char *lib, int flag, uint64_t hwcap, const char *key)
     case FLAG_ELF:
     case FLAG_ELF_LIBC5:
     case FLAG_ELF_LIBC6:
-      fputs (flag_descr [flag & FLAG_TYPE_MASK], stdout);
+      fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
       break;
     default:
       fputs ("unknown", stdout);
@@ -85,6 +87,23 @@ print_entry (const char *lib, int flag, uint64_t hwcap, const char *key)
     }
   if (hwcap != 0)
     printf (", hwcap: 0x%" PRIx64, hwcap);
+  if (osversion != 0)
+    {
+      static const char *const abi_tag_os[] =
+      {
+	[0] = "Linux",
+	[1] = "Hurd",
+	[2] = "Solaris",
+	[3] = "Unknown OS"
+      };
+      unsigned int os = osversion >> 24;
+
+      printf (", OS ABI: %s %d.%d.%d",
+	      abi_tag_os[os > 3 ? 3 : os],
+	      (osversion >> 16) & 0xff,
+	      (osversion >> 8) & 0xff,
+	      osversion & 0xff);
+    }
   printf (") => %s\n", key);
 }
 
@@ -139,7 +158,8 @@ print_cache (const char *cache_name)
   else
     {
       size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
-				   + cache->nlibs * sizeof (struct file_entry));
+				   + (cache->nlibs
+				      * sizeof (struct file_entry)));
       /* This is where the strings start.  */
       cache_data = (const char *) &cache->libs[cache->nlibs];
 
@@ -150,9 +170,10 @@ print_cache (const char *cache_name)
 
 	  cache_new = (struct cache_file_new *) ((void *)cache + offset);
 
-	  if (!memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
-	      && !memcmp (cache_new->version, CACHE_VERSION,
-			  sizeof CACHE_VERSION - 1))
+	  if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
+		      sizeof CACHEMAGIC_NEW - 1) == 0
+	      && memcmp (cache_new->version, CACHE_VERSION,
+			 sizeof CACHE_VERSION - 1) == 0)
 	    {
 	      cache_data = (const char *) cache_new;
 	      format = 1;
@@ -167,17 +188,19 @@ print_cache (const char *cache_name)
       /* Print everything.  */
       for (i = 0; i < cache->nlibs; i++)
 	print_entry (cache_data + cache->libs[i].key,
-		     cache->libs[i].flags, 0,
+		     cache->libs[i].flags, 0, 0,
 		     cache_data + cache->libs[i].value);
     }
   else if (format == 1)
     {
-      printf (_("%d libs found in cache `%s'\n"), cache_new->nlibs, cache_name);
+      printf (_("%d libs found in cache `%s'\n"),
+	      cache_new->nlibs, cache_name);
 
       /* Print everything.  */
       for (i = 0; i < cache_new->nlibs; i++)
 	print_entry (cache_data + cache_new->libs[i].key,
 		     cache_new->libs[i].flags,
+		     cache_new->libs[i].osversion,
 		     cache_new->libs[i].hwcap,
 		     cache_data + cache_new->libs[i].value);
     }
@@ -217,6 +240,10 @@ int compare (const struct cache_entry *e1, const struct cache_entry *e2)
 	return 1;
       else if (e2->hwcap < e1->hwcap)
 	return -1;
+      if (e2->osversion > e1->osversion)
+	return 1;
+      if (e2->osversion < e1->osversion)
+	return -1;
     }
   return res;
 }
@@ -280,12 +307,15 @@ save_cache (const char *cache_name)
       /* And the list of all entries in the new format.  */
       file_entries_new_size = sizeof (struct cache_file_new)
 	+ cache_entry_count * sizeof (struct file_entry_new);
-      file_entries_new = (struct cache_file_new *) xmalloc (file_entries_new_size);
+      file_entries_new =
+	(struct cache_file_new *) xmalloc (file_entries_new_size);
 
       /* Fill in the header.  */
       memset (file_entries_new, 0, sizeof (struct cache_file_new));
-      memcpy (file_entries_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1);
-      memcpy (file_entries_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1);
+      memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
+	      sizeof CACHEMAGIC_NEW - 1);
+      memcpy (file_entries_new->version, CACHE_VERSION,
+	      sizeof CACHE_VERSION - 1);
 
       file_entries_new->nlibs = cache_entry_count;
       file_entries_new->len_strings = total_strlen;
@@ -319,9 +349,9 @@ save_cache (const char *cache_name)
 	     always begins at the beginning of the the new cache
 	     struct.  */
 	  file_entries_new->libs[idx_new].flags = entry->flags;
+	  file_entries_new->libs[idx_new].osversion = entry->osversion;
 	  file_entries_new->libs[idx_new].hwcap = entry->hwcap;
 	  file_entries_new->libs[idx_new].key = str_offset;
-	  file_entries_new->libs[idx_new].__unused = 0;
 	}
       len = strlen (entry->lib);
       str = stpcpy (str, entry->lib);
@@ -363,7 +393,8 @@ save_cache (const char *cache_name)
   /* Write contents.  */
   if (opt_format != 2)
     {
-      if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size)
+      if (write (fd, file_entries, file_entries_size)
+	  != (ssize_t)file_entries_size)
 	error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
     }
   if (opt_format != 0)
@@ -371,7 +402,7 @@ save_cache (const char *cache_name)
       /* Align cache.  */
       if (opt_format != 2)
 	{
-	  char zero [pad];
+	  char zero[pad];
 	  if (write (fd, zero, pad) != (ssize_t)pad)
 	    error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
 	}
@@ -414,7 +445,7 @@ save_cache (const char *cache_name)
 /* Add one library to the cache.  */
 void
 add_to_cache (const char *path, const char *lib, int flags,
-	      uint64_t hwcap)
+	      unsigned int osversion, uint64_t hwcap)
 {
   struct cache_entry *new_entry, *ptr, *prev;
   char *full_path;
@@ -430,6 +461,7 @@ add_to_cache (const char *path, const char *lib, int flags,
   new_entry->lib = xstrdup (lib);
   new_entry->path = full_path;
   new_entry->flags = flags;
+  new_entry->osversion = osversion;
   new_entry->hwcap = hwcap;
   new_entry->bits_hwcap = 0;
 
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;
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index 5184c1136c..8922edcd71 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -252,6 +252,8 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
 	  || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
 	{
 	  errno = ERANGE;
+	  if (endptr != NULL)
+	    *endptr = (char *) nptr;
 	  return ULONG_MAX;
 	}
       result *= base;
@@ -259,5 +261,7 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
       ++nptr;
     }
 
+  if (endptr != NULL)
+    *endptr = (char *) nptr;
   return result * sign;
 }
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 4c00bce8fe..d3c5355156 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -48,19 +48,11 @@
 
 #define PACKAGE _libc_intl_domainname
 
-struct lib_entry
-  {
-    int flags;
-    uint64_t hwcap;
-    char *lib;
-    char *path;
-  };
-
 static const struct
 {
   const char *name;
   int flag;
-} lib_types [] =
+} lib_types[] =
 {
   {"libc4", FLAG_LIBC4},
   {"libc5", FLAG_ELF_LIBC5},
@@ -316,7 +308,7 @@ add_dir (const char *line)
       *equal_sign = '\0';
       ++equal_sign;
       entry->flag = FLAG_ANY;
-      for (i = 0; i < sizeof (lib_types) / sizeof (lib_types [0]); ++i)
+      for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
 	if (strcmp (equal_sign, lib_types[i].name) == 0)
 	  {
 	    entry->flag = lib_types[i].flag;
@@ -334,7 +326,7 @@ add_dir (const char *line)
   i = strlen (entry->path) - 1;
   while (entry->path[i] == '/' && i > 0)
     {
-      entry->path [i] = '\0';
+      entry->path[i] = '\0';
       --i;
     }
 
@@ -460,6 +452,7 @@ manual_link (char *library)
   char *soname;
   struct stat64 stat_buf;
   int flag;
+  unsigned int osversion;
 
   /* Prepare arguments for create_links call.  Split library name in
      directory and filename first.  Since path is allocated, we've got
@@ -524,7 +517,8 @@ manual_link (char *library)
       free (path);
       return;
     }
-  if (process_file (real_library, library, libname, &flag, &soname, 0))
+  if (process_file (real_library, library, libname, &flag, &osversion,
+		    &soname, 0))
     {
       error (0, 0, _("No link created since soname could not be found for %s"),
 	     library);
@@ -568,6 +562,7 @@ struct dlib_entry
   char *soname;
   int flag;
   int is_link;
+  unsigned int osversion;
   struct dlib_entry *next;
 };
 
@@ -585,6 +580,7 @@ search_dir (const struct dir_entry *entry)
   struct stat64 stat_buf;
   int is_link;
   uint64_t hwcap = path_hwcap (entry->path);
+  unsigned int osversion;
 
   file_name_len = PATH_MAX;
   file_name = alloca (file_name_len);
@@ -700,7 +696,7 @@ search_dir (const struct dir_entry *entry)
 	real_name = real_file_name;
 
       if (process_file (real_name, file_name, direntry->d_name, &flag,
-			&soname, is_link))
+			&osversion, &soname, is_link))
 	{
 	  if (real_name != real_file_name)
 	    free (real_name);
@@ -762,6 +758,11 @@ search_dir (const struct dir_entry *entry)
 			error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
 			       dlib_ptr->name, direntry->d_name, entry->path);
 		    }
+		  /* OS version should be the same - sanity check.  */
+		  if (dlib_ptr->osversion != osversion)
+		    error (0, 0, _("libraries %s and %s in directory %s have same\n"
+				   "soname but different minimal supported OS version."),
+			   dlib_ptr->name, direntry->d_name, entry->path);
 		  free (dlib_ptr->name);
 		  dlib_ptr->name = xstrdup (direntry->d_name);
 		  dlib_ptr->is_link = is_link;
@@ -778,6 +779,7 @@ search_dir (const struct dir_entry *entry)
 	  dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
 	  dlib_ptr->name = xstrdup (direntry->d_name);
 	  dlib_ptr->flag = flag;
+	  dlib_ptr->osversion = osversion;
 	  dlib_ptr->soname = soname;
 	  dlib_ptr->is_link = is_link;
 	  /* Add at head of list.  */
@@ -797,7 +799,8 @@ search_dir (const struct dir_entry *entry)
 	create_links (dir_name, entry->path, dlib_ptr->name,
 		      dlib_ptr->soname);
       if (opt_build_cache)
-	add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
+	add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
+		      dlib_ptr->osversion, hwcap);
     }
 
   /* Free all resources.  */
@@ -909,7 +912,7 @@ main (int argc, char **argv)
     {
       int i;
       for (i = remaining; i < argc; ++i)
-	add_dir (argv [i]);
+	add_dir (argv[i]);
     }
 
   if (opt_chroot)
@@ -990,7 +993,7 @@ main (int argc, char **argv)
       int i;
 
       for (i = remaining; i < argc; ++i)
-	manual_link (argv [i]);
+	manual_link (argv[i]);
 
       exit (0);
     }
diff --git a/elf/readlib.c b/elf/readlib.c
index 746c78f345..2886c5d30f 100644
--- a/elf/readlib.c
+++ b/elf/readlib.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
 		  Jakub Jelinek <jakub@redhat.com>, 1999.
@@ -48,18 +48,18 @@ struct known_names
   int flag;
 };
 
-static struct known_names interpreters [] =
+static struct known_names interpreters[] =
 {
-  {"/lib/" LD_SO, FLAG_ELF_LIBC6},
+  { "/lib/" LD_SO, FLAG_ELF_LIBC6 },
 #ifdef SYSDEP_KNOWN_INTERPRETER_NAMES
   SYSDEP_KNOWN_INTERPRETER_NAMES
 #endif
 };
 
-static struct known_names known_libs [] =
+static struct known_names known_libs[] =
 {
-  {LIBC_SO, FLAG_ELF_LIBC6},
-  {LIBM_SO, FLAG_ELF_LIBC6},
+  { LIBC_SO, FLAG_ELF_LIBC6 },
+  { LIBM_SO, FLAG_ELF_LIBC6 },
 #ifdef SYSDEP_KNOWN_LIBRARY_NAMES
   SYSDEP_KNOWN_LIBRARY_NAMES
 #endif
@@ -70,13 +70,13 @@ static struct known_names known_libs [] =
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_file (const char *real_file_name, const char *file_name,
-	      const char *lib, int *flag, char **soname, int is_link)
+	      const char *lib, int *flag, unsigned int *osversion,
+	      char **soname, int is_link)
 {
   FILE *file;
   struct stat64 statbuf;
   void *file_contents;
   int ret;
-
   ElfW(Ehdr) *elf_header;
   struct exec *aout_header;
 
@@ -142,10 +142,7 @@ process_file (const char *real_file_name, const char *file_name,
     }
 
   elf_header = (ElfW(Ehdr) *) file_contents;
-  if (elf_header->e_ident [EI_MAG0] != ELFMAG0
-      || elf_header->e_ident [EI_MAG1] != ELFMAG1
-      || elf_header->e_ident [EI_MAG2] != ELFMAG2
-      || elf_header->e_ident [EI_MAG3] != ELFMAG3)
+  if (memcmp (elf_header->e_ident, ELFMAG, SELFMAG) != 0)
     {
       /* The file is neither ELF nor aout.  Check if it's a linker script,
 	 like libc.so - otherwise complain.  */
@@ -161,8 +158,8 @@ process_file (const char *real_file_name, const char *file_name,
       goto done;
     }
 
-  if (process_elf_file (file_name, lib, flag, soname, file_contents,
-			statbuf.st_size))
+  if (process_elf_file (file_name, lib, flag, osversion, soname,
+			file_contents, statbuf.st_size))
     ret = 1;
 
  done: