aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxRunner.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java17
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java3
-rw-r--r--src/main/tools/linux-sandbox-options.cc24
-rw-r--r--src/main/tools/linux-sandbox-options.h8
-rw-r--r--src/main/tools/linux-sandbox-pid1.cc87
-rw-r--r--src/main/tools/linux-sandbox.cc19
-rw-r--r--src/main/tools/linux-sandbox.h1
8 files changed, 152 insertions, 23 deletions
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 cceed552ba..c3d36a615f 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
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.sandbox;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.shell.Command;
@@ -40,25 +41,31 @@ final class LinuxSandboxRunner extends SandboxRunner {
private final Path execRoot;
private final Path sandboxExecRoot;
+ private final Path sandboxTempDir;
private final Path argumentsFilePath;
private final Set<Path> writableDirs;
private final Set<Path> inaccessiblePaths;
+ private final Set<Path> bindMounts;
private final boolean sandboxDebug;
LinuxSandboxRunner(
Path execRoot,
Path sandboxPath,
Path sandboxExecRoot,
+ Path sandboxTempDir,
Set<Path> writableDirs,
Set<Path> inaccessiblePaths,
+ ImmutableSet<Path> bindMounts,
boolean verboseFailures,
boolean sandboxDebug) {
super(sandboxPath, sandboxExecRoot, verboseFailures);
this.execRoot = execRoot;
this.sandboxExecRoot = sandboxExecRoot;
+ this.sandboxTempDir = sandboxTempDir;
this.argumentsFilePath = sandboxPath.getRelative("linux-sandbox.params");
this.writableDirs = writableDirs;
this.inaccessiblePaths = inaccessiblePaths;
+ this.bindMounts = bindMounts;
this.sandboxDebug = sandboxDebug;
}
@@ -116,6 +123,10 @@ final class LinuxSandboxRunner extends SandboxRunner {
fileArgs.add("-D");
}
+ // Temporary directory of the sandbox.
+ fileArgs.add("-S");
+ fileArgs.add(sandboxTempDir.toString());
+
// Working directory of the spawn.
fileArgs.add("-W");
fileArgs.add(sandboxExecRoot.toString());
@@ -137,6 +148,11 @@ final class LinuxSandboxRunner extends SandboxRunner {
fileArgs.add(inaccessiblePath.getPathString());
}
+ for (Path bindMount : bindMounts) {
+ fileArgs.add("-b");
+ fileArgs.add(bindMount.getPathString());
+ }
+
if (!allowNetwork) {
// Block network access out of the namespace.
fileArgs.add("-N");
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 be49446a82..0e38d0d891 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
@@ -101,6 +101,7 @@ public class LinuxSandboxedStrategy extends SandboxStrategy {
// Each invocation of "exec" gets its own sandbox.
Path sandboxPath = SandboxHelpers.getSandboxRoot(blazeDirs, productName, uuid, execCounter);
Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName());
+ Path sandboxTempDir = sandboxPath.getRelative("tmp");
try {
@@ -110,6 +111,7 @@ public class LinuxSandboxedStrategy extends SandboxStrategy {
Set<Path> writableDirs = getWritableDirs(sandboxExecRoot, spawn.getEnvironment(), outputs);
symlinkedExecRoot.createFileSystem(
getMounts(spawn, actionExecutionContext), outputs, writableDirs);
+ sandboxTempDir.createDirectory();
final SandboxRunner runner;
if (fullySupported) {
@@ -118,8 +120,10 @@ public class LinuxSandboxedStrategy extends SandboxStrategy {
execRoot,
sandboxPath,
sandboxExecRoot,
+ sandboxTempDir,
getWritableDirs(sandboxExecRoot, spawn.getEnvironment(), outputs),
getInaccessiblePaths(),
+ getBindMounts(blazeDirs),
verboseFailures,
sandboxOptions.sandboxDebug);
} else {
@@ -143,4 +147,17 @@ public class LinuxSandboxedStrategy extends SandboxStrategy {
}
}
+ private ImmutableSet<Path> getBindMounts(BlazeDirectories blazeDirs) {
+ Path tmpPath = blazeDirs.getFileSystem().getPath("/tmp");
+ ImmutableSet.Builder<Path> bindMounts = ImmutableSet.builder();
+ if (blazeDirs.getWorkspace().startsWith(tmpPath)) {
+
+ bindMounts.add(blazeDirs.getWorkspace());
+ }
+ if (blazeDirs.getOutputBase().startsWith(tmpPath)) {
+ bindMounts.add(blazeDirs.getOutputBase());
+ }
+ return bindMounts.build();
+ }
+
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
index 8573ad5fa7..004c8dffbc 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
@@ -128,7 +128,6 @@ final class SandboxHelpers {
return blazeDirs
.getOutputBase()
.getRelative(productName + "-sandbox")
- .getRelative(uuid + "-" + execCounter.getAndIncrement())
- .getRelative(blazeDirs.getExecRoot().getBaseName());
+ .getRelative(uuid + "-" + execCounter.getAndIncrement());
}
}
diff --git a/src/main/tools/linux-sandbox-options.cc b/src/main/tools/linux-sandbox-options.cc
index 0b43a2cfb4..49e6eafeeb 100644
--- a/src/main/tools/linux-sandbox-options.cc
+++ b/src/main/tools/linux-sandbox-options.cc
@@ -69,6 +69,7 @@ static void Usage(char *program_name, const char *fmt, ...) {
" -i <file> make a file or directory inaccessible for the "
"sandboxed process\n"
" -e <dir> mount an empty tmpfs on a directory\n"
+ " -b <dir> bind mount a file or directory inside the sandbox\n"
" -N if set, a new network namespace will be created\n"
" -R if set, make the uid/gid be root, otherwise use nobody\n"
" -D if set, debug info will be printed\n"
@@ -112,13 +113,25 @@ static void ParseCommandLine(unique_ptr<vector<char *>> args) {
extern int optind, optopt;
int c;
- while ((c = getopt(args->size(), args->data(), ":CS:W:T:t:l:L:w:i:e:NRD")) !=
- -1) {
+ while ((c = getopt(args->size(), args->data(),
+ ":CS:W:T:t:l:L:w:i:e:b:NRD")) != -1) {
switch (c) {
case 'C':
// Shortcut for the "does this system support sandboxing" check.
exit(CheckNamespacesSupported());
break;
+ case 'S':
+ if (opt.sandbox_root_dir == NULL) {
+ if (optarg[0] != '/') {
+ Usage(args->front(),
+ "The -r option must be used with absolute paths only.");
+ }
+ opt.sandbox_root_dir = strdup(optarg);
+ } else {
+ Usage(args->front(),
+ "Multiple root directories (-r) specified, expected one.");
+ }
+ break;
case 'W':
if (opt.working_dir == NULL) {
if (optarg[0] != '/') {
@@ -180,6 +193,13 @@ static void ParseCommandLine(unique_ptr<vector<char *>> args) {
}
opt.tmpfs_dirs.push_back(strdup(optarg));
break;
+ case 'b':
+ if (optarg[0] != '/') {
+ Usage(args->front(),
+ "The -b option must be used with absolute paths only.");
+ }
+ opt.bind_mounts.push_back(strdup(optarg));
+ break;
case 'N':
opt.create_netns = true;
break;
diff --git a/src/main/tools/linux-sandbox-options.h b/src/main/tools/linux-sandbox-options.h
index 57004a8206..5554f9e41f 100644
--- a/src/main/tools/linux-sandbox-options.h
+++ b/src/main/tools/linux-sandbox-options.h
@@ -22,6 +22,8 @@
// Options parsing result.
struct Options {
+ // Temporary root directory (-S)
+ const char *sandbox_root_dir;
// Working directory (-W)
const char *working_dir;
// How long to wait before killing the child (-T)
@@ -32,12 +34,14 @@ struct Options {
const char *stdout_path;
// Where to redirect stderr (-L)
const char *stderr_path;
- // Files to make writable for the sandboxed process (-w)
+ // Files or directories to make writable for the sandboxed process (-w)
std::vector<const char *> writable_files;
- // Files to make inaccessible for the sandboxed process (-i)
+ // Files or directories to make inaccessible for the sandboxed process (-i)
std::vector<const char *> inaccessible_files;
// Directories where to mount an empty tmpfs (-e)
std::vector<const char *> tmpfs_dirs;
+ // Files or directories to explicitly bind mount into the sandbox (-b)
+ std::vector<const char *> bind_mounts;
// Create a new network namespace (-N)
bool create_netns;
// Pretend to be root inside the namespace (-R)
diff --git a/src/main/tools/linux-sandbox-pid1.cc b/src/main/tools/linux-sandbox-pid1.cc
index 1dd049a1f4..dc6aadc84f 100644
--- a/src/main/tools/linux-sandbox-pid1.cc
+++ b/src/main/tools/linux-sandbox-pid1.cc
@@ -55,8 +55,8 @@
#include <unistd.h>
static int global_child_pid;
-static char global_inaccessible_directory[] = "/tmp/empty.XXXXXX";
-static char global_inaccessible_file[] = "/tmp/empty.XXXXXX";
+static char global_inaccessible_directory[] = "tmp/empty.XXXXXX";
+static char global_inaccessible_file[] = "tmp/empty.XXXXXX";
static void SetupSelfDestruction(int *sync_pipe) {
// We could also poll() on the pipe fd to find out when the parent goes away,
@@ -167,13 +167,74 @@ static void SetupHelperFiles() {
}
}
+static bool IsDirectory(const char *path) {
+ struct stat sb;
+ if (stat(path, &sb) < 0) {
+ DIE("stat(%s)", path);
+ }
+ return S_ISDIR(sb.st_mode);
+}
+
+// Recursively creates the file or directory specified in "path" and its parent
+// directories.
+static int CreateTarget(const char *path, bool is_directory) {
+ PRINT_DEBUG("CreateTarget(%s, %s)", path, is_directory ? "true" : "false");
+ if (path == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ struct stat sb;
+ // If the path already exists...
+ if (stat(path, &sb) == 0) {
+ if (is_directory && S_ISDIR(sb.st_mode)) {
+ // and it's a directory and supposed to be a directory, we're done here.
+ return 0;
+ } else if (!is_directory && S_ISREG(sb.st_mode)) {
+ // and it's a regular file and supposed to be one, we're done here.
+ return 0;
+ } else {
+ // otherwise something is really wrong.
+ errno = is_directory ? ENOTDIR : EEXIST;
+ return -1;
+ }
+ } else {
+ // If stat failed because of any error other than "the path does not exist",
+ // this is an error.
+ if (errno != ENOENT) {
+ return -1;
+ }
+ }
+
+ // Create the parent directory.
+ if (CreateTarget(dirname(strdupa(path)), true) < 0) {
+ DIE("CreateTarget(%s, true)", dirname(strdupa(path)));
+ }
+
+ if (is_directory) {
+ if (mkdir(path, 0755) < 0) {
+ DIE("mkdir(%s, 0755)", path);
+ }
+ } else {
+ int handle;
+ if ((handle = open(path, O_CREAT | O_WRONLY | O_EXCL, 0666)) < 0) {
+ DIE("open(%s, O_CREAT | O_WRONLY | O_EXCL, 0666)", path);
+ }
+ if (close(handle) < 0) {
+ DIE("close(%d)", handle);
+ }
+ }
+
+ return 0;
+}
+
static void MountFilesystems() {
- if (mount("/", global_sandbox_root, NULL, MS_BIND | MS_REC, NULL) < 0) {
- DIE("mount(/, %s, NULL, MS_BIND | MS_REC, NULL)", global_sandbox_root);
+ if (mount("/", opt.sandbox_root_dir, NULL, MS_BIND | MS_REC, NULL) < 0) {
+ DIE("mount(/, %s, NULL, MS_BIND | MS_REC, NULL)", opt.sandbox_root_dir);
}
- if (chdir(global_sandbox_root) < 0) {
- DIE("chdir(%s)", global_sandbox_root);
+ if (chdir(opt.sandbox_root_dir) < 0) {
+ DIE("chdir(%s)", opt.sandbox_root_dir);
}
for (const char *tmpfs_dir : opt.tmpfs_dirs) {
@@ -187,11 +248,21 @@ static void MountFilesystems() {
// Make sure that our working directory is a mount point. The easiest way to
// do this is by bind-mounting it upon itself.
+ PRINT_DEBUG("working dir: %s", opt.working_dir);
+ CreateTarget(opt.working_dir + 1, true);
if (mount(opt.working_dir, opt.working_dir + 1, NULL, MS_BIND, NULL) < 0) {
DIE("mount(%s, %s, NULL, MS_BIND, NULL)", opt.working_dir,
opt.working_dir + 1);
}
+ for (const char *bind_mount : opt.bind_mounts) {
+ PRINT_DEBUG("bind mount: %s", bind_mount);
+ CreateTarget(bind_mount + 1, IsDirectory(bind_mount));
+ if (mount(bind_mount, bind_mount + 1, NULL, MS_BIND, NULL) < 0) {
+ DIE("mount(%s, %s, NULL, MS_BIND, NULL)", bind_mount, bind_mount + 1);
+ }
+ }
+
for (const char *writable_file : opt.writable_files) {
PRINT_DEBUG("writable: %s", writable_file);
if (mount(writable_file, writable_file + 1, NULL, MS_BIND, NULL) < 0) {
@@ -229,7 +300,7 @@ static void MountFilesystems() {
// We later remount everything read-only, except the paths for which this method
// returns true.
static bool ShouldBeWritable(char *mnt_dir) {
- mnt_dir += strlen(global_sandbox_root);
+ mnt_dir += strlen(opt.sandbox_root_dir);
if (strcmp(mnt_dir, opt.working_dir) == 0) {
return true;
@@ -261,7 +332,7 @@ static void MakeFilesystemMostlyReadOnly() {
struct mntent *ent;
while ((ent = getmntent(mounts)) != NULL) {
// Skip mounts that do not belong to our sandbox.
- if (strstr(ent->mnt_dir, global_sandbox_root) != ent->mnt_dir) {
+ if (strstr(ent->mnt_dir, opt.sandbox_root_dir) != ent->mnt_dir) {
continue;
}
diff --git a/src/main/tools/linux-sandbox.cc b/src/main/tools/linux-sandbox.cc
index 8eeef841e6..865bf86ea2 100644
--- a/src/main/tools/linux-sandbox.cc
+++ b/src/main/tools/linux-sandbox.cc
@@ -72,8 +72,8 @@
int global_outer_uid;
int global_outer_gid;
-char global_sandbox_root[] = "/tmp/sandbox.XXXXXX";
+static char global_sandbox_root[] = "/tmp/sandbox.XXXXXX";
static int global_child_pid;
// The signal that will be sent to the child when a timeout occurs.
@@ -119,18 +119,22 @@ static void CloseFds() {
}
}
-static void SetupSandboxRoot() {
- if (mkdtemp(global_sandbox_root) == NULL) {
- DIE("mkdtemp(%s)", global_sandbox_root);
- }
-}
-
static void RemoveSandboxRoot() {
if (rmdir(global_sandbox_root) < 0) {
DIE("rmdir(%s)", global_sandbox_root);
}
}
+static void SetupSandboxRoot() {
+ if (opt.sandbox_root_dir == NULL) {
+ if (mkdtemp(global_sandbox_root) == NULL) {
+ DIE("mkdtemp(%s)", global_sandbox_root);
+ }
+ atexit(RemoveSandboxRoot);
+ opt.sandbox_root_dir = global_sandbox_root;
+ }
+}
+
static void HandleSignal(int signum, void (*handler)(int)) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
@@ -277,7 +281,6 @@ int main(int argc, char *argv[]) {
CloseFds();
SetupSandboxRoot();
- atexit(RemoveSandboxRoot);
HandleSignal(SIGALRM, OnTimeout);
if (opt.timeout_secs > 0) {
diff --git a/src/main/tools/linux-sandbox.h b/src/main/tools/linux-sandbox.h
index 5ff778da38..df07dee39f 100644
--- a/src/main/tools/linux-sandbox.h
+++ b/src/main/tools/linux-sandbox.h
@@ -17,6 +17,5 @@
extern int global_outer_uid;
extern int global_outer_gid;
-extern char global_sandbox_root[];
#endif