[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#63183: [PATCH] 'struct dynamic' is actually ELF32 specific, breaks ldconfig



Package: ld.so
Version: 1.9.11-7
Severity: important

Hi,

<linux/elf.h> (still, as of 2.3.99pre) contains:

typedef struct dynamic{
  Elf32_Sword d_tag;
  union{
    Elf32_Sword	d_val;
    Elf32_Addr	d_ptr;
  } d_un;
} Elf32_Dyn;

typedef struct {
  Elf64_Word d_tag;		/* entry tag value */
  union {
    Elf64_Word d_val;
    Elf64_Word d_ptr;
  } d_un;
} Elf64_Dyn;

Notice that, unlike the way in which struct elfhdr and struct elf_phdr
are handled (i.e. #defined to either the ELF32 or ELF64 structs based
on ELF_CLASS), struct dynamic is declared to be the ELF32 version.  Is
there any good reason for this that I'm obviously overlooking?

Anyway, ldconfig uses 'struct dynamic' generically, and thus it
doesn't find the soname on Alpha.  (and other ELF64 targets,
presumably).  The Sparc patches from Red Hat that were submitted in
#49279 supposedly handle ELF64, but I don't actually see any evidence
that they really work, due to the abovementioned problem.

I've forwarded this to axp-list so that RH can either integrate it
into their packages, or show us where they have already patched/worked
around the problem.

(to other distributions, sorry ... I don't know where you people hang
out...)

This patch to ld.so fixes this and a few other alpha and 64-bit
uncleanlinesses in ldconfig:

It works on my Alphas running Debian with glibc 2.1 (built with Linux
2.2.14 headers), as well as my Intel laptop running Debian with glibc
2.1.  Not sure how it holds up elsewhere.

diff -urN ld.so-1.9.11/util/readelf.c ld.so-1.9.11-fixed/util/readelf.c
--- ld.so-1.9.11/util/readelf.c	Mon Oct 25 12:13:00 1999
+++ ld.so-1.9.11-fixed/util/readelf.c	Thu Apr 27 17:17:56 2000
@@ -2,16 +2,14 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
+#include <linux/elf.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
-#include <linux/elf.h>
 #include "../config.h"
 #include "readelf.h"
 #include <sys/types.h>
 
-#define ELF32_R_SYM(x) ((x) >> 8)
-#define ELF32_R_TYPE(x) ((x) & 0xff)
-
 void warn(char *fmt, ...);
 char *xstrdup(char *);
 
@@ -31,18 +29,25 @@
   { NULL,           LIB_ELF }
 };
 
+#if ELF_CLASS == ELFCLASS32
+typedef Elf32_Dyn Elf_Dyn;
+#else
+typedef Elf64_Dyn Elf_Dyn;
+#endif
+
 char *readsoname(char *name, FILE *infile, int expected_type, int *type)
 {
   struct elfhdr *epnt;
   struct elf_phdr *ppnt;
   int i, j;
   char *header;
-  unsigned int dynamic_addr = 0;
-  unsigned int dynamic_size = 0;
+  unsigned long dynamic_addr = 0;
+  unsigned long dynamic_size = 0;
+  unsigned long pagesize = getpagesize();
   int strtab_val = 0;
   int needed_val;
-  int loadaddr = -1;
-  struct dynamic *dpnt;
+  long loadaddr = -1;
+  Elf_Dyn *dpnt;
   struct stat st;
   char *needed;
   char *soname = NULL;
@@ -63,20 +73,20 @@
     return NULL;
 
   epnt = (struct elfhdr *)header;
-  if ((int)(epnt+1) > (int)(header + st.st_size))
+  if ((unsigned long)(epnt+1) > (unsigned long)(header + st.st_size))
     goto skip;
 
   ppnt = (struct elf_phdr *)&header[epnt->e_phoff];
-  if ((int)ppnt < (int)header ||
-      (int)(ppnt+epnt->e_phnum) > (int)(header + st.st_size))
+  if ((unsigned long)ppnt < (unsigned long)header ||
+      (unsigned long)(ppnt+epnt->e_phnum) > (unsigned long)(header + st.st_size))
     goto skip;
 
   for(i = 0; i < epnt->e_phnum; i++)
   {
     if (loadaddr == -1 && ppnt->p_type == PT_LOAD) 
-      loadaddr = (ppnt->p_vaddr & 0xfffff000) -
-	(ppnt->p_offset & 0xfffff000);
-    if(ppnt->p_type == 2)
+      loadaddr = (ppnt->p_vaddr & ~(pagesize-1)) -
+	(ppnt->p_offset & ~(pagesize-1));
+    if(ppnt->p_type == PT_DYNAMIC)
     {
       dynamic_addr = ppnt->p_offset;
       dynamic_size = ppnt->p_filesz;
@@ -84,10 +94,10 @@
     ppnt++;
   };
     
-  dpnt = (struct dynamic *) &header[dynamic_addr];
-  dynamic_size = dynamic_size / sizeof(struct dynamic);
-  if ((int)dpnt < (int)header ||
-      (int)(dpnt+dynamic_size) > (int)(header + st.st_size))
+  dpnt = (Elf_Dyn *) &header[dynamic_addr];
+  dynamic_size = dynamic_size / sizeof(Elf_Dyn);
+  if ((unsigned long)dpnt < (unsigned long)header ||
+      (unsigned long)(dpnt+dynamic_size) > (unsigned long)(header + st.st_size))
     goto skip;
   
   while (dpnt->d_tag != DT_NULL)
@@ -100,7 +110,7 @@
   if (!strtab_val)
     goto skip;
 
-  dpnt = (struct dynamic *) &header[dynamic_addr];
+  dpnt = (Elf_Dyn *) &header[dynamic_addr];
   while (dpnt->d_tag != DT_NULL)
   {
     if (dpnt->d_tag == DT_SONAME || dpnt->d_tag == DT_NEEDED)

-- 
David Huggins-Daines, GNU/Linux Consultant, Linuxcare, Inc.
613.223.0225 mobile
dhd@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.


Reply to: