Skip to content

async: move off the deprecated AsyncFd constructors - #344

Merged
congwang-mk merged 3 commits into
mainfrom
asyncfd-register
Nov 6, 2026
Merged

congwang-mk merged 3 commits into
mainfrom
asyncfd-register

Conversation

@congwang-mk

Copy link
Copy Markdown
Contributor

Fixes #343.

RUSTSEC-2026-0386 marks tokio's safe AsyncFd constructors unsound, and tokio 1.51.6 and 1.53.3+ deprecate them in favour of the unsafe AsyncFd::register. Our lockfile was on 1.51.0, so we never saw the warnings, but downstream users on newer tokio get the deprecation.

  • deps: sandlock-core and sandlock-oci now require tokio 1.53.3, because register doesn't exist before then on this line (1.52 isn't patched). The lockfile moves to 1.54.1.
  • Owned sites: the eight registrations that hand over an OwnedFd, a ControlFd, or an Arc<OwnedFd> move to register / register_with_interest, each with a one-line SAFETY note. This includes sandlock-oci's exit_watcher, which the issue didn't list.
  • Borrowed sites: Reaper::exit and MainExit::wait registered a raw fd borrowed from a struct. They now register their own dup, so the safety argument stays local. This also means a second concurrent waiter no longer gets EEXIST from epoll, which used to make exit() return before the reaper had exited.

Test plan

  • Full CI passes on the branch via workflow_dispatch (run 42089060012): Rust x86_64/arm64, musl, low-ABI, riscv64 cross-build, feature builds, fmt, Go and Python suites.

🤖 Generated with Claude Code

RUSTSEC-2026-0386 marks tokio's safe AsyncFd constructors unsound: they
accept any AsRawFd, so a registration can outlive the descriptor it
names. The fixed releases deprecate them in favour of the unsafe
AsyncFd::register, which exists only from 1.51.6 and 1.53.3 on (1.52 is
not patched), so the crates that register descriptors must require it.

Signed-off-by: Cong Wang <cwang@multikernel.io>
tokio deprecates the safe AsyncFd constructors because nothing ties the
registration to the descriptor's lifetime. Every site here hands the
AsyncFd an owned fd, or an Arc that keeps it open, so the unsafe
constructor's contract holds by construction and the SAFETY notes say
which.

Signed-off-by: Cong Wang <cwang@multikernel.io>
Reaper::exit and MainExit::wait registered a raw fd borrowed from a
struct, so their soundness rested on callers never dropping the owner
early, and a second concurrent waiter would hit EEXIST from epoll:
exit() would then return before the reaper exited. Each waiter now
registers its own dup, which shares readiness with the original and
keeps the AsyncFd contract local.

Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk
congwang-mk merged commit 42a2c2d into main Nov 6, 2026
50 checks passed
@congwang-mk
congwang-mk deleted the asyncfd-register branch November 6, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tokio 1.53.3+ deprecates the AsyncFd constructors sandlock-core uses

1 participant