Under the IPC grate, every coreutils test that begins with a touch of a fixture file fails
immediately. touch reports setting times of 'X': Bad file descriptor and the test aborts via
framework_failure. This single bug accounts for ~80 of the 123 IPC-grate failures (the chmod/,
chown/, cp/, ln/, ls/, mv/, readlink/, rm/, touch/* groups). It does not reproduce on the
bare wasm runtime or the witness grate.
Reproduction
./run_default_tests.sh --grate ipc touch/relative
Output:
/bin/touch: setting times of `f': Bad file descriptor
/tests/touch/relative: failure in testing framework
Call path (traced)
- touch f → src/touch.c:136 calls fd_reopen(STDIN_FILENO, file, O_WRONLY|O_CREAT|…) — the file
is opened onto fd 0. The open succeeds (no open_errno).
- src/touch.c:168 → gl_futimens(fd=0, file, t) → lib/utimens.c:269 → futimens(0, ts).
- lind glibc sysdeps/unix/sysv/linux/futimens.c:32 → __utimensat64_helper(0, NULL, &tsp64[0],
0).
- sysdeps/unix/sysv/linux/utimensat.c:63 → MAKE_LEGACY_SYSCALL(UTIMENSAT_SYSCALL, …, fd=0,
host_file=0, host_tsp, flags=0, …).
- rawposix fs_calls.rs:4185 — path_arg == 0 branch (the futimens form) → fs_calls.rs:4189:
let kernel_fd = convert_fd_to_host(virtual_fd as u64, dirfd_cageid, cageid);
if kernel_fd < 0 { return handle_errno(-kernel_fd, "utimensat"); }
- convert_fd_to_host (typemap/src/cage_helpers.rs:51) does
fdtables::translate_virtual_fd(arg_cageid, virtual_fd); the lookup fails and returns -EBADF.
Root cause (suspected)
The fd lookup is done against dirfd_cageid (the cage-id tagged on the fd argument). On the bare runtime dirfd_cageid == cageid and the lookup of virtual fd 0 succeeds. Under the IPC grate, the syscall is forwarded by the grate and the fd argument carries the grate's cage-id (or fd 0 is not registered in the cage's fdtable the grate hands to rawposix), so translate_virtual_fd finds nothing and returns EBADF.
Note this is specific to the futimens form (path_arg == 0), where the fd is the operand. Plain
read/write/open work under the IPC grate, so the regression is in how the grate routes the
dirfd/fd argument of UTIMENSAT_SYSCALL (and likely all *at syscalls) — not in read/write.
Suggested fix
In ipc-grate/src/main.rs (lines 53–116) the grate registers ~60 syscall handlers — SYS_OPEN,
SYS_OPENAT, SYS_READ, SYS_FSTAT, SYS_FCHMOD, etc. — but SYS_UTIMENSAT is not in the list. The fix is to register a utimensat_handler (and likely SYS_UTIME/SYS_UTIMES/SYS_FUTIMESAT too) that translates the dirfd via forward_with_dirfd1
(handlers.rs:69) — or, since utimensat's fd arg is a dirfd that can be AT_FDCWD, a handler that
translates a real fd but passes AT_FDCWD through.
Impact
~80 IPC-grate failures. All cascade from the first touch in each test, so the affected tests
never run their real assertions — fixing this should drop the IPC failure count from 123 toward
the bare-wasm baseline (~35).
Under the IPC grate, every coreutils test that begins with a touch of a fixture file fails
immediately. touch reports setting times of 'X': Bad file descriptor and the test aborts via
framework_failure. This single bug accounts for ~80 of the 123 IPC-grate failures (the chmod/,
chown/, cp/, ln/, ls/, mv/, readlink/, rm/, touch/* groups). It does not reproduce on the
bare wasm runtime or the witness grate.
Reproduction
Call path (traced)
is opened onto fd 0. The open succeeds (no open_errno).
0).
host_file=0, host_tsp, flags=0, …).
let kernel_fd = convert_fd_to_host(virtual_fd as u64, dirfd_cageid, cageid);
if kernel_fd < 0 { return handle_errno(-kernel_fd, "utimensat"); }
fdtables::translate_virtual_fd(arg_cageid, virtual_fd); the lookup fails and returns -EBADF.
Root cause (suspected)
The fd lookup is done against dirfd_cageid (the cage-id tagged on the fd argument). On the bare runtime dirfd_cageid == cageid and the lookup of virtual fd 0 succeeds. Under the IPC grate, the syscall is forwarded by the grate and the fd argument carries the grate's cage-id (or fd 0 is not registered in the cage's fdtable the grate hands to rawposix), so translate_virtual_fd finds nothing and returns EBADF.
Note this is specific to the futimens form (path_arg == 0), where the fd is the operand. Plain
read/write/open work under the IPC grate, so the regression is in how the grate routes the
dirfd/fd argument of UTIMENSAT_SYSCALL (and likely all *at syscalls) — not in read/write.
Suggested fix
In ipc-grate/src/main.rs (lines 53–116) the grate registers ~60 syscall handlers — SYS_OPEN,
SYS_OPENAT, SYS_READ, SYS_FSTAT, SYS_FCHMOD, etc. — but SYS_UTIMENSAT is not in the list. The fix is to register a utimensat_handler (and likely SYS_UTIME/SYS_UTIMES/SYS_FUTIMESAT too) that translates the dirfd via forward_with_dirfd1
(handlers.rs:69) — or, since utimensat's fd arg is a dirfd that can be AT_FDCWD, a handler that
translates a real fd but passes AT_FDCWD through.
Impact
~80 IPC-grate failures. All cascade from the first touch in each test, so the affected tests
never run their real assertions — fixing this should drop the IPC failure count from 123 toward
the bare-wasm baseline (~35).