SCMSender.beforeSave disconnects the endpoint on save: it shuts down and
closes the host fd, leaving fd = -1. Send already handles this state via
its IsSendClosed check (beforeSave sets sendShutdown), so writes fail
with EPIPE, but Recv had no guard and passed -1 to recvmsg(2), leaking
EBADF to applications for an fd that is still valid in their fd table.
Return ErrClosedForReceive instead, which the socket layer already
surfaces as read() == 0, matching Linux EOF semantics for a socket whose
read side is shut down and making a severed host endpoint behave like
any socket whose peer has gone away.
The guard keys on fd < 0 rather than IsRecvClosed: after a local SHUT_RD
on a live fd, the host socket may still hold queued data that must be
drained before EOF, and host recvmsg(2) handles that correctly.
PiperOrigin-RevId: 976063849
- In HostSender.HostReadiness, return hangup and readable/writeable events
((ReadableEvents | WriteableEvents | EventHUp | EventRdHUp) & mask) when
the host FD is closed (c.fd < 0), ensuring pollers (epoll/poll) are notified
of EOF and disconnection instead of masking the closed state.
- In SCMSender.beforeSave, return early if e.fd < 0 to make beforeSave
idempotent and prevent nil-pointer dereferences in fdnotifier.RemoveFD(-1)
on already-closed endpoints.
PiperOrigin-RevId: 975898094
The peer payload is sliced at the size of a struct ifinfomsg before anything measures it, so 4 bytes panic the Sentry and take the sandbox with it. Any user reaches it after unshare -Ur -n.
Check the length instead of re-testing a lookup that already succeeded. A short payload now answers EINVAL.
Fixes#14516
As of Linux commit 5d39580f68e6, SO_ATTACH_FILTER requires
CAP_NET_ADMIN for TCP sockets.
Skip in tests if we don't have it, and update Netstack to require it
too.
Make existing mutex and atomic ownership explicit for networking state.
Annotate self-locking helpers and synchronous forwarding paths, keeping
queue references and callback lifetime requirements in their comments.
Document collection, callback and helper identity limits where the
checker cannot enforce the existing ownership contract.
Co-authored-by: Hanzo Dev <[email protected]>
When calling cgo.Read, cgo.Write, and cgo.Sendto with a single-block BlockSeq,
the backing slice address was converted to uintptr via Addr(). Because Go's
garbage collector does not recognize uintptr as a live pointer reference, the
underlying backing array could be collected or reused during the CGO call.
This adds runtime.KeepAlive on the BlockSeq arguments after each single-block
CGO call in ReadToBlocks and WriteFromBlocks.
PiperOrigin-RevId: 968029244
Three nearly identical names covered three unrelated concepts
(ConnectedEndpoint, connectedEndpoint, connectionedEndpoint), and the
notification callbacks were named for the opposite of what they do
(RecvNotify woke writers, SendNotify woke readers).
- ConnectedEndpoint -> Sender, the write half of a connection
(implementations queueSender, HostSender, SCMSender); the
baseEndpoint field becomes connected -> peer: the type is named for
what you do with it, the field for its role to the holder.
- SendNotify -> NotifyDataReady, RecvNotify -> NotifyWriteSpace,
CloseNotify -> NotifyStateChange; each named for the wakeup it
delivers. NotifyStateChange must wake hangup-only pollers.
- queue's embedded waiter queues become readerWaiters/writerWaiters,
and baseEndpoint's embedded *waiter.Queue becomes a named field,
WaitQueue, so wakeup call sites name their target.
- writeShutdown and wrShutdown/rdShutdown ->
sendShutdown/recvShutdown, the shutdown(2) directions they track.
- A package doc block describes how the pieces fit together.
No behavior change.
PiperOrigin-RevId: 966732452
The shutdown notification paths only notified ReadableEvents and
WritableEvents, so a poller waiting only for POLLHUP or POLLRDHUP was
never woken and slept until its timeout. Linux wakes all waiters via
sk_state_change(). Notifications now include EventRdHUp and EventHUp
where the closed direction can newly satisfy them; over-notifying is
harmless since woken waiters re-check readiness.
PiperOrigin-RevId: 966685883
Libibverbs, in the function ibv_get_device_list, uses netlink to discover
devices available on a machine. If netlink is not supported, it will scan the
sysfs tree and collect information about devices there as a fallback. In the
second phase of device discovery, any devices are matched with a known driver.
If a device was found through netlink, a driver is automatically matched, while
devices found with sysfs will have to be matched to a driver through a known
vendor PCI ID table. Google's custom rNICs are not in the rdma-core table, and
so device discovery does not work with the current form of rdmaproxy out of the
box.
All information required by the protocol is gathered during the RDMA sysfs
snapshot collection, before chroot. Then any netlink messages produced by a
guest process will be served using the data collected in the snapshot, so the
sentry never has to make a real netlink request to the kernel.
We also add "resource" to the list of pciAttrNames because pcilib needs it to
be exposed to consider a device non-corrupt.
In iptables, a malformed ruleset containing jump loops (e.g. a rule jumping
to itself or a cycle of jumps between user-defined chains) previously caused
checkChain to recurse infinitely during packet evaluation, triggering a
goroutine stack overflow (runtime: goroutine stack exceeds 1000000000-byte
limit).
assisted-by:agy
PiperOrigin-RevId: 959981821
Prior to this CL, we assumed that execution would never fall through to
UserChainTargets, because every chain ends with an unconditional RETURN or
policy rule. This is not true with setsockopt(IP6T_SO_SET_REPLACE), with which
a userspace program can supply an arbitrary table layout.
Linux already rejects such tables, and so now we do too. Additionally, such
failures in Linux are handled by just calling ipt_error which logs an error
message instead of panicking, so replacing our panic with a BugTracebackOnce
makes sense as well. This traceback isn't triggered, but it's here just for
future-proofing.
PiperOrigin-RevId: 959886702
A zero-length recvmsg() on a unix socket returned 0 immediately,
without touching the message queue. On Linux, such a receive still
interacts with the queue. It blocks or returns EAGAIN when the queue
is empty. On packet (datagram and seqpacket) sockets, it dequeues the
next message: its control messages are delivered, MSG_TRUNC is set in
msg_flags when a non-empty payload is discarded, and the message is
consumed, unless MSG_PEEK is set. On stream sockets, no payload is
consumed, but the control messages at the current read position are
delivered.
Route zero-length receives through the same path as MSG_TRUNC reads
with a zero-byte destination, which already implements these
semantics.
PiperOrigin-RevId: 958610858
shutdown(SHUT_WR) on a unix datagram socket closed the queue it sends
to, which is the peer's receive queue: subsequent receives on the peer
returned 0 (EOF) instead of blocking or failing with EAGAIN. On Linux,
write shutdown propagates to the peer's read side only for stream and
seqpacket sockets (see unix_shutdown() in net/unix/af_unix.c); the
peer of a datagram socket is unaffected. Worse, for a bound datagram
socket with multiple senders, one sender's shutdown closed the shared
receive queue out from under every other sender.
Track write shutdown as endpoint-local state instead: local sends fail
with EPIPE, and the peer's read side is only closed on stream and
seqpacket sockets.
Also, we now eport POLLRDHUP and POLLHUP on connectionless unix sockets.
Their Readiness() never included these bits. Linux sets EPOLLRDHUP once
the read side is shut down, and EPOLLHUP once both sides are shutdown.
PiperOrigin-RevId: 958555643
- Userspace can use `chain-id` to refer to a chain in a batch request.
- Jump/goto/verdict maps can use chain-id in a batch request.
- Chain-id is not used for updating/deleting a chain.
- Can be overwritten.
PiperOrigin-RevId: 957707305
- There was no lock taken for Nftables rule evaluation.
So, it could happen that while processing and simultaneous update,
a packet could pass to half updated ruleset.
- Changed logic to replace atomic pointer, instead of
replacing fields in the Nftables.
- All the rule evaluation, can now go without needing any reader lock.
- A lock is require for updating Nftables object though,
to serialize the Netlink messages.
PiperOrigin-RevId: 957516505
NewSCMCredentials previously resolved the specified PID into a thread group with separate calls to ThreadGroupWithID() and PIDNamespacedIDs().
Both of these functions separately take and release the TaskSet lock.
This causes a race condition where between the two function calls, the thread group might get reaped, leading to the panic() being reached.
This commit addresses this issue by moving the thread group resolution/PID namespace map creation into a single critical section.
A regression syscall test is also included.
Reported-by: [email protected]
- Added support for NFT_MSG_DELRULE/NFT_MSG_DESTROYRULE
- Added `destroy` interface for operations to cleanup.
- Added `nftables.GC` and `table.GC` to delete left out objects.
PiperOrigin-RevId: 956605231
Linux skips the mount-level write check when opening a character device, block device, FIFO, or socket, so write-opening /dev/null on a read-only bind mount succeeds.
Mark the remaining FileDescriptions backed by special-file inodes. Also skip overlay copy-up for writable opens of special files; Linux overlayfs applies the same special_file() exception before deciding whether copy-up is required.
Add regression coverage for character devices and FIFOs through read-only bind mounts.
The masq op updates the packet's source IP address to the
primary IP address of the router's outgoing interface.
- Added support masq op.
- Updated Dockerfile to include `nc` and `ip tools`.
- Fix setting reg in nft_nat.go as well.
PiperOrigin-RevId: 951260153
Host networking did not have checkpoint/restore support. A sandbox running with `--network=host` could not be checkpointed because `hostinet.Stack` was not savable, and restore did not define what should happen to open host sockets.
This change makes the hostinet stack savable and defines that restore contract. Host socket fds cannot cross a checkpoint boundary, so `Socket.fd` is tagged `state:"nosave"` and save does not touch host sockets. With checkpoint `--leave-running`, the original sandbox keeps serving traffic on its existing connections. If save fails, the sandbox is left unharmed.
Without `--leave-running`, the sandbox exits after save and the host kernel closes its sockets. That sends `FIN` or `RST` so remote peers do not hang on half-open connections.
In the restored sandbox, `afterLoad` sets each socket fd to `-1`. Host syscalls then fail with `EBADF`. `Readiness` reports hangup and error so `epoll` waiters wake immediately, and tasks that were blocked in I/O see `EBADF` when their syscall restarts. `State()` reports no TCP state for these sockets rather than logging a warning on every `/proc/net/tcp` read. Applications are expected to reconnect after restore.
The stack's host-derived state is not saved. This includes `/proc/net/dev`, `/proc/net/snmp`, TCP buffer sizes, and allowed socket types. During restore, runsc configures a fresh hostinet stack before seccomp filters are installed. `ReplaceConfig` then copies the destination host configuration into the deserialized stack and transfers ownership of the fresh proc net handles. The restored sandbox therefore uses the destination host configuration and limits.
A hostinet checkpoint contains no netstack state and a netstack checkpoint contains no hostinet state, so the checkpoint now records the network type in its metadata. Restore fails with a clear error when the network stack kind differs between checkpoint and restore, instead of panicking inside `ReplaceConfig` during kernel load. Sandbox and none networking both use netstack and remain interchangeable. Checkpoints taken before the network type was recorded skip this check.
The hostinet `save_resume` syscall tests are enabled because save does not touch host sockets. The save and restore syscall tests remain excluded because they expect sockets to keep working after restore.
Container tests cover restored socket behavior for TCP, UDP, `epoll`, and a blocked accept. They also cover remote peer close after checkpoint, continued service after checkpoint `--leave-running`, and the error when restoring a host networking checkpoint with sandbox networking. The focused hostinet unit tests and the hostinet `save_resume` syscall tests pass on `x86_64`. The checkpoint/restore user guide documents the restored socket behavior.
Fixes#6243
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/13404 from shayonj:hostinet-save-restore-v2 734480ee348d774346ec024b6483b89ea0a91adb
PiperOrigin-RevId: 950854464
This change refactors the network configuration flow during sandbox restore
and defers the creation of network links and routes in runsc to run after
seccomp filters are installed.
- Replaced ReplaceConfig with ResetConfig in inet.Stack. Introduced
inet.NetworkArgs to configure the stack during restore, updating k.LoadFrom
to use it.
- Renamed CreateLinksAndRoutes URPC to SetNetworkArgs, which now configures
host sockets before seccomp is installed, deferring link/route creation to run
after seccomp.
- Fixed S/R support by saving and restoring limit/burst state.
- Minor seccomp filter adjustments and test updates.
PiperOrigin-RevId: 945995430
Previously, during sandbox restore the network configuration was restored by
creating a new network stack (which has all the config scraped from the host)
and the replacing this new config such as NICs, routes and IP addresses from
the new stack to the loaded/restored stack.
This change refactors the process by introducing a new `inet.NetworkArgs`
interface that abstracts how the network stack is configured. The `Loader` now
implements this interface and configures the loaded stack directly using the
configuration scraped from the host during restore. `Kernel.LoadFrom` accepts
this interface (instead of stack), allowing it to configure the restored stack
using either the Loader's configuration.
PiperOrigin-RevId: 941330876
- This change enables sockets to set and get the `SO_MARK` option, which marks
outgoing packets.
- It also implements Netfilter (iptables) support for matching
packet marks using the `mark` match extension.
- Added unit and E2E tests to verify mark match and capabilities.
PiperOrigin-RevId: 938123591
Before this change, gvisor dropped the packets if owner was marked nil in the
packet. Linux does not drop the packet in this case and allows the packet to
flow through the other rules. This changes fixes the behavior with gvisor and
makes it compatible with linux. Added an iptables test to verify the fix.
PiperOrigin-RevId: 937515484
The warning for unsupported ifi_flags printed ifinfomsg.Change instead of
ifinfomsg.Flags. Print the field actually being validated.
Co-authored-by: Hanzo Dev <[email protected]>
This frees implementations of getsockopt to no longer return EINVAL when
userspace specifies a buffer smaller than the output.
Some callers, such as resolved, pass a null buffer to probe the output
size before passing a real buffer to getsockopt. This allows those
callers to succeed.
This commit also removes EINVAL returns from netlink route sockets related to
the userspace-provided size to allow this pattern.