commit 3fd4ff9f86cec02f3e8c5b8fac906be678325e31
Author: François Trahay <francois.trahay@telecom-sudparis.eu>
Date:   Fri Nov 11 16:33:42 2016 +0100

    fix pptrace for applications compiled with -fPIE

diff --git a/src/pptrace/arch/bfd.c b/src/pptrace/arch/bfd.c
index a0f4169..7583570 100644
--- a/src/pptrace/arch/bfd.c
+++ b/src/pptrace/arch/bfd.c
@@ -166,6 +166,18 @@ void* symbol_from_bfd_sym(bfd *abfd __attribute__((unused)), asymbol *sym,
     result->section_name = strdup(bfd_get_section(sym)->name);
     result->section_addr = bfd_asymbol_base(sym);
   }
+
+  if(abfd->flags & DYNAMIC) {
+    /* The binary is relocatable (ie. compiled with -fPIE). The address
+     * is thus an offset from the base address of the binary
+     */
+    result->flags=ZZT_FLAG_DYNAMIC;
+  } else {
+    /* the address is the exact place where the symbol will be (ie. not
+     * compiled with -fPIE)
+     */
+    result->flags=ZZT_FLAG_STATIC;
+  }
   result->symbol_size = zzt_asymbol_size(sym);
 
 #ifdef __arm__
