Skip to content

Commit 2793f29

Browse files
register_handler: calling cage should be the destination grate. (#979)
* register_handler: use destination grate as the calling cage * update interpose-register tests.
1 parent 794f77f commit 2793f29

File tree

3 files changed

+149
-134
lines changed

3 files changed

+149
-134
lines changed

src/glibc/lind_syscall/lind_syscall.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,14 @@ int register_handler (int64_t targetcage,
122122
uint64_t this_grate_id,
123123
uint64_t in_grate_fn_ptr_u64)
124124
{
125+
// register_handler is treated as a syscall called by `this_grate_id`.
126+
// This approach allows us to interpose on register_handler calls based on which cage
127+
// this syscall was meant to be redirected to.
125128
return make_threei_call(
126129
REGISTER_HANDLER_SYSCALL,
127130
NOTUSED, // callname is not used in the trampoline
128-
targetcage, // pass targetcage as self_cageid
129-
targetcage, // pass targetcage as target_cageid. Self_cageid and target_cageid are the same to adapt with regular make_syscall lookup logic in 3i
131+
this_grate_id, // pass grate calling register handler as self_cageid
132+
this_grate_id, // self_cageid and target_cageid are the same to adapt with regular make_syscall lookup logic in 3i
130133
targetcage,
131134
targetcallnum,
132135
NOTUSED, // runtime_id currently not used

tests/grate-tests/interposing-calls/interpose-register.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,32 @@
33
#include <unistd.h>
44
#include <assert.h>
55
#include <lind_syscall.h>
6+
#include <sys/wait.h>
67

8+
// This is grate-2. It spawns a child cage and tries to interpose the child's
9+
// geteuid syscall.
710
int main(int argc, char *argv[]) {
8-
printf("[Cage|interpose-register] In cage %d, about to register handler for geteuid\n", getpid());
9-
int ret_reg = register_handler(2, 107, 1, 0);
10-
if (ret_reg != 0) {
11-
fprintf(stderr, "[Cage|interpose-register] Failed to register handler for cage %d in "
12-
"grate %d with fn ptr addr: %llu, ret: %d\n",
13-
2, 1, 0ULL, ret_reg);
14-
assert(0);
15-
}
16-
int ret = geteuid();
17-
if (ret != 10) {
18-
fprintf(stderr, "[Cage|interpose-register] FAIL: expected 10, got %d\n", ret);
19-
assert(0);
20-
}
21-
printf("[Cage|interpose-register] PASS: geteuid ret = %d\n", ret);
22-
return 0;
11+
int grateid = getpid();
12+
13+
int pid = fork();
14+
15+
if (pid < 0) {
16+
exit(1);
17+
} else if (pid == 0) {
18+
int cageid = getpid();
19+
// This grateid has it's register_handler interposed. This call
20+
// should go to the grate-1.
21+
printf("[cage] registering 107. grateid: %d cageid: %d\n",
22+
grateid, cageid);
23+
register_handler(cageid, 107, grateid, 0);
24+
25+
int ret = geteuid();
26+
if (ret != 10) {
27+
assert(0);
28+
}
29+
} else {
30+
wait(NULL);
31+
}
32+
33+
return 0;
2334
}

tests/grate-tests/interposing-calls/interpose-register_grate.c

Lines changed: 118 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -9,129 +9,130 @@
99

1010
// Dispatcher function
1111
int pass_fptr_to_wt(uint64_t fn_ptr_uint, uint64_t cageid, uint64_t arg1,
12-
uint64_t arg1cage, uint64_t arg2, uint64_t arg2cage,
13-
uint64_t arg3, uint64_t arg3cage, uint64_t arg4,
14-
uint64_t arg4cage, uint64_t arg5, uint64_t arg5cage,
15-
uint64_t arg6, uint64_t arg6cage) {
16-
if (fn_ptr_uint == 0) {
17-
fprintf(stderr, "[Grate|interpose-register] Invalid function ptr=%llu\n", fn_ptr_uint);
18-
assert(0);
19-
}
20-
21-
printf("[Grate|interpose-register] Handling function ptr: %llu from cage: %llu\n",
22-
fn_ptr_uint, cageid);
23-
24-
int (*fn)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
25-
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
26-
uint64_t, uint64_t, uint64_t) =
27-
(int (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
28-
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
29-
uint64_t, uint64_t, uint64_t))(uintptr_t)fn_ptr_uint;
30-
31-
32-
return fn(cageid, arg1, arg1cage, arg2, arg2cage,
33-
arg3, arg3cage, arg4, arg4cage,
34-
arg5, arg5cage, arg6, arg6cage);
12+
uint64_t arg1cage, uint64_t arg2, uint64_t arg2cage,
13+
uint64_t arg3, uint64_t arg3cage, uint64_t arg4,
14+
uint64_t arg4cage, uint64_t arg5, uint64_t arg5cage,
15+
uint64_t arg6, uint64_t arg6cage) {
16+
if (fn_ptr_uint == 0) {
17+
fprintf(
18+
stderr,
19+
"[Grate|interpose-register] Invalid function ptr=%llu\n",
20+
fn_ptr_uint);
21+
assert(0);
22+
}
23+
24+
printf("[Grate|interpose-register] Handling function ptr: %llu from "
25+
"cage: %llu\n",
26+
fn_ptr_uint, cageid);
27+
28+
int (*fn)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
29+
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
30+
uint64_t) =
31+
(int (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
32+
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
33+
uint64_t))(uintptr_t)fn_ptr_uint;
34+
35+
return fn(cageid, arg1, arg1cage, arg2, arg2cage, arg3, arg3cage, arg4,
36+
arg4cage, arg5, arg5cage, arg6, arg6cage);
3537
}
3638

37-
int geteuid_grate(uint64_t cageid,
38-
uint64_t arg1, uint64_t arg1cage,
39-
uint64_t arg2, uint64_t arg2cage,
40-
uint64_t arg3, uint64_t arg3cage,
41-
uint64_t arg4, uint64_t arg4cage,
42-
uint64_t arg5, uint64_t arg5cage,
43-
uint64_t arg6, uint64_t arg6cage) {
44-
printf("[Grate|interpose-register] In register_grate %d handler for cage: %llu\n",
45-
getpid(), cageid);
46-
return 10;
39+
int geteuid_grate(uint64_t cageid, uint64_t arg1, uint64_t arg1cage,
40+
uint64_t arg2, uint64_t arg2cage, uint64_t arg3,
41+
uint64_t arg3cage, uint64_t arg4, uint64_t arg4cage,
42+
uint64_t arg5, uint64_t arg5cage, uint64_t arg6,
43+
uint64_t arg6cage) {
44+
printf("[Grate|interpose-register] In register_grate %d handler for "
45+
"cage: %llu\n",
46+
getpid(), cageid);
47+
return 10;
4748
}
4849

49-
// We want to register a handler for geteuid (syscall num 107) in child cage, but also
50-
// monitor the register_handler behaviors, and the blow handler function
51-
// will redirect the register_handler call from cage to this grate, attach the function ptr
52-
// as the arg and then this grate will call the register_handler syscall to register
53-
// the handler in the target cage.
54-
int register_grate(uint64_t cageid,
55-
uint64_t arg1, uint64_t arg1cage,
56-
uint64_t arg2, uint64_t arg2cage,
57-
uint64_t arg3, uint64_t arg3cage,
58-
uint64_t arg4, uint64_t arg4cage,
59-
uint64_t arg5, uint64_t arg5cage,
60-
uint64_t arg6, uint64_t arg6cage) {
61-
printf("[Grate|interpose-register] In register_grate %d handler for cage: %llu\n",
62-
getpid(), cageid);
63-
int self_grate_id = getpid();
64-
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&geteuid_grate;
65-
printf("[Grate|geteuid] Registering geteuid handler for cage %llu in "
66-
"grate %d with fn ptr addr: %llu\n",
67-
cageid, self_grate_id, fn_ptr_addr);
68-
int ret = make_threei_call(
69-
1001, // syscallnum for register_handler
70-
0, // callname is not used in the trampoline, set to 0
71-
self_grate_id, // self_grate_id is used in the 3i
72-
arg1cage, // target_cageid is used in the 3i
73-
arg1, arg1cage,
74-
arg2, arg2cage,
75-
fn_ptr_addr, arg3cage,
76-
arg4, arg4cage,
77-
arg5, arg5cage,
78-
arg6, arg6cage,
79-
0 // we will handle the errno in this grate instead of translating it to -1 in the trampoline
80-
);
81-
return ret;
50+
// We interpose on a child grate's register_handler syscall.
51+
//
52+
// This implementation overrides the (fn_ptr_addr, grate-2) with
53+
// (&geteuid_grate, grate-1)
54+
int register_grate(uint64_t cageid, uint64_t arg1, uint64_t arg1cage,
55+
uint64_t arg2, uint64_t arg2cage, uint64_t arg3,
56+
uint64_t arg3cage, uint64_t arg4, uint64_t arg4cage,
57+
uint64_t arg5, uint64_t arg5cage, uint64_t arg6,
58+
uint64_t arg6cage) {
59+
printf("[Grate|interpose-register] In register_grate %d handler for "
60+
"cage: %llu\n",
61+
getpid(), cageid);
62+
63+
int self_grate_id = getpid();
64+
int target_cage = arg1;
65+
int syscall_num = arg1cage;
66+
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&geteuid_grate;
67+
68+
printf("[Grate|geteuid] Registering geteuid handler for cage %llu in "
69+
"grate %d with fn ptr addr: %llu\n",
70+
cageid, self_grate_id, fn_ptr_addr);
71+
72+
int ret = register_handler(target_cage, syscall_num, self_grate_id,
73+
fn_ptr_addr);
74+
75+
return ret;
8276
}
8377

8478
// Main function will always be same in all grates
8579
int main(int argc, char *argv[]) {
86-
// Should be at least two inputs (at least one grate file and one cage file)
87-
if (argc < 2) {
88-
fprintf(stderr, "Usage: %s <cage_file> <grate_file> <cage_file> [...]\n",
89-
argv[0]);
90-
assert(0);
91-
}
92-
93-
int grateid = getpid();
94-
95-
for (int i = 1; i < (argc < 3 ? argc : 3); i++) {
96-
pid_t pid = fork();
97-
if (pid < 0) {
98-
perror("fork failed");
99-
assert(0);
100-
} else if (pid == 0) {
101-
// Next one is cage, only set the register_handler when next one is cage
102-
int cageid = getpid();
103-
// Set the register_handler (syscallnum=1001) of this cage to call this grate
104-
// function register_grate
105-
// Syntax of register_handler:
106-
// <targetcage, targetcallnum, this_grate_id, fn_ptr_u64)>
107-
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&register_grate;
108-
printf("[Grate|interpose-register] Registering register_handler for cage %d in "
109-
"grate %d with fn ptr addr: %llu\n",
110-
cageid, grateid, fn_ptr_addr);
111-
int ret = register_handler(cageid, 1001, grateid, fn_ptr_addr);
112-
if (ret != 0) {
113-
fprintf(stderr, "[Grate|interpose-register] Failed to register handler for cage %d in "
114-
"grate %d with fn ptr addr: %llu, ret: %d\n",
115-
cageid, grateid, fn_ptr_addr, ret);
116-
assert(0);
117-
}
118-
119-
if (execv(argv[i], &argv[i]) == -1) {
120-
perror("execv failed");
121-
assert(0);
122-
}
123-
}
124-
}
125-
126-
int status;
127-
int failed = 0;
128-
while (wait(&status) > 0) {
129-
if (status != 0) {
130-
fprintf(stderr, "[Grate|interpose-register] FAIL: child exited with status %d\n", status);
131-
assert(0);
132-
}
133-
}
134-
135-
printf("[Grate|interpose-register] PASS\n");
136-
return 0;
80+
// Should be at least two inputs (at least one grate file and one cage
81+
// file)
82+
if (argc < 2) {
83+
fprintf(
84+
stderr,
85+
"Usage: %s <cage_file> <grate_file> <cage_file> [...]\n",
86+
argv[0]);
87+
assert(0);
88+
}
89+
90+
int grateid = getpid();
91+
92+
pid_t pid = fork();
93+
if (pid < 0) {
94+
perror("fork failed");
95+
assert(0);
96+
} else if (pid == 0) {
97+
int cageid = getpid();
98+
// Set the register_handler (syscallnum=1001) of this cage to
99+
// call this grate function register_grate Syntax of
100+
// register_handler: <targetcage, targetcallnum, this_grate_id,
101+
// fn_ptr_u64)>
102+
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&register_grate;
103+
printf("[Grate|interpose-register] Registering "
104+
"register_handler for cage %d in "
105+
"grate %d with fn ptr addr: %llu\n",
106+
cageid, grateid, fn_ptr_addr);
107+
108+
int ret = register_handler(cageid, 1001, grateid, fn_ptr_addr);
109+
if (ret != 0) {
110+
fprintf(stderr,
111+
"[Grate|interpose-register] Failed to register "
112+
"handler for cage %d in "
113+
"grate %d with fn ptr addr: %llu, ret: %d\n",
114+
cageid, grateid, fn_ptr_addr, ret);
115+
assert(0);
116+
}
117+
118+
if (execv(argv[1], &argv[1]) == -1) {
119+
perror("execv failed");
120+
assert(0);
121+
}
122+
}
123+
124+
int status;
125+
int failed = 0;
126+
while (wait(&status) > 0) {
127+
if (status != 0) {
128+
fprintf(stderr,
129+
"[Grate|interpose-register] FAIL: child exited "
130+
"with status %d\n",
131+
status);
132+
assert(0);
133+
}
134+
}
135+
136+
printf("[Grate|interpose-register] PASS\n");
137+
return 0;
137138
}

0 commit comments

Comments
 (0)