Skip to content

Commit 1577145

Browse files
Update README.md and geteuid_grate.c comments.
1 parent 2ee4687 commit 1577145

File tree

6 files changed

+121
-110
lines changed

6 files changed

+121
-110
lines changed

README.md

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Grates provide custom syscall wrappers for Lind cages. Each example grate here d
66

77
For more details on Lind and grates, refer to the official [documentation.](https://lind-project.github.io/lind-wasm/)
88

9-
## Repository Structure
9+
## Repository Structure
1010

1111
Each directory under `examples/` contains a standalone grate implementation.
1212

@@ -15,19 +15,19 @@ For a grate written in `C`, the typical structure for an individual grate is:
1515
```
1616
examples/<name>-grate
1717
├── src/ // .c and .h source files.
18-
├── tests/ // Tests for this grate, run as child cages.
18+
├── tests/ // Tests for this grate.
1919
├── build.conf // Configuration file to describe additional build flags, `--max-memory` for wasm, and entry point for the grate.
20-
├── compile_grate.sh // Compilation script that places the final *.wasm files in the `output/` folder.
21-
└── README.md
20+
├── compile_grate.sh // Compile script to generate *.wasm and *.cwasm binaries
21+
└── README.md
2222
```
2323

2424
## Writing a Grate
2525

26-
By default, syscalls called by a grate are redirected to `rawposix`. With grates, specific specific syscalls from a child cage can be redirected to custom handlers defined in the grate.
26+
By default, syscalls invoked by a cage are forwarded to `rawposix`. A grate allows selected syscalls from a child cage to be intercepted and handled by custom functions.
2727

28-
Following the example in `examples/geteuid-grate`:
28+
Using the example in `examples/geteuid-grate` to illustrate this process:
2929

30-
**Registering Syscalls:**
30+
**Registering Syscall Handlers:**
3131

3232
First, define a custom implementation of the syscall.
3333

@@ -40,25 +40,27 @@ int geteuid_grate(uint64_t cageid) {
4040
Next, register this function as the handler for `geteuid` using the `register_handler` function
4141
4242
```c
43+
// Fork a child process
4344
pid_t pid = fork();
4445
if (pid == 0) {
4546
int cageid = getpid();
4647
48+
// Register our custom handler
4749
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t_) &geteuid_grate;
4850
register_handler(cageid, 107, 1, grateid, fn_ptr_addr);
4951
50-
// Typically, the cage executable is provided as argv[1]
52+
// Run the cage (provided as argv[1])
5153
execv(argv[1], &argv[1]);
5254
}
5355
```
5456

5557
**Dispatch Handling:**
5658

57-
Each grate must define a dispatcher function named `pass_fptr_to_wt` which serves as the entry point for all interecepted syscalls in that grate.
59+
Each grate must define a dispatcher function named `pass_fptr_to_wt` which serves as the entry point for all intercepted syscalls in that grate.
5860

59-
The dispatcher is invoked using:
60-
- Function pointer registered for this syscall,
61-
- Calling cage id,
61+
The dispatcher is invoked with:
62+
- Function pointer registered for this syscall,
63+
- Calling cage id,
6264
- Syscall arguments (and their associated cage IDs)
6365

6466
```c
@@ -72,27 +74,37 @@ int pass_fptr_to_wt(uint64_t fn_ptr_uint, uint64_t cageid, uint64_t arg1,
7274
return -1;
7375
}
7476

75-
// Extract the function based on the function pointer that was passed.
76-
// This is the same address that was passed to the register_handler function.
77+
// Extract the function based on the function pointer that was passed.
78+
// This is the same address that was passed to the register_handler function.
7779
int (*fn)(uint64_t) = (int (*)(uint64_t))(uintptr_t)fn_ptr_uint;
7880

7981
// In this case, we only pass down the cageid as the argument for the geteuid syscall.
8082
return fn(cageid);
8183
}
8284
```
8385
86+
**Process Coordination:**
87+
88+
Each grate must invoke `execv(argv[1], &argv[1])` exactly once, after registering its syscall handlers.
89+
90+
This design avoids centralized process coordination. Once `execv` is called, further process creation or handler registrations are the responsibility of the executed cage.
91+
92+
This also allows multiple grates to be interposed. For example:
93+
94+
```lind_run geteuid_grate.wasm getuid_grate.wasm example.wasm```
95+
96+
8497
## Compiling a Grate
8598
86-
Grates are compiled similarly to regular Lind programs, with the additional requirement that the `pass_fptr_to_wt` function must be an export of the WASM module.
99+
Grates are compiled similarly to standard Lind programs, with the additional requirement that the WASM module exports the `pass_fptr_to_wt` function.
87100
88101
Example of a compile script: [`examples/geteuid-grate/compile_grate.sh`](./examples/geteuid-grate/compile_grate.sh)
89102
90103
## Running a Grate
91104
92-
Grates are run like regular lind programs, using the `lind_run` script.
93-
94-
By convention, a grate expects the child cage's command-line arguments to begin at `argv[1]`. The grate must execute the child cage using `execv(argv[1], &argv[1]`, thereby forwarding all remaining arguments to the cage unchanged.
105+
Grates are executed like standard Lind programs, that expect cage binaries to be present at `argv[1]`.
95106
96107
Example usage:
97108
98-
`lind_run geteuid_grate.wasm geteuid.wasm`
109+
```lind_run geteuid_grate.wasm example.wasm```
110+

examples/geteuid-grate/build.conf

Whitespace-only changes.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include <errno.h>
2+
#include <lind_syscall.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <sys/types.h>
6+
#include <sys/wait.h>
7+
#include <unistd.h>
8+
9+
// Dispatcher function
10+
int pass_fptr_to_wt(uint64_t fn_ptr_uint, uint64_t cageid, uint64_t arg1,
11+
uint64_t arg1cage, uint64_t arg2, uint64_t arg2cage,
12+
uint64_t arg3, uint64_t arg3cage, uint64_t arg4,
13+
uint64_t arg4cage, uint64_t arg5, uint64_t arg5cage,
14+
uint64_t arg6, uint64_t arg6cage) {
15+
if (fn_ptr_uint == 0) {
16+
fprintf(stderr, "[Grate|geteuid] Invalid function ptr\n");
17+
return -1;
18+
}
19+
20+
printf("[Grate|geteuid] Handling function ptr: %llu from cage: %llu\n",
21+
fn_ptr_uint, cageid);
22+
23+
int (*fn)(uint64_t) = (int (*)(uint64_t))(uintptr_t)fn_ptr_uint;
24+
25+
return fn(cageid);
26+
}
27+
28+
// Function ptr and signatures of this grate
29+
int geteuid_grate(uint64_t);
30+
31+
int geteuid_grate(uint64_t cageid) {
32+
printf("[Grate|geteuid] In geteuid_grate %d handler for cage: %llu\n",
33+
getpid(), cageid);
34+
return 10;
35+
}
36+
37+
// Main function will always be same in all grates
38+
int main(int argc, char *argv[]) {
39+
// Should be at least two inputs (at least one grate file and one cage file)
40+
if (argc < 2) {
41+
fprintf(stderr, "Usage: %s <cage_file>\n", argv[0]);
42+
exit(EXIT_FAILURE);
43+
}
44+
45+
int grateid = getpid();
46+
47+
// Because we assume that all cages are unaware of the existence of grate,
48+
// cages will not handle the logic of `exec`ing grate.
49+
// Instead, a grate instance is responsible for mananging this.
50+
//
51+
// It forks and execs exactly once: To execute the child binary provided
52+
// as argv[1], passing argv[1..] as that program's command-line arguments.
53+
// Any further process management is handled by this executed program, not
54+
// by the original grate.
55+
56+
pid_t pid = fork();
57+
if (pid < 0) {
58+
perror("fork failed");
59+
exit(EXIT_FAILURE);
60+
} else if (pid == 0) {
61+
int cageid = getpid();
62+
// Set the geteuid (syscallnum=107) of this cage to call this grate
63+
// function geteuid_grate (func index=0)
64+
// Syntax of register_handler:
65+
// register_handler(
66+
// int64_t targetcage, - Cage ID to be intercepted
67+
// uint64_t targetcallnum, - Syscall number to be intercepted
68+
// uint64_t handlefunc_flag, - 0 for deregister non-0 for register
69+
// uint64_t this_grate_id, - Grate ID to redirect call to
70+
// uint64_t optional_arg - Handler function pointer if registering
71+
// )
72+
uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&geteuid_grate;
73+
printf("[Grate|geteuid] Registering geteuid handler for cage %d in "
74+
"grate %d with fn ptr addr: %llu\n",
75+
cageid, grateid, fn_ptr_addr);
76+
int ret = register_handler(cageid, 107, 1, grateid, fn_ptr_addr);
77+
78+
if (execv(argv[1], &argv[1]) == -1) {
79+
perror("execv failed");
80+
exit(EXIT_FAILURE);
81+
}
82+
}
83+
84+
int status;
85+
while (wait(&status) > 0) {
86+
printf("[Grate|geteuid] terminated, status: %d\n", status);
87+
}
88+
89+
return 0;
90+
}

tests/grate-tests/geteuid_grate.c

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)