@@ -223,6 +235,7 @@ size_t read_zstring(void *bin, zzt_symbol *symbol __attribute__((unused)), zzt_w
   asection *sect;
   uint8_t buf;
   bfd *abfd = (bfd*) bin;
+
   for (sect = abfd->sections; sect != NULL; sect = sect->next) {
     if (sect->vma <= addr && addr < sect->vma + sect->size) {
       addr -= sect->vma;
diff --git a/src/pptrace/binary.h b/src/pptrace/binary.h
index 9b8b89d..5f3b98f 100644
--- a/src/pptrace/binary.h
+++ b/src/pptrace/binary.h
@@ -48,6 +48,11 @@ typedef struct _zzt_symbol {
   zzt_word symbol_size;
   char *section_name;
   zzt_word section_addr;
+  uint32_t flags;
+  /* the address can be used as is */
+#define ZZT_FLAG_STATIC 1
+  /* the address is only an offset from the binary base address */
+#define ZZT_FLAG_DYNAMIC 1<<1
 } zzt_symbol;
 
 #define INIT_ZZT_SYMBOL(n, addr, size) zzt_symbol n; n.symbol_name = #n; n.symbol_size = (zzt_word)(size); n.section_name = NULL; n.section_addr = (zzt_word)0; n.symbol_offset = (zzt_word)(addr);
diff --git a/src/pptrace/os/linux/linux.c b/src/pptrace/os/linux/linux.c
index 6e1c316..d4641ed 100644
--- a/src/pptrace/os/linux/linux.c
+++ b/src/pptrace/os/linux/linux.c
@@ -154,12 +154,14 @@ pid_t trace_run(char *path, char **argv, char **envp, int debug) {
     if (child == 0)
       _ptrace(PTRACE_TRACEME, 0, NULL, NULL);
 
+    /* wait until the parent process is attached */
     read(fds[0], &plop, sizeof(char));
     close(fds[0]);
     if (path == NULL) { // No execution is asked (fork only) so return to the calling function
       kill(getpid(), SIGTRAP); // signal the parent to emulate execve call.
       return 0;
     }
+    /* run the application */
     pptrace_debug(PPTRACE_DEBUG_LEVEL_ALL, "execve(%s, ...)\n", path);
     execve(path, argv, envp);
     pptrace_debug(PPTRACE_DEBUG_LEVEL_VERBOSE, "Execution of %s failed\n",
@@ -169,16 +171,20 @@ pid_t trace_run(char *path, char **argv, char **envp, int debug) {
   pid_t tpid = debug ? child : getppid();
   if (debug == 0)
     _ptrace(PTRACE_ATTACH, tpid, NULL, NULL);
+
+  /* notify the child process that we are attached */
   plop = 'a';
   write(fds[1], &plop, sizeof(char));
   close(fds[1]);
   waitpid(tpid, &status, 0);
+
   while (!WIFEXITED(status)
     && (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP)) {
     _ptrace(PTRACE_CONT, tpid, NULL, NULL);
     waitpid(tpid, &status, 0);
   }
   pptrace_debug(PPTRACE_DEBUG_LEVEL_ALL, "execve(%s, ...) passed\n", path);
+
   if (WIFEXITED(status)) {
     pptrace_debug(
 	PPTRACE_DEBUG_LEVEL_VERBOSE,
@@ -186,6 +192,7 @@ pid_t trace_run(char *path, char **argv, char **envp, int debug) {
 	path);
     return -1;
   }
+
   return tpid;
 }
 
diff --git a/src/pptrace/pptrace.c b/src/pptrace/pptrace.c
index da536c1..0fcdbf8 100644
--- a/src/pptrace/pptrace.c
+++ b/src/pptrace/pptrace.c
@@ -58,6 +58,7 @@ typedef struct __pptrace_internal_binary {
   void *binary;  // Binary structure
 
   char **debugger; // Argument list to debugger an argument matching "{name}" will be replaced by the binary name and arguments matching "{pid}" will be replaced by the program pid
+  zzt_word baseaddr;		/* base address of the binary */
   // List of libraries
   pptrace_internal_library* first;
   pptrace_internal_library* last;
@@ -223,6 +224,7 @@ pptrace_internal_hijack* pptrace_get_hijack(pptrace_internal_binary *bin,
   }
   free(params_copy);
 
+  /* search for the address of the symbol */
   hijack->funSym = get_symbol(bin->binary, hijack->function);
   if (!hijack->funSym) {
     pptrace_debug(PPTRACE_DEBUG_LEVEL_INFO,
@@ -469,6 +471,7 @@ char* pptrace_create_preload(pptrace_internal_library *first) {
   return result;
 }
 
+/* preload the libraries, and load the application */
 pid_t pptrace_launch_preload(char *path, char **argv, char **envp,
 			     pptrace_internal_library *first, int debug) {
   // Adding LD_PRELOAD=libraries in envp
@@ -548,6 +551,28 @@ void pptrace_apply_library_baseaddr(pptrace_internal_library *lib,
   }
 }
 
+/* search for the base address of binary (once it is loaded) and fill
+ * the baseaddr field of the binary structure
+ */
+int pptrace_get_base_address(pid_t child, pptrace_internal_binary* binary) {
+  binary->baseaddr = 0;
+  /* the binary is mapped at this address:
+     grep "<binary->name>$" /proc/<child>/maps  |grep "r-xp"|cut -d'-' -f1
+  */
+  char cmd[4096];
+  snprintf(cmd, 4096, "grep \"$(basename %s)$\" /proc/%d/maps  |grep \" r-xp \"|cut -d'-' -f1", binary->name, child);
+  FILE*f = popen(cmd, "r");
+  if(!f) {
+    fprintf(stderr, "popen(%s) failed\n", cmd);
+    return -1;
+  }
+  uint64_t ptr;
+  fscanf(f, "%lx", &binary->baseaddr);
+  pptrace_debug(PPTRACE_DEBUG_LEVEL_VERBOSE,
+		"Binary base address: %p\n", binary->baseaddr);
+  return 0;
+}
+
 int pptrace_wait_library(pid_t child, pptrace_internal_binary* binary) {
   char *library;
   // Wait for dlopen(argv[1])
@@ -629,6 +654,14 @@ int pptrace_install_hijacks(pid_t child, pptrace_internal_binary* binary) {
       for (i = 0; lib->hijacks[i] != NULL; i++) {
 	if (lib->hijacks[i]->funSym != NULL
 	  && lib->hijacks[i]->funSym->symbol_offset) {
+
+	  if(lib->hijacks[i]->funSym->flags & ZZT_FLAG_DYNAMIC) {
+	    /* the symbol is in a relocated binary (ie. compiled with
+	     * -fPIE. We need to shift the base address.
+	     */
+	    lib->hijacks[i]->funSym->section_addr = lib->hijacks[i]->funSym->section_addr + binary->baseaddr;
+	  }
+
 	  // Replacing symbol only when the symbol is not in a dynamic library
 	  if (hijack(binary->binary, child, lib->hijacks[i]->funSym,
 		     lib->hijacks[i]->origSym, lib->hijacks[i]->replSym) < 0) {
@@ -668,6 +701,13 @@ int pptrace_run(void *bin, char **argv, char **envp) {
   }
   pptrace_debug(PPTRACE_DEBUG_LEVEL_INFO, "ok (pid = %d)\n", child);
 
+  pptrace_debug(PPTRACE_DEBUG_LEVEL_INFO, "Getting the binary base address\n");
+  if (pptrace_get_base_address(child, binary)) {
+    pptrace_error("Failed to get the base address of the binary, exiting after detaching child process...");
+    pptrace_free_binary(binary);
+    return -1;
+  }
+
   pptrace_debug(PPTRACE_DEBUG_LEVEL_INFO, "Getting libraries' addresses\n");
   if (pptrace_wait_libraries(child, binary)) {
     pptrace_error(
