| // 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.devtools.build.lib.actions.UserExecException; |
| import com.google.devtools.build.lib.runtime.BlazeWorkspace; |
| import com.google.devtools.build.lib.server.FailureDetails.Sandbox.Code; |
| 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 java.io.IOException; |
| import java.util.Map; |
| |
| /** Utility functions for the {@code linux-sandbox} embedded tool. */ |
| public final class LinuxSandboxUtil { |
| private static final String LINUX_SANDBOX = "linux-sandbox" + OsUtils.executableExtension(); |
| |
| /** Returns whether using the {@code linux-sandbox} is supported in the command environment. */ |
| public static boolean isSupported(BlazeWorkspace blazeWorkspace) { |
| // We can only use the linux-sandbox if the linux-sandbox exists in the embedded tools. |
| // This might not always be the case, e.g. while bootstrapping. |
| return getLinuxSandbox(blazeWorkspace) != null; |
| } |
| |
| /** Returns the path of the {@code linux-sandbox} binary, or null if it doesn't exist. */ |
| public static Path getLinuxSandbox(BlazeWorkspace blazeWorkspace) { |
| return blazeWorkspace.getBinTools().getEmbeddedPath(LINUX_SANDBOX); |
| } |
| |
| /** |
| * This method does the following things: |
| * |
| * <ul> |
| * <li>If mount source does not exist on the host system, throw an error message |
| * <li>If mount target exists, check whether the source and target are of the same type |
| * <li>If mount target does not exist on the host system, throw an error message |
| * </ul> |
| * |
| * @param bindMounts the bind mounts map with target as key and source as value |
| * @throws UserExecException if any of the mount points are not valid |
| */ |
| public static void validateBindMounts(Map<Path, Path> bindMounts) throws UserExecException { |
| for (Map.Entry<Path, Path> bindMount : bindMounts.entrySet()) { |
| final Path source = bindMount.getValue(); |
| final Path target = bindMount.getKey(); |
| // Mount source should exist in the file system |
| if (!source.exists()) { |
| throw new UserExecException( |
| SandboxHelpers.createFailureDetail( |
| String.format("Mount source '%s' does not exist.", source), |
| Code.MOUNT_SOURCE_DOES_NOT_EXIST)); |
| } |
| // If target exists, but is not of the same type as the source, then we cannot mount it. |
| if (target.exists()) { |
| boolean areBothDirectories = source.isDirectory() && target.isDirectory(); |
| boolean isSourceFile = source.isFile() || source.isSymbolicLink(); |
| boolean isTargetFile = target.isFile() || target.isSymbolicLink(); |
| boolean areBothFiles = isSourceFile && isTargetFile; |
| if (!(areBothDirectories || areBothFiles)) { |
| // Source and target are not of the same type; we cannot mount it. |
| throw new UserExecException( |
| SandboxHelpers.createFailureDetail( |
| String.format( |
| "Mount target '%s' is a %s but mount source '%s' is a %s, they must be the" |
| + " same type.", |
| target, |
| (isTargetFile ? "file" : "directory"), |
| source, |
| (isSourceFile ? "file" : "directory")), |
| Code.MOUNT_SOURCE_TARGET_TYPE_MISMATCH)); |
| } |
| } else { |
| // Mount target should exist in the file system |
| throw new UserExecException( |
| SandboxHelpers.createFailureDetail( |
| String.format( |
| "Mount target '%s' does not exist. Bazel only supports bind mounting on top of " |
| + "existing files/directories. Please create an empty file or directory at " |
| + "the mount target path according to the type of mount source.", |
| target), |
| Code.MOUNT_TARGET_DOES_NOT_EXIST)); |
| } |
| } |
| } |
| |
| /** Returns a newly created inaccessible file underneath the given directory. */ |
| public static Path getInaccessibleHelperFile(Path sandboxBase) throws IOException { |
| // The order of the permissions settings calls matters, see |
| // https://github.com/bazelbuild/bazel/issues/16364 |
| Path inaccessibleHelperFile = sandboxBase.getRelative("inaccessibleHelperFile"); |
| FileSystemUtils.touchFile(inaccessibleHelperFile); |
| inaccessibleHelperFile.setExecutable(false); |
| inaccessibleHelperFile.setWritable(false); |
| inaccessibleHelperFile.setReadable(false); |
| return inaccessibleHelperFile; |
| } |
| |
| /** Returns a newly created inaccessible directory underneath the given directory. */ |
| public static Path getInaccessibleHelperDir(Path sandboxBase) throws IOException { |
| // The order of the permissions settings calls matters, see |
| // https://github.com/bazelbuild/bazel/issues/16364 |
| Path inaccessibleHelperDir = sandboxBase.getRelative("inaccessibleHelperDir"); |
| inaccessibleHelperDir.createDirectory(); |
| inaccessibleHelperDir.setExecutable(false); |
| inaccessibleHelperDir.setWritable(false); |
| inaccessibleHelperDir.setReadable(false); |
| return inaccessibleHelperDir; |
| } |
| } |