Fixing invalid reads in find_elf_note due to setenv invocation 86/107686/1 submit/tizen/20170206.023855
authorRoman Marchenko <r.marchenko@samsung.com>
Thu, 29 Dec 2016 07:53:19 +0000 (09:53 +0200)
committerRoman Marchenko <r.marchenko@samsung.com>
Thu, 29 Dec 2016 08:16:31 +0000 (10:16 +0200)
Resolves issue on mailing list and Red Hat Bugzilla 1163404.

Change-Id: I7d162bb30ad45e907203fb5192f18d54bab17818
Signed-off-by: Roman Marchenko <r.marchenko@samsung.com>
proc/sysinfo.c

index f318376..85a9cb9 100644 (file)
@@ -36,6 +36,9 @@
 #include <netinet/in.h>  /* htons */
 #endif
 
+#include <link.h>
+#include <elf.h>
+
 long smp_num_cpus;     /* number of CPUs */
 
 #define BAD_OPEN_MESSAGE                                       \
@@ -242,15 +245,67 @@ static void old_Hertz_hack(void){
 
 extern char** environ;
 
-/* for ELF executables, notes are pushed before environment and args */
-static unsigned long find_elf_note(unsigned long findme){
+static unsigned long find_elf_note(unsigned long type)
+{
+  ElfW(auxv_t) auxv_struct;
+  ElfW(auxv_t) *auxv_temp;
+  FILE *fd;
+  int i;
+  static ElfW(auxv_t) *auxv = NULL;
   unsigned long *ep = (unsigned long *)environ;
-  while(*ep++);
-  while(*ep){
-    if(ep[0]==findme) return ep[1];
-    ep+=2;
+  unsigned long ret_val = NOTE_NOT_FOUND;
+
+
+  if(!auxv) {
+
+    fd = fopen("/proc/self/auxv", "rb");
+
+    if(!fd) {  // can't open auxv? that could be caused by euid change
+               // ... and we need to fall back to the old and unsafe
+               // ... method that doesn't work when calling library
+               // ... functions with dlopen -> FIXME :(
+
+      while(*ep++);  // for ELF executables, notes are pushed
+      while(*ep){    // ... before environment and args
+        if(ep[0]==type) return ep[1];
+        ep+=2;
+      }
+      return NOTE_NOT_FOUND;
+    }
+
+    auxv = (ElfW(auxv_t) *) malloc(getpagesize());
+    if (!auxv) {
+      perror("malloc");
+      exit(EXIT_FAILURE);
+    }
+
+    i = 0;
+    do {
+      fread(&auxv_struct, sizeof(ElfW(auxv_t)), 1, fd);
+      auxv[i] = auxv_struct;
+      i++;
+    } while (auxv_struct.a_type != AT_NULL);
+
+    fclose(fd);
+
+  }
+
+  auxv_temp = auxv;
+  i = 0;
+  do {
+    if(auxv_temp[i].a_type == type) {
+      ret_val = (unsigned long)auxv_temp[i].a_un.a_val;
+      break;
+    }
+    i++;
+  } while (auxv_temp[i].a_type != AT_NULL);
+
+  if (auxv){
+         auxv_temp = NULL;
+         free(auxv);
+         auxv = NULL;
   }
-  return NOTE_NOT_FOUND;
+  return ret_val;
 }
 
 int have_privs;