diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 87bf8b2f0e..2a60dde6f7 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -118,7 +118,9 @@ set(shadow_srcs host/syscall/mman.c host/syscall/process.c host/syscall/random.c + host/syscall/signal.c host/syscall/socket.c + host/syscall/sysinfo.c host/syscall/time.c host/syscall/timerfd.c host/syscall/unistd.c diff --git a/src/main/host/host.c b/src/main/host/host.c index 3547f7f1dc..6017c47768 100644 --- a/src/main/host/host.c +++ b/src/main/host/host.c @@ -651,3 +651,24 @@ const gchar* host_getDataPath(Host* host) { } FutexTable* host_getFutexTable(Host* host) { return host->futexTable; } + +pid_t host_getNativeTID(Host* host, pid_t virtualPID, pid_t virtualTID) { + MAGIC_ASSERT(host); + + // TODO: once we have a process table, we can do a constant time lookup instead + GList* current = g_queue_peek_head_link(host->processes); + pid_t nativeTID = 0; + + while (current != NULL) { + Process* proc = current->data; + nativeTID = process_findNativeTID(proc, virtualPID, virtualTID); + + if (nativeTID > 0) { + break; + } + + current = current->next; + } + + return nativeTID; // 0 if no process/thread has the given virtual PID/TID +} diff --git a/src/main/host/host.h b/src/main/host/host.h index aac9197d9f..89d8cf12fa 100644 --- a/src/main/host/host.h +++ b/src/main/host/host.h @@ -122,4 +122,7 @@ in_port_t host_getRandomFreePort(Host* host, ProtocolType type, FutexTable* host_getFutexTable(Host* host); +// converts a virtual (shadow) tid into the native tid +pid_t host_getNativeTID(Host* host, pid_t virtualPID, pid_t virtualTID); + #endif /* SHD_HOST_H_ */ diff --git a/src/main/host/process.c b/src/main/host/process.c index b6553e0a26..b817b70fc5 100644 --- a/src/main/host/process.c +++ b/src/main/host/process.c @@ -247,6 +247,33 @@ static Thread* _process_threadLeader(Process* proc) { return g_hash_table_lookup(proc->threads, GUINT_TO_POINTER(proc->processID)); } +pid_t process_findNativeTID(Process* proc, pid_t virtualPID, pid_t virtualTID) { + MAGIC_ASSERT(proc); + + Thread* thread = NULL; + + if (virtualPID > 0 && virtualTID > 0) { + // Both PID and TID must match + if (proc->processID == virtualPID) { + thread = g_hash_table_lookup(proc->threads, GINT_TO_POINTER(virtualTID)); + } + } else if (virtualPID > 0) { + // Get the TID of the main thread if the PID matches + if (proc->processID == virtualPID) { + thread = _process_threadLeader(proc); + } + } else if (virtualTID > 0) { + // Get the TID of any thread that matches, ignoring PID + thread = g_hash_table_lookup(proc->threads, GINT_TO_POINTER(virtualTID)); + } + + if (thread != NULL) { + return thread_getNativeTid(thread); + } else { + return 0; // not found + } +} + static void _process_check(Process* proc) { MAGIC_ASSERT(proc); diff --git a/src/main/host/process.h b/src/main/host/process.h index d7757356d2..0692d7b30e 100644 --- a/src/main/host/process.h +++ b/src/main/host/process.h @@ -71,6 +71,14 @@ const gchar* process_getPluginName(Process* proc); /* Returns the processID that was assigned to us in process_new */ guint process_getProcessID(Process* proc); +/* Returns the native tid of the thread with the given virtual PID and TID. + * Although the process knows its own virtualPID already, giving it as a param + * here allows us to control which of the PIF and TID get matched: + * - If virtualPID is 0, then we only check for matching TIDs. + * - If virtualTID is 0, then we return the TID of the main thread if the virutal PIDs match. + * - If we don't find a matching thread, return 0. */ +pid_t process_findNativeTID(Process* proc, pid_t virtualPID, pid_t virtualTID); + /* Handle all of the descriptors owned by this process. */ int process_registerCompatDescriptor(Process* proc, CompatDescriptor* compatDesc); void process_deregisterCompatDescriptor(Process* proc, int handle); diff --git a/src/main/host/syscall/futex.c b/src/main/host/syscall/futex.c index 29b501b624..bb9c81fa3d 100644 --- a/src/main/host/syscall/futex.c +++ b/src/main/host/syscall/futex.c @@ -184,3 +184,19 @@ SysCallReturn syscallhandler_futex(SysCallHandler* sys, const SysCallArgs* args) return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = result}; } + +SysCallReturn syscallhandler_get_robust_list(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + + info("get_robust_list was called but we don't yet support it"); + + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS}; +} + +SysCallReturn syscallhandler_set_robust_list(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + + info("set_robust_list was called but we don't yet support it"); + + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS}; +} diff --git a/src/main/host/syscall/futex.h b/src/main/host/syscall/futex.h index c4a95fbd02..da9004bf4a 100644 --- a/src/main/host/syscall/futex.h +++ b/src/main/host/syscall/futex.h @@ -9,5 +9,7 @@ #include "main/host/syscall/protected.h" SYSCALL_HANDLER(futex); +SYSCALL_HANDLER(get_robust_list); +SYSCALL_HANDLER(set_robust_list); #endif /* SRC_MAIN_HOST_SYSCALL_FUTEX_H_ */ diff --git a/src/main/host/syscall/process.c b/src/main/host/syscall/process.c index 1b6217b113..492e2605a7 100644 --- a/src/main/host/syscall/process.c +++ b/src/main/host/syscall/process.c @@ -5,7 +5,82 @@ #include "main/host/syscall/process.h" +#include +#include + #include "main/host/syscall/protected.h" +#include "main/host/thread.h" +#include "support/logger/logger.h" + +/////////////////////////////////////////////////////////// +// Helpers +/////////////////////////////////////////////////////////// + +static SysCallReturn _syscallhandler_prlimitHelper(SysCallHandler* sys, pid_t pid, int resource, + PluginPtr newlim, PluginPtr oldlim) { + // TODO: for determinism, we may want to enforce static limits for certain resources, like + // RLIMIT_NOFILE. Some applications like Tor will change behavior depending on these limits. + if (pid == 0) { + // process is calling prlimit on itself + return (SysCallReturn){.state = SYSCALL_NATIVE}; + } else { + // TODO: we do not currently support adjusting other processes limits. + // To support it, we just need to find the native pid associated + // with pid, and call prlimit on the native pid instead. + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS}; + } +} + +/////////////////////////////////////////////////////////// +// System Calls +/////////////////////////////////////////////////////////// + +SysCallReturn syscallhandler_prctl(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + + int option = args->args[0].as_i64; + debug("prctl called with option %i", option); + + if (option == PR_GET_TID_ADDRESS) { + PluginVirtualPtr tid_addr = thread_getTidAddress(sys->thread); + + // Make sure we have somewhere to copy the output + PluginPtr outptr = args->args[1].as_ptr; + if (!outptr.val) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT}; + } + + int** out = process_getWriteablePtr(sys->process, sys->thread, outptr, sizeof(*out)); + if (!out) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT}; + } + + *out = (int*)tid_addr.val; + return (SysCallReturn){.state = SYSCALL_DONE}; + } else { + return (SysCallReturn){.state = SYSCALL_NATIVE}; + } +} + +SysCallReturn syscallhandler_prlimit(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + pid_t pid = args->args[0].as_i64; + int resource = args->args[1].as_i64; + PluginPtr newlim = args->args[2].as_ptr; // const struct rlimit* + PluginPtr oldlim = args->args[3].as_ptr; // const struct rlimit* + debug("prlimit called on pid %i for resource %i", pid, resource); + return _syscallhandler_prlimitHelper(sys, pid, resource, newlim, oldlim); +} + +SysCallReturn syscallhandler_prlimit64(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + pid_t pid = args->args[0].as_i64; + int resource = args->args[1].as_i64; + PluginPtr newlim = args->args[2].as_ptr; // const struct rlimit* + PluginPtr oldlim = args->args[3].as_ptr; // const struct rlimit* + debug("prlimit called on pid %i for resource %i", pid, resource); + return _syscallhandler_prlimitHelper(sys, pid, resource, newlim, oldlim); +} SysCallReturn syscallhandler_execve(SysCallHandler* sys, const SysCallArgs* args) { // The MemoryManager's state is no longer valid after an exec. diff --git a/src/main/host/syscall/process.h b/src/main/host/syscall/process.h index 295bfc2872..11415d687f 100644 --- a/src/main/host/syscall/process.h +++ b/src/main/host/syscall/process.h @@ -9,5 +9,8 @@ #include "main/host/syscall/protected.h" SYSCALL_HANDLER(execve); +SYSCALL_HANDLER(prctl); +SYSCALL_HANDLER(prlimit); +SYSCALL_HANDLER(prlimit64); #endif diff --git a/src/main/host/syscall/signal.c b/src/main/host/syscall/signal.c new file mode 100644 index 0000000000..cd0913eaad --- /dev/null +++ b/src/main/host/syscall/signal.c @@ -0,0 +1,126 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ + +#include "main/host/syscall/process.h" + +#include +#include +#include + +#include "main/host/host.h" +#include "main/host/syscall/protected.h" +#include "main/host/thread.h" +#include "main/utility/syscall.h" +#include "support/logger/logger.h" + +/////////////////////////////////////////////////////////// +// Helpers +/////////////////////////////////////////////////////////// + +static SysCallReturn _syscallhandler_killHelper(SysCallHandler* sys, pid_t pid, pid_t tid, int sig, + long syscallnum) { + pid_t my_tid = thread_getNativeTid(sys->thread); + + // Return error if trying to stop/continue a process so we don't disrupt our ptracer. + // NOTE: If we run into signal problems, we could consider only allowing a process to + // send signals to itself, i.e., disallow inter-process signaling. See Github PR#1075. + if (sig == SIGSTOP || sig == SIGCONT) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS}; + } + + debug( + "making syscall %li in native thread %i (pid=%i and tid=%i)", syscallnum, my_tid, pid, tid); + + long result = 0; + + switch (syscallnum) { + case SYS_kill: result = thread_nativeSyscall(sys->thread, SYS_kill, pid, sig); break; + case SYS_tkill: result = thread_nativeSyscall(sys->thread, SYS_tkill, tid, sig); break; + case SYS_tgkill: + result = thread_nativeSyscall(sys->thread, SYS_tgkill, pid, tid, sig); + break; + default: error("Invalid syscall number %li given", syscallnum); break; + } + + int error = syscall_rawReturnValueToErrno(result); + + debug("native syscall returned error code %i", error); + + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -error}; +} + +/////////////////////////////////////////////////////////// +// System Calls +/////////////////////////////////////////////////////////// + +SysCallReturn syscallhandler_kill(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + pid_t pid = args->args[0].as_i64; + int sig = args->args[1].as_i64; + + debug("kill called on pid %i with signal %i", pid, sig); + + pid_t native_pid = 0; + + if (pid == -1 || pid == 0) { + // Special pids do not need translation + native_pid = pid; + } else { + // Translate from virtual to native pid + // Support -pid for kill + native_pid = (pid > 0) ? host_getNativeTID(sys->host, pid, 0) + : -host_getNativeTID(sys->host, -pid, 0); + + // If there is no such thread, it's an error + if (native_pid == 0) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH}; + } + } + + debug("translated virtual pid %i to native pid %i", pid, native_pid); + return _syscallhandler_killHelper(sys, native_pid, 0, sig, SYS_kill); +} + +SysCallReturn syscallhandler_tgkill(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + + pid_t tgid = args->args[0].as_i64; + pid_t tid = args->args[1].as_i64; + int sig = args->args[2].as_i64; + + debug("tgkill called on tgid %i and tid %i with signal %i", tgid, tid, sig); + + // Translate from virtual to native tgid and tid + pid_t native_tgid = host_getNativeTID(sys->host, tgid, 0); + pid_t native_tid = host_getNativeTID(sys->host, tgid, tid); + + // If there is no such threads it's an error + if (native_tgid == 0 || native_tid == 0) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH}; + } + + debug("translated virtual tgid %i to native tgid %i and virtual tid %i to native tid %i", tgid, + native_tgid, tid, native_tid); + return _syscallhandler_killHelper(sys, native_tgid, native_tid, sig, SYS_tgkill); +} + +SysCallReturn syscallhandler_tkill(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + pid_t tid = args->args[0].as_i64; + int sig = args->args[1].as_i64; + + debug("tkill called on tid %i with signal %i", tid, sig); + + // Translate from virtual to native tid + pid_t native_tid = host_getNativeTID(sys->host, 0, tid); + + // If there is no such thread it's an error + if (native_tid == 0) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH}; + } + + debug("translated virtual tid %i to native tid %i", tid, native_tid); + return _syscallhandler_killHelper(sys, 0, native_tid, sig, SYS_tkill); +} diff --git a/src/main/host/syscall/signal.h b/src/main/host/syscall/signal.h new file mode 100644 index 0000000000..1af7bf0e8d --- /dev/null +++ b/src/main/host/syscall/signal.h @@ -0,0 +1,15 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ + +#ifndef MAIN_HOST_SYSCALL_SIGNAL_H +#define MAIN_HOST_SYSCALL_SIGNAL_H + +#include "main/host/syscall/protected.h" + +SYSCALL_HANDLER(kill); +SYSCALL_HANDLER(tgkill); +SYSCALL_HANDLER(tkill); + +#endif diff --git a/src/main/host/syscall/sysinfo.c b/src/main/host/syscall/sysinfo.c new file mode 100644 index 0000000000..ab8b434699 --- /dev/null +++ b/src/main/host/syscall/sysinfo.c @@ -0,0 +1,53 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ + +#include "main/host/syscall/process.h" + +#include +#include + +#include "main/core/worker.h" +#include "main/host/process.h" +#include "main/host/syscall/protected.h" +#include "main/host/thread.h" +#include "support/logger/logger.h" + +SysCallReturn syscallhandler_sysinfo(SysCallHandler* sys, const SysCallArgs* args) { + utility_assert(sys && args); + PluginPtr info_ptr = args->args[0].as_ptr; // struct sysinfo* + + debug("sysinfo called"); + + if (!info_ptr.val) { + return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT}; + } + + struct sysinfo* info = + process_getWriteablePtr(sys->process, sys->thread, info_ptr, sizeof(*info)); + + if (!info) { + error("Unable to allocate memory for sysinfo struct."); + } + + // These values are chosen arbitrarily; we don't think it matters too much, + // except to maintain determinism. For example, Tor make decisions about how many + // circuits to allow to be open (and other OOM settings) based on available memory. + info->uptime = worker_getCurrentTime() / SIMTIME_ONE_SECOND; + info->loads[0] = 1; + info->loads[1] = 1; + info->loads[2] = 1; + info->totalram = 32; + info->freeram = 24; + info->sharedram = 4; + info->bufferram = 4; + info->totalswap = 0; + info->freeswap = 0; + info->procs = 100; + info->totalhigh = 4; + info->freehigh = 3; + info->mem_unit = 1024 * 1024 * 1024; // GiB + + return (SysCallReturn){.state = SYSCALL_DONE}; +} diff --git a/src/main/host/syscall/sysinfo.h b/src/main/host/syscall/sysinfo.h new file mode 100644 index 0000000000..22a7cd55b9 --- /dev/null +++ b/src/main/host/syscall/sysinfo.h @@ -0,0 +1,13 @@ +/* + * The Shadow Simulator + * See LICENSE for licensing information + */ + +#ifndef MAIN_HOST_SYSCALL_SYSINFO_H +#define MAIN_HOST_SYSCALL_SYSINFO_H + +#include "main/host/syscall/protected.h" + +SYSCALL_HANDLER(sysinfo); + +#endif diff --git a/src/main/host/syscall_handler.c b/src/main/host/syscall_handler.c index a6f6111794..929a3f22ae 100644 --- a/src/main/host/syscall_handler.c +++ b/src/main/host/syscall_handler.c @@ -32,7 +32,9 @@ #include "main/host/syscall/process.h" #include "main/host/syscall/protected.h" #include "main/host/syscall/random.h" +#include "main/host/syscall/signal.h" #include "main/host/syscall/socket.h" +#include "main/host/syscall/sysinfo.h" #include "main/host/syscall/time.h" #include "main/host/syscall/timerfd.h" #include "main/host/syscall/uio.h" @@ -145,7 +147,8 @@ static void _syscallhandler_post_syscall(SysCallHandler* sys, long number, ? "DONE" : scr->state == SYSCALL_BLOCK ? "BLOCK" : scr->state == SYSCALL_NATIVE ? "NATIVE" : "UNKNOWN", - (int)scr->retval.as_i64, strerror(-scr->retval.as_i64), sys->perfSecondsCurrent); + (int)scr->retval.as_i64, scr->retval.as_i64 < 0 ? strerror(-scr->retval.as_i64) : "n/a", + sys->perfSecondsCurrent); if (scr->state != SYSCALL_BLOCK) { /* The syscall completed, count it and the cumulative time to complete it. */ @@ -253,10 +256,12 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(getpid); HANDLE(gettid); HANDLE(getrandom); + HANDLE(get_robust_list); HANDLE(getsockname); HANDLE(getsockopt); HANDLE(gettimeofday); HANDLE(ioctl); + HANDLE(kill); HANDLE(linkat); HANDLE(listen); HANDLE(lseek); @@ -275,10 +280,17 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(openat); HANDLE_RUST(pipe); HANDLE_RUST(pipe2); + HANDLE(prctl); HANDLE(pread64); HANDLE(preadv); #ifdef SYS_preadv2 HANDLE(preadv2); +#endif +#ifdef SYS_prlimit + HANDLE(prlimit); +#endif +#ifdef SYS_prlimit64 + HANDLE(prlimit64); #endif HANDLE(pwrite64); HANDLE(pwritev); @@ -294,6 +306,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(renameat2); HANDLE(sendto); HANDLE(setsockopt); + HANDLE(set_robust_list); HANDLE(set_tid_address); HANDLE(shutdown); HANDLE(socket); @@ -304,10 +317,13 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, HANDLE(symlinkat); HANDLE(sync_file_range); HANDLE(syncfs); + HANDLE(sysinfo); + HANDLE(tgkill); HANDLE(time); HANDLE(timerfd_create); HANDLE(timerfd_gettime); HANDLE(timerfd_settime); + HANDLE(tkill); HANDLE(uname); HANDLE(unlinkat); HANDLE(utimensat); @@ -317,21 +333,11 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, // ************************************** // Not handled (yet): // ************************************** - NATIVE(arch_prctl); NATIVE(io_getevents); - NATIVE(prctl); - NATIVE(prlimit64); - NATIVE(rt_sigaction); - NATIVE(rt_sigprocmask); - NATIVE(get_robust_list); - NATIVE(set_robust_list); - NATIVE(sysinfo); NATIVE(waitid); + NATIVE(msync); // operations on pids (shadow overrides pids) - NATIVE(kill); - NATIVE(tkill); - NATIVE(tgkill); NATIVE(sched_getaffinity); NATIVE(sched_setaffinity); @@ -361,6 +367,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, // (because the plugin can natively): // *************************************** NATIVE(access); + NATIVE(arch_prctl); NATIVE(exit); NATIVE(exit_group); NATIVE(getcwd); @@ -373,6 +380,8 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys, NATIVE(madvise); NATIVE(mkdir); NATIVE(readlink); + NATIVE(rt_sigaction); + NATIVE(rt_sigprocmask); NATIVE(setrlimit); NATIVE(stat); #ifdef SYS_stat64 diff --git a/src/shim/preload_syscalls.c b/src/shim/preload_syscalls.c index 3a93a324a8..62f974d4f5 100644 --- a/src/shim/preload_syscalls.c +++ b/src/shim/preload_syscalls.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -260,6 +261,7 @@ NOREMAP(ssize_t, getrandom, (void* a, size_t b, unsigned int c), a, b, c); NOREMAP(int, getsockname, (int a, struct sockaddr* b, socklen_t* c), a, b, c); NOREMAP(int, getsockopt, (int a, int b, int c, void* d, socklen_t* e), a, b, c, d, e); static REMAP(int, ioctl_explicit, ioctl, (int a, unsigned long b, char* c), a,b,c); +NOREMAP(int, kill, (pid_t a, int b), a, b); NOREMAP(int, linkat, (int a, const char* b, int c, const char* d, int e), a, b, c, d, e); NOREMAP(int, listen, (int a, int b), a, b); NOREMAP(off_t, lseek, (int a, off_t b, int c), a, b, c); @@ -286,6 +288,12 @@ NOREMAP(ssize_t, preadv, (int a, const struct iovec* b, int c, off_t d), a, b, c #ifdef SYS_preadv2 NOREMAP(ssize_t, preadv2, (int a, const struct iovec* b, int c, off_t d, int e), a, b, c, d, e); #endif +#ifdef SYS_prlimit +NOREMAP(int, prlimit, (int a, int b, const struct rlimit* c, struct rlimit* d), a, b, c, d); +#endif +#ifdef SYS_prlimit64 +NOREMAP(int, prlimit64, (int a, enum __rlimit_resource b, const struct rlimit64* c, struct rlimit64* d), a, b, c, d); +#endif NOREMAP(ssize_t, pwrite64, (int a, const void* b, size_t c, off_t d), a, b, c, d); NOREMAP(ssize_t, pwritev, (int a, const struct iovec* b, int c, off_t d), a, b, c, d); #ifdef SYS_pwritev2 @@ -313,6 +321,8 @@ NOREMAP(int, statx, (int a, const char* b, int c, unsigned int d, struct statx* NOREMAP(int, symlinkat, (const char* a, int b, const char* c), a, b, c); NOREMAP(int, sync_file_range, (int a, off64_t b, off64_t c, unsigned int d), a, b, c, d); NOREMAP(int, syncfs, (int a), a); +NOREMAP(int, tkill, (int a, int b), a, b); +NOREMAP(int, tgkill, (int a, int b, int c), a, b, c); NOREMAP(int, uname, (struct utsname* a), a); NOREMAP(int, unlinkat, (int a, const char *b, int c), a, b, c); NOREMAP(int, utimensat, (int a, const char* b, const struct timespec c[2], int d), a, b, c, d); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 3da4307482..e6bf8e6f21 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -53,7 +53,7 @@ add_subdirectory(poll) add_subdirectory(pthreads) add_subdirectory(random) add_subdirectory(resolver) -# FIXME add_subdirectory(signal) +add_subdirectory(signal) add_subdirectory(sleep) add_subdirectory(sockbuf) add_subdirectory(socket) diff --git a/src/test/signal/CMakeLists.txt b/src/test/signal/CMakeLists.txt index d895a0f2a5..ea5359bed5 100644 --- a/src/test/signal/CMakeLists.txt +++ b/src/test/signal/CMakeLists.txt @@ -10,7 +10,7 @@ add_test( NAME signal-shadow-ptrace COMMAND sh -c "\ ${yaml2xml} ${CMAKE_CURRENT_SOURCE_DIR}/signal.test.shadow.config.yaml --output - \ - | shadow-test-launcher-fail ${CMAKE_BINARY_DIR}/src/main/shadow --interpose-method=ptrace -l debug -d signal.shadow-ptrace.data - \ + | ${CMAKE_BINARY_DIR}/src/main/shadow --interpose-method=ptrace -l debug -d signal.shadow-ptrace.data - \ " ) # FIXME add_test(NAME signal-shadow-preload COMMAND shadow-test-launcher-fail ${CMAKE_BINARY_DIR}/src/main/shadow --interpose-method=preload -l debug -d signal.shadow-preload.data ${CMAKE_CURRENT_SOURCE_DIR}/signal.test.shadow.config.xml) diff --git a/src/test/signal/signal.test.shadow.config.yaml b/src/test/signal/signal.test.shadow.config.yaml index 2fc6d3238a..e33f941251 100644 --- a/src/test/signal/signal.test.shadow.config.yaml +++ b/src/test/signal/signal.test.shadow.config.yaml @@ -1,3 +1,5 @@ +options: + stoptime: 5 topology: - graphml: | @@ -18,8 +20,6 @@ topology: -kill: -- time: 5 plugins: - id: testsignal path: test-signal diff --git a/src/test/signal/test_signal.c b/src/test/signal/test_signal.c index 69a9e57efa..982162b862 100644 --- a/src/test/signal/test_signal.c +++ b/src/test/signal/test_signal.c @@ -3,11 +3,15 @@ * See LICENSE for licensing information */ +#include #include #include #include +#include +#include +#include +#include -typedef void (*func_t)(int arg); int signal_handled_count = 0; void signal_handled_func(int signum) { @@ -25,17 +29,38 @@ void signal_handled_func(int signum) { int main(int argc, char* argv[]) { fprintf(stdout, "########## signal test starting ##########\n"); + pid_t pid = syscall(SYS_getpid); + pid_t tid = syscall(SYS_gettid); + + if (syscall(SYS_kill, pid, 0) < 0) { + fprintf(stdout, "kill(%li,0) has error %i: %s\n", (long)pid, errno, strerror(errno)); + fprintf(stdout, "########## signal test failed ##########\n"); + return EXIT_FAILURE; + } + + if (syscall(SYS_tkill, tid, 0) < 0) { + fprintf(stdout, "tkill(%li,0) has error %i: %s\n", (long)tid, errno, strerror(errno)); + fprintf(stdout, "########## signal test failed ##########\n"); + return EXIT_FAILURE; + } + + if (syscall(SYS_tgkill, pid, tid, 0) < 0) { + fprintf(stdout, "tgkill(%li,%li,0) has error %i: %s\n", (long)pid, (long)tid, errno, + strerror(errno)); + fprintf(stdout, "########## signal test failed ##########\n"); + return EXIT_FAILURE; + } + struct sigaction action; action.sa_handler = signal_handled_func; sigemptyset(&action.sa_mask); action.sa_flags = 0; /* handle the signal */ - sigaction(SIGSEGV, &action, NULL); + sigaction(SIGUSR1, &action, NULL); /* trigger the signal */ - func_t func = NULL; - func(128); // SIGSEGV + kill(pid, SIGUSR1); /* they should have been handled */ fprintf(stdout, "signals were not handled\n"); diff --git a/src/test/unistd/test_unistd.rs b/src/test/unistd/test_unistd.rs index 1f54dcc7f9..65f931f622 100644 --- a/src/test/unistd/test_unistd.rs +++ b/src/test/unistd/test_unistd.rs @@ -7,7 +7,7 @@ use std::ffi::CStr; use std::ffi::CString; use std::process; use std::sync::atomic::{AtomicUsize, Ordering}; -use test_utils::{get_errno, running_in_shadow}; +use test_utils::get_errno; static SIGACTION_COUNT: AtomicUsize = AtomicUsize::new(0); @@ -47,13 +47,8 @@ fn main() { test_getpid_nodeps(); test_gethostname(&expected_name.nodename); - - if !running_in_shadow() { - // TODO: Implement uname in shadow - test_uname(&expected_name); - // TODO: Support `kill` in shadow (and/or find another way of validating the pid) - test_getpid_kill(); - } + test_uname(&expected_name); + test_getpid_kill(); } /// Tests that the results are plausible, but can't really validate that it's our