Skip to content

docs: add Lind-Wasm threat model#1295

Open
rennergade wants to merge 2 commits into
mainfrom
docs/threat-model
Open

docs: add Lind-Wasm threat model#1295
rennergade wants to merge 2 commits into
mainfrom
docs/threat-model

Conversation

@rennergade

Copy link
Copy Markdown
Contributor

Summary

Adds a threat model document for Lind-Wasm to the internal docs, plus the actor-topology figure it references.

  • docs/internal/threat-model.md — actors, trust relationships (TCB vs. trusted policy surface), attacker model, the attacker×victim matrix with per-cell reasoning, security properties (P1–P6), and out-of-scope items.
  • docs/images/doc-images/actor-topology.png — Figure 1, the actor topology.
  • Registered the page under Internal Documentation in mkdocs.yml nav so it's linked in the published site.

Notes

  • Image path follows the existing docs/images/doc-images/ convention; the relative link resolves from docs/internal/.
  • Content was drafted with assistance and is intended as a starting point for discussion/review — feedback on the trust model and matrix reasoning welcome.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

End-to-End Test Report

Test Preview
grate harness

Grate Test Report

MetricValue
Total15
Success15
Failures0
Compile Failures0
Runtime Failures0
Timeout Failures0
Missing Pair Failures0

Cases

TestStatusError TypeOutput
concurrent-request/geteuid_grate.cSuccess
STDOUT:
[Grate|geteuid] Registering geteuid handler for cage 2 in grate 1 with fn ptr addr: 3
[Cage | geteuid] PASS: 1000000 calls returned 10
[Grate|geteuid] PASS

STDERR:

concurrent-request/race-test_grate.cSuccess
STDOUT:
pass

STDERR:

concurrent-request/thread_race_grate.cSuccess
STDOUT:
[thread_race] Registering handler for cage 2 in grate 1 with fn ptr addr: 3
[thread_race] PASS: 20 threads x 100000 calls returned 10
[thread_race] PASS

STDERR:

copy-data-between-cages/cp-stncpy_grate.cSuccess
STDOUT:
[cage] pathname addr=0xfffb6ff9
[cage] pathname='random'
[Grate|open] intercepts open call: thiscage=1, arg1cage=2
[Grate|open] copied pathname: random
[cage] fd=10

STDERR:

copy-data-between-cages/cpdata_grate.cSuccess
STDOUT:
[Grate|open] intercepts open call: thiscage=1, arg1cage=2
[Grate|open] copied pathname: random
[cage] fd=10

STDERR:

interposing-calls/fork-with-newret_grate.cSuccess
STDOUT:
[Grate|interpose-fork] Registering fork handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|interpose-fork] Handling function ptr: 3 from cage: 1
[Grate|interpose-fork] In fork_grate 1 handler for cage: 1
[Cage] Forked process with PID: 10
[Grate|interpose-fork] PASS

STDERR:

interposing-calls/interpose-exec_grate.cSuccess
STDOUT:
[Grate|interpose-exec] Registering exec handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|interpose-exec] Handling function ptr: 3 from cage: 1
[Grate|interpose-exec] In exec_grate 1 handler for cage: 1
[Grate|interpose-exec] Handling function ptr: 3 from cage: 1
[Grate|interpose-exec] In exec_grate 1 handler for cage: 1
Exec successful, argv[1]: --execd
[Grate|interpose-exec] PASS

STDERR:

interposing-calls/interpose-exit_grate.cSuccess
STDOUT:
[Grate|interpose-exit] Registering exit handler for cage 2 in grate 1 with fn ptr addr: 3
Exiting...

[Grate|interpose-exit] PASS

STDERR:

interposing-calls/interpose-fork_grate.cSuccess
STDOUT:
[Grate|interpose-fork] Registering fork handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|interpose-fork] Handling function ptr: 3 from cage: 1
[Grate|interpose-fork] In fork_grate 1 handler for cage: 1
[Grate|interpose-fork] PASS

STDERR:

interposing-calls/interpose-mmap_grate.cSuccess
STDOUT:
[Grate|interpose-mmap] Registering mmap handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|interpose-mmap] Handling function ptr: 3 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 3 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 3 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 3 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 3 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
mmap test: PASS
[Grate|interpose-mmap] PASS

STDERR:

