Allow binding sockets in the macOS sandbox when networking is blocked - #30865
Closed
fmeum wants to merge 4 commits into
Closed
Allow binding sockets in the macOS sandbox when networking is blocked#30865fmeum wants to merge 4 commits into
fmeum wants to merge 4 commits into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
fmeum
force-pushed
the
claude/bazel-issue-14828-4ms8yp
branch
from
August 26, 2026 11:18
2a276ec to
bc8d63c
Compare
fmeum
force-pushed
the
claude/bazel-issue-14828-4ms8yp
branch
from
August 26, 2026 11:25
bc8d63c to
fdaa76b
Compare
The sandbox profile generated for block-network spawns denied `network-bind`: it allowed accepting and establishing loopback connections, but binding a socket - what any local test server does first - was still rejected by `(deny network*)`. As a result, tests using e.g. OkHttp MockWebServer or Dropwizard failed on macOS while passing inside the Linux sandbox's network namespace. Allow `network-bind` for any local address: servers commonly bind to the wildcard address (0.0.0.0 or ::), which the "localhost" filter does not match, and a bound socket still cannot exchange traffic with other hosts because inbound and outbound traffic remains restricted to loopback. Also allow local Unix domain sockets, which are filesystem-scoped IPC, in both directions. This matches the behavior of the Linux sandbox, where arbitrary binds succeed but only the loopback interface exists. Adds a regression test that inspects the generated sandbox profile. Fixes bazelbuild#14828
Extend bazel_sandboxing_networking_test.sh, which runs on both Linux and macOS, with in-sandbox server coverage for the various kinds of localhost binding: * binding to 127.0.0.1, ::1, and the "localhost" hostname (in addition to the existing wildcard-address coverage via :loopback), * binding and connecting to a Unix domain socket inside the sandbox. Exercising real binds through the sandbox is what actually establishes that the profile works; asserting on the generated profile text would not. testing_server.py gains a --bind_address flag so the test server can bind a specific address instead of the wildcard address. The :loopback target now also carries the tags under test so that the tag-based block-network scenario exercises in-sandbox servers as well.
The negative direction - blocked spawns must not be able to reach anything beyond loopback - was previously only covered when REMOTE_NETWORK_ADDRESS was explicitly set, which CI does not do. Add hermetic checks that do not require Internet connectivity, using a non-loopback address of the local machine: one genrule connects to the existing wildcard-bound test server through that address, another binds its own server to it. The expected outcome differs per platform, so assert it either way instead of skipping. The linux-sandbox runs blocked spawns in a network namespace that only has a loopback interface, so the address is unreachable there and the bind fails. The macOS sandbox cannot express "loopback only": the host part of an SBPL "ip" filter may only be "*" or "localhost", and "localhost" matches every address assigned to the local machine rather than just 127.0.0.1 and ::1, so both checks still succeed there. Neither sandbox lets a blocked spawn reach any other host, which remains covered by the remote-ip and remote-name checks. Both checks are skipped on machines without a non-loopback address. Also make testing_server.py fail fast when a bind cannot succeed: retrying a permanent failure with a different port would loop forever and hang the caller waiting for the "started" line.
The flag is only implemented by the linux-sandbox, which sets the hostname to "localhost" inside a UTS namespace. Everywhere else it is silently accepted and does nothing, and the test returned early outside Linux, leaving that behavior unasserted. Run the same test with and without the flag and compare the hostname it observes: on Linux it must become "localhost", everywhere else it must be unchanged. Comparing against the hostname seen by the very same test avoids having to predict how the machine's hostname resolves.
fmeum
force-pushed
the
claude/bazel-issue-14828-4ms8yp
branch
from
August 26, 2026 12:53
fdaa76b to
1b8679e
Compare
fmeum
marked this pull request as ready for review
August 26, 2026 12:54
meisterT
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The macOS sandbox denied
bind()outright when network access was blocked, so any action that starts a local server failed under--experimental_sandbox_default_allow_network=falseor theblock-networktag. This adds three rules to the generated SBPL profile: binding to any local address, and Unix domain sockets in both directions. Servers commonly bind the wildcard address (0.0.0.0or::), which thelocalhostfilter does not match, which is why the bind rule is unrestricted.Outbound traffic stays restricted to loopback, so a blocked spawn still cannot reach another host: connecting to the default gateway and to a public address both fail with
EPERM, while loopback and the machine's own addresses succeed.One limitation is worth flagging for review and is documented in the code. Inbound traffic cannot be constrained the same way, because macOS decides
network-inboundfrom the local address alone, and itslocalhostfilter matches every address assigned to the machine rather than just127.0.0.1and::1. Filteringnetwork-inboundon the remote address is not an option either: such a rule compiles but has no effect, confirmed by placing(deny network-inbound (remote ip "*:*"))last in the profile and observing that accepts still succeed, whereas the same rule keyed on the local address breaks listening. A peer elsewhere on the network can therefore reach a spawn that listens on a non-loopback address. The Linux sandbox does not have this gap because its network namespace only ever has a loopback interface. Closing it would mean disallowing the wildcard bind, which is the bug this PR fixes.The remaining commits are test-only.
The new coverage is added as integration tests rather than as assertions on the generated profile text, since exercising real binds through the sandbox is what actually establishes that the profile works, and it runs on Linux as well.
DarwinSandboxedSpawnRunnerTestis left untouched.The networking integration test gains cases for binding to
127.0.0.1,::1,localhost, a Unix socket, and a non-loopback address of the machine, plus a check that blocked spawns cannot reach a non-loopback address. Where the expected outcome genuinely differs per platform it is asserted either way rather than skipped, so no case is silently dropped on either OS.--sandbox_fake_hostnameis only implemented by the linux-sandbox and is silently accepted elsewhere. That test previously returned early outside Linux; it now runs the same test with and without the flag and asserts that the hostname becomeslocalhoston Linux and is unchanged everywhere else.testing_server.pyretried every bind failure with a new port forever, which would hang a caller waiting for thestartedline if the address could never be bound. It now only retries onEADDRINUSE.Motivation
Fixes #14828.
Build API Changes
No
Checklist
Release Notes
RELNOTES: The macOS sandbox now allows actions to bind sockets when network access is blocked, matching the behavior of the Linux sandbox. Note that macOS cannot restrict inbound connections by peer, so an action that listens on a non-loopback address is reachable from other hosts on the network; outbound traffic remains restricted to loopback.