From d0d6cf7f2a88624e443a7f5e50e21e6653f73d3e Mon Sep 17 00:00:00 2001 From: Yue Gan Date: Mon, 29 Aug 2016 11:21:52 +0000 Subject: Add LinuxAlmostSandboxRunner which uses process-wrapper instead of linux-sandbox in the same sandbox execution environment. -- Change-Id: I51a875a87d92ae13ad575eb41026ce5d3db94f8b Reviewed-on: https://bazel-review.googlesource.com/#/c/5611/ MOS_MIGRATED_REVID=131578077 --- .../lib/sandbox/LinuxAlmostSandboxRunner.java | 82 ++++++++++++++++++++++ .../build/lib/sandbox/LinuxSandboxRunner.java | 80 ++++++++++++++------- .../build/lib/sandbox/LinuxSandboxedStrategy.java | 38 +++++++--- .../lib/sandbox/SandboxActionContextConsumer.java | 4 +- .../lib/sandbox/SandboxActionContextProvider.java | 10 ++- 5 files changed, 175 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/sandbox/LinuxAlmostSandboxRunner.java diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxAlmostSandboxRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxAlmostSandboxRunner.java new file mode 100644 index 0000000000..73185f3bf0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxAlmostSandboxRunner.java @@ -0,0 +1,82 @@ +// Copyright 2016 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.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.util.OsUtils; +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.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Helper class for running the Linux sandbox. This runner is a subclass of LinuxSandboxRunner which + * uses process-wrapper instead of linux-sandbox in the same sandbox execution environment. + */ +public class LinuxAlmostSandboxRunner extends LinuxSandboxRunner { + + LinuxAlmostSandboxRunner( + Path execRoot, + Path sandboxExecRoot, + Set writablePaths, + List inaccessiblePaths, + boolean verboseFailures, + boolean sandboxDebug) { + super( + execRoot, sandboxExecRoot, writablePaths, inaccessiblePaths, verboseFailures, sandboxDebug); + } + + 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; + } + + @Override + protected void runPreparation(int timeout, boolean allowNetwork) throws IOException { + // Create all needed directories. + for (Path writablePath : super.getWritablePaths()) { + if (writablePath.startsWith(super.getSandboxExecRoot())) { + FileSystemUtils.createDirectoryAndParents(writablePath); + } + } + } + + @Override + protected List runCommandLineArgs(List spawnArguments, int timeout) { + List commandLineArgs = new ArrayList<>(); + + commandLineArgs.add(super.getExecRoot().getRelative("_bin/process-wrapper").getPathString()); + commandLineArgs.add(Integer.toString(timeout)); + commandLineArgs.add("5"); /* kill delay: give some time to print stacktraces and whatnot. */ + commandLineArgs.add("-"); /* stdout. */ + commandLineArgs.add("-"); /* stderr. */ + + commandLineArgs.addAll(spawnArguments); + + return commandLineArgs; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxRunner.java index 4a786100f3..38c4db558c 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxRunner.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxRunner.java @@ -47,7 +47,24 @@ import java.util.Set; * handles sandbox output, performs cleanup and changes invocation if necessary. */ public class LinuxSandboxRunner { - private static final String LINUX_SANDBOX = "linux-sandbox" + OsUtils.executableExtension(); + protected static final String LINUX_SANDBOX = "linux-sandbox" + OsUtils.executableExtension(); + + protected Path getExecRoot() { + return execRoot; + } + + protected Path getSandboxExecRoot() { + return sandboxExecRoot; + } + + protected Set getWritablePaths() { + return writablePaths; + } + + protected boolean isVerboseFailures() { + return verboseFailures; + } + private final Path execRoot; private final Path sandboxExecRoot; private final Path argumentsFilePath; @@ -106,30 +123,10 @@ public class LinuxSandboxRunner { return true; } - /** - * Runs given - * - * @param spawnArguments - arguments of spawn to run inside the sandbox - * @param env - environment to run sandbox in - * @param outErr - error output to capture sandbox's and command's stderr - * @param outputs - files to extract from the sandbox, paths are relative to the exec root @throws - * ExecException - */ - public void run( - List spawnArguments, - Map env, - FileOutErr outErr, - Map inputs, - Collection outputs, - int timeout, - boolean allowNetwork) - throws IOException, ExecException { - createFileSystem(inputs, outputs); - List fileArgs = new ArrayList<>(); - List commandLineArgs = new ArrayList<>(); + protected void runPreparation(int timeout, boolean allowNetwork) throws IOException { - commandLineArgs.add(execRoot.getRelative("_bin/linux-sandbox").getPathString()); + List fileArgs = new ArrayList<>(); if (sandboxDebug) { fileArgs.add("-D"); @@ -165,11 +162,44 @@ public class LinuxSandboxRunner { } FileSystemUtils.writeLinesAs(argumentsFilePath, StandardCharsets.ISO_8859_1, fileArgs); + } + + protected List runCommandLineArgs(List spawnArguments, int timeout) { + List commandLineArgs = new ArrayList<>(); + + commandLineArgs.add(execRoot.getRelative("_bin/linux-sandbox").getPathString()); + commandLineArgs.add("@" + argumentsFilePath.getPathString()); commandLineArgs.add("--"); commandLineArgs.addAll(spawnArguments); + return commandLineArgs; + } + + /** + * Runs given + * + * @param spawnArguments - arguments of spawn to run inside the sandbox + * @param env - environment to run sandbox in + * @param outErr - error output to capture sandbox's and command's stderr + * @param outputs - files to extract from the sandbox, paths are relative to the exec root @throws + * ExecException + */ + public void run( + List spawnArguments, + Map env, + FileOutErr outErr, + Map inputs, + Collection outputs, + int timeout, + boolean allowNetwork) + throws IOException, ExecException { + createFileSystem(inputs, outputs); + + runPreparation(timeout, allowNetwork); + + List commandLineArgs = runCommandLineArgs(spawnArguments, timeout); Command cmd = new Command(commandLineArgs.toArray(new String[0]), env, sandboxExecRoot.getPathFile()); @@ -196,7 +226,7 @@ public class LinuxSandboxRunner { } } - private void createFileSystem(Map inputs, Collection outputs) + protected void createFileSystem(Map inputs, Collection outputs) throws IOException { Set createdDirs = new HashSet<>(); FileSystemUtils.createDirectoryAndParentsWithCache(createdDirs, sandboxExecRoot); @@ -245,7 +275,7 @@ public class LinuxSandboxRunner { } } - private void copyOutputs(Collection outputs) throws IOException { + protected void copyOutputs(Collection outputs) throws IOException { for (PathFragment output : outputs) { Path source = sandboxExecRoot.getRelative(output); if (source.isFile() || source.isSymbolicLink()) { 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 d6e65c34d7..962d24a349 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 @@ -63,7 +63,9 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { public static boolean isSupported(CommandEnvironment env) { if (sandboxingSupported == null) { - sandboxingSupported = LinuxSandboxRunner.isSupported(env); + // Currently LinuxSandboxRunner support <= LinuxAlmostSandboxRunner support + sandboxingSupported = + LinuxAlmostSandboxRunner.isSupported(env) || LinuxSandboxRunner.isSupported(env); } return sandboxingSupported.booleanValue(); } @@ -78,13 +80,15 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { private final UUID uuid = UUID.randomUUID(); private final AtomicInteger execCounter = new AtomicInteger(); private final String productName; + private final boolean fullySupported; LinuxSandboxedStrategy( BuildRequest buildRequest, BlazeDirectories blazeDirs, ExecutorService backgroundWorkers, boolean verboseFailures, - String productName) { + String productName, + boolean fullySupported) { this.buildRequest = buildRequest; this.sandboxOptions = buildRequest.getOptions(SandboxOptions.class); this.blazeDirs = blazeDirs; @@ -92,6 +96,7 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { this.backgroundWorkers = Preconditions.checkNotNull(backgroundWorkers); this.verboseFailures = verboseFailures; this.productName = productName; + this.fullySupported = fullySupported; } /** @@ -154,14 +159,27 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { } try { - final LinuxSandboxRunner runner = - new LinuxSandboxRunner( - execRoot, - sandboxExecRoot, - writablePaths, - inaccessiblePaths, - verboseFailures, - sandboxOptions.sandboxDebug); + final LinuxSandboxRunner runner; + if (fullySupported) { + runner = + new LinuxSandboxRunner( + execRoot, + sandboxExecRoot, + writablePaths, + inaccessiblePaths, + verboseFailures, + sandboxOptions.sandboxDebug); + } else { + // Then LinuxAlmostSandboxRunner must be supported + runner = + new LinuxAlmostSandboxRunner( + execRoot, + sandboxExecRoot, + writablePaths, + inaccessiblePaths, + verboseFailures, + sandboxOptions.sandboxDebug); + } try { runner.run( spawn.getArguments(), diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java index 7b4e30218a..83edc09130 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextConsumer.java @@ -20,6 +20,7 @@ import com.google.devtools.build.lib.actions.ActionContextConsumer; import com.google.devtools.build.lib.actions.Executor.ActionContext; import com.google.devtools.build.lib.actions.SpawnActionContext; import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.util.OS; /** * {@link ActionContextConsumer} that requests the action contexts necessary for sandboxed @@ -33,7 +34,8 @@ public class SandboxActionContextConsumer implements ActionContextConsumer { ImmutableMultimap.Builder, String> contexts = ImmutableMultimap.builder(); - if (LinuxSandboxedStrategy.isSupported(env)) { + if ((OS.getCurrent() == OS.LINUX && LinuxSandboxedStrategy.isSupported(env)) + || (OS.getCurrent() == OS.DARWIN && DarwinSandboxRunner.isSupported())) { contexts.put(SpawnActionContext.class, "sandboxed"); } 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 40f11aaf0e..0c7d7aa318 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 @@ -50,15 +50,19 @@ public 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) { + env.getReporter().handle(Event.warn(SANDBOX_NOT_SUPPORTED_MESSAGE)); + } contexts.add( new LinuxSandboxedStrategy( buildRequest, env.getDirectories(), backgroundWorkers, verboseFailures, - env.getRuntime().getProductName())); - } else if (!buildRequest.getOptions(SandboxOptions.class).ignoreUnsupportedSandboxing) { - env.getReporter().handle(Event.warn(SANDBOX_NOT_SUPPORTED_MESSAGE)); + env.getRuntime().getProductName(), + fullySupported)); } break; case DARWIN: -- cgit v1.2.3