fix(ext/node): require --allow-net=unix for node:net unix sockets (#35835)
Deno's native Unix-domain socket path treats a socket as both a
filesystem entry and an outbound network primitive. Connecting to or
listening on a Unix socket requires filesystem access to the socket path
*and* an `--allow-net=unix:<path>` grant. This is deliberate: read/write
access to a socket path such as `/var/run/docker.sock` should not, by
itself, be enough to reach local IPC services like Docker, dbus, or
podman. The native helper `check_unix_socket_path` in
`ext/net/ops_unix.rs` enforces both checks.
The node-compat `PipeWrap` path — the native backing for `node:net` Unix
sockets — only performed the filesystem `check_open` check. It never
required the Unix-socket network grant. As a result,
`node:net.createConnection(path)` and `net.createServer().listen(path)`
could reach a Unix socket under `--deny-net` as long as filesystem
permission for the socket path was granted, diverging from the native
`Deno.connect({ transport: "unix" })` and `Deno.listen({ transport:
"unix" })` behaviour.
Rather than duplicating the check pair, `check_unix_socket_path` is now
public in `deno_net` (returning `PermissionCheckError` directly; its
`ext/net` call sites keep working through the existing `#[from]`
conversion into `NetError`) and `PipeWrap::connect`, `bind`, and
`listen` call it, so the node-compat path enforces exactly the same
invariant as the native one and the two cannot drift apart again.
Sharing the helper also fixes abstract socket handling (Linux, leading
NUL). Abstract sockets have no filesystem entry, so — like the native
path — they now skip the filesystem check and are governed by the
network check alone. Previously the node-compat path incorrectly
required filesystem permission on the NUL-prefixed pseudo-path, which
no filesystem grant could meaningfully scope.
Note that on Windows `PipeWrap` backs `node:net` named pipes
(`\\.\pipe\...`), which now also require a net grant in addition to the
filesystem check. This is intentional: the threat model is the same
(e.g. Docker Desktop listens on `\\.\pipe\docker_engine`). `unix:` net
rules parse on all platforms and accept any absolute path, so named
pipes can be granted with `--allow-net=unix:\\.\pipe\<name>` or a
blanket `--allow-net`.
Spec tests: one step grants full `--allow-read`/`--allow-write` with
`--deny-net` and asserts that `connect` and `bind` through the
low-level pipe binding are denied, including for an abstract path. A
Linux-only step grants only `--allow-net` (no filesystem permissions)
and asserts that binding an abstract socket succeeds while binding a
path-based socket is still denied by the filesystem check.