interposing-calls/interpose-register_grate.cSuccess
STDOUT:
[Grate|interpose-register] Registering register_handler for cage 2 in grate 1 with fn ptr addr: 4
[cage] registering 107. grateid: 2 cageid: 3
[Grate|interpose-register] Handling function ptr: 4 from cage: 1
[Grate|interpose-register] In register_grate 1 handler for cage: 1
[Grate|geteuid] Registering geteuid handler for cage 1 in grate 1 with fn ptr addr: 3
[Grate|interpose-register] Handling function ptr: 3 from cage: 1
[Grate|interpose-register] In register_grate 1 handler for cage: 1
[Grate|interpose-register] PASS

STDERR:

multi-register_grate.cSuccess
STDOUT:
[Grate|multi-register_grate] Registering geteuid handler for cage 2 in grate 1 with fn ptr addr: 4
[Grate|multi-register_grate] Registering getuid handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|multi-register_grate] Handling function ptr: 4 from cage: 1
[Grate|multi-register_grate] In multi-register_grate 1 handler for cage: 1
[Grate|multi-register_grate] Handling function ptr: 3 from cage: 1
[Grate|multi-register_grate] In multi-register_grate 1 handler for cage: 1
[Cage | multi-register] PASS: geteuid=10, getuid=20
[Grate|multi-register] PASS

STDERR:

simple-tests/copy-handler-table_grate.cSuccess
STDOUT:
[Grate|copy-handler-table] Registering geteuid handler for cage 2 in grate 1
[Grate|copy-handler-table] geteuid handler invoked for cage 1
[Grate|copy-handler-table] geteuid handler invoked for cage 1
[Cage|copy-handler-table] PASS: child inherited handler, then overwrite changed geteuid to 0
[Cage|copy-handler-table] PASS: parent=123 child_exit=0
[Grate|copy-handler-table] PASS

STDERR:

simple-tests/diff-cage-args_grate.cSuccess
STDOUT:
[Grate|diff-cage-args] Handling function ptr: 3 from cage: 1
[Grate|diff-cage-args] In open_grate 1 handler for cage: 1
Hello world. FD=-1
[Grate|diff-cage-args] Handling function ptr: 4 from cage: 1
Goodbye world! ret=4321 buf=helloworld
[Grate|diff-cage-args] PASS

STDERR:

simple-tests/geteuid_grate.cSuccess
STDOUT:
[Grate|geteuid] Registering geteuid handler for cage 2 in grate 1 with fn ptr addr: 3
[Grate|geteuid] Handling function ptr: 3 from cage: 1
[Grate|geteuid] In geteuid_grate 1 handler for cage: 1
[Cage | geteuid] PASS: geteuid ret = 10
[Grate|geteuid] PASS

STDERR:

static harness

Test Report

Deterministic Tests

Summary

MetricCount
Total Test Cases3
Number of Successes3
Number of Failures0
Number of Compilation Failure Native0
Number of Runtime Failure Native0
Number of Segmentation Fault Native0
Number of Timeout During Native0
Number of Lind Wasm Compile Failure0
Number of Lind Wasm Runtime Failure0
Number of Lind Wasm Segmentation Failure0
Number of Timeout During Lind Wasm run0
Number of Unknown Failure0
Number of C Compiler and Wasm Output mismatch0
Number of Fail Test: Native Succeeded (Should Fail)0
Number of Fail Test: Wasm Succeeded (Should Fail)0
Number of Fail Test: Both Native and Wasm Succeeded (Should Fail)0
Number of Fail Test: Native Compilation Failure (Should Succeed)0
Number of Fail Test: Wasm Compilation Failure (Should Succeed)0

Test Results by Category

Test CaseStatusError TypeNative TimeWasm TimeOutput
Static Tests
fork_simple.cSuccessNone0.061151s4.131615s
Success
thread.cSuccessNone0.053396s4.195499s
Success
tls_test.cSuccessNone0.060952s4.243295s
Success

Fail Tests

Summary

MetricCount
Total Test Cases0
Number of Successes0
Number of Failures0
Number of Compilation Failure Native0
Number of Runtime Failure Native0
Number of Segmentation Fault Native0
Number of Timeout During Native0
Number of Lind Wasm Compile Failure0
Number of Lind Wasm Runtime Failure0
Number of Lind Wasm Segmentation Failure0
Number of Timeout During Lind Wasm run0
Number of Unknown Failure0
Number of C Compiler and Wasm Output mismatch0
Number of Fail Test: Native Succeeded (Should Fail)0
Number of Fail Test: Wasm Succeeded (Should Fail)0
Number of Fail Test: Both Native and Wasm Succeeded (Should Fail)0
Number of Fail Test: Native Compilation Failure (Should Succeed)0
Number of Fail Test: Wasm Compilation Failure (Should Succeed)0
wasm harness

Test Report

Deterministic Tests

Summary

