1612e2641e
A user was trying to use OUT_DIR=/tmp/...-out DIST_DIR=/tmp/...-dist Test: OUT_DIR=/tmp/test-out DIST_DIR=/tmp/test-dist m nothing Change-Id: I811cc8e1bda8d766406603df47309a8637cef48c
227 lines
5.9 KiB
Go
227 lines
5.9 KiB
Go
// Copyright 2017 Google Inc. 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 build
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"os/exec"
|
|
"os/user"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
type Sandbox struct {
|
|
Enabled bool
|
|
DisableWhenUsingGoma bool
|
|
|
|
AllowBuildBrokenUsesNetwork bool
|
|
}
|
|
|
|
var (
|
|
noSandbox = Sandbox{}
|
|
basicSandbox = Sandbox{
|
|
Enabled: true,
|
|
}
|
|
|
|
dumpvarsSandbox = basicSandbox
|
|
katiSandbox = basicSandbox
|
|
soongSandbox = basicSandbox
|
|
ninjaSandbox = Sandbox{
|
|
Enabled: true,
|
|
DisableWhenUsingGoma: true,
|
|
|
|
AllowBuildBrokenUsesNetwork: true,
|
|
}
|
|
)
|
|
|
|
const nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
|
|
|
|
var sandboxConfig struct {
|
|
once sync.Once
|
|
|
|
working bool
|
|
group string
|
|
srcDir string
|
|
outDir string
|
|
distDir string
|
|
}
|
|
|
|
func (c *Cmd) sandboxSupported() bool {
|
|
if !c.Sandbox.Enabled {
|
|
return false
|
|
}
|
|
|
|
// Goma is incompatible with PID namespaces and Mount namespaces. b/122767582
|
|
if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() {
|
|
return false
|
|
}
|
|
|
|
sandboxConfig.once.Do(func() {
|
|
sandboxConfig.group = "nogroup"
|
|
if _, err := user.LookupGroup(sandboxConfig.group); err != nil {
|
|
sandboxConfig.group = "nobody"
|
|
}
|
|
|
|
// These directories will be bind mounted
|
|
// so we need full non-symlink paths
|
|
sandboxConfig.srcDir = absPath(c.ctx, ".")
|
|
if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
|
|
sandboxConfig.srcDir = absPath(c.ctx, derefPath)
|
|
}
|
|
sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
|
|
if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
|
|
sandboxConfig.outDir = absPath(c.ctx, derefPath)
|
|
}
|
|
sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
|
|
if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
|
|
sandboxConfig.distDir = absPath(c.ctx, derefPath)
|
|
}
|
|
|
|
sandboxArgs := []string{
|
|
"-H", "android-build",
|
|
"-e",
|
|
"-u", "nobody",
|
|
"-g", sandboxConfig.group,
|
|
"-R", "/",
|
|
"-B", sandboxConfig.srcDir,
|
|
"-B", "/tmp",
|
|
"-B", sandboxConfig.outDir,
|
|
}
|
|
|
|
if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
|
|
//Mount dist dir as read-write if it already exists
|
|
sandboxArgs = append(sandboxArgs, "-B",
|
|
sandboxConfig.distDir)
|
|
}
|
|
|
|
sandboxArgs = append(sandboxArgs,
|
|
"--disable_clone_newcgroup",
|
|
"--",
|
|
"/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
|
|
|
|
cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
|
|
|
|
cmd.Env = c.config.Environment().Environ()
|
|
|
|
c.ctx.Verboseln(cmd.Args)
|
|
data, err := cmd.CombinedOutput()
|
|
if err == nil && bytes.Contains(data, []byte("Android Success")) {
|
|
sandboxConfig.working = true
|
|
return
|
|
}
|
|
|
|
c.ctx.Println("Build sandboxing disabled due to nsjail error.")
|
|
|
|
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
|
|
c.ctx.Verboseln(line)
|
|
}
|
|
|
|
if err == nil {
|
|
c.ctx.Verboseln("nsjail exited successfully, but without the correct output")
|
|
} else if e, ok := err.(*exec.ExitError); ok {
|
|
c.ctx.Verbosef("nsjail failed with %v", e.ProcessState.String())
|
|
} else {
|
|
c.ctx.Verbosef("nsjail failed with %v", err)
|
|
}
|
|
})
|
|
|
|
return sandboxConfig.working
|
|
}
|
|
|
|
func (c *Cmd) wrapSandbox() {
|
|
wd, _ := os.Getwd()
|
|
|
|
sandboxArgs := []string{
|
|
// The executable to run
|
|
"-x", c.Path,
|
|
|
|
// Set the hostname to something consistent
|
|
"-H", "android-build",
|
|
|
|
// Use the current working dir
|
|
"--cwd", wd,
|
|
|
|
// No time limit
|
|
"-t", "0",
|
|
|
|
// Keep all environment variables, we already filter them out
|
|
// in soong_ui
|
|
"-e",
|
|
|
|
// Mount /proc read-write, necessary to run a nested nsjail or minijail0
|
|
"--proc_rw",
|
|
|
|
// Use a consistent user & group.
|
|
// Note that these are mapped back to the real UID/GID when
|
|
// doing filesystem operations, so they're rather arbitrary.
|
|
"-u", "nobody",
|
|
"-g", sandboxConfig.group,
|
|
|
|
// Set high values, as nsjail uses low defaults.
|
|
"--rlimit_as", "soft",
|
|
"--rlimit_core", "soft",
|
|
"--rlimit_cpu", "soft",
|
|
"--rlimit_fsize", "soft",
|
|
"--rlimit_nofile", "soft",
|
|
|
|
// For now, just map everything. Make most things readonly.
|
|
"-R", "/",
|
|
|
|
// Mount a writable tmp dir
|
|
"-B", "/tmp",
|
|
|
|
// Mount source are read-write
|
|
"-B", sandboxConfig.srcDir,
|
|
|
|
//Mount out dir as read-write
|
|
"-B", sandboxConfig.outDir,
|
|
|
|
// Disable newcgroup for now, since it may require newer kernels
|
|
// TODO: try out cgroups
|
|
"--disable_clone_newcgroup",
|
|
|
|
// Only log important warnings / errors
|
|
"-q",
|
|
}
|
|
|
|
if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
|
|
//Mount dist dir as read-write if it already exists
|
|
sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
|
|
}
|
|
|
|
if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
|
|
c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
|
|
c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
|
|
sandboxArgs = append(sandboxArgs, "-N")
|
|
} else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
|
|
// The debugger is enabled and soong_build will pause until a remote delve process connects, allow
|
|
// network connections.
|
|
sandboxArgs = append(sandboxArgs, "-N")
|
|
}
|
|
|
|
// Stop nsjail from parsing arguments
|
|
sandboxArgs = append(sandboxArgs, "--")
|
|
|
|
c.Args = append(sandboxArgs, c.Args[1:]...)
|
|
c.Path = nsjailPath
|
|
|
|
env := Environment(c.Env)
|
|
if _, hasUser := env.Get("USER"); hasUser {
|
|
env.Set("USER", "nobody")
|
|
}
|
|
c.Env = []string(env)
|
|
}
|