Skip to content

Commit a1f71da

Browse files
authored
Merge 6d2bdc7 into 2448c17
2 parents 2448c17 + 6d2bdc7 commit a1f71da

20 files changed

Lines changed: 431 additions & 28 deletions

src/main/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ set(shadow_srcs
118118
host/syscall/mman.c
119119
host/syscall/process.c
120120
host/syscall/random.c
121+
host/syscall/signal.c
121122
host/syscall/socket.c
123+
host/syscall/sysinfo.c
122124
host/syscall/time.c
123125
host/syscall/timerfd.c
124126
host/syscall/unistd.c

src/main/host/host.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,24 @@ const gchar* host_getDataPath(Host* host) {
651651
}
652652

653653
FutexTable* host_getFutexTable(Host* host) { return host->futexTable; }
654+
655+
pid_t host_getNativeTID(Host* host, pid_t virtualPID, pid_t virtualTID) {
656+
MAGIC_ASSERT(host);
657+
658+
// TODO: once we have a process table, we can do a constant time lookup instead
659+
GList* current = g_queue_peek_head_link(host->processes);
660+
pid_t nativeTID = 0;
661+
662+
while (current != NULL) {
663+
Process* proc = current->data;
664+
nativeTID = process_findNativeTID(proc, virtualPID, virtualTID);
665+
666+
if (nativeTID > 0) {
667+
break;
668+
}
669+
670+
current = current->next;
671+
}
672+
673+
return nativeTID; // 0 if no process/thread has the given virtual PID/TID
674+
}

src/main/host/host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,7 @@ in_port_t host_getRandomFreePort(Host* host, ProtocolType type,
122122

123123
FutexTable* host_getFutexTable(Host* host);
124124

125+
// converts a virtual (shadow) tid into the native tid
126+
pid_t host_getNativeTID(Host* host, pid_t virtualPID, pid_t virtualTID);
127+
125128
#endif /* SHD_HOST_H_ */

src/main/host/process.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,33 @@ static Thread* _process_threadLeader(Process* proc) {
247247
return g_hash_table_lookup(proc->threads, GUINT_TO_POINTER(proc->processID));
248248
}
249249

250+
pid_t process_findNativeTID(Process* proc, pid_t virtualPID, pid_t virtualTID) {
251+
MAGIC_ASSERT(proc);
252+
253+
Thread* thread = NULL;
254+
255+
if (virtualPID > 0 && virtualTID > 0) {
256+
// Both PID and TID must match
257+
if (proc->processID == virtualPID) {
258+
thread = g_hash_table_lookup(proc->threads, GINT_TO_POINTER(virtualTID));
259+
}
260+
} else if (virtualPID > 0) {
261+
// Get the TID of the main thread if the PID matches
262+
if (proc->processID == virtualPID) {
263+
thread = _process_threadLeader(proc);
264+
}
265+
} else if (virtualTID > 0) {
266+
// Get the TID of any thread that matches, ignoring PID
267+
thread = g_hash_table_lookup(proc->threads, GINT_TO_POINTER(virtualTID));
268+
}
269+
270+
if (thread != NULL) {
271+
return thread_getNativeTid(thread);
272+
} else {
273+
return 0; // not found
274+
}
275+
}
276+
250277
static void _process_check(Process* proc) {
251278
MAGIC_ASSERT(proc);
252279

src/main/host/process.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ const gchar* process_getPluginName(Process* proc);
7171
/* Returns the processID that was assigned to us in process_new */
7272
guint process_getProcessID(Process* proc);
7373

74+
/* Returns the native tid of the thread with the given virtual PID and TID.
75+
* Although the process knows its own virtualPID already, giving it as a param
76+
* here allows us to control which of the PIF and TID get matched:
77+
* - If virtualPID is 0, then we only check for matching TIDs.
78+
* - If virtualTID is 0, then we return the TID of the main thread if the virutal PIDs match.
79+
* - If we don't find a matching thread, return 0. */
80+
pid_t process_findNativeTID(Process* proc, pid_t virtualPID, pid_t virtualTID);
81+
7482
/* Handle all of the descriptors owned by this process. */
7583
int process_registerCompatDescriptor(Process* proc, CompatDescriptor* compatDesc);
7684
void process_deregisterCompatDescriptor(Process* proc, int handle);

src/main/host/syscall/futex.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,19 @@ SysCallReturn syscallhandler_futex(SysCallHandler* sys, const SysCallArgs* args)
184184

185185
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = result};
186186
}
187+
188+
SysCallReturn syscallhandler_get_robust_list(SysCallHandler* sys, const SysCallArgs* args) {
189+
utility_assert(sys && args);
190+
191+
info("get_robust_list was called but we don't yet support it");
192+
193+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS};
194+
}
195+
196+
SysCallReturn syscallhandler_set_robust_list(SysCallHandler* sys, const SysCallArgs* args) {
197+
utility_assert(sys && args);
198+
199+
info("set_robust_list was called but we don't yet support it");
200+
201+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS};
202+
}