MetricCount
Total Test Cases234
Number of Successes234
Number of Failures0
Number of Compilation Failure Native0
Number of Runtime Failure Native0
Number of Segmentation Fault Native0
Number of Timeout During Native0
Number of Lind Wasm Compile Failure0
Number of Lind Wasm Runtime Failure0
Number of Lind Wasm Segmentation Failure0
Number of Timeout During Lind Wasm run0
Number of Unknown Failure0
Number of C Compiler and Wasm Output mismatch0
Number of Fail Test: Native Succeeded (Should Fail)0
Number of Fail Test: Wasm Succeeded (Should Fail)0
Number of Fail Test: Both Native and Wasm Succeeded (Should Fail)0
Number of Fail Test: Native Compilation Failure (Should Succeed)0
Number of Fail Test: Wasm Compilation Failure (Should Succeed)0

Test Results by Category

Test CaseStatusError TypeNative TimeWasm TimeOutput
Dylink Tests
basic.cSuccessNone0.054445s0.132514s
Success
dlopen_fork.cSuccessNone0.057149s0.159077s
Success
dlopen_thread.cSuccessNone0.058334s0.160791s
Success
double_fork_dlopen.cSuccessNone0.062196s0.211068s
Success
fork_dlopen.cSuccessNone0.057986s0.160186s
Success
longjmp_dlopen.cSuccessNone0.056085s0.148526s
Success
rdynamic_main.cSuccessNone0.057534s0.148792s
Success
File Tests
chartests.cSuccessNone0.055870s0.163694s
Success
chdir_getcwd.cSuccessNone0.054431s0.128191s
Success
chmod.cSuccessNone0.061568s0.139565s
Success
clock_gettime_highlevel.cSuccessNone0.125668s0.174288s
Success
clock_gettime_simple.cSuccessNone0.048901s0.119562s
Success
cloexec.cSuccessNone0.058841s0.152342s
Success
close.cSuccessNone0.066656s0.149609s
Success
copy_file_range.cSuccessNone0.060459s0.150492s
Success
creat_access.cSuccessNone0.059540s0.130083s
Success
doubleclose.cSuccessNone0.052889s0.114013s
Success
dup.cSuccessNone0.051486s0.123295s
Success
dup2.cSuccessNone0.056457s0.130622s
Success
dup3.cSuccessNone0.055099s0.125571s
Success
dupwrite.cSuccessNone0.062109s0.131087s
Success
etc_conf.cSuccessNone0.054197s0.130882s
Success
faccessat.cSuccessNone0.053440s0.128217s
Success
fchdir.cSuccessNone0.060497s0.145143s
Success
fchmod.cSuccessNone0.061875s0.147738s
Success
fchmodat.cSuccessNone0.053813s0.124759s
Success
fcntl.cSuccessNone0.056601s0.147059s
Success
fcntl_dupfd.cSuccessNone0.051739s0.122915s
Success
fdatasync.cSuccessNone0.055352s0.128335s
Success
filetest.cSuccessNone0.057936s0.126062s
Success
filetest1000.cSuccessNone0.067366s0.135662s
Success
flock.cSuccessNone0.066188s0.186257s
Success
fstat.cSuccessNone0.061817s0.146957s
Success
fstatfs.cSuccessNone0.053639s0.119894s
Success
fsync.cSuccessNone0.058248s0.127251s
Success
ftruncate.cSuccessNone0.061410s0.222424s
Success
getcwd.cSuccessNone0.053722s0.122380s
Success
getcwd_null.cSuccessNone0.060212s0.134009s
Success
getpgid.cSuccessNone0.050903s0.112693s
Success
getrandom.cSuccessNone0.058733s0.147013s
Success
ioctl.cSuccessNone0.059832s0.133120s
Success
link.cSuccessNone0.062318s0.173422s
Success
locale_test.cSuccessNone0.072753s0.332974s
Success
lseek.cSuccessNone0.062790s0.203432s
Success
lstat.cSuccessNone0.065423s0.147810s
Success
mkdir_rmdir.cSuccessNone0.058837s0.134751s
Success
mkfifo_test.cSuccessNone0.065687s0.182640s
Success
mknod.cSuccessNone0.057848s0.139146s
Success
nocancel_io.cSuccessNone0.063837s0.153661s
Success
open.cSuccessNone0.051681s0.115989s
Success
openat.cSuccessNone0.053355s0.127290s
Success
path_conversion_safety.cSuccessNone0.063297s0.150209s
Success
ppoll.cSuccessNone0.063466s0.139791s
Success
pread_pwrite.cSuccessNone0.055533s0.137627s
Success
preadv_pwritev.cSuccessNone0.060431s0.143775s
Success
printf.cSuccessNone0.050754s0.110848s
Success
prlimit64.cSuccessNone0.050249s0.115556s
Success
read.cSuccessNone0.058828s0.138482s
Success
readbytes.cSuccessNone0.054621s0.120782s
Success
readdir_basic.cSuccessNone0.062760s0.160327s
Success
readlink.cSuccessNone0.057493s0.135384s
Success
readlinkat.cSuccessNone0.061006s0.140454s
Success
readv_writev_test.cSuccessNone0.058854s0.143603s
Success
rename.cSuccessNone0.061859s0.132813s
Success
renameat.cSuccessNone0.060755s0.147559s
Success
sc-writev.cSuccessNone0.058759s0.125215s
Success
stat.cSuccessNone0.059776s0.139392s
Success
statfs.cSuccessNone0.051649s0.119596s
Success
symlink.cSuccessNone0.061397s0.160290s
Success
sync_file_range.cSuccessNone0.056078s0.124241s
Success
timespec_time_t_compat.cSuccessNone0.054975s0.123888s
Success
trailing_slash.cSuccessNone0.058950s0.132263s
Success
truncate.cSuccessNone0.059903s0.149588s
Success
unlink.cSuccessNone0.061323s0.166876s
Success
unlinkat.cSuccessNone0.060406s0.145479s
Success
utimensat.cSuccessNone0.058472s0.147607s
Success
write.cSuccessNone0.051815s0.112194s
Success
writeloop.cSuccessNone0.061283s0.137754s
Success
writepartial.cSuccessNone0.058207s0.121016s
Success
writev.cSuccessNone0.060379s0.132619s
Success
Math Tests
math_link_smoke.cSuccessNone0.062932s0.120043s
Success
math_tests.cSuccessNone0.066609s0.151677s
Success
printf_float.cSuccessNone0.067042s0.143677s
Success
Memory Tests
brk.cSuccessNone0.057062s0.122568s
Success
fork_large_memory.cSuccessNone0.091441s0.480368s
Success
malloc.cSuccessNone0.053039s0.114801s
Success
malloc_large.cSuccessNone0.054372s0.114969s
Success
memcpy.cSuccessNone0.056336s0.119042s
Success
memory_error_test.cSuccessNone0.060859s0.151032s
Success
mmap.cSuccessNone0.051416s0.117405s
Success
mmap_address_truncation.cSuccessNone0.051938s0.119365s
Success
mmap_aligned.cSuccessNone0.052437s0.129737s
Success
mmap_complicated.cSuccessNone0.061185s0.159863s
Success
mmap_file.cSuccessNone0.058962s0.130092s
Success
mmap_shared.cSuccessNone0.054660s0.145530s
Success
mmaptest.cSuccessNone0.055640s0.121113s
Success
mprotect.cSuccessNone0.052834s0.117543s
Success
mprotect_boundary.cSuccessNone0.052477s0.126817s
Success
mprotect_end_region.cSuccessNone0.049078s0.118757s
Success
mprotect_middle_region.cSuccessNone0.049577s0.119174s
Success
mprotect_multiple_times.cSuccessNone0.052044s0.126666s
Success
mprotect_same_value.cSuccessNone0.051945s0.121977s
Success
mprotect_spanning_regions.cSuccessNone0.050312s0.139106s
Success
munmap_adjacent_shm.cSuccessNone0.055005s0.135646s
Success
sbrk.cSuccessNone0.055036s0.119684s
Success
segfault.cSuccessNone0.061786s0.161837s
Success
shm.cSuccessNone0.060593s0.162134s
Success
shmtest.cSuccessNone0.050697s0.120260s
Success
thread_malloc_sequential.cSuccessNone0.061587s0.213118s
Success
vtable.cSuccessNone0.062289s0.136680s
Success
Networking Tests
accept4.cSuccessNone0.063234s0.154963s
Success
dns_resolve_test.cSuccessNone0.073801s0.132712s
Success
dnstest.cSuccessNone0.061983s0.135802s
Success
epoll_badfd.cSuccessNone0.058419s0.113484s
Success
epoll_edge_triggered.cSuccessNone0.220547s0.407571s
Success
epollcreate1.cSuccessNone0.059007s0.145033s
Success
error_handling_net.cSuccessNone0.064083s0.205340s
Success
getaddrinfo_test.cSuccessNone0.063579s0.177322s
Success
getaddrinfo_unspec.cSuccessNone0.061838s0.136873s
Success
gethostname.cSuccessNone0.055096s0.124855s
Success
getifaddrs.cSuccessNone0.066545s0.139191s
Success
getsockname.cSuccessNone0.063815s0.148251s
Success
getsockopt.cSuccessNone0.062196s0.171748s
Success
ipv6_basic.cSuccessNone0.070819s0.178667s
Success
makepipe.cSuccessNone0.057143s0.120777s
Success
nonblocking_eagain.cSuccessNone0.064542s0.175365s
Success
pipe.cSuccessNone0.059583s0.140538s
Success
pipe2.cSuccessNone0.062190s0.134822s
Success
pipeinput.cSuccessNone0.061808s0.182030s
Success
pipeinput2.cSuccessNone0.068264s0.198253s
Success
pipeonestring.cSuccessNone0.061601s0.165829s
Success
pipepong.cSuccessNone0.061400s0.179587s
Success
pipewrite.cSuccessNone0.054783s0.138760s
Success
poll.cSuccessNone0.058218s0.132094s
Success
recvfrom-sendto.cSuccessNone0.061752s0.143701s
Success
sendmsg_recvmsg_test.cSuccessNone0.065613s0.159263s
Success
serverclient.cSuccessNone0.062543s0.148289s
Success
shutdown.cSuccessNone0.065176s0.153849s
Success
shutdown_fork.cSuccessNone0.059384s0.156137s
Success
simple-select.cSuccessNone0.065606s0.177744s
Success
simple_epoll.cSuccessNone0.059923s0.132287s
Success
socket.cSuccessNone0.070164s0.140263s
Success
socket_cloexec.cSuccessNone0.057561s0.122987s
Success
socket_options_advanced.cSuccessNone0.067104s0.198474s
Success
socketepoll.cSuccessNone0.054983s0.130364s
Success
socketpair.cSuccessNone0.057864s0.156374s
Success
socketselect.cSuccessNone0.059217s0.141317s
Success
udp_send_recv.cSuccessNone0.169791s0.304021s
Success
uds-getsockname.cSuccessNone0.061287s0.135648s
Success
uds-nb-select.cSuccessNone2.069502s2.231650s
Success
uds-serverclient.cSuccessNone0.067374s0.179531s
Success
uds-socketselect.cSuccessNone0.061085s0.144158s
Success
uds_listen_poll.cSuccessNone1.068722s1.194429s
Success
writev_socket.cSuccessNone0.064722s0.168105s
Success
Process Tests
barrier_test.cSuccessNone0.057455s0.148849s
Success
chain_thread.cSuccessNone1.056282s1.154055s
Success
ctor_syscall_test.cSuccessNone0.046796s0.111976s
Success
cxa_atexit_test.cSuccessNone0.055674s0.123828s
Success
exec_non_utf8.cSuccessNone0.058041s0.127397s
Success
execve_shebang.cSuccessNone0.057603s0.124999s
Success
exit.cSuccessNone0.054369s0.115930s
Success
exit_failure.cSuccessNone0.058923s0.145133s
Success
exit_group_thread.cSuccessNone0.060753s0.166632s
Success
exit_status_first_wins.cSuccessNone0.062034s0.173870s
Success
flockfile_test.cSuccessNone0.057730s0.156223s
Success
fork2malloc.cSuccessNone0.061624s0.156992s
Success
fork_select.cSuccessNone0.058081s0.159626s
Success
fork_simple.cSuccessNone0.055117s0.141585s
Success
fork_syscall.cSuccessNone0.061352s0.639282s
Success
fork_tls_ctype.cSuccessNone0.058201s0.166896s
Success
forkandopen.cSuccessNone0.056871s0.156573s
Success
forkdup.cSuccessNone0.064490s0.160689s
Success
forkexecuid.cSuccessNone0.056009s0.170909s
Success
forkexecv-arg.cSuccessNone0.055598s0.166740s
Success
forkexecv.cSuccessNone0.053609s0.157372s
Success
forkfiles.cSuccessNone0.056030s0.152330s
Success
forkmalloc.cSuccessNone0.060076s0.149705s
Success
forknodup.cSuccessNone0.056931s0.155945s
Success
function-ptr.cSuccessNone0.054108s0.117306s
Success
getegid_syscall.cSuccessNone0.058595s0.502633s
Success
getgid_syscall.cSuccessNone0.058127s0.511612s
Success
getpid.cSuccessNone0.049281s0.107859s
Success
getpid_syscall.cSuccessNone0.060778s0.511299s
Success
getppid.cSuccessNone0.060191s0.143869s
Success
getppid_syscall.cSuccessNone0.061421s0.428959s
Success
getuid.cSuccessNone0.058247s0.123199s
Success
getuid_syscall.cSuccessNone0.057015s0.266913s
Success
hello-arg.cSuccessNone0.050456s0.121397s
Success
hello.cSuccessNone0.050669s0.112806s
Success
longjmp.cSuccessNone0.049107s0.118803s
Success
mutex.cSuccessNone2.058382s2.140208s
Success
printf_deadlock_smoke.cSuccessNone0.067514s0.179883s
Success
printf_thread_test.cSuccessNone0.056240s0.157999s
Success
sem_forks.cSuccessNone0.058483s0.189329s
Success
setjmp_edge.cSuccessNone0.053183s0.191329s
Success
setsid.cSuccessNone0.049618s0.113885s
Success
template.cSuccessNone0.055531s0.197902s
Success
test_crossmodule_longjmp.cSuccessNone0.059566s0.157258s
Success
test_exec_nofork.cSuccessNone0.053447s0.150476s
Success
test_unlink_open_file.cSuccessNone0.053226s0.109710s
Success
thread-guard.cSuccessNone0.056534s0.145277s
Success
thread-test.cSuccessNone0.053128s0.136374s
Success
thread.cSuccessNone0.052638s0.128683s
Success
thread_cageid_race.cSuccessNone0.053865s0.304615s
Success
tls_test.cSuccessNone0.056993s0.177004s
Success
uname.cSuccessNone0.051981s0.113351s
Success
wait.cSuccessNone0.053176s0.166302s
Success
waitpid_anychild.cSuccessNone0.057573s0.147858s
Success
waitpid_syscall.cSuccessNone1.057432s1.250974s
Success
waitpid_wnohang.cSuccessNone0.058455s0.157988s
Success
Signal Tests
alarm.cSuccessNone7.057827s7.158895s
Success
eintr_fork_signal.cSuccessNone1.058449s1.167917s
Success
kill.cSuccessNone1.059385s1.141678s
Success
pause_test.cSuccessNone1.060671s1.155092s
Success
setitimer.cSuccessNone7.060684s7.164246s
Success
sigalrm.cSuccessNone2.059692s2.145015s
Success
sigaltstack.cSuccessNone0.059242s0.139244s
Success
sigchld.cSuccessNone1.061188s1.152044s
Success
signal-fork.cSuccessNone4.061490s4.148443s
Success
signal-simple.cSuccessNone0.056729s0.134850s
Success
signal_SIGCHLD.cSuccessNone0.060219s0.162544s
Success
signal_fork.cSuccessNone0.052844s0.153324s
Success
signal_int_ignored.cSuccessNone2.058323s2.147436s
Success
signal_kill_cleanup.cSuccessNone1.060849s1.146395s
Success
signal_procmask.cSuccessNone0.050929s0.130136s
Success
signal_read_interrupt.cSuccessNone0.565363s0.664316s
Success
signal_recursive.cSuccessNone0.051815s0.138124s
Success
signal_sa_mask.cSuccessNone0.050323s0.128473s
Success
signal_select_interrupt.cSuccessNone0.570612s0.666913s
Success
signal_write_interrupt.cSuccessNone1.060561s1.142415s
Success
sigpipe.cSuccessNone1.060616s1.152519s
Success
sigprocmask.cSuccessNone1.055397s1.133290s
Success
sigsuspend_test.cSuccessNone1.056097s1.151723s
Success
test_sigsetjmp.cSuccessNone0.064377s0.162603s
Success

