Skip to content

[draft] fix(net): symmetric named-AF_UNIX datagram gating (reference implementation)#130

Draft
dzerik wants to merge 1 commit into
multikernel:mainfrom
dzerik:fix/net-unix-dgram-symmetry
Draft

[draft] fix(net): symmetric named-AF_UNIX datagram gating (reference implementation)#130
dzerik wants to merge 1 commit into
multikernel:mainfrom
dzerik:fix/net-unix-dgram-symmetry

Conversation

@dzerik

@dzerik dzerik commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Draft / reference implementation — not requesting merge. Posted so the concrete shape of the fix is reviewable; you own the OCI in-sandbox path, so priority and testing are your call.

Finding

A named (pathname/abstract) AF_UNIX SOCK_DGRAM sendmsg/sendmmsg under a destination policy with the unix fs-gate off returns EAFNOSUPPORT, while the identical sendto Continues and works. The IP send path (send_msghdr_on_behalfparse_ip_from_sockaddrNone) fails closed for a non-IP address, but sendto's non-IP branch (_ => Continue) does not — so the two syscalls disagree on the same destination.

Separately, sendto's _ => Continue decides on the transient address family: an AF_INET socket presenting an AF_UNIX address at check time Continues, and a racing thread can then swap msg_name to a denied IP before the kernel re-reads it — a latent TOCTOU on the destination policy.

Fix

Gate on the stable socket domain (socket_is_unix, SO_DOMAIN), not the address family:

  • send_msghdr_on_behalf returns a MsgOutcome: a non-connected, non-IP address Continues when the socket is AF_UNIX (the kernel constrains an AF_UNIX socket to AF_UNIX destinations, so a swap to an IP is kernel-rejected — the re-read race can't bypass the IP policy), and fails closed with EAFNOSUPPORT on an AF_INET socket.
  • sendmsg/sendmmsg return Continue on that outcome (in a batch only at entry 0, since a unix socket carries only unix entries).
  • sendto's _ => Continue is tightened the same way, closing the TOCTOU above.
  • Connected AF_UNIX (the fix(net): pass through connected AF_UNIX sendmsg under a destination policy #125 path) is unchanged — still on-behalf.

Reachability — why this is low-severity and hard to test

The precondition is the unix fs-gate being off, which means empty fs grants, which means Landlock denies all filesystem access. That makes the path unreachable through every exec-based run (run/spawn): execve needs a Landlock EXECUTE grant, and any grant turns the fs-gate on. fork()/work_fn installs a kernel-only seccomp filter with no user-notification supervisor, so the on-behalf handler never runs there either.

The only path that reaches sendmsg_on_behalf under an off fs-gate is the OCI in-sandbox PID-1 (ChildEntry::InProcess): a no-exec child with the full notif supervisor. So this affects a self-confining process (empty fs, net policy, named-unix datagram) — real, but niche, hence no destination-policy bypass and only an availability/consistency wart. A dedicated end-to-end test needs the OCI in-process harness (the python integration harness can't run under an off fs-gate), which is why this is a draft rather than a merge-ready PR with its own regression test.

Full sandlock-core lib suite is green (444) with no regressions; cargo clippy adds no new warnings. Happy to fold this in (or drop it) per your read on priority.

… the address family

Reference implementation — see the PR description for reachability and testing.

A named (pathname/abstract) AF_UNIX SOCK_DGRAM sendmsg/sendmmsg under a
destination policy with the unix fs-gate off returned EAFNOSUPPORT, while the
identical sendto Continued. `send_msghdr_on_behalf` now returns a `MsgOutcome`:
for a non-connected, non-IP address it Continues when the socket is AF_UNIX
(the kernel constrains an AF_UNIX socket to AF_UNIX destinations, so a racing
msg_name swap to an IP address cannot bypass the IP policy — gating on the
stable socket domain is TOCTOU-safe) and fails closed with EAFNOSUPPORT on an
AF_INET socket. sendmsg/sendmmsg return Continue on that outcome (in a batch
only at entry 0, since a unix socket carries only unix entries).

sendto's `_ => Continue` is tightened the same way: it now Continues only when
the socket is AF_UNIX, closing a latent TOCTOU where an AF_INET socket presenting
a transient AF_UNIX address could Continue and then have the address swapped to a
denied IP on the kernel's re-read.

Connected AF_UNIX (the multikernel#125 path) is unchanged — it still goes on-behalf.
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.

1 participant