aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2019-01-02 12:24:44 -0800
committerDan Willemsen <dwillemsen@google.com>2019-01-15 13:47:31 -0800
commit63663c6bc9ee270e02b06ff3d4f8812f1ef4d49b (patch)
tree43841e3620caf538eb63f1061fd58e5741c920ea /ui
parent073941d780016e0770f083e1edd425739d15b80a (diff)
downloadbuild_soong-63663c6bc9ee270e02b06ff3d4f8812f1ef4d49b.tar.gz
build_soong-63663c6bc9ee270e02b06ff3d4f8812f1ef4d49b.tar.bz2
build_soong-63663c6bc9ee270e02b06ff3d4f8812f1ef4d49b.zip
Implement linux sandboxing with nsjail
This really only initializes the sandbox, it does not attempt to change the view of the filesystem, nor does it turn off networking. Bug: 122270019 Test: m Test: trigger nsjail check failure; lunch; m; cat out/soong.log Test: USE_GOMA=true m libc Change-Id: Ib291072dcee8247c7a15f5b6831295ead6e4fc22
Diffstat (limited to 'ui')
-rw-r--r--ui/build/ninja.go1
-rw-r--r--ui/build/sandbox_darwin.go12
-rw-r--r--ui/build/sandbox_linux.go154
3 files changed, 151 insertions, 16 deletions
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 835f8203..cb41579c 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -59,6 +59,7 @@ func runNinja(ctx Context, config Config) {
"-w", "missingdepfile=err")
cmd := Command(ctx, config, "ninja", executable, args...)
+ cmd.Sandbox = ninjaSandbox
if config.HasKatiSuffix() {
cmd.Environment.AppendFromKati(config.KatiEnvFile())
}
diff --git a/ui/build/sandbox_darwin.go b/ui/build/sandbox_darwin.go
index 7e75167a..43c5480c 100644
--- a/ui/build/sandbox_darwin.go
+++ b/ui/build/sandbox_darwin.go
@@ -21,12 +21,12 @@ import (
type Sandbox string
const (
- noSandbox = ""
- globalSandbox = "build/soong/ui/build/sandbox/darwin/global.sb"
- dumpvarsSandbox = globalSandbox
- soongSandbox = globalSandbox
- katiSandbox = globalSandbox
- katiCleanSpecSandbox = globalSandbox
+ noSandbox = ""
+ globalSandbox = "build/soong/ui/build/sandbox/darwin/global.sb"
+ dumpvarsSandbox = globalSandbox
+ soongSandbox = globalSandbox
+ katiSandbox = globalSandbox
+ ninjaSandbox = noSandbox
)
var sandboxExecPath string
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index f2bfac29..b87637f7 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -14,20 +14,154 @@
package build
-type Sandbox bool
-
-const (
- noSandbox = false
- globalSandbox = false
- dumpvarsSandbox = false
- soongSandbox = false
- katiSandbox = false
- katiCleanSpecSandbox = false
+import (
+ "bytes"
+ "os"
+ "os/exec"
+ "os/user"
+ "strings"
+ "sync"
)
+type Sandbox struct {
+ Enabled bool
+ DisableWhenUsingGoma bool
+}
+
+var (
+ noSandbox = Sandbox{}
+ basicSandbox = Sandbox{
+ Enabled: true,
+ }
+
+ dumpvarsSandbox = basicSandbox
+ katiSandbox = basicSandbox
+ soongSandbox = basicSandbox
+ ninjaSandbox = Sandbox{
+ Enabled: true,
+ DisableWhenUsingGoma: true,
+ }
+)
+
+const nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
+
+var sandboxConfig struct {
+ once sync.Once
+
+ working bool
+ group string
+}
+
func (c *Cmd) sandboxSupported() bool {
- return false
+ 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"
+ }
+
+ cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
+ "-H", "android-build",
+ "-e",
+ "-u", "nobody",
+ "-g", sandboxConfig.group,
+ "-B", "/",
+ "--disable_clone_newcgroup",
+ "--",
+ "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
+ 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. This may become fatal in the future.")
+ c.ctx.Println("Please let us know why nsjail doesn't work in your environment at:")
+ c.ctx.Println(" https://groups.google.com/forum/#!forum/android-building")
+ c.ctx.Println(" https://issuetracker.google.com/issues/new?component=381517")
+
+ 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",
+
+ // 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. Eventually we should limit this, especially to make most things readonly.
+ "-B", "/",
+
+ // Enable networking for now. TODO: remove
+ "-N",
+
+ // Disable newcgroup for now, since it may require newer kernels
+ // TODO: try out cgroups
+ "--disable_clone_newcgroup",
+
+ // Only log important warnings / errors
+ "-q",
+
+ // Stop parsing arguments
+ "--",
+ }
+ 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)
}