diff options
author | Philipp Wollermann <philwo@google.com> | 2017-03-24 21:26:02 +0000 |
---|---|---|
committer | Philipp Wollermann <philwo@google.com> | 2017-03-27 11:36:36 +0000 |
commit | 21c1073612760a0f011257197b98152e3356d7ae (patch) | |
tree | 6d2352e3d990b71fd50e9c14f0435a12e49961aa | |
parent | 6f1d60839c6dc16d7e8b9d5c0d85acadc3fab1f6 (diff) |
sandbox: Enable the process-wrapper + symlink tree sandbox on FreeBSD.
Extract the process-wrapper + symlink tree sandbox strategy into its own
class and allow its use in FreeBSD.
RELNOTES: Bazel can now use the process-wrapper + symlink tree based sandbox implementation in FreeBSD.
--
PiperOrigin-RevId: 151171652
MOS_MIGRATED_REVID=151171652
4 files changed, 163 insertions, 49 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java index 8825025ebf..22a980bc07 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java @@ -47,14 +47,8 @@ import java.util.concurrent.atomic.AtomicReference; contextType = SpawnActionContext.class ) public class LinuxSandboxedStrategy extends SandboxStrategy { - private static Boolean sandboxingSupported = null; - public static boolean isSupported(CommandEnvironment env) { - if (sandboxingSupported == null) { - sandboxingSupported = - ProcessWrapperRunner.isSupported(env) || LinuxSandboxRunner.isSupported(env); - } - return sandboxingSupported.booleanValue(); + return LinuxSandboxRunner.isSupported(env); } private final SandboxOptions sandboxOptions; @@ -62,7 +56,6 @@ public class LinuxSandboxedStrategy extends SandboxStrategy { private final Path execRoot; private final boolean verboseFailures; private final String productName; - private final boolean fullySupported; private final UUID uuid = UUID.randomUUID(); private final AtomicInteger execCounter = new AtomicInteger(); @@ -71,8 +64,7 @@ public class LinuxSandboxedStrategy extends SandboxStrategy { BuildRequest buildRequest, BlazeDirectories blazeDirs, boolean verboseFailures, - String productName, - boolean fullySupported) { + String productName) { super( buildRequest, blazeDirs, @@ -83,7 +75,6 @@ public class LinuxSandboxedStrategy extends SandboxStrategy { this.execRoot = blazeDirs.getExecRoot(); this.verboseFailures = verboseFailures; this.productName = productName; - this.fullySupported = fullySupported; } @Override @@ -113,7 +104,17 @@ public class LinuxSandboxedStrategy extends SandboxStrategy { throw new UserExecException("I/O error during sandboxed execution", e); } - SandboxRunner runner = getSandboxRunner(sandboxPath, sandboxExecRoot, writableDirs); + SandboxRunner runner = + new LinuxSandboxRunner( + execRoot, + sandboxPath, + sandboxExecRoot, + writableDirs, + getTmpfsPaths(), + getReadOnlyBindMounts(blazeDirs, sandboxExecRoot), + verboseFailures, + sandboxOptions.sandboxDebug); + try { runSpawn( spawn, @@ -140,23 +141,6 @@ public class LinuxSandboxedStrategy extends SandboxStrategy { } } - private SandboxRunner getSandboxRunner( - Path sandboxPath, Path sandboxExecRoot, Set<Path> writableDirs) throws UserExecException { - if (fullySupported) { - return new LinuxSandboxRunner( - execRoot, - sandboxPath, - sandboxExecRoot, - writableDirs, - getTmpfsPaths(), - getReadOnlyBindMounts(blazeDirs, sandboxExecRoot), - verboseFailures, - sandboxOptions.sandboxDebug); - } else { - return new ProcessWrapperRunner(execRoot, sandboxExecRoot, verboseFailures); - } - } - @Override protected ImmutableSet<Path> getWritableDirs(Path sandboxExecRoot, Map<String, String> env) throws IOException { diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperRunner.java index f3ee9d14d1..1d6271925f 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperRunner.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperRunner.java @@ -18,7 +18,6 @@ import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.shell.Command; import com.google.devtools.build.lib.util.OsUtils; import com.google.devtools.build.lib.vfs.Path; -import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -28,28 +27,21 @@ import java.util.Map; * platforms and gives at least some isolation between running actions. */ final class ProcessWrapperRunner extends SandboxRunner { + private static final String PROCESS_WRAPPER = "process-wrapper" + OsUtils.executableExtension(); + private final Path execRoot; private final Path sandboxExecRoot; - ProcessWrapperRunner( - Path execRoot, Path sandboxExecRoot, boolean verboseFailures) { + ProcessWrapperRunner(Path execRoot, Path sandboxExecRoot, boolean verboseFailures) { super(verboseFailures); this.execRoot = execRoot; this.sandboxExecRoot = sandboxExecRoot; } static boolean isSupported(CommandEnvironment commandEnv) { - PathFragment embeddedTool = - commandEnv - .getBlazeWorkspace() - .getBinTools() - .getExecPath("process-wrapper" + OsUtils.executableExtension()); - if (embeddedTool == null) { - // The embedded tool does not exist, meaning that we don't support sandboxing (e.g., while - // bootstrapping). - return false; - } - return true; + // We can only use this runner, if the process-wrapper exists in the embedded tools. + // This might not always be the case, e.g. while bootstrapping. + return commandEnv.getBlazeWorkspace().getBinTools().getExecPath(PROCESS_WRAPPER) != null; } @Override diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java new file mode 100644 index 0000000000..f7b310a2fe --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java @@ -0,0 +1,126 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.sandbox; + +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.actions.ActionExecutionContext; +import com.google.devtools.build.lib.actions.ActionStatusMessage; +import com.google.devtools.build.lib.actions.ExecException; +import com.google.devtools.build.lib.actions.ExecutionStrategy; +import com.google.devtools.build.lib.actions.Executor; +import com.google.devtools.build.lib.actions.Spawn; +import com.google.devtools.build.lib.actions.SpawnActionContext; +import com.google.devtools.build.lib.actions.UserExecException; +import com.google.devtools.build.lib.analysis.BlazeDirectories; +import com.google.devtools.build.lib.buildtool.BuildRequest; +import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.vfs.FileSystemUtils; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.PathFragment; +import java.io.IOException; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +/** Strategy that uses sandboxing to execute a process. */ +@ExecutionStrategy( + name = {"sandboxed"}, + contextType = SpawnActionContext.class +) +public class ProcessWrapperSandboxedStrategy extends SandboxStrategy { + public static boolean isSupported(CommandEnvironment env) { + return ProcessWrapperRunner.isSupported(env); + } + + private final SandboxOptions sandboxOptions; + private final BlazeDirectories blazeDirs; + private final Path execRoot; + private final boolean verboseFailures; + private final String productName; + + private final UUID uuid = UUID.randomUUID(); + private final AtomicInteger execCounter = new AtomicInteger(); + + ProcessWrapperSandboxedStrategy( + BuildRequest buildRequest, + BlazeDirectories blazeDirs, + boolean verboseFailures, + String productName) { + super(buildRequest, blazeDirs, verboseFailures, buildRequest.getOptions(SandboxOptions.class)); + this.sandboxOptions = buildRequest.getOptions(SandboxOptions.class); + this.blazeDirs = blazeDirs; + this.execRoot = blazeDirs.getExecRoot(); + this.verboseFailures = verboseFailures; + this.productName = productName; + } + + @Override + protected void actuallyExec( + Spawn spawn, + ActionExecutionContext actionExecutionContext, + AtomicReference<Class<? extends SpawnActionContext>> writeOutputFiles) + throws ExecException, InterruptedException { + Executor executor = actionExecutionContext.getExecutor(); + executor + .getEventBus() + .post( + ActionStatusMessage.runningStrategy( + spawn.getResourceOwner(), "processwrapper-sandbox")); + SandboxHelpers.reportSubcommand(executor, spawn); + + // Each invocation of "exec" gets its own sandbox. + Path sandboxPath = SandboxHelpers.getSandboxRoot(blazeDirs, productName, uuid, execCounter); + Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName()); + + Set<Path> writableDirs; + SymlinkedExecRoot symlinkedExecRoot = new SymlinkedExecRoot(sandboxExecRoot); + ImmutableSet<PathFragment> outputs = SandboxHelpers.getOutputFiles(spawn); + try { + writableDirs = getWritableDirs(sandboxExecRoot, spawn.getEnvironment()); + symlinkedExecRoot.createFileSystem( + getMounts(spawn, actionExecutionContext), outputs, writableDirs); + } catch (IOException e) { + throw new UserExecException("I/O error during sandboxed execution", e); + } + + SandboxRunner runner = new ProcessWrapperRunner(execRoot, sandboxExecRoot, verboseFailures); + try { + runSpawn( + spawn, + actionExecutionContext, + spawn.getEnvironment(), + symlinkedExecRoot, + outputs, + runner, + writeOutputFiles); + } finally { + if (!sandboxOptions.sandboxDebug) { + try { + FileSystemUtils.deleteTree(sandboxPath); + } catch (IOException e) { + executor + .getEventHandler() + .handle( + Event.warn( + String.format( + "Cannot delete sandbox directory after action execution: %s (%s)", + sandboxPath.getPathString(), e))); + } + } + } + } +} 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 d27bd5517f..26bf01ec69 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 @@ -49,18 +49,22 @@ final class SandboxActionContextProvider extends ActionContextProvider { switch (OS.getCurrent()) { case LINUX: if (LinuxSandboxedStrategy.isSupported(env)) { - boolean fullySupported = LinuxSandboxRunner.isSupported(env); - if (!fullySupported - && !buildRequest.getOptions(SandboxOptions.class).ignoreUnsupportedSandboxing) { + contexts.add( + new LinuxSandboxedStrategy( + buildRequest, + env.getDirectories(), + verboseFailures, + env.getRuntime().getProductName())); + } else { + if (!buildRequest.getOptions(SandboxOptions.class).ignoreUnsupportedSandboxing) { env.getReporter().handle(Event.warn(SANDBOX_NOT_SUPPORTED_MESSAGE)); } contexts.add( - new LinuxSandboxedStrategy( + new ProcessWrapperSandboxedStrategy( buildRequest, env.getDirectories(), verboseFailures, - env.getRuntime().getProductName(), - fullySupported)); + env.getRuntime().getProductName())); } break; case DARWIN: @@ -78,6 +82,14 @@ final class SandboxActionContextProvider extends ActionContextProvider { } } break; + case FREEBSD: + contexts.add( + new ProcessWrapperSandboxedStrategy( + buildRequest, + env.getDirectories(), + verboseFailures, + env.getRuntime().getProductName())); + break; default: // No sandboxing available. } |