diff options
author | jmmv <jmmv@google.com> | 2018-03-22 15:12:00 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-03-22 15:13:47 -0700 |
commit | 3a7b8bc2abeaf8b8647c037bed1dd5fd73b8392b (patch) | |
tree | 3da0966322e6c347efbc59851f2a9acb9a1fd13d /src/main/java/com/google/devtools/build/lib/sandbox | |
parent | 4ef3dc67e8226ee56a098e3174be5dce2685c70f (diff) |
Add support for sandboxfs-based sandboxing to macOS.
This only modifies the DarwinSandboxedSpawnRunner for now and leaves behind
the Linux version.
The latter is a bit more complex to do because of the need to deal with tmpfs
and bind-mount interactions. We expect sandboxfs to have the biggest impact
on macOS anyway, not Linux, so this can wait until this has proven that it
deserves staying for the long-term.
Tested: Manually ran a self-build of Bazel on a version of Bazel built with
these changes and the build passed.
RELNOTES: None.
PiperOrigin-RevId: 190133429
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/sandbox')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java | 103 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java | 4 |
2 files changed, 76 insertions, 31 deletions
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 6bf48fe22b..e80edf03f1 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 @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.sandbox; import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -49,6 +50,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; /** Spawn runner that uses Darwin (macOS) sandboxing to execute a process. */ @ExecutionStrategy( @@ -56,7 +58,14 @@ import java.util.Set; contextType = SpawnActionContext.class ) final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { - private static final String SANDBOX_EXEC = "/usr/bin/sandbox-exec"; + + /** Path to the {@code getconf} system tool to use. */ + @VisibleForTesting + static String getconfBinary = "/usr/bin/getconf"; + + /** Path to the {@code sandbox-exec} system tool to use. */ + @VisibleForTesting + static String sandboxExecBinary = "/usr/bin/sandbox-exec"; public static boolean isSupported(CommandEnvironment cmdEnv) { if (OS.getCurrent() != OS.DARWIN) { @@ -67,7 +76,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { } List<String> args = new ArrayList<>(); - args.add(SANDBOX_EXEC); + args.add(sandboxExecBinary); args.add("-p"); args.add("(version 1) (allow default)"); args.add("/usr/bin/true"); @@ -90,6 +99,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { private final String productName; private final Path processWrapper; private final Optional<Duration> timeoutKillDelay; + private final @Nullable SandboxfsProcess sandboxfsProcess; /** * The set of directories that always should be writable, independent of the Spawn itself. @@ -109,7 +119,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { */ DarwinSandboxedSpawnRunner(CommandEnvironment cmdEnv, Path sandboxBase, String productName) throws IOException { - this(cmdEnv, sandboxBase, productName, Optional.empty()); + this(cmdEnv, sandboxBase, productName, Optional.empty(), null); } /** @@ -125,7 +135,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { DarwinSandboxedSpawnRunner( CommandEnvironment cmdEnv, Path sandboxBase, String productName, Duration timeoutKillDelay) throws IOException { - this(cmdEnv, sandboxBase, productName, Optional.of(timeoutKillDelay)); + this(cmdEnv, sandboxBase, productName, Optional.of(timeoutKillDelay), null); } /** @@ -137,12 +147,15 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { * @param productName the product name to use * @param timeoutKillDelay an optional, additional grace period before killing timing out * commands. If not present, then no grace period is used and commands are killed instantly. + * @param sandboxfsProcess instance of the sandboxfs process to use; may be null for none, in + * which case the runner uses a symlinked sandbox */ DarwinSandboxedSpawnRunner( CommandEnvironment cmdEnv, Path sandboxBase, String productName, - Optional<Duration> timeoutKillDelay) + Optional<Duration> timeoutKillDelay, + @Nullable SandboxfsProcess sandboxfsProcess) throws IOException { super(cmdEnv, sandboxBase); this.execRoot = cmdEnv.getExecRoot(); @@ -153,6 +166,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { this.localEnvProvider = new XcodeLocalEnvProvider(cmdEnv.getRuntime().getProductName(), cmdEnv.getClientEnv()); this.timeoutKillDelay = timeoutKillDelay; + this.sandboxfsProcess = sandboxfsProcess; } private static void addPathToSetIfExists(FileSystem fs, Set<Path> paths, String path) @@ -200,7 +214,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { */ private static String getConfStr(String confVar) throws IOException { String[] commandArr = new String[2]; - commandArr[0] = "/usr/bin/getconf"; + commandArr[0] = getconfBinary; commandArr[1] = confVar; Command cmd = new Command(commandArr); CommandResult res; @@ -219,9 +233,13 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { Path sandboxPath = getSandboxRoot(); Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName()); - // Each sandboxed action runs in its own execroot, so we don't need to make the temp directory's + // Each sandboxed action runs in its own directory so we don't need to make the temp directory's // name unique (like we have to with standalone execution strategy). - Path tmpDir = sandboxExecRoot.getRelative("tmp"); + // + // Note that, for sandboxfs-based executions, this temp directory lives outside of the sandboxfs + // instance. This is perfectly fine (because sandbox-exec controls accesses to this directory) + // and is actually desirable for performance reasons. + Path tmpDir = sandboxPath.getRelative("tmp"); Map<String, String> environment = localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, tmpDir.getPathString()); @@ -253,33 +271,60 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { ImmutableList<String> commandLine = ImmutableList.<String>builder() - .add(SANDBOX_EXEC) + .add(sandboxExecBinary) .add("-f") .add(sandboxConfigPath.getPathString()) .addAll(processWrapperCommandLineBuilder.build()) .build(); boolean allowNetworkForThisSpawn = allowNetwork || Spawns.requiresNetwork(spawn); - SandboxedSpawn sandbox = - new SymlinkedSandboxedSpawn( - sandboxPath, - sandboxExecRoot, - commandLine, - environment, - SandboxHelpers.getInputFiles(spawn, policy, execRoot), - outputs, - writableDirs) { - @Override - public void createFileSystem() throws IOException { - super.createFileSystem(); - writeConfig( - sandboxConfigPath, - writableDirs, - getInaccessiblePaths(), - allowNetworkForThisSpawn, - statisticsPath); - } - }; + + Map<PathFragment, Path> inputs = SandboxHelpers.getInputFiles(spawn, policy, execRoot); + + SandboxedSpawn sandbox; + if (sandboxfsProcess != null) { + sandbox = + new SandboxfsSandboxedSpawn( + sandboxfsProcess, + sandboxPath, + commandLine, + environment, + inputs, + outputs, + ImmutableSet.of()) { + @Override + public void createFileSystem() throws IOException { + super.createFileSystem(); + writeConfig( + sandboxConfigPath, + writableDirs, + getInaccessiblePaths(), + allowNetworkForThisSpawn, + statisticsPath); + } + }; + } else { + sandbox = + new SymlinkedSandboxedSpawn( + sandboxPath, + sandboxExecRoot, + commandLine, + environment, + inputs, + outputs, + writableDirs) { + @Override + public void createFileSystem() throws IOException { + super.createFileSystem(); + writeConfig( + sandboxConfigPath, + writableDirs, + getInaccessiblePaths(), + allowNetworkForThisSpawn, + statisticsPath); + } + }; + } return runSpawn(spawn, sandbox, policy, execRoot, tmpDir, timeout, statisticsPath); } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java index 9067ba42e5..37b100cf6d 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java @@ -84,11 +84,11 @@ final class SandboxActionContextProvider extends ActionContextProvider { // This is the preferred sandboxing strategy on macOS. if (DarwinSandboxedSpawnRunner.isSupported(cmdEnv)) { - // TODO(jmmv): Inject process into spawn runner. SpawnRunner spawnRunner = withFallback( cmdEnv, - new DarwinSandboxedSpawnRunner(cmdEnv, sandboxBase, productName, timeoutKillDelay)); + new DarwinSandboxedSpawnRunner(cmdEnv, sandboxBase, productName, timeoutKillDelay, + process)); contexts.add(new DarwinSandboxedStrategy(cmdEnv.getExecRoot(), spawnRunner)); } |