Skip to content

Fix sandbox escape via absolute paths in *at syscalls#1088

Open
moogchi wants to merge 2 commits intomainfrom
absoluate_path_reject
Open

Fix sandbox escape via absolute paths in *at syscalls#1088
moogchi wants to merge 2 commits intomainfrom
absoluate_path_reject

Conversation

@moogchi
Copy link
Copy Markdown
Contributor

@moogchi moogchi commented Apr 19, 2026

Summary

Fixes sandbox escape via absolute paths in *at syscalls (fixes #1077).

Background

symlinkat, openat, unlinkat, and readlinkat all pass the raw guest path directly to the host kernel when a real dirfd is provided. Per POSIX, the host kernel ignores dirfd entirely when the path is absolute — allowing a malicious guest to escape the cage sandbox with a single syscall:

symlinkat("payload", any_valid_fd, "/etc/cron.d/backdoor");

Fix

Reject absolute paths in the dirfd branch of all four syscalls with EACCES before passing to the host kernel:

if raw_path.to_bytes().starts_with(b"/") {
    return syscall_error(Errno::EACCES, "symlinkat", "absolute path bypasses dirfd sandbox");
}

Affected syscalls

  • symlinkat_syscall
  • openat_syscall
  • unlinkat_syscall
  • readlinkat_syscall

@github-actions
Copy link
Copy Markdown
Contributor

End-to-End Test Report

Test Preview

Unified Test Report

grate harness

MetricValue
Total11
Success11
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: 2
[Cage | geteuid] PASS: 1000000 calls returned 10
[Grate|geteuid] 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: 2
[Grate|interpose-exec] Handling function ptr: 2 from cage: 1
[Grate|interpose-exec] In exec_grate 1 handler for cage: 1
[Grate|interpose-exec] Handling function ptr: 2 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: 2
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: 2
[Grate|interpose-fork] Handling function ptr: 2 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: 2
[Grate|interpose-mmap] Handling function ptr: 2 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 2 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 2 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 2 from cage: 1
[Grate|interpose-mmap] In mmap_grate 1 handler for cage: 1
[Grate|interpose-mmap] Handling function ptr: 2 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: 3
[cage] registering 107. grateid: 2 cageid: 3
[Grate|interpose-register] Handling function ptr: 3 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: 2
[Grate|interpose-register] Handling function ptr: 2 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: 2
[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: 2 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:

race-test_grate.cSuccess
STDOUT:
pass

STDERR:

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

STDERR:

simple-tests/diff-cage-args_grate.cSuccess
STDOUT:
[Grate|diff-cage-args] Handling function ptr: 2 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: 3 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: 2
[Grate|geteuid] Handling function ptr: 2 from cage: 1
[Grate|geteuid] In geteuid_grate 1 handler for cage: 1
[Cage | geteuid] PASS: geteuid ret = 10
[Grate|geteuid] PASS

STDERR:

wasm harness

Test Report

Deterministic Tests

Summary

MetricCount
Total Test Cases205
Number of Successes205
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
File Tests
chartests.cSuccessNone0.041517s0.162467s
Success
chdir_getcwd.cSuccessNone0.041988s0.130041s
Success
chmod.cSuccessNone0.044910s0.136044s
Success
clock_gettime_highlevel.cSuccessNone0.097702s0.283587s
Success
clock_gettime_simple.cSuccessNone0.038018s0.117229s
Success
cloexec.cSuccessNone0.069013s0.196968s
Success
close.cSuccessNone0.052186s0.154697s
Success
creat_access.cSuccessNone0.043007s0.127760s
Success
doubleclose.cSuccessNone0.038004s0.111995s
Success
dup.cSuccessNone0.038282s0.127341s
Success
dup2.cSuccessNone0.043426s0.147886s
Success
dup3.cSuccessNone0.042406s0.131160s
Success
dupwrite.cSuccessNone0.061813s0.141081s
Success
etc_conf.cSuccessNone0.039550s0.141587s
Success
fchdir.cSuccessNone0.045097s0.270525s
Success
fchmod.cSuccessNone0.045434s0.137350s
Success
fcntl.cSuccessNone0.043491s0.131938s
Success
fdatasync.cSuccessNone0.114437s0.124203s
Success
filetest.cSuccessNone0.042749s0.122791s
Success
filetest1000.cSuccessNone0.050662s0.142040s
Success
flock.cSuccessNone0.083459s0.157513s
Success
fstat.cSuccessNone0.049998s0.134803s
Success
fstatfs.cSuccessNone0.039745s0.230820s
Success
fsync.cSuccessNone0.043512s0.144950s
Success
ftruncate.cSuccessNone0.047569s0.246847s
Success
getcwd.cSuccessNone0.041454s0.121829s
Success
getrandom.cSuccessNone0.158300s0.126694s
Success
ioctl.cSuccessNone0.185989s0.162773s
Success
link.cSuccessNone0.045620s0.174858s
Success
locale_test.cSuccessNone0.064454s0.517248s
Success
lseek.cSuccessNone0.047074s0.229364s
Success
lstat.cSuccessNone0.045246s0.148819s
Success
mkdir_rmdir.cSuccessNone0.102282s0.126972s
Success
mkfifo_test.cSuccessNone0.048163s0.167836s
Success
mknod.cSuccessNone0.050905s0.187406s
Success
nocancel_io.cSuccessNone0.045511s0.151604s
Success
open.cSuccessNone0.041368s0.186401s
Success
openat.cSuccessNone0.039942s0.121207s
Success
path_conversion_safety.cSuccessNone0.046686s0.178525s
Success
pread_pwrite.cSuccessNone0.044444s0.139013s
Success
preadv_pwritev.cSuccessNone0.044999s0.139588s
Success
printf.cSuccessNone0.037020s0.200701s
Success
prlimit64.cSuccessNone0.038905s0.136355s
Success
read.cSuccessNone0.044880s0.133717s
Success
readbytes.cSuccessNone0.041463s0.119049s
Success
readdir_basic.cSuccessNone0.046504s0.146819s
Success
readlink.cSuccessNone0.105101s0.127045s
Success
readlinkat.cSuccessNone0.044258s0.242450s
Success
readv_writev_test.cSuccessNone0.044106s0.137345s
Success
rename.cSuccessNone0.045126s0.125768s
Success
sc-writev.cSuccessNone0.043251s0.127942s
Success
stat.cSuccessNone0.044287s0.134298s
Success
statfs.cSuccessNone0.039266s0.120262s
Success
symlink.cSuccessNone0.108689s0.161229s
Success
sync_file_range.cSuccessNone0.041716s0.126899s
Success
timespec_time_t_compat.cSuccessNone0.041770s0.119424s
Success
truncate.cSuccessNone0.045114s0.144808s
Success
unlink.cSuccessNone0.046111s0.171172s
Success
unlinkat.cSuccessNone0.045387s0.188956s
Success
write.cSuccessNone0.039261s0.116102s
Success
writeloop.cSuccessNone0.045963s0.127180s
Success
writepartial.cSuccessNone0.043984s0.120848s
Success
writev.cSuccessNone0.044180s0.310043s
Success
Math Tests
math_link_smoke.cSuccessNone0.047620s0.123447s
Success
math_tests.cSuccessNone0.049659s0.146633s
Success
Memory Tests
brk.cSuccessNone0.043358s0.125604s
Success
fork_large_memory.cSuccessNone0.069757s0.352761s
Success
malloc.cSuccessNone0.041153s0.115972s
Success
malloc_large.cSuccessNone0.040432s0.125181s
Success
memcpy.cSuccessNone0.041324s0.394556s
Success
memory_error_test.cSuccessNone0.051771s0.155949s
Success
mmap.cSuccessNone0.039164s0.121584s
Success
mmap_aligned.cSuccessNone0.041129s0.133065s
Success
mmap_complicated.cSuccessNone0.049064s0.137703s
Success
mmap_file.cSuccessNone0.044885s0.131565s
Success
mmap_shared.cSuccessNone0.044035s0.135733s
Success
mmaptest.cSuccessNone0.041300s0.125894s
Success
mprotect.cSuccessNone0.040307s0.240527s
Success
mprotect_boundary.cSuccessNone0.040238s0.136768s
Success
mprotect_end_region.cSuccessNone0.040661s0.129848s
Success
mprotect_middle_region.cSuccessNone0.039303s0.175940s
Success
mprotect_multiple_times.cSuccessNone0.039085s0.129232s
Success
mprotect_same_value.cSuccessNone0.039838s0.125054s
Success
mprotect_spanning_regions.cSuccessNone0.040382s0.138465s
Success
sbrk.cSuccessNone0.041093s0.119709s
Success
segfault.cSuccessNone0.045507s0.145303s
Success
shm.cSuccessNone0.043549s0.338789s
Success
shmtest.cSuccessNone0.041076s0.128573s
Success
thread_malloc_sequential.cSuccessNone0.045962s0.163588s
Success
vtable.cSuccessNone0.049188s0.171440s
Success
Networking Tests
accept4.cSuccessNone0.047656s0.144991s
Success
dns_resolve_test.cSuccessNone0.044475s0.131989s
Success
dnstest.cSuccessNone0.045225s0.137094s
Success
epoll_edge_triggered.cSuccessNone0.200886s0.448403s
Success
epollcreate1.cSuccessNone0.045039s0.137914s
Success
error_handling_net.cSuccessNone0.050909s0.393762s
Success
getaddrinfo_test.cSuccessNone0.047049s0.270334s
Success
getaddrinfo_unspec.cSuccessNone0.117064s0.177351s
Success
gethostname.cSuccessNone0.039591s0.116015s
Success
getifaddrs.cSuccessNone0.044918s0.129725s
Success
getsockname.cSuccessNone0.048345s0.130807s
Success
getsockopt.cSuccessNone0.046674s0.175691s
Success
ipv6_basic.cSuccessNone0.047483s0.174408s
Success
makepipe.cSuccessNone0.039117s0.112663s
Success
nonblocking_eagain.cSuccessNone0.047968s0.186510s
Success
pipe.cSuccessNone0.046898s0.143549s
Success
pipe2.cSuccessNone0.045696s0.130668s
Success
pipeinput.cSuccessNone0.048107s0.146339s
Success
pipeinput2.cSuccessNone0.046439s0.148733s
Success
pipeonestring.cSuccessNone0.047608s0.147621s
Success
pipepong.cSuccessNone0.046304s0.151681s
Success
pipewrite.cSuccessNone0.042358s0.133786s
Success
poll.cSuccessNone0.044551s0.125467s
Success
recvfrom-sendto.cSuccessNone0.046338s0.143507s
Success
sendmsg_recvmsg_test.cSuccessNone0.046022s0.142781s
Success
serverclient.cSuccessNone0.046211s0.303090s
Success
shutdown.cSuccessNone0.045727s0.133125s
Success
shutdown_fork.cSuccessNone0.046119s0.138857s
Success
simple-select.cSuccessNone0.046197s0.151527s
Success
simple_epoll.cSuccessNone0.048189s0.139291s
Success
socket.cSuccessNone0.043874s0.124526s
Success
socket_cloexec.cSuccessNone0.043464s0.122685s
Success
socket_options_advanced.cSuccessNone0.049091s0.192537s
Success
socketepoll.cSuccessNone0.043878s0.127381s
Success
socketpair.cSuccessNone0.043697s0.135490s
Success
socketselect.cSuccessNone0.045331s0.134636s
Success
udp_send_recv.cSuccessNone0.149253s0.291507s
Success
uds-getsockname.cSuccessNone0.044208s0.128463s
Success
uds-nb-select.cSuccessNone2.050868s2.190242s
Success
uds-serverclient.cSuccessNone0.057038s0.162521s
Success
uds-socketselect.cSuccessNone0.045731s0.132554s
Success
writev_socket.cSuccessNone0.047058s0.168406s
Success
Process Tests
barrier_test.cSuccessNone0.043325s0.131236s
Success
chain_thread.cSuccessNone1.045141s1.135829s
Success
ctor_syscall_test.cSuccessNone0.038146s0.117422s
Success
cxa_atexit_test.cSuccessNone0.041303s0.118383s
Success
execve_shebang.cSuccessNone0.046259s0.131458s
Success
exit.cSuccessNone0.041884s0.115748s
Success
exit_failure.cSuccessNone0.043740s0.260267s
Success
exit_group_thread.cSuccessNone0.063399s0.135650s
Success
flockfile_test.cSuccessNone0.045520s0.147735s
Success
fork2malloc.cSuccessNone0.044574s0.129303s
Success
fork_select.cSuccessNone0.043763s0.138822s
Success
fork_simple.cSuccessNone0.044884s0.126888s
Success
fork_syscall.cSuccessNone0.047632s0.255505s
Success
fork_tls_ctype.cSuccessNone0.046216s0.151351s
Success
forkandopen.cSuccessNone0.044162s0.142812s
Success
forkdup.cSuccessNone0.046106s0.139984s
Success
forkexecuid.cSuccessNone0.044343s0.196006s
Success
forkexecv-arg.cSuccessNone0.045401s0.182325s
Success
forkexecv.cSuccessNone0.042919s0.172511s
Success
forkfiles.cSuccessNone0.045075s0.139357s
Success
forkmalloc.cSuccessNone0.051051s0.125208s
Success
forknodup.cSuccessNone0.045756s0.145688s
Success
function-ptr.cSuccessNone0.040164s0.118967s
Success
getegid_syscall.cSuccessNone0.044812s0.216729s
Success
getgid_syscall.cSuccessNone0.044425s0.220344s
Success
getpid.cSuccessNone0.039540s0.113462s
Success
getpid_syscall.cSuccessNone0.046081s0.237272s
Success
getppid.cSuccessNone0.043862s0.130750s
Success
getppid_syscall.cSuccessNone0.046204s0.209731s
Success
getuid.cSuccessNone0.044185s0.122318s
Success
getuid_syscall.cSuccessNone0.043589s0.163923s
Success
hello-arg.cSuccessNone0.037368s0.120782s
Success
hello.cSuccessNone0.037453s0.113538s
Success
longjmp.cSuccessNone0.038503s0.124586s
Success
mutex.cSuccessNone2.046385s2.143745s
Success
printf_deadlock_smoke.cSuccessNone0.050342s0.166582s
Success
printf_thread_test.cSuccessNone0.046421s0.138558s
Success
sem_forks.cSuccessNone0.126271s0.143808s
Success
setsid.cSuccessNone0.039678s0.114509s
Success
template.cSuccessNone0.210434s0.206676s
Success
test_exec_nofork.cSuccessNone0.043373s0.175320s
Success
test_unlink_open_file.cSuccessNone0.040397s0.116755s
Success
thread-guard.cSuccessNone0.042458s0.133874s
Success
thread-test.cSuccessNone0.040753s0.123069s
Success
thread.cSuccessNone0.041624s0.121089s
Success
thread_cageid_race.cSuccessNone0.041796s0.148287s
Success
tls_test.cSuccessNone0.043257s0.133200s
Success
uname.cSuccessNone0.039136s0.115234s
Success
wait.cSuccessNone2.042392s2.130943s
Success
waitpid_anychild.cSuccessNone0.044700s0.127761s
Success
waitpid_syscall.cSuccessNone1.044069s1.158292s
Success
waitpid_wnohang.cSuccessNone0.045827s0.129001s
Success
Signal Tests
alarm.cSuccessNone7.044055s7.154291s
Success
eintr_fork_signal.cSuccessNone1.045317s1.144209s
Success
kill.cSuccessNone1.044749s1.151203s
Success
setitimer.cSuccessNone7.045045s7.152670s
Success
sigalrm.cSuccessNone2.043524s2.140644s
Success
sigaltstack.cSuccessNone0.046049s0.138003s
Success
sigchld.cSuccessNone1.045529s1.131887s
Success
signal-fork.cSuccessNone4.044706s4.145254s
Success
signal-simple.cSuccessNone0.044038s0.123088s
Success
signal_SIGCHLD.cSuccessNone0.043016s0.133813s
Success
signal_fork.cSuccessNone0.043057s0.141892s
Success
signal_int_ignored.cSuccessNone2.044764s2.135436s
Success
signal_kill_cleanup.cSuccessNone1.042240s1.130789s
Success
signal_procmask.cSuccessNone0.041003s0.174203s
Success
signal_read_interrupt.cSuccessNone0.546534s0.735269s
Success
signal_recursive.cSuccessNone0.041201s0.131038s
Success
signal_sa_mask.cSuccessNone0.040259s0.122568s
Success
signal_select_interrupt.cSuccessNone0.547108s0.646596s
Success
signal_write_interrupt.cSuccessNone1.045147s1.142227s
Success
sigpipe.cSuccessNone1.045565s1.147189s
Success
sigprocmask.cSuccessNone1.044369s1.139086s
Success
Fail Tests

Summary

MetricCount
Total Test Cases4
Number of Successes4
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.038580s0.115849s
Success
Memory Tests
mmap-negative1.cSuccessNone0.203481s0.135645s
Success
mmap-negative2.cSuccessNone0.092909s0.130843s
Success
Signal Tests
signal_resethand.cSuccessNone1.046147s1.137190s
Success

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.

Security Bug: Sandbox Escape via Absolute Path in symlinkat_syscall

1 participant