Allow binding to localhost form within the darwin sandbox.

This allows, for example, Bazel to run itself within an integration test.
(Ideally Bazel would be using a Unix socket here, but allowing loopback
connections within a test seems legitimate.)

I'm not sure why `(allow network-bind)`, which I found in the various
configuration files in /usr/share/sandbox/ doesn't work... but I think
this change opens up the sandbox in the minimal way to allow this.

Fixes #10305 and improves upon #10068.

RELNOTES: None.
PiperOrigin-RevId: 282735849
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
index c7df774..297ca89 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
@@ -340,6 +340,7 @@
 
       if (!allowNetwork) {
         out.println("(deny network*)");
+        out.println("(allow network-inbound (local ip \"localhost:*\"))");
         out.println("(allow network* (remote ip \"localhost:*\"))");
         out.println("(allow network* (remote unix-socket))");
       }
diff --git a/src/test/shell/bazel/bazel_sandboxing_test.sh b/src/test/shell/bazel/bazel_sandboxing_test.sh
index 1a7145a..cff484b 100755
--- a/src/test/shell/bazel/bazel_sandboxing_test.sh
+++ b/src/test/shell/bazel/bazel_sandboxing_test.sh
@@ -377,6 +377,17 @@
   cmd = "curl --unix-socket ${socket} -o \$@ irrelevant-url",
   tags = [ ${tags} ],
 )
+
+genrule(
+  name = "loopback",
+  outs = [ "loopback.txt" ],
+  cmd = "python $python_server always $(pwd)/file_to_serve >port.txt & "
+      + "pid=\$\$!; "
+      + "while ! grep started port.txt; do sleep 1; done; "
+      + "port=\$\$(head -n 1 port.txt); "
+      + "curl -o \$@ localhost:\$\$port; "
+      + "kill \$\$pid",
+)
 EOF
 
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
@@ -451,6 +462,7 @@
 
   check_network_ok localhost
   check_network_ok unix-socket
+  check_network_ok loopback
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
     check_network_ok remote-ip
     check_network_ok remote-name
@@ -472,6 +484,7 @@
       ;;
   esac
   check_network_ok unix-socket --experimental_sandbox_default_allow_network=false
+  check_network_ok loopback --experimental_sandbox_default_allow_network=false
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
     check_network_not_ok remote-ip --experimental_sandbox_default_allow_network=false
     check_network_not_ok remote-name --experimental_sandbox_default_allow_network=false
@@ -483,6 +496,7 @@
 
   check_network_ok localhost
   check_network_ok unix-socket
+  check_network_ok loopback
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
     check_network_ok remote-ip
     check_network_ok remote-name
@@ -494,6 +508,7 @@
 
   check_network_ok localhost --experimental_sandbox_default_allow_network=false
   check_network_ok unix-socket --experimental_sandbox_default_allow_network=false
+  check_network_ok loopback --experimental_sandbox_default_allow_network=false
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
     check_network_ok remote-ip --experimental_sandbox_default_allow_network=false
     check_network_ok remote-name --experimental_sandbox_default_allow_network=false
@@ -515,6 +530,7 @@
       ;;
   esac
   check_network_ok unix-socket --experimental_sandbox_default_allow_network=true
+  check_network_ok loopback --experimental_sandbox_default_allow_network=true
   if [[ -n "${REMOTE_NETWORK_ADDRESS}" ]]; then
     check_network_not_ok remote-ip --experimental_sandbox_default_allow_network=true
     check_network_not_ok remote-name --experimental_sandbox_default_allow_network=true