aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/tools
diff options
context:
space:
mode:
authorGravatar Philipp Wollermann <philwo@google.com>2016-09-20 12:53:37 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2016-09-21 07:04:12 +0000
commit52f4e8bbaf18ea489acd2db464f267757e8eb6d4 (patch)
tree608c16dd0160d6b355def1f71c0cee4239bed3f5 /src/main/tools
parent08849b29198230eacd4e85fc7246be8e399e4c4d (diff)
Fix Bazel failing to build anything when its workspace or output base is in /tmp.
Add "-b" option to linux-sandbox to explicitly bind mount files / directories into the sandbox. This is used to pull in the workspace and output base of Bazel even when they're located in /tmp and would thus be hidden by the tmpfs we mount on the /tmp directory in the sandbox. Add "-S" option to linux-sandbox to explicitly specify a temporary directory to be used to contain the sandbox. This can be created by Bazel and then removed more reliably, compared to the earlier behavior where the sandbox would create its own temporary root directory in /tmp/sandbox.XXXXXX (and fail to delete it in case it gets killed by a signal). Fix spurious empty.XXXXXX files and directories not being deleted from /tmp. -- MOS_MIGRATED_REVID=133695992
Diffstat (limited to 'src/main/tools')
-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
5 files changed, 118 insertions, 21 deletions
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