RReverser edited Issue #2669:
_Originally reported on the Rust repo at https://github.com/rust-lang/rust/issues/82277_
I tried this code:
fn main() { std::fs::hard_link("/a", "/b").unwrap(); }
I compiled it with
--target wasm32-wasi
and executed with latest Wasmtime 0.23.0 withwasmtime --mapdir=/::.
where the current directory contains valid filea
.I expected to see this happen:
A hard link
b
is created that points toa
.Instead, this happened:
It fails with an error:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 28, kind: InvalidInput, message: "Invalid argument" }', temp.rs:2:36 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Error: failed to run main module `temp.wasm` Caused by: 0: failed to invoke command default 1: wasm trap: unreachable wasm backtrace: 0: 0x7b4c - <unknown>!__rust_start_panic 1: 0x75e5 - <unknown>!rust_panic 2: 0x71bd - <unknown>!std::panicking::rust_panic_with_hook::hb9189a2ae1f00dd6 3: 0x6928 - <unknown>!std::panicking::begin_panic_handler::{{closure}}::ha38be87363679287 4: 0x6869 - <unknown>!std::sys_common::backtrace::__rust_end_short_backtrace::h955bbbeea72dc4a0 5: 0x7061 - <unknown>!rust_begin_unwind 6: 0xd0a6 - <unknown>!core::panicking::panic_fmt::h904ce09f3cb14707 7: 0xdbcc - <unknown>!core::option::expect_none_failed::ha29c9c4296a18e58 8: 0xfee - <unknown>!core::result::Result<T,E>::unwrap::hcf72e0af954224e8 9: 0x9b7 - <unknown>!temp::main::hdc57b3c35eac1777 10: 0xac2 - <unknown>!core::ops::function::FnOnce::call_once::h9d9b1f2044973e11 11: 0x8ac - <unknown>!std::sys_common::backtrace::__rust_begin_short_backtrace::h0d198c55a40ffd2e 12: 0xdf2 - <unknown>!std::rt::lang_start::{{closure}}::he287b5106de2dbae 13: 0x76f6 - <unknown>!std::rt::lang_start_internal::h81003f47a7b429a5 14: 0xdc6 - <unknown>!std::rt::lang_start::h75812a9706ce1699 15: 0x9e8 - <unknown>!__original_main 16: 0x3f9 - <unknown>!_start note: run with `WASMTIME_BACKTRACE_DETAILS=1` environment variable to display more information
Meta
rustc --version --verbose
:rustc 1.49.0 (e1884a8e3 2020-12-29) binary: rustc commit-hash: e1884a8e3c3e813aada8254edfa120e85bf5ffca commit-date: 2020-12-29 host: x86_64-unknown-linux-gnu release: 1.49.0
wasmtime --version
:wasmtime 0.23.0
</p>
</details>Other attempts
Equivalent C code
I've also tried to compile an equivalent C code:
#include <unistd.h> int main() { return link("/a", "/b"); }
When this is compiled with WASI SDK
clang --target=wasm32-wasi
and executed with the same command in Wasmtime, it successfully creates the hardlink.Node.js WASI
I've also tried to execute those Wasm files with Node.js WASI support, and both Wasm files create hard links successfully.
Older Wasmtime
Finally, I've tried to execute both with Wasmtime 0.22, and both also create hardlinks successfully, indicating a regression in Wasmtime itself.
sunfishcode commented on Issue #2669:
The short answer is it's a bug in Rust's WASI support; see https://github.com/rust-lang/rust/pull/81984 for a fix. Shorter-term fixes are also possible, so if you need something sooner, let's discuss it.
The longer answer is:
POSIX's
linkat
function has a flags argument which can beAT_SYMLINK_FOLLOW
, allowing the user to control whether symlinks are followed. Unlikeopen
'sO_NOFOLLOW
however, which fails on a symlink,linkat
withoutAT_SYMLINK_FOLLOW
succeeds and simply creates a link to the symlink.WASI's
link
function is modeled after CloudABI's which is modeled after POSIX's, so it has an equivalent ofAT_SYMLINK_FOLLOW
. However, it's not safe to implement it in terms of a host call tolinkat
withAT_SYMLINK_FOLLOW
set, because that would blindly follow the symlink and could link to something outside the sandbox. Since there's no way to makelinkat
fail on a symlink, there's no way to implement a sandboxedlinkat
withAT_SYMLINK_FOLLOW
without introducing race conditions.
linkat
withAT_SYMLINK_FOLLOW
is rare in practice anyway, so I'm preparing to propose a change to WASI to not support it. Wasmtime is admittedly ahead of the curve in that it already doesn't support it. Creating hard links is pretty uncommon in general, and even moreso in code intended to be portable, so I guessed that this might not come up, but I appear to have been wrong :-}.
RReverser commented on Issue #2669:
@sunfishcode Thanks for the detailed explanation! It's always exciting to be hitting bugs that live in a crossover of spec and several implementations :sweat_smile:
Last updated: Dec 23 2024 at 12:05 UTC