override self/exe
authornotaz <notasas@gmail.com>
Sat, 9 Jan 2016 22:41:40 +0000 (00:41 +0200)
committernotaz <notasas@gmail.com>
Sat, 9 Jan 2016 23:39:03 +0000 (01:39 +0200)
loader/ginge_dyn.symver
loader/header.h
loader/loader.c
loader/override.c
loader/patches.c
loader/syscalls.S
loader/syscalls.h

index 93b953b..2f1ed5e 100644 (file)
@@ -18,6 +18,7 @@ global:
        execvp;
        execve;
        chdir;
+       readlink;
 
 local:
        *;
index 208e5ab..ec4a495 100644 (file)
@@ -60,6 +60,8 @@ enum  { GP2X_UP = 0,      GP2X_LEFT = 2,      GP2X_DOWN = 4,  GP2X_RIGHT = 6,
         GP2X_A = 12,      GP2X_B = 13,        GP2X_X = 14,    GP2X_Y = 15,
         GP2X_VOL_UP = 16, GP2X_VOL_DOWN = 17, GP2X_PUSH = 18 };
 
+extern char *bin_path;
+
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
 #endif /* INCLUDE_sQt5fY5eUJn5tKV0IBTDxK0zqQutTqTp */
index 7e71d4d..2d7d3d2 100644 (file)
@@ -8,11 +8,16 @@
 #include <stdlib.h>
 #include <string.h>
 #include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <sys/mman.h>
 
 #include "header.h"
 #include "realfuncs.h"
 
+char *bin_path;
+
 #define CHECK_(val, fail_operator, expect, err_msg) \
   if (val fail_operator expect) { \
     fprintf(stderr, err_msg ", exiting (%d)\n", (int)(long)val); \
@@ -68,6 +73,8 @@ int main(int argc, char *argv[])
   int map_cnt;
   int i, ret, envc, sfp;
   long *stack_frame;
+  struct stat st;
+  char buf[64];
 
   if (argc < 2) {
     fprintf(stderr, "usage: %s <program> [args]\n", argv[0]);
@@ -154,6 +161,19 @@ int main(int argc, char *argv[])
       lowest_segment = map_ptr;
   }
 
+  // build self bin path
+  snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(fi));
+  if (lstat(buf, &st) != 0)
+    FAIL_PERROR("lstat bin_path");
+  bin_path = malloc(st.st_size + 1);
+  CHECK_NE(bin_path, NULL, "bin_path");
+  ret = readlink(buf, bin_path, st.st_size);
+  if (ret < 0)
+    FAIL_PERROR("readlink");
+  bin_path[ret] = 0;
+
+  fclose(fi);
+
   emu_init(lowest_segment);
 
   // generate stack frame: argc, argv[], NULL, env[], NULL
@@ -166,6 +186,9 @@ int main(int argc, char *argv[])
     return 1;
   }
 
+  // update the environment
+  setenv("_", bin_path, 1);
+
   sfp = 0;
   stack_frame[sfp++] = argc - 1;
   for (i = 1; i < argc; i++)
index a9d545b..5a722d9 100644 (file)
@@ -268,7 +268,26 @@ static int w_chdir(const char *path)
     ret = 0;
   else
     ret = g_chdir_raw(path);
-  strace("chdir(%s) = %d\n", path, ret);
+
+  strace("chdir(%s) = %ld\n", path, ret);
+  return g_syscall_error(ret);
+}
+
+static ssize_t w_readlink(const char *path, char *buf, size_t bufsiz)
+{
+  long ret;
+
+  if (path != NULL && strncmp(path, "/proc/", 6) == 0
+      && strcmp(strrchr(path, '/'), "/exe") == 0)
+  {
+    ret = snprintf(buf, bufsiz, "%s", bin_path);
+    if (ret > bufsiz)
+      ret = bufsiz;
+  }
+  else
+    ret = g_readlink_raw(path, buf, bufsiz);
+
+  strace("readlink(%s, %s, %zd) = %ld\n", path, buf, bufsiz, ret);
   return g_syscall_error(ret);
 }
 
@@ -290,6 +309,7 @@ static int w_chdir(const char *path)
 #undef execvp
 #undef execve
 #undef chdir
+#undef readlink
 
 #ifdef DL
 
@@ -320,6 +340,7 @@ MAKE_WRAP_SYM_N(execv);
 MAKE_WRAP_SYM_N(execvp);
 MAKE_WRAP_SYM(execve);
 MAKE_WRAP_SYM_N(chdir);
+MAKE_WRAP_SYM_N(readlink);
 typeof(mmap) mmap2 __attribute__((alias("w_mmap")));
 
 #define REAL_FUNC_NP(name) \
@@ -446,6 +467,12 @@ int real_chdir(const char *path)
   return g_syscall_error(ret);
 }
 
+ssize_t real_readlink(const char *path, char *buf, size_t bufsiz)
+{
+  long ret = g_readlink_raw(path, buf, bufsiz);
+  return g_syscall_error(ret);
+}
+
 void real_sleep(unsigned int seconds)
 {
   struct timespec ts = { seconds, 0 };
index ada0043..b7ea613 100644 (file)
@@ -130,6 +130,13 @@ static const unsigned int sig_mask_chdir[] = {
   0xffffffff, 0xffffffff, 0xffffffff, 0xff000000
 };
 
+static const unsigned int sig_readlink[] = {
+  0xef900055, // svc  0x900055
+  0xe3700a01, // cmn  r0, #0x1000
+  0x312fff1e, // bxcc lr
+};
+#define sig_mask_readlink sig_mask_all
+
 /* special */
 static const unsigned int sig_cache1[] = {
   0xee073f5e, // mcr 15, 0, r3, cr7, cr14, 2
@@ -190,6 +197,7 @@ static const struct {
   PATCH (sigaction),
 //  PATCH_(execve, execve2, 0), // hangs
   PATCH (chdir),
+  PATCH (readlink),
   PATCH_(cache1, NULL, 2),
   PATCH_(cache2, NULL, 2),
 };
index 0d47b81..7c57ef2 100644 (file)
@@ -88,6 +88,7 @@ raw_syscall_easy g_close_raw,          __NR_close
 raw_syscall_easy g_chdir_raw,          __NR_chdir
 raw_syscall_easy g_futex_raw,          __NR_futex
 raw_syscall_easy g_nanosleep_raw,      __NR_nanosleep
+raw_syscall_easy g_readlink_raw,       __NR_readlink
 raw_syscall_easy g_clock_gettime_raw,  __NR_clock_gettime
 raw_syscall_easy g_rt_sigprocmask_raw, __NR_rt_sigprocmask
 raw_syscall_easy g_exit_group_raw,     __NR_exit_group
index 9a91bd4..d5a8048 100644 (file)
@@ -24,6 +24,7 @@ long g_chdir_raw(const char *path);
 long g_futex_raw(int *uaddr, int op, int val,
                  const struct timespec *timeout);
 long g_nanosleep_raw(const struct timespec *req, struct timespec *rem);
+long g_readlink_raw(const char *pathname, char *buf, size_t bufsiz);
 long g_clock_gettime_raw(int clk_id, const struct timespec *tp);
 long g_rt_sigprocmask_raw(int how, const void *set, void *oldset,
                           size_t sigsetsize);