src/main/host/syscall/futex.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@
99
#include "main/host/syscall/protected.h"
1010

1111
SYSCALL_HANDLER(futex);
12+
SYSCALL_HANDLER(get_robust_list);
13+
SYSCALL_HANDLER(set_robust_list);
1214

1315
#endif /* SRC_MAIN_HOST_SYSCALL_FUTEX_H_ */

src/main/host/syscall/process.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,82 @@
55

66
#include "main/host/syscall/process.h"
77

8+
#include <errno.h>
9+
#include <sys/prctl.h>
10+
811
#include "main/host/syscall/protected.h"
12+
#include "main/host/thread.h"
13+
#include "support/logger/logger.h"
14+
15+
///////////////////////////////////////////////////////////
16+
// Helpers
17+
///////////////////////////////////////////////////////////
18+
19+
static SysCallReturn _syscallhandler_prlimitHelper(SysCallHandler* sys, pid_t pid, int resource,
20+
PluginPtr newlim, PluginPtr oldlim) {
21+
// TODO: for determinism, we may want to enforce static limits for certain resources, like
22+
// RLIMIT_NOFILE. Some applications like Tor will change behavior depending on these limits.
23+
if (pid == 0) {
24+
// process is calling prlimit on itself
25+
return (SysCallReturn){.state = SYSCALL_NATIVE};
26+
} else {
27+
// TODO: we do not currently support adjusting other processes limits.
28+
// To support it, we just need to find the native pid associated
29+
// with pid, and call prlimit on the native pid instead.
30+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS};
31+
}
32+
}
33+
34+
///////////////////////////////////////////////////////////
35+
// System Calls
36+
///////////////////////////////////////////////////////////
37+
38+
SysCallReturn syscallhandler_prctl(SysCallHandler* sys, const SysCallArgs* args) {
39+
utility_assert(sys && args);
40+
41+
int option = args->args[0].as_i64;
42+
debug("prctl called with option %i", option);
43+
44+
if (option == PR_GET_TID_ADDRESS) {
45+
PluginVirtualPtr tid_addr = thread_getTidAddress(sys->thread);
46+
47+
// Make sure we have somewhere to copy the output
48+
PluginPtr outptr = args->args[1].as_ptr;
49+
if (!outptr.val) {
50+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT};
51+
}
52+
53+
int** out = process_getWriteablePtr(sys->process, sys->thread, outptr, sizeof(*out));
54+
if (!out) {
55+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT};
56+
}
57+
58+
*out = (int*)tid_addr.val;
59+
return (SysCallReturn){.state = SYSCALL_DONE};
60+
} else {
61+
return (SysCallReturn){.state = SYSCALL_NATIVE};
62+
}
63+
}
64+
65+
SysCallReturn syscallhandler_prlimit(SysCallHandler* sys, const SysCallArgs* args) {
66+
utility_assert(sys && args);
67+
pid_t pid = args->args[0].as_i64;
68+
int resource = args->args[1].as_i64;
69+
PluginPtr newlim = args->args[2].as_ptr; // const struct rlimit*
70+
PluginPtr oldlim = args->args[3].as_ptr; // const struct rlimit*
71+
debug("prlimit called on pid %i for resource %i", pid, resource);
72+
return _syscallhandler_prlimitHelper(sys, pid, resource, newlim, oldlim);
73+
}
74+
75+
SysCallReturn syscallhandler_prlimit64(SysCallHandler* sys, const SysCallArgs* args) {
76+
utility_assert(sys && args);
77+
pid_t pid = args->args[0].as_i64;
78+
int resource = args->args[1].as_i64;
79+
PluginPtr newlim = args->args[2].as_ptr; // const struct rlimit*
80+
PluginPtr oldlim = args->args[3].as_ptr; // const struct rlimit*
81+
debug("prlimit called on pid %i for resource %i", pid, resource);
82+
return _syscallhandler_prlimitHelper(sys, pid, resource, newlim, oldlim);
83+
}
984