Fail Tests

Summary

MetricCount
Total Test Cases6
Number of Successes6
Number of Failures0
Number of Compilation Failure Native0
Number of Runtime Failure Native0
Number of Segmentation Fault Native0
Number of Timeout During Native0
Number of Lind Wasm Compile Failure0
Number of Lind Wasm Runtime Failure0
Number of Lind Wasm Segmentation Failure0
Number of Timeout During Lind Wasm run0
Number of Unknown Failure0
Number of C Compiler and Wasm Output mismatch0
Number of Fail Test: Native Succeeded (Should Fail)0
Number of Fail Test: Wasm Succeeded (Should Fail)0
Number of Fail Test: Both Native and Wasm Succeeded (Should Fail)0
Number of Fail Test: Native Compilation Failure (Should Succeed)0
Number of Fail Test: Wasm Compilation Failure (Should Succeed)0

Test Results by Category

Test CaseStatusError TypeNative TimeWasm TimeOutput
Dylink Tests
dlerror.cSuccessNone0.051048s0.123387s
Success
Memory Tests
invalid_access_direct.cSuccessNone0.117701s0.120003s
Success
invalid_access_fork.cSuccessNone0.127778s0.170115s
Success
mmap-negative1.cSuccessNone0.148606s0.117038s
Success
mmap-negative2.cSuccessNone0.132861s0.129325s
Success
Signal Tests
signal_resethand.cSuccessNone1.058810s1.141491s
Success

