diff --git a/bin/pyda b/bin/pyda index 3b3ba77..56a2797 100755 --- a/bin/pyda +++ b/bin/pyda @@ -1,4 +1,4 @@ #!/bin/bash ROOT=$(dirname "$0")/../ -ASAN_OPTIONS=detect_leaks=0 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PYTHONHOME/lib/ PYDA_SCRIPT=$1 exec $DYNAMORIO_HOME/bin64/drrun -stack_size 1024K -c $ROOT/build/pyda_core/libtool.so ${@:2} +ASAN_OPTIONS=$ASAN_OPTIONS:detect_leaks=0 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PYTHONHOME/lib/ PYDA_SCRIPT=$1 exec $DYNAMORIO_HOME/bin64/drrun -stack_size 1024K -c $ROOT/build/pyda_core/libtool.so ${@:2} diff --git a/lib/pyda/base.py b/lib/pyda/base.py index 75c32e5..e004060 100644 --- a/lib/pyda/base.py +++ b/lib/pyda/base.py @@ -2,7 +2,7 @@ from pyda_core import MemoryError, ThreadExitError, InvalidStateError, FatalSignalError from .process import Process, Map from . import arch -import sys +import sys, os INIT = False @@ -31,4 +31,10 @@ def xinfo(addr): path, start, end, perms = res return Map(path=path, vaddr=start, size=end - start, perms=perms) -FatalSignalError.__str__ = lambda self: f"Signal {self.args[0]} on Thread {self.args[1]}\nBacktrace:\n{self.args[2]}" \ No newline at end of file +FatalSignalError.__str__ = lambda self: f"Signal {self.args[0]} on Thread {self.args[1]}\nBacktrace:\n{self.args[2]}" + +def exit(*args, **kwargs): + raise RuntimeError("exit") + +os._exit = exit +sys.exit = exit diff --git a/patches/dynamorio-10.0.patch b/patches/dynamorio-10.0.patch index 2cac7a5..3d7cf42 100644 --- a/patches/dynamorio-10.0.patch +++ b/patches/dynamorio-10.0.patch @@ -743,6 +743,18 @@ index d5133bf16..106d0672a 100644 if (ksynch_get_value(&ostd->suspended) == 0) { /* If it still has to wait, give up the cpu. */ os_thread_yield(); +diff --git a/core/unix/os_exports.h b/core/unix/os_exports.h +index c234c265c..304819704 100644 +--- a/core/unix/os_exports.h ++++ b/core/unix/os_exports.h +@@ -299,6 +299,7 @@ dynamorio_set_envp(char **envp); + /* drinjectlib wants the libc version while the core wants the private version */ + # define getenv our_getenv + #endif ++DR_API + char * + our_getenv(const char *name); + diff --git a/core/unix/rseq_linux.c b/core/unix/rseq_linux.c index 4d3b9e60f..4ce713450 100644 --- a/core/unix/rseq_linux.c diff --git a/pyda_core/pyda_patch_python.c b/pyda_core/pyda_patch_python.c index 11d1139..9fbcb7b 100644 --- a/pyda_core/pyda_patch_python.c +++ b/pyda_core/pyda_patch_python.c @@ -22,7 +22,8 @@ static redirect_import_t python_redirect_imports[] = { { "pthread_detach", (app_pc)pyda_thread_detach }, { "dlopen", (app_pc)pyda_dlopen }, { "dlsym", (app_pc)pyda_dlsym }, - { "getauxval", (app_pc)pyda_getauxval } + { "getauxval", (app_pc)pyda_getauxval }, + { "getenv", (app_pc)pyda_getenv } }; #define NUM_NEW_IMPORTS (sizeof(python_redirect_imports) / sizeof(redirect_import_t)) diff --git a/pyda_core/pyda_threads.c b/pyda_core/pyda_threads.c index a7f01aa..4ad5aca 100644 --- a/pyda_core/pyda_threads.c +++ b/pyda_core/pyda_threads.c @@ -174,4 +174,50 @@ unsigned long pyda_getauxval(unsigned long type) { return os_minsigstksz(); } return getauxval(type); -} \ No newline at end of file +} + +int pyda_attach_mode; + +extern const char *our_getenv(const char *name); +const char *pyda_getenv(const char *name) { + if (pyda_attach_mode) { + // Dynamorio does not have the correct ENV in attach mode. + DEBUG_PRINTF("getenv2 %s=%s\n", name, getenv(name)); + return getenv(name); + } else { + DEBUG_PRINTF("getenv %s=%s\n", name, our_getenv(name)); + return our_getenv(name); + } +} + +void parse_proc_environ() { + FILE *f = fopen("/proc/self/environ", "r"); + if (!f) { + DEBUG_PRINTF("Failed to open /proc/self/environ\n"); + return; + } + + // /proc/self/environ is a NULL-separated list of strings + // each of the form KEY=VALUE + + // We store the new environment in attach_env + // and we will use that in the attach mode. + + char buf[4096]; + size_t len = fread(buf, 1, sizeof(buf), f); + fclose(f); + + if (len == sizeof(buf)) { + DEBUG_PRINTF("Warning: /proc/self/environ too large\n"); + } + + char *key = buf; + while (key < buf + len) { + char *k = strtok(key, "="); + char *v = key + strlen(k) + 1; + // DEBUG_PRINTF("setenv %s=%s\n", k, v); + setenv(k, v, 0); + key = v + strlen(v) + 1; + } + +} diff --git a/pyda_core/pyda_threads.h b/pyda_core/pyda_threads.h index 2b94de0..aeb5a45 100644 --- a/pyda_core/pyda_threads.h +++ b/pyda_core/pyda_threads.h @@ -20,4 +20,7 @@ int pyda_thread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*st int pyda_thread_detach(pthread_t thread); void* python_thread_init(void *pyda_thread); -unsigned long pyda_getauxval(unsigned long type); \ No newline at end of file +unsigned long pyda_getauxval(unsigned long type); +const char *pyda_getenv(const char *name); + +void parse_proc_environ(void); \ No newline at end of file diff --git a/pyda_core/tool.c b/pyda_core/tool.c index 11d3ac3..aa169f4 100644 --- a/pyda_core/tool.c +++ b/pyda_core/tool.c @@ -41,6 +41,7 @@ static void event_attach_post(void); extern int is_dynamorio_running; +extern int pyda_attach_mode; pthread_cond_t python_thread_init1; pthread_cond_t python_thread_init2; @@ -373,6 +374,9 @@ static void fork_event(void *drcontext) { } static void event_attach_post() { + pyda_attach_mode = 1; + parse_proc_environ(); + DEBUG_PRINTF("event_attach_post on tid %d\n", dr_get_thread_id(dr_get_current_drcontext())); pyda_thread *t = pyda_thread_getspecific(g_pyda_tls_idx);