1085
SysCallReturn syscallhandler_execve(SysCallHandler* sys, const SysCallArgs* args) {
1186
// The MemoryManager's state is no longer valid after an exec.

src/main/host/syscall/process.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@
99
#include "main/host/syscall/protected.h"
1010

1111
SYSCALL_HANDLER(execve);
12+
SYSCALL_HANDLER(prctl);
13+
SYSCALL_HANDLER(prlimit);
14+
SYSCALL_HANDLER(prlimit64);
1215

1316
#endif

src/main/host/syscall/signal.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* The Shadow Simulator
3+
* See LICENSE for licensing information
4+
*/
5+
6+
#include "main/host/syscall/process.h"
7+
8+
#include <errno.h>
9+
#include <stdbool.h>
10+
#include <sys/syscall.h>
11+
12+
#include "main/host/host.h"
13+
#include "main/host/syscall/protected.h"
14+
#include "main/host/thread.h"
15+
#include "main/utility/syscall.h"
16+
#include "support/logger/logger.h"
17+
18+
///////////////////////////////////////////////////////////
19+
// Helpers
20+
///////////////////////////////////////////////////////////
21+
22+
static SysCallReturn _syscallhandler_killHelper(SysCallHandler* sys, pid_t pid, pid_t tid, int sig,
23+
long syscallnum) {
24+
pid_t my_tid = thread_getNativeTid(sys->thread);
25+
26+
// Return error if trying to stop/continue a process so we don't disrupt our ptracer.
27+
// NOTE: If we run into signal problems, we could consider only allowing a process to
28+
// send signals to itself, i.e., disallow inter-process signaling. See Github PR#1075.
29+
if (sig == SIGSTOP || sig == SIGCONT) {
30+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOSYS};
31+
}
32+
33+
debug(
34+
"making syscall %li in native thread %i (pid=%i and tid=%i)", syscallnum, my_tid, pid, tid);
35+
36+
long result = 0;
37+
38+
switch (syscallnum) {
39+
case SYS_kill: result = thread_nativeSyscall(sys->thread, SYS_kill, pid, sig); break;
40+
case SYS_tkill: result = thread_nativeSyscall(sys->thread, SYS_tkill, tid, sig); break;
41+
case SYS_tgkill:
42+
result = thread_nativeSyscall(sys->thread, SYS_tgkill, pid, tid, sig);
43+
break;
44+
default: error("Invalid syscall number %li given", syscallnum); break;
45+
}
46+
47+
int error = syscall_rawReturnValueToErrno(result);
48+
49+
debug("native syscall returned error code %i", error);
50+
51+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -error};
52+
}
53+
54+
///////////////////////////////////////////////////////////
55+
// System Calls
56+
///////////////////////////////////////////////////////////
57+
58+
SysCallReturn syscallhandler_kill(SysCallHandler* sys, const SysCallArgs* args) {
59+
utility_assert(sys && args);
60+
pid_t pid = args->args[0].as_i64;
61+
int sig = args->args[1].as_i64;
62+
63+
debug("kill called on pid %i with signal %i", pid, sig);
64+
65+
pid_t native_pid = 0;
66+
67+
if (pid == -1 || pid == 0) {
68+
// Special pids do not need translation
69+
native_pid = pid;
70+
} else {
71+
// Translate from virtual to native pid
72+
// Support -pid for kill
73+
native_pid = (pid > 0) ? host_getNativeTID(sys->host, pid, 0)
74+
: -host_getNativeTID(sys->host, -pid, 0);
75+
76+
// If there is no such thread, it's an error
77+
if (native_pid == 0) {
78+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH};
79+
}
80+
}
81+
82+
debug("translated virtual pid %i to native pid %i", pid, native_pid);
83+
return _syscallhandler_killHelper(sys, native_pid, 0, sig, SYS_kill);
84+
}
85+
86+
SysCallReturn syscallhandler_tgkill(SysCallHandler* sys, const SysCallArgs* args) {
87+
utility_assert(sys && args);
88+
89+
pid_t tgid = args->args[0].as_i64;
90+
pid_t tid = args->args[1].as_i64;
91+
int sig = args->args[2].as_i64;
92+
93+
debug("tgkill called on tgid %i and tid %i with signal %i", tgid, tid, sig);
94+
95+
// Translate from virtual to native tgid and tid
96+
pid_t native_tgid = host_getNativeTID(sys->host, tgid, 0);
97+
pid_t native_tid = host_getNativeTID(sys->host, tgid, tid);
98+
99+
// If there is no such threads it's an error
100+
if (native_tgid == 0 || native_tid == 0) {
101+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH};
102+
}
103+
104+
debug("translated virtual tgid %i to native tgid %i and virtual tid %i to native tid %i", tgid,
105+
native_tgid, tid, native_tid);
106+
return _syscallhandler_killHelper(sys, native_tgid, native_tid, sig, SYS_tgkill);
107+
}
108+
109+
SysCallReturn syscallhandler_tkill(SysCallHandler* sys, const SysCallArgs* args) {
110+
utility_assert(sys && args);
111+
pid_t tid = args->args[0].as_i64;
112+
int sig = args->args[1].as_i64;
113+
114+
debug("tkill called on tid %i with signal %i", tid, sig);
115+
116+
// Translate from virtual to native tid
117+
pid_t native_tid = host_getNativeTID(sys->host, 0, tid);
118+
119+
// If there is no such thread it's an error
120+
if (native_tid == 0) {
121+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ESRCH};
122+
}
123+
124+
debug("translated virtual tid %i to native tid %i", tid, native_tid);
125+
return _syscallhandler_killHelper(sys, 0, native_tid, sig, SYS_tkill);
126+
}

0 commit comments

Comments
 (0)