C++ harness

Summary

MetricValue
Total1
Success1
Failures0
Compile failures0
Runtime failures0
Output mismatch0
Timeouts0

Cases

TestStatusError typeNative timeWasm timeOutput
tests/unit-tests/cpp/sort.cppSuccess0.399502s8.797091s
LIBCPP_SORT_OK 1 2 3

@JustinCappos JustinCappos left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this is for Lind, not specifically Lind-Wasm. I don't know if it's worth making that clearer here. I do know have a large cleanup project once we start to make that transition.


It cannot, by the Wasm memory model rather than any policy check, address host
memory, issue raw Linux syscalls, alter JIT output, or reach another cage's
memory.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to include this:
Wasm runtimes also prohibit access to virtual files within the /proc/self directory. This prevents cages from accessing host information such as secrets through the likes of /proc/self/mem.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasm runtimes also prohibit access to virtual files within the /proc/self directory

This feature is provided by wasi API, which is not used in our lind-wasm implementation. lind-wasm provides fs isolation by enforce chroot at initialization -- only gives cage/grates access to lindfs/ -- but doesn't prohibit access to /proc/self inside lindfs.


**Case 5: cage or grate against the runtime or kernel (U).** Neither has a path
downward. The runtime's state is host memory it cannot address (Section 4), and
the only way up is a runtime bug, which is Case 4. So these cells are unaffected.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further up you mention that a cage can cause a fault in RawPOSIX:

