-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathlind_syscall.c
More file actions
190 lines (182 loc) · 8.3 KB
/
lind_syscall.c
File metadata and controls
190 lines (182 loc) · 8.3 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include <errno.h>
#include <stdint.h> // For uint64_t definition
#include "addr_translation.h"
#include "lind_syscall_num.h"
#include "lind_constants.h"
// Entry point for wasmtime, lind_syscall is an imported function from wasmtime
int __lind_make_syscall_trampoline(unsigned int callnumber,
uint64_t callname,
uint64_t self_cageid, uint64_t target_cageid,
uint64_t arg1, uint64_t arg1cageid,
uint64_t arg2, uint64_t arg2cageid,
uint64_t arg3, uint64_t arg3cageid,
uint64_t arg4, uint64_t arg4cageid,
uint64_t arg5, uint64_t arg5cageid,
uint64_t arg6, uint64_t arg6cageid
) __attribute__((
__import_module__("lind"),
__import_name__("make-syscall")
));
/*
* make_threei_call:
*
* Unified function used to invoke threei style syscalls. This is the
* core entry point for all syscall transitions into the lind runtime,
* including inter-cage calls and grates. Unlike MAKE_LEGACY_SYSCALL, this function
* explicitly specifies both `self_cageid` and `target_cageid`, allowing
* fine-grained routing of syscalls across cage boundaries.
*
* Each logical argument is passed in a (value, cageid) pair, enabling
* three-i's interposition layer to perform selective rewriting, mediation,
* or redirection. The final argument, `translate_errno`, determines whether
* lind_syscall should apply standard POSIX errno translation or return
* the raw trampoline result directly.
*
* make_threei_call is designed to be the **canonical** macro for all new
* inter-cage or grate-level syscall invocations. Grates and higher-level
* components should call make_threei_call directly rather than relying on
* MAKE_LEGACY_SYSCALL.
*
* This function acts as the middle layer between:
* (1) the MAKE_LEGACY_SYSCALL macros in glibc, and
* (2) the actual Wasmtime entry function (__lind_make_syscall_trampoline).
*
* It forwards all syscall parameters—including the inter-cage metadata
* (self_cageid, target_cageid, argX_cageid pairs) to the underlying
* trampoline, but also optionally performs post-processing on the return
* value depending on `translate_errno`.
*
* The `translate_errno` controls whether this wrapper should apply the standard
* errno handling:
*
* translate_errno == 1 (TRANSLATE_ERRNO_ON):
* The return value is treated as a complete syscall result.
* Negative values in the range [-255, -1] are interpreted as
* `-errno`, errno is set accordingly, and the wrapper returns -1.
* All other values are returned directly.
*
* translate_errno == 0 (TRANSLATE_ERRNO_OFF):
* The wrapper does *not* apply any errno translation.
* The raw return value from the trampoline is returned as-is.
*
* This distinction is required because some syscalls—especially futex-related
* operations (e.g., lll_futex_wake, lll_futex_requeue, etc.) expect the
* trampoline to return raw -errno value and must not receive additional errno
* post-processing at this layer. Other syscalls, however, rely on the standard
* POSIX errno translation implemented here.
*/
int make_threei_call (unsigned int callnumber,
uint64_t callname,
uint64_t self_cageid, uint64_t target_cageid,
uint64_t arg1, uint64_t arg1cageid,
uint64_t arg2, uint64_t arg2cageid,
uint64_t arg3, uint64_t arg3cageid,
uint64_t arg4, uint64_t arg4cageid,
uint64_t arg5, uint64_t arg5cageid,
uint64_t arg6, uint64_t arg6cageid,
int translate_errno)
{
int ret = __lind_make_syscall_trampoline(callnumber,
callname,
self_cageid, target_cageid,
TRANSLATE_ARG_TO_HOST(arg1, arg1cageid),
TRANSLATE_ARG_TO_HOST(arg2, arg2cageid),
TRANSLATE_ARG_TO_HOST(arg3, arg3cageid),
TRANSLATE_ARG_TO_HOST(arg4, arg4cageid),
TRANSLATE_ARG_TO_HOST(arg5, arg5cageid),
TRANSLATE_ARG_TO_HOST(arg6, arg6cageid));
// if translate_errno is not enabled, we do not do any further process to errno handling and directly return the result
if(translate_errno == TRANSLATE_ERRNO_OFF) return ret;
// handle the errno
// in rawposix, we use -errno as the return value to indicate the error
// but this may cause some issues for mmap syscall, because mmap syscall
// is returning an 32-bit address, which may overflow the int type (i32)
// luckily we can handle this easily because the return value of mmap is always
// multiple of pages (typically 4096) even when overflow, therefore we can distinguish
// the errno and mmap result by simply checking if the return value is
// within the valid errno range
if(ret < 0 && ret > -MAX_ERRNO)
{
errno = -ret;
return -1;
}
else
{
errno = 0;
}
return ret;
}
// ---------------------------------------------------------------------------------------------------------------------
// 3i function call to register or deregister a syscall handler in a target cage
// targetcage: the cage id where the syscall will be registered
// targetcallnum: the syscall number to be registered in the target cage
// this_grate_id: the grate id of the syscall jump ends
// register_flag: deregister(0) or register(non-0)
// in_grate_fn_ptr_u64: the function pointer (cast to uint64_t) of the syscall handler in the grate, only used when register_flag is non-0
int register_handler (int64_t targetcage,
uint64_t targetcallnum,
uint64_t this_grate_id,
uint64_t in_grate_fn_ptr_u64)
{
return make_threei_call(
REGISTER_HANDLER_SYSCALL,
NOTUSED, // callname is not used in the trampoline
targetcage, // pass targetcage as self_cageid
targetcage, // pass targetcage as target_cageid. Self_cageid and target_cageid are the same to adapt with regular make_syscall lookup logic in 3i
targetcage,
targetcallnum,
NOTUSED, // runtime_id currently not used
this_grate_id, // handlefunccage is the grate id of the handler function, which is the same as this_grate_id
in_grate_fn_ptr_u64,
NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED,
TRANSLATE_ERRNO_OFF /* do not translate errno: return the raw result */
);
}
// ---------------------------------------------------------------------------------------------------------------------
// 3i function call to copy data between cages
// thiscage: the cage id of the caller cage
// targetcage: the cage id of the target cage
// srcaddr: the source address to copy from
// srccage: the cage id of the source address
// destaddr: the destination address to copy to
// destcage: the cage id of the destination address
// len: the length of data to copy
// copytype: the type of copy, 0 for normal copy, 1 for string copy
int copy_data_between_cages(uint64_t thiscage, uint64_t targetcage, uint64_t srcaddr, uint64_t srccage, uint64_t destaddr, uint64_t destcage, uint64_t len, uint64_t copytype)
{
return make_threei_call(
COPY_DATA_BETWEEN_CAGES_SYSCALL,
NOTUSED, // callname is not used in the trampoline
thiscage, // self_cageid
thiscage, // target_cageid. Self_cageid and target_cageid are the same to adapt with regular make_syscall lookup logic in 3i
TRANSLATE_UADDR_TO_HOST(srcaddr, srccage),
TRANSLATE_UADDR_TO_HOST(destaddr, destcage),
len, NOTUSED,
copytype, NOTUSED,
NOTUSED, NOTUSED, NOTUSED, NOTUSED,
TRANSLATE_ERRNO_OFF /* do not translate errno: return the raw result */
);
}
// 3i function call to copy handler table to a target cage
// typically used when a new cage is created and we need to copy the syscall handler
// table from another cage (has the handlers different than default rawposix registration)
// to the new cage
// thiscage: the cage id of the caller cage
// targetcage: the cage id of the target cage
int copy_handler_table_to_cage(uint64_t thiscage, uint64_t targetcage)
{
return make_threei_call(
COPY_HANDLER_TABLE_TO_CAGE_SYSCALL,
NOTUSED, // callname is not used in the trampoline
thiscage, // self_cageid
thiscage, // target_cageid. Self_cageid and target_cageid are the same to adapt with regular make_syscall lookup logic in 3i
thiscage,
targetcage,
NOTUSED, NOTUSED,
NOTUSED, NOTUSED,
NOTUSED, NOTUSED,
NOTUSED, NOTUSED,
NOTUSED, NOTUSED,
TRANSLATE_ERRNO_OFF /* do not translate errno: return the raw result */
);
}