Skip to content

fix(fspy): forward calls with -1 as the directory descriptor - #862

Open
magurotuna wants to merge 6 commits into
voidzero-dev:mainfrom
magurotuna:fix/fspy-invalid-dirfd
Open

magurotuna wants to merge 6 commits into
voidzero-dev:mainfrom
magurotuna:fix/fspy-invalid-dirfd

Conversation

@magurotuna

Copy link
Copy Markdown
Member

Motivation

In a cached task, the ps -p <pid> command aborts with the SIGABRT signal if the process <pid> has already exited. Outside of vp run, the same command exits with status 1.

Some file system calls, such as openat, take a directory descriptor: an open file descriptor of a directory, which the call uses to resolve a relative path. Starting with version 4.0.6 (5e4886ae), ps from procps-ng opens /proc/<pid> as a directory descriptor and then reads the status file relative to it. If the process has exited, the open fails and returns -1. ps does not check the result, and calls openat(-1, "status", O_RDONLY). This call is harmless by itself: the kernel fails it with the EBADF error.

On Linux and macOS, fspy injects interceptors into tracked programs. An interceptor is a function that replaces a libc function, such as openat, records the path, and then calls the original function. The interceptor converted the directory descriptor with the BorrowedFd::borrow_raw function, which panics on -1. The injected library aborts on panic, so the panic aborted ps.

Any tracked program that passes -1 as a directory descriptor aborted in the same way. The ps command is the reported case.

Fixes voidzero-dev/vite-plus#2954.

Changes

  • Add the BorrowedFd::try_borrow_raw function, which returns None for -1. The interceptors use this function, so that they forward a call with -1 to the original function instead of panicking.
  • If the path is absolute, the kernel ignores the directory descriptor, so fspy still records the path. If the path is relative, the call fails, so fspy does not record the path.
  • The changed interceptors are openat, fstatat, faccessat, statx, syscall(SYS_statx), fdopendir, getdirentries, and execveat, and on macOS also openat$NOCANCEL and __getdirentries64.
  • This change does not affect the seccomp path, which fspy uses for static programs and musl builds. The seccomp handler already ignores a failed descriptor lookup.
  • Add the crates/fspy/tests/invalid_dirfd.rs tests. The tests call statx with the syscall function, and call the glibc statx and execveat functions through the dlsym function, so that the tests build for glibc 2.17 and musl.

magurotuna and others added 5 commits October 16, 2026 21:48
A tracked program can pass -1 as a directory descriptor, such as a
failed `open` result it does not check. procps-ng's `ps -p <pid>` does
this for an exited process, and the interposers abort it while
borrowing -1 (voidzero-dev/vite-plus#2954).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The interposers borrowed every descriptor argument with
`BorrowedFd::borrow_raw`, which panics on -1, so a tracked program that
passed a failed `open` result to `openat`, `fstatat`, `faccessat`,
`statx`, `fdopendir`, or `execveat` aborted. procps-ng's `ps -p <pid>`
does this when the process has exited.

Borrow descriptor arguments as `Option`, with `None` for -1. An
absolute pathname is still tracked, since the kernel ignores the
descriptor; a relative pathname or a lone descriptor is not, since the
call fails with `EBADF`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…rget

The tests called the libc `statx` wrapper, which glibc 2.17 lacks and
the libc crate does not declare for musl, so the Linux CI builds failed.
Call `statx` through `syscall` instead, and resolve the glibc `statx`
and `execveat` wrappers with `dlsym` so that their interposers are still
covered on glibc.

Also cover `statx` with a null path and `AT_EMPTY_PATH`, and check that
a relative path at -1 is not recorded under the current directory.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@magurotuna magurotuna added the ci: full Run the slow CI jobs (macOS x64, musl) on this pull request label Oct 18, 2026
…#862

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci: full Run the slow CI jobs (macOS x64, musl) on this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fspy: procps ps aborts when querying an exited process in cached tasks

1 participant