Skip to content

IPC grate: futimens() returns EBADF, breaking ~80 coreutils tests #172

@vidyalakshmir

Description

@vidyalakshmir

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)

  1. 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).
  2. src/touch.c:168 → gl_futimens(fd=0, file, t) → lib/utimens.c:269 → futimens(0, ts).
  3. lind glibc sysdeps/unix/sysv/linux/futimens.c:32 → __utimensat64_helper(0, NULL, &tsp64[0],
    0).
  4. sysdeps/unix/sysv/linux/utimensat.c:63 → MAKE_LEGACY_SYSCALL(UTIMENSAT_SYSCALL, …, fd=0,
    host_file=0, host_tsp, flags=0, …).
  5. 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"); }
  6. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions