Home | History | Annotate | Download | only in run_pie
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <dlfcn.h>
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <sys/prctl.h>
      9 #include <unistd.h>
     10 
     11 // This is a wrapper to run position independent executables on Android ICS,
     12 // where the linker doesn't support PIE. This requires the PIE binaries to be
     13 // built with CFLAGS +=-fvisibility=default -fPIE, and LDFLAGS += -rdynamic -pie
     14 // such that the main() symbol remains exported and can be dlsym-ed.
     15 
     16 #define ERR_PREFIX "[PIE Loader] "
     17 
     18 typedef int (*main_t)(int, char**);
     19 
     20 
     21 int main(int argc, char** argv) {
     22   if (argc < 2) {
     23     printf("Usage: %s path_to_pie_executable [args]\n", argv[0]);
     24     return -1;
     25   }
     26 
     27   // Shift left the argv[]. argv is what /proc/PID/cmdline prints out. In turn
     28   // cmdline is what Android "ps" prints out. In turn "ps" is what many scripts
     29   // look for to decide which processes to kill / killall.
     30   int i;
     31   char* next_argv_start = argv[0];
     32   for (i = 1; i < argc; ++i) {
     33     const size_t argv_len = strlen(argv[i]) + 1;
     34     memcpy(argv[i - 1], argv[i], argv_len);
     35     next_argv_start += argv_len;
     36     argv[i] = next_argv_start;
     37   }
     38   argv[argc - 1] = NULL;  // The last argv must be a NULL ptr.
     39 
     40   // Set also the proc name accordingly (/proc/PID/comm).
     41   prctl(PR_SET_NAME, (long) argv[0]);
     42 
     43   // dlopen should not fail, unless:
     44   // - The target binary does not exists:
     45   // - The dependent .so libs cannot be loaded.
     46   // In both cases, just bail out with an explicit error message.
     47   void* handle = dlopen(argv[0], RTLD_NOW);
     48   if (handle == NULL) {
     49     printf(ERR_PREFIX "dlopen() failed: %s.\n", dlerror());
     50     return -1;
     51   }
     52 
     53   main_t pie_main = (main_t) dlsym(handle, "main");
     54   if (pie_main) {
     55     return pie_main(argc - 1, argv);
     56   }
     57 
     58   // If we reached this point dlsym failed, very likely because the target
     59   // binary has not been compiled with the proper CFLAGS / LDFLAGS.
     60   // At this point the most sensible thing to do is running that normally
     61   // via exec and hope that the target binary wasn't a PIE.
     62   execv(argv[0], argv);
     63 
     64   // exevc is supposed to never return, unless it fails.
     65   printf(ERR_PREFIX "Both dlsym() and the execv() fallback failed.\n");
     66   perror("execv");
     67   return -1;
     68 }
     69