Skip to content

Commit

Permalink
[sandbox] Run sandbox from common execroot
Browse files Browse the repository at this point in the history
Make sandboxed process run under main execroot instead of unique sandboxed execroot. This way, we do not need to copy/symlink input files before execution and clean up sandbox base after execution.

Summary of how it works:

- `windows-sandbox` blocks all file access under current directory (main execroot).
- Declared input paths will be marked readable.
- Declared output paths will be marked writable.
- If sandboxed process tries to open file for read/write when the path is not marked with that permission, the operation will fail (e.g. `fopen` will return `nullptr`).

Closes #8849.

PiperOrigin-RevId: 257408096
  • Loading branch information
rongjiecomputer authored and copybara-github committed Jul 10, 2019
1 parent 4bcdb75 commit 6605b23
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,13 @@ protected ImmutableSet<Path> getWritableDirs(Path sandboxExecRoot, Map<String, S
throws IOException {
// We have to make the TEST_TMPDIR directory writable if it is specified.
ImmutableSet.Builder<Path> writablePaths = ImmutableSet.builder();
writablePaths.add(sandboxExecRoot);

// On Windows, sandboxExecRoot is actually the main execroot. We will specify
// exactly which output path is writable.
if (OS.getCurrent() != OS.WINDOWS) {
writablePaths.add(sandboxExecRoot);
}

String testTmpdir = env.get("TEST_TMPDIR");
if (testTmpdir != null) {
addWritablePath(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,7 @@ private void setup(CommandEnvironment cmdEnv, ExecutorBuilder builder)
SpawnRunner spawnRunner =
withFallback(
cmdEnv,
new WindowsSandboxedSpawnRunner(
cmdEnv, sandboxBase, timeoutKillDelay, windowsSandboxPath, treeDeleter));
new WindowsSandboxedSpawnRunner(cmdEnv, timeoutKillDelay, windowsSandboxPath));
spawnRunners.add(spawnRunner);
builder.addActionContext(new WindowsSandboxedStrategy(cmdEnv.getExecRoot(), spawnRunner));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;

/** Utility functions for the {@code windows-sandbox}. */
Expand Down Expand Up @@ -105,6 +107,8 @@ public static class CommandLineBuilder {
private Path stdoutPath;
private Path stderrPath;
private Set<Path> writableFilesAndDirectories = ImmutableSet.of();
private Map<PathFragment, Path> readableFilesAndDirectories = new TreeMap<>();
private Set<Path> inaccessiblePaths = ImmutableSet.of();
private boolean useDebugMode = false;
private List<String> commandArguments = ImmutableList.of();

Expand Down Expand Up @@ -153,6 +157,19 @@ public CommandLineBuilder setWritableFilesAndDirectories(
return this;
}

/** Sets the files or directories to make readable for the sandboxed process, if any. */
public CommandLineBuilder setReadableFilesAndDirectories(
Map<PathFragment, Path> readableFilesAndDirectories) {
this.readableFilesAndDirectories = readableFilesAndDirectories;
return this;
}

/** Sets the files or directories to make inaccessible for the sandboxed process, if any. */
public CommandLineBuilder setInaccessiblePaths(Set<Path> inaccessiblePaths) {
this.inaccessiblePaths = inaccessiblePaths;
return this;
}

/** Sets whether to enable debug mode (e.g. to print debugging messages). */
public CommandLineBuilder setUseDebugMode(boolean useDebugMode) {
this.useDebugMode = useDebugMode;
Expand Down Expand Up @@ -187,6 +204,12 @@ public ImmutableList<String> build() {
for (Path writablePath : writableFilesAndDirectories) {
commandLineBuilder.add("-w", writablePath.getPathString());
}
for (Path readablePath : readableFilesAndDirectories.values()) {
commandLineBuilder.add("-r", readablePath.getPathString());
}
for (Path writablePath : inaccessiblePaths) {
commandLineBuilder.add("-b", writablePath.getPathString());
}
if (useDebugMode) {
commandLineBuilder.add("-D");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2019 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.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.vfs.Path;
import java.io.IOException;

/** Implements detour-based sandboxed spawn. */
public class WindowsSandboxedSpawn implements SandboxedSpawn {

private final Path execRoot;
private final ImmutableMap<String, String> environment;
private final ImmutableList<String> arguments;

public WindowsSandboxedSpawn(
Path execRoot, ImmutableMap<String, String> environment, ImmutableList<String> arguments) {
this.execRoot = execRoot;
this.environment = environment;
this.arguments = arguments;
}

@Override
public Path getSandboxExecRoot() {
return execRoot;
}

@Override
public ImmutableList<String> getArguments() {
return arguments;
}

@Override
public ImmutableMap<String, String> getEnvironment() {
return environment;
}

@Override
public void createFileSystem() throws IOException {}

@Override
public void copyOutputs(Path execRoot) throws IOException {}

@Override
public void delete() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@

package com.google.devtools.build.lib.sandbox;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.exec.TreeDeleter;
import com.google.devtools.build.lib.exec.local.LocalEnvProvider;
import com.google.devtools.build.lib.exec.local.WindowsLocalEnvProvider;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.sandbox.SandboxHelpers.SandboxOutputs;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
Expand All @@ -34,62 +34,56 @@ final class WindowsSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {

private final Path execRoot;
private final PathFragment windowsSandbox;
private final Path sandboxBase;
private final LocalEnvProvider localEnvProvider;
private final Duration timeoutKillDelay;
private final TreeDeleter treeDeleter;

/**
* Creates a sandboxed spawn runner that uses the {@code windows-sandbox} tool.
*
* @param cmdEnv the command environment to use
* @param sandboxBase path to the sandbox base directory
* @param timeoutKillDelay an additional grace period before killing timing out commands
* @param windowsSandboxPath path to windows-sandbox binary
*/
WindowsSandboxedSpawnRunner(
CommandEnvironment cmdEnv,
Path sandboxBase,
Duration timeoutKillDelay,
PathFragment windowsSandboxPath,
TreeDeleter treeDeleter) {
CommandEnvironment cmdEnv, Duration timeoutKillDelay, PathFragment windowsSandboxPath) {
super(cmdEnv);
this.execRoot = cmdEnv.getExecRoot();
this.windowsSandbox = windowsSandboxPath;
this.sandboxBase = sandboxBase;
this.timeoutKillDelay = timeoutKillDelay;
this.localEnvProvider = new WindowsLocalEnvProvider(cmdEnv.getClientEnv());
this.treeDeleter = treeDeleter;
}

@Override
protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionContext context)
throws IOException, ExecException, InterruptedException {
// Each invocation of "exec" gets its own sandbox base.
// Note that the value returned by context.getId() is only unique inside one given SpawnRunner,
// so we have to prefix our name to turn it into a globally unique value.
Path sandboxPath =
sandboxBase.getRelative(getName()).getRelative(Integer.toString(context.getId()));
sandboxPath.createDirectoryAndParents();

// b/64689608: The execroot of the sandboxed process must end with the workspace name, just like
// the normal execroot does.
Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName());
sandboxExecRoot.createDirectoryAndParents();

Path tmpDir = createActionTemp(execRoot);
Path commandTmpDir = tmpDir.getRelative("work");
commandTmpDir.createDirectory();
Map<String, String> environment =
localEnvProvider.rewriteLocalEnv(
spawn.getEnvironment(), binTools, commandTmpDir.getPathString());
ImmutableMap<String, String> environment =
ImmutableMap.copyOf(
localEnvProvider.rewriteLocalEnv(
spawn.getEnvironment(), binTools, commandTmpDir.getPathString()));

Map<PathFragment, Path> readablePaths =
SandboxHelpers.processInputFiles(
spawn,
context,
execRoot,
getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree);

ImmutableSet.Builder<Path> writablePaths = ImmutableSet.builder();
writablePaths.addAll(getWritableDirs(execRoot, environment));
for (ActionInput output : spawn.getOutputFiles()) {
writablePaths.add(execRoot.getRelative(output.getExecPath()));
}

ImmutableSet<Path> writableDirs = getWritableDirs(sandboxExecRoot, environment);
SandboxOutputs outputs = SandboxHelpers.getOutputs(spawn);
Duration timeout = context.getTimeout();

WindowsSandboxUtil.CommandLineBuilder commandLineBuilder =
WindowsSandboxUtil.commandLineBuilder(windowsSandbox, spawn.getArguments())
.setWritableFilesAndDirectories(writableDirs)
.setWritableFilesAndDirectories(writablePaths.build())
.setReadableFilesAndDirectories(readablePaths)
.setInaccessiblePaths(getInaccessiblePaths())
.setUseDebugMode(getSandboxOptions().sandboxDebug)
.setKillDelay(timeoutKillDelay);

Expand All @@ -100,19 +94,7 @@ protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionContext context)
Path statisticsPath = null;

SandboxedSpawn sandbox =
new CopyingSandboxedSpawn(
sandboxPath,
sandboxExecRoot,
commandLineBuilder.build(),
environment,
SandboxHelpers.processInputFiles(
spawn,
context,
execRoot,
getSandboxOptions().symlinkedSandboxExpandsTreeArtifactsInRunfilesTree),
outputs,
writableDirs,
treeDeleter);
new WindowsSandboxedSpawn(execRoot, environment, commandLineBuilder.build());

return runSpawn(spawn, sandbox, context, execRoot, timeout, statisticsPath);
}
Expand Down

0 comments on commit 6605b23

Please sign in to comment.