This is the mail archive of the libc-hacker@sourceware.cygnus.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


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

readelf: pointer validy checks patch



ldconfig crashed when one of the elf structures is broken and a
pointer points outside the mmapped region.  I've added now checks to
prevent the most common cases.  We can still segfault if e.g. the end
of file is in the middle of a string - but I don't think we should
test all those cases and concentrate on the common ones first.

I'll commit this patch later,
Andreas

2000-05-26  Andreas Jaeger  <aj@suse.de>

	* sysdeps/generic/readelflib.c (check_ptr): New.
	(process_elf_file): Use check_ptr to check all accesses to the
	mmapped file.

	* elf/readlib.c (known_libs): Add more libraries.


============================================================
Index: elf/ldconfig.h
--- elf/ldconfig.h	2000/05/07 21:20:01	1.3
+++ elf/ldconfig.h	2000/05/26 09:42:23
@@ -46,7 +46,8 @@
 
 /* Declared in readelflib.c.  */
 extern int process_elf_file (const char *file_name, const char *lib, int *flag,
-			     char **soname, void *file_contents);
+			     char **soname, void *file_contents,
+			     size_t file_length);
 
 
 /* Declared in ldconfig.c.  */
============================================================
Index: elf/readlib.c
--- elf/readlib.c	2000/04/11 16:22:06	1.3
+++ elf/readlib.c	2000/05/26 09:42:23
@@ -56,8 +56,10 @@
 static struct known_names known_libs [] =
 {
   {"libc.so.6", FLAG_ELF_LIBC6},
+  {"libc.so.6.1", FLAG_ELF_LIBC6},
   {"libc.so.5", FLAG_ELF_LIBC5},
   {"libm.so.6", FLAG_ELF_LIBC6},
+  {"libm.so.6.1", FLAG_ELF_LIBC6},
   {"libm.so.5", FLAG_ELF_LIBC5}
 };
 
@@ -65,7 +67,8 @@
 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
-process_file (const char *file_name, const char *lib, int *flag, char **soname, int is_link)
+process_file (const char *file_name, const char *lib, int *flag,
+	      char **soname, int is_link)
 {
   FILE *file;
   struct stat statbuf;
@@ -156,7 +159,8 @@
       goto done;
     }
 
-  if (process_elf_file (file_name, lib, flag, soname, file_contents))
+  if (process_elf_file (file_name, lib, flag, soname, file_contents,
+			statbuf.st_size))
     ret = 1;
 
  done:
============================================================
Index: sysdeps/generic/readelflib.c
--- sysdeps/generic/readelflib.c	1999/12/04 07:56:05	1.1
+++ sysdeps/generic/readelflib.c	2000/05/26 09:42:23
@@ -23,10 +23,24 @@
    which need to handle both 32bit and 64bit ELF libraries,  this file is
    included twice for each arch size.  */
 
+/* check_ptr checks that a pointer is in the mmaped file and doesn't
+   point outside it.  */
+#define check_ptr(ptr)						\
+do								\
+  {								\
+    if ((void *)(ptr) < file_contents				\
+	|| (void *)(ptr) > (file_contents+file_length))		\
+      {								\
+	error (0, 0, _("file %s is truncated\n"), file_name);	\
+	return 1;						\
+      }								\
+  }								\
+ while (0);
+ 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
-process_elf_file (const char *file_name, const char *lib, int *flag, char **soname,
-		  void *file_contents)
+process_elf_file (const char *file_name, const char *lib, int *flag,
+		  char **soname, void *file_contents, size_t file_length)
 {
   int i;
   unsigned int j;
@@ -65,6 +79,7 @@
   
   /* Get information from elf program header.  */
   elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
+  check_ptr (elf_pheader);
 
   /* The library is an elf library, now search for soname and
      libc5/libc6.  */
@@ -77,6 +92,8 @@
   for (i = 0, segment = elf_pheader;
        i < elf_header->e_phnum; i++, segment++)
     {
+      check_ptr (segment);
+
       switch (segment->p_type)
 	{
 	case PT_LOAD:
@@ -94,6 +111,7 @@
 	  break;
 	case PT_INTERP:
 	  program_interpreter = (char *) (file_contents + segment->p_offset);
+	  check_ptr (program_interpreter);
 
 	  /* Check if this is enough to classify the binary.  */
 	  for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
@@ -120,15 +138,18 @@
     return 1;
   
   dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
+  check_ptr (dynamic_segment);
 
   /* Find the string table.  */
   dynamic_strings = NULL;
   for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
        ++dyn_entry)
     {
+      check_ptr (dyn_entry);
       if (dyn_entry->d_tag == DT_STRTAB)
 	{
 	  dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
+	  check_ptr (dynamic_strings);
 	  break;
 	}
     }
@@ -143,6 +164,7 @@
       if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
 	{
 	  char *name = dynamic_strings + dyn_entry->d_un.d_val;
+	  check_ptr (name);
 
 	  if (dyn_entry->d_tag == DT_NEEDED)
 	    {
============================================================
Index: sysdeps/unix/sysv/linux/sparc/readelflib.c
--- sysdeps/unix/sysv/linux/sparc/readelflib.c	1999/12/04 07:55:35	1.1
+++ sysdeps/unix/sysv/linux/sparc/readelflib.c	2000/05/26 09:42:23
@@ -20,23 +20,27 @@
 
 
 int process_elf32_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents);
+			char **soname, void *file_contents,
+			size_t file_length);
 int process_elf64_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents);
+			char **soname, void *file_contents,
+			size_t file_length);
 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_elf_file (const char *file_name, const char *lib, int *flag,
-		  char **soname, void *file_contents)
+		  char **soname, void *file_contents, size_t size)
 {
   ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
   int ret;
 
   if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
-    return process_elf32_file (file_name, lib, flag, soname, file_contents);
+    return process_elf32_file (file_name, lib, flag, soname, file_contents,
+			       file_length);
   else
     {
-      ret = process_elf64_file (file_name, lib, flag, soname, file_contents);
+      ret = process_elf64_file (file_name, lib, flag, soname, file_contents,
+				file_length);
       /* Sparc 64bit libraries are always libc.so.6+.  */
       if (!ret)
 	*flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;

-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.rhein-neckar.de

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