// 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.ExecException; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.SpawnResult; import com.google.devtools.build.lib.exec.apple.XcodeLocalEnvProvider; import com.google.devtools.build.lib.exec.local.LocalEnvProvider; import com.google.devtools.build.lib.exec.local.PosixLocalEnvProvider; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.runtime.ProcessWrapperUtil; import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.Path; import java.io.IOException; import java.time.Duration; import java.util.Map; /** Strategy that uses sandboxing to execute a process. */ final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunner { public static boolean isSupported(CommandEnvironment cmdEnv) { return OS.isPosixCompatible() && ProcessWrapperUtil.isSupported(cmdEnv); } private final Path processWrapper; private final Path execRoot; private final Path sandboxBase; private final LocalEnvProvider localEnvProvider; private final Duration timeoutKillDelay; /** * Creates a sandboxed spawn runner that uses the {@code process-wrapper} tool. * * @param cmdEnv the command environment to use * @param sandboxBase path to the sandbox base directory * @param productName the product name to use * @param timeoutKillDelay additional grace period before killing timing out commands */ ProcessWrapperSandboxedSpawnRunner( CommandEnvironment cmdEnv, Path sandboxBase, String productName, Duration timeoutKillDelay) { super(cmdEnv); this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv); this.execRoot = cmdEnv.getExecRoot(); this.localEnvProvider = OS.getCurrent() == OS.DARWIN ? new XcodeLocalEnvProvider(cmdEnv.getClientEnv()) : new PosixLocalEnvProvider(cmdEnv.getClientEnv()); this.sandboxBase = sandboxBase; this.timeoutKillDelay = timeoutKillDelay; } @Override protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionContext context) throws ExecException, IOException, 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.getParentDirectory().createDirectory(); sandboxPath.createDirectory(); // 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.getParentDirectory().createDirectory(); sandboxExecRoot.createDirectory(); Map environment = localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, "/tmp"); Duration timeout = context.getTimeout(); ProcessWrapperUtil.CommandLineBuilder commandLineBuilder = ProcessWrapperUtil.commandLineBuilder(processWrapper.getPathString(), spawn.getArguments()) .setTimeout(timeout); commandLineBuilder.setKillDelay(timeoutKillDelay); Path statisticsPath = null; if (getSandboxOptions().collectLocalSandboxExecutionStatistics) { statisticsPath = sandboxPath.getRelative("stats.out"); commandLineBuilder.setStatisticsPath(statisticsPath); } SandboxedSpawn sandbox = new SymlinkedSandboxedSpawn( sandboxPath, sandboxExecRoot, commandLineBuilder.build(), environment, SandboxHelpers.processInputFiles(spawn, context, execRoot), SandboxHelpers.getOutputFiles(spawn), getWritableDirs(sandboxExecRoot, environment)); return runSpawn(spawn, sandbox, context, execRoot, timeout, statisticsPath); } @Override public String getName() { return "processwrapper-sandbox"; } }