Either it travels down tagged with its originating cage and RawPOSIX faults if it falls outside that cage's address space, or the grate pulls the bytes in with the
copy-from-cage call, which checks the same provenance before copying.

Does this mean a cage can cause the runtime to crash, or will this fault be contained?

My observation is that it kills the whole runtime (see attached code and log).

faultlog.txt
hello.c

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I have same confusion here.

Section 5 says a compromised cage can call host imports and syscall APIs with arbitrary inputs, including make_syscall, register_handler, and copy_handler_table_to_cage. That is a direct input path into 3i/RawPOSIX/Wasmtime.

Also Fredrik's comment showing malformed pointer behavior can kill the whole runtime... I'm not sure should we make this more precise here..?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bug to me yes? We shouldn't be able to kill the runtime like this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a cage should be designed to not crash host, if that happens, this is a bug that should be fixed immediately. We shouldn't rely on current lind implementation to define/test threat model as it could have bugs, threat model is a more high level design stuff where the implementation should follows


**Case 5: cage or grate against the runtime or kernel (U).** Neither has a path
downward. The runtime's state is host memory it cannot address (Section 4), and
the only way up is a runtime bug, which is Case 4. So these cells are unaffected.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I have same confusion here.

Section 5 says a compromised cage can call host imports and syscall APIs with arbitrary inputs, including make_syscall, register_handler, and copy_handler_table_to_cage. That is a direct input path into 3i/RawPOSIX/Wasmtime.

