From: notaz Date: Sat, 9 Jan 2016 22:41:40 +0000 (+0200) Subject: override self/exe X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ginge.git;a=commitdiff_plain;h=c3831532675b527bd34ee92377b1b6d323345cb1;hp=b4f4cb40a6f3f4ecc05c7b6c8f2e852282234519 override self/exe --- diff --git a/loader/ginge_dyn.symver b/loader/ginge_dyn.symver index 93b953b..2f1ed5e 100644 --- a/loader/ginge_dyn.symver +++ b/loader/ginge_dyn.symver @@ -18,6 +18,7 @@ global: execvp; execve; chdir; + readlink; local: *; diff --git a/loader/header.h b/loader/header.h index 208e5ab..ec4a495 100644 --- a/loader/header.h +++ b/loader/header.h @@ -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 */ diff --git a/loader/loader.c b/loader/loader.c index 7e71d4d..2d7d3d2 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -8,11 +8,16 @@ #include #include #include +#include +#include +#include #include #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 [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++) diff --git a/loader/override.c b/loader/override.c index a9d545b..5a722d9 100644 --- a/loader/override.c +++ b/loader/override.c @@ -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 }; diff --git a/loader/patches.c b/loader/patches.c index ada0043..b7ea613 100644 --- a/loader/patches.c +++ b/loader/patches.c @@ -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), }; diff --git a/loader/syscalls.S b/loader/syscalls.S index 0d47b81..7c57ef2 100644 --- a/loader/syscalls.S +++ b/loader/syscalls.S @@ -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 diff --git a/loader/syscalls.h b/loader/syscalls.h index 9a91bd4..d5a8048 100644 --- a/loader/syscalls.h +++ b/loader/syscalls.h @@ -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);