-
Notifications
You must be signed in to change notification settings - Fork 190
/
libos_syscalls.c
144 lines (121 loc) · 4.74 KB
/
libos_syscalls.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2020 Intel Corporation
* Borys Popławski <borysp@invisiblethingslab.com>
*/
#include "asan.h"
#include "libos_defs.h"
#include "libos_internal.h"
#include "libos_lock.h"
#include "libos_signal.h"
#include "libos_table.h"
#include "libos_tcb.h"
#include "libos_thread.h"
#include "libos_utils.h"
#include "linux_abi/errors.h"
#include "toml_utils.h"
typedef arch_syscall_arg_t (*six_args_syscall_t)(arch_syscall_arg_t, arch_syscall_arg_t,
arch_syscall_arg_t, arch_syscall_arg_t,
arch_syscall_arg_t, arch_syscall_arg_t);
/*
* `context` is expected to be placed at the bottom of Gramine-internal stack.
* If you change this function please also look at `libos_syscall_rt_sigsuspend`!
*/
noreturn void libos_emulate_syscall(PAL_CONTEXT* context) {
LIBOS_TCB_SET(context.regs, context);
unsigned long sysnr = pal_context_get_syscall(context);
arch_syscall_arg_t ret = 0;
if (sysnr == GRAMINE_CUSTOM_SYSCALL_NR) {
unsigned long args[] = { ALL_SYSCALL_ARGS(context) };
ret = handle_libos_call(args[0], args[1], args[2]);
} else {
if (sysnr >= LIBOS_SYSCALL_BOUND || !libos_syscall_table[sysnr]) {
warn_unsupported_syscall(sysnr);
ret = -ENOSYS;
goto out;
}
LIBOS_TCB_SET(context.syscall_nr, sysnr);
six_args_syscall_t syscall_func = (six_args_syscall_t)libos_syscall_table[sysnr];
debug_print_syscall_before(sysnr, ALL_SYSCALL_ARGS(context));
ret = syscall_func(ALL_SYSCALL_ARGS(context));
debug_print_syscall_after(sysnr, ret, ALL_SYSCALL_ARGS(context));
}
out:
pal_context_set_retval(context, ret);
/* Some syscalls e.g. `sigreturn` could have changed context and in reality we might be not
* returning from a syscall. */
if (!handle_signal(context) && LIBOS_TCB_GET(context.syscall_nr) >= 0) {
switch (ret) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
restart_syscall(context, sysnr);
break;
default:
break;
}
}
struct libos_thread* current = get_cur_thread();
if (current->has_saved_sigmask) {
lock(¤t->lock);
set_sig_mask(current, ¤t->saved_sigmask);
unlock(¤t->lock);
current->has_saved_sigmask = false;
}
LIBOS_TCB_SET(context.syscall_nr, -1);
LIBOS_TCB_SET(context.regs, NULL);
return_from_syscall(context);
}
__attribute_no_sanitize_address
noreturn void return_from_syscall(PAL_CONTEXT* context) {
#ifdef ASAN
uintptr_t libos_stack_bottom = (uintptr_t)LIBOS_TCB_GET(libos_stack_bottom);
asan_unpoison_region(libos_stack_bottom - LIBOS_THREAD_LIBOS_STACK_SIZE,
LIBOS_THREAD_LIBOS_STACK_SIZE);
#endif
_return_from_syscall(context);
}
int init_syscalls(void) {
assert(g_manifest_root);
int ret;
toml_table_t* manifest_sys = toml_table_in(g_manifest_root, "sys");
if (!manifest_sys)
return 0;
toml_array_t* toml_disallowed_syscalls = toml_array_in(manifest_sys, "disallowed_syscalls");
if (!toml_disallowed_syscalls)
return 0;
ssize_t toml_disallowed_syscalls_cnt = toml_array_nelem(toml_disallowed_syscalls);
if (toml_disallowed_syscalls_cnt < 0)
return -EPERM;
if (toml_disallowed_syscalls_cnt == 0)
return 0;
char* toml_disallowed_syscall_str = NULL;
for (ssize_t i = 0; i < toml_disallowed_syscalls_cnt; i++) {
toml_raw_t toml_disallowed_syscall_raw = toml_raw_at(toml_disallowed_syscalls, i);
if (!toml_disallowed_syscall_raw) {
log_error("Invalid disallowed syscall in manifest at index %ld", i);
return -EINVAL;
goto out;
}
ret = toml_rtos(toml_disallowed_syscall_raw, &toml_disallowed_syscall_str);
if (ret < 0) {
log_error("Invalid disallowed syscall in manifest at index %ld (not a string)", i);
return -EINVAL;
goto out;
}
uint64_t sysno = get_syscall_number(toml_disallowed_syscall_str);
if (sysno >= LIBOS_SYSCALL_BOUND) {
log_error("Unrecognized disallowed syscall `%s` in manifest at index %ld",
toml_disallowed_syscall_str, i);
return -EINVAL;
goto out;
}
/* force the syscall to be unrecognized by LibOS and thus return -ENOSYS */
libos_syscall_table[sysno] = NULL;
free(toml_disallowed_syscall_str);
toml_disallowed_syscall_str = NULL;
}
ret = 0;
out:
free(toml_disallowed_syscall_str);
return ret;
}