Also Fredrik's comment showing malformed pointer behavior can kill the whole runtime... I'm not sure should we make this more precise here..?

| Victim \ Attacker | Cage A | Grate B | Cage C | Grate D | Runtime | Kernel+HW |
| --- | --- | --- | --- | --- | --- | --- |
| **Cage A** | N/A | CC | RE | RE | KO | KO |
| **Grate B** | FE | N/A | RE | RE | KO | KO |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Grate B only has RE against unrelated Cage C / Grate D is not precise enough.. Actually a grate can copy from arbitrary cage IDs (from the compromised-grate section and our current implementation)


**P4: handler-table integrity.** The 3i logic and per-cage handler tables are
host memory, unreachable from any cage (Section 4), so routing cannot be tampered
with even if the 3i policy logic has a bug. A cage influences routing only

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

routing cannot be tampered
with even if the 3i policy logic has a bug

This claim might be too strong. The routing correctness needs to depend on correct 3i scoping checks


It cannot, by the Wasm memory model rather than any policy check, address host
memory, issue raw Linux syscalls, alter JIT output, or reach another cage's
memory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasm runtimes also prohibit access to virtual files within the /proc/self directory

This feature is provided by wasi API, which is not used in our lind-wasm implementation. lind-wasm provides fs isolation by enforce chroot at initialization -- only gives cage/grates access to lindfs/ -- but doesn't prohibit access to /proc/self inside lindfs.

## 2. Methodology

We do not sort components into trusted and untrusted, because that hides the fact
that a grate is trusted by the cages it isolates and by nothing else. Instead we

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because that hides the fact that a grate is trusted by the cages it isolates and by nothing else

