diff --git a/.travis.yml b/.travis.yml index 09c865a4..abca6564 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ matrix: - env: PLATFORM="x86_64" script: + - make -C docker/vsyscall_emu - docker build --rm -t quay.io/pypa/manylinux1_$PLATFORM:$TRAVIS_COMMIT -f docker/Dockerfile-$PLATFORM docker/ diff --git a/docker/Dockerfile-x86_64 b/docker/Dockerfile-x86_64 index abcfcb13..7336df3d 100644 --- a/docker/Dockerfile-x86_64 +++ b/docker/Dockerfile-x86_64 @@ -8,6 +8,9 @@ ENV PATH /opt/rh/devtoolset-2/root/usr/bin:$PATH ENV LD_LIBRARY_PATH /opt/rh/devtoolset-2/root/usr/lib64:/opt/rh/devtoolset-2/root/usr/lib:/usr/local/lib64:/usr/local/lib ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig +COPY vsyscall_emu/vsyscall_emu.so /usr/local/lib/vsyscall_emu.so +COPY vsyscall_emu/ld.so.preload /etc/ld.so.preload + COPY build_scripts /build_scripts RUN bash build_scripts/build.sh && rm -r build_scripts diff --git a/docker/vsyscall_emu/.gitignore b/docker/vsyscall_emu/.gitignore new file mode 100644 index 00000000..c2933cf4 --- /dev/null +++ b/docker/vsyscall_emu/.gitignore @@ -0,0 +1 @@ +vsyscall_emu.so diff --git a/docker/vsyscall_emu/Makefile b/docker/vsyscall_emu/Makefile new file mode 100644 index 00000000..aa343d94 --- /dev/null +++ b/docker/vsyscall_emu/Makefile @@ -0,0 +1,13 @@ +ifeq ($(PLATFORM),x86_64) + all: vsyscall_emu.so +else + all: +endif + +vsyscall_emu.so: vsyscall_emu.c + $(CC) -fPIC -shared -o $@ $< -ldl + +clean: + $(RM) -f vsyscall_emu.so + +.PHONY: clean diff --git a/docker/vsyscall_emu/ld.so.preload b/docker/vsyscall_emu/ld.so.preload new file mode 100644 index 00000000..ecbe8be4 --- /dev/null +++ b/docker/vsyscall_emu/ld.so.preload @@ -0,0 +1 @@ +/usr/local/lib/vsyscall_emu.so diff --git a/docker/vsyscall_emu/vsyscall_emu.c b/docker/vsyscall_emu/vsyscall_emu.c new file mode 100644 index 00000000..93934330 --- /dev/null +++ b/docker/vsyscall_emu/vsyscall_emu.c @@ -0,0 +1,138 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +static struct sigaction next_handler = { + .sa_handler = SIG_DFL, +}; + +static int (*real_sigaction)(int, const struct sigaction *, struct sigaction *); + +static sigset_t visible_oldset; + +static int (*real_sigprocmask)(int, const sigset_t *, sigset_t *); + +int +sigaction(int signum, + const struct sigaction *act, + struct sigaction *old_act) +{ + if (signum != SIGSEGV) { + return real_sigaction(signum, act, old_act); + } + + if (old_act) { + *old_act = next_handler; + } + if (act) { + next_handler = *act; + } + return 0; +} + +sighandler_t +signal(int signum, sighandler_t handler) +{ + struct sigaction sa = { + .sa_handler = handler, + .sa_flags = SA_RESETHAND | SA_NODEFER, + }, oldsa; + if (sigaction(signum, &sa, &oldsa) == 0) { + return oldsa.sa_handler; + } else { + return SIG_ERR; + } +} + +int +sigprocmask (int how, const sigset_t *newset, sigset_t *oldset) +{ + sigset_t newset_without_sigsegv; + const sigset_t *to_install; + int result; + + if (newset && how == SIG_BLOCK && sigismember(newset, SIGSEGV)) { + newset_without_sigsegv = *newset; + sigdelset(&newset_without_sigsegv, SIGSEGV); + to_install = &newset_without_sigsegv; + } else { + to_install = newset; + } + + result = real_sigprocmask(how, to_install, oldset); + if (oldset) { + *oldset = visible_oldset; + } + if (newset) { + visible_oldset = *newset; + } + return result; +} + +static greg_t VSYS_gettimeofday = 0xffffffffff600000; +static long +syscall_gettimeofday(long arg1, long arg2) { + return syscall(SYS_gettimeofday, arg1, arg2); +} + +static greg_t VSYS_time = 0xffffffffff600400; +static long +syscall_time(long arg1) { + return syscall(SYS_time, arg1); +} + +static greg_t VSYS_getcpu = 0xffffffffff600800; +static long +syscall_getcpu(long arg1, long arg2, long arg3) { + return syscall(SYS_getcpu, arg1, arg2, arg3); +} + +static void +handler(int sig, siginfo_t *si, void *ctx) +{ + greg_t *regs = ((ucontext_t *)ctx)->uc_mcontext.gregs; + if (regs[REG_RIP] == VSYS_gettimeofday) { + regs[REG_RIP] = (greg_t)(void *)syscall_gettimeofday; + } else if (regs[REG_RIP] == VSYS_time) { + regs[REG_RIP] = (greg_t)(void *)syscall_time; + } else if (regs[REG_RIP] == VSYS_getcpu) { + regs[REG_RIP] = (greg_t)(void *)syscall_getcpu; + } else if (next_handler.sa_flags & SA_SIGINFO) { + next_handler.sa_sigaction(sig, si, ctx); + } else if (next_handler.sa_handler != SIG_DFL && next_handler.sa_handler != SIG_IGN) { + next_handler.sa_handler(sig); + } else { + // SIG_IGN is treated as SIG_DFL + struct sigaction sa = { + .sa_handler = SIG_DFL, + }; + real_sigaction(sig, &sa, NULL); + } +} + +__attribute__((constructor)) +static void +init(void) +{ + real_sigaction = dlsym(RTLD_NEXT, "sigaction"); + if (!real_sigaction) { + return; + } + + real_sigprocmask = dlsym(RTLD_NEXT, "sigprocmask"); + if (!real_sigprocmask) { + return; + } + if (real_sigprocmask(SIG_BLOCK, NULL, &visible_oldset) == -1) { + return; + } + + struct sigaction sa = { + .sa_sigaction = handler, + .sa_flags = SA_RESTART | SA_SIGINFO, + }; + real_sigaction(SIGSEGV, &sa, NULL); +}