Probably a better way to say is,

We do not sort components into trusted and untrusted; there is no global notion of trust. Instead, each component is trusted by a specific set of other components — a grate, for example, is trusted by the cages it isolates and by nothing else.


### Compromised grate

A grate that is compromised can observe, change, drop, or fake results for any

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In earlier section, it is mentioned
A grate is trusted only by its own descendant cages, and only to enforce their policy.

Does having a grate compromised affect the trust relationship in anyway?

Or is trust and a component getting compromised not related?

@vidyalakshmir

vidyalakshmir commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Most of this is for Lind, not specifically Lind-Wasm. I don't know if it's worth making that clearer here. I do know have a large cleanup project once we start to make that transition.

I think wasm related is specifically the P6 in Section 8 - Security Properties. In general, any SFI can guarantee cross-cage memory isolation etc.

@vidyalakshmir

Copy link
Copy Markdown
Contributor

One thing not discussed is about kernel attack surface reduction or if attacks targeting kernel is made harder through Lind design. Some thoughts on this..

There are two cases here : 1) In a conventional Linux environment, an attacker who finds a memory-safety bug in the application — a buffer overflow, a use-after-free, a format string vulnerability — can exploit it to gain controlled execution within the process and then immediately leverage that foothold to issue arbitrary syscalls with attacker-chosen arguments, targeting known vulnerabilities in the kernel's syscall handlers. 2) Even without fully compromising the application's control flow, an attacker who can influence what data the application processes — through a malicious file, a crafted network packet, or attacker-controlled input that flows into a syscall argument — can steer the application into making a syscall that triggers a kernel bug without the application itself being "exploited" in the traditional sense. In both cases, the kernel's attack surface is the full Linux syscall table, reachable with arbitrary argument values, and a single kernel vulnerability reachable through this path can result in privilege escalation, arbitrary memory corruption across all processes, or a full system compromise.

In Lind, both attack paths are disrupted by the same structural property: a cage's only route to the OS is through lind_syscall → 3i → RawPOSIX → kernel. Even if an attacker fully exploits an application cage and achieves arbitrary Wasm code execution, they cannot issue raw kernel syscalls directly — every syscall is intercepted by RawPOSIX, which validates all pointer arguments against the cage's vmmap, enforces unconditional policy rules regardless of argument values, and forwards to the kernel only the subset of operations it deems well-formed and cage-appropriate. A syscall argument deliberately crafted to trigger a specific kernel bug must pass through this validation layer first. Critically, this defence holds even when the application cage is fully compromised — because the interposition is not inside the application but in the trusted host code the cage cannot modify or bypass.

@rennergade

Copy link
Copy Markdown
Contributor Author

One thing not discussed is about kernel attack surface reduction or if attacks targeting kernel is made harder through Lind design. Some thoughts on this..

There are two cases here : 1) In a conventional Linux environment, an attacker who finds a memory-safety bug in the application — a buffer overflow, a use-after-free, a format string vulnerability — can exploit it to gain controlled execution within the process and then immediately leverage that foothold to issue arbitrary syscalls with attacker-chosen arguments, targeting known vulnerabilities in the kernel's syscall handlers. 2) Even without fully compromising the application's control flow, an attacker who can influence what data the application processes — through a malicious file, a crafted network packet, or attacker-controlled input that flows into a syscall argument — can steer the application into making a syscall that triggers a kernel bug without the application itself being "exploited" in the traditional sense. In both cases, the kernel's attack surface is the full Linux syscall table, reachable with arbitrary argument values, and a single kernel vulnerability reachable through this path can result in privilege escalation, arbitrary memory corruption across all processes, or a full system compromise.

In Lind, both attack paths are disrupted by the same structural property: a cage's only route to the OS is through lind_syscall → 3i → RawPOSIX → kernel. Even if an attacker fully exploits an application cage and achieves arbitrary Wasm code execution, they cannot issue raw kernel syscalls directly — every syscall is intercepted by RawPOSIX, which validates all pointer arguments against the cage's vmmap, enforces unconditional policy rules regardless of argument values, and forwards to the kernel only the subset of operations it deems well-formed and cage-appropriate. A syscall argument deliberately crafted to trigger a specific kernel bug must pass through this validation layer first. Critically, this defence holds even when the application cage is fully compromised — because the interposition is not inside the application but in the trusted host code the cage cannot modify or bypass.

I do think some of this has merit, I'll try to integrate some here. What I think we want to avoid is a "popular paths" style argument in surface reduction, since at this point its really just "we didnt implement these syscalls", even though something like that could be done with a grate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants