aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/build/Android.bp11
-rw-r--r--ui/build/build.go10
-rw-r--r--ui/build/exec.go107
-rw-r--r--ui/build/kati.go20
-rw-r--r--ui/build/make.go6
-rw-r--r--ui/build/ninja.go28
-rw-r--r--ui/build/sandbox/darwin/global.sb40
-rw-r--r--ui/build/sandbox_darwin.go69
-rw-r--r--ui/build/sandbox_linux.go32
-rw-r--r--ui/build/soong.go34
10 files changed, 285 insertions, 72 deletions
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 51aed2c1..d44c112d 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -24,6 +24,7 @@ bootstrap_go_package {
"config.go",
"context.go",
"environment.go",
+ "exec.go",
"kati.go",
"make.go",
"ninja.go",
@@ -36,9 +37,15 @@ bootstrap_go_package {
"util_test.go",
],
darwin: {
- srcs: ["util_darwin.go"],
+ srcs: [
+ "sandbox_darwin.go",
+ "util_darwin.go"
+ ],
},
linux: {
- srcs: ["util_linux.go"],
+ srcs: [
+ "sandbox_linux.go",
+ "util_linux.go"
+ ],
},
}
diff --git a/ui/build/build.go b/ui/build/build.go
index 506ff519..d6059c0b 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -16,7 +16,6 @@ package build
import (
"os"
- "os/exec"
"path/filepath"
"text/template"
)
@@ -67,13 +66,12 @@ func Build(ctx Context, config Config, what int) {
ctx.Verboseln("Environment:", config.Environment().Environ())
if inList("help", config.Arguments()) {
- cmd := exec.CommandContext(ctx.Context, "make", "-f", "build/core/help.mk")
- cmd.Env = config.Environment().Environ()
+ cmd := Command(ctx, config, "make",
+ "make", "-f", "build/core/help.mk")
+ cmd.Sandbox = makeSandbox
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
- if err := cmd.Run(); err != nil {
- ctx.Fatalln("Failed to run make:", err)
- }
+ cmd.RunOrFatal()
return
}
diff --git a/ui/build/exec.go b/ui/build/exec.go
new file mode 100644
index 00000000..4c45c507
--- /dev/null
+++ b/ui/build/exec.go
@@ -0,0 +1,107 @@
+// 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 (
+ "os/exec"
+)
+
+// Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
+// logging, the config's Environment for simpler environment modification, and
+// implements hooks for sandboxing
+type Cmd struct {
+ *exec.Cmd
+
+ Environment *Environment
+ Sandbox Sandbox
+
+ ctx Context
+ config Config
+ name string
+}
+
+func Command(ctx Context, config Config, name string, executable string, args ...string) *Cmd {
+ ret := &Cmd{
+ Cmd: exec.CommandContext(ctx.Context, executable, args...),
+ Environment: config.Environment().Copy(),
+ Sandbox: noSandbox,
+
+ ctx: ctx,
+ config: config,
+ name: name,
+ }
+
+ return ret
+}
+
+func (c *Cmd) prepare() {
+ if c.Env == nil {
+ c.Env = c.Environment.Environ()
+ }
+ if c.sandboxSupported() {
+ c.wrapSandbox()
+ }
+
+ c.ctx.Verboseln(c.Path, c.Args)
+}
+
+func (c *Cmd) Start() error {
+ c.prepare()
+ return c.Cmd.Start()
+}
+
+func (c *Cmd) Run() error {
+ c.prepare()
+ return c.Cmd.Run()
+}
+
+func (c *Cmd) Output() ([]byte, error) {
+ c.prepare()
+ return c.Cmd.Output()
+}
+
+func (c *Cmd) CombinedOutput() ([]byte, error) {
+ c.prepare()
+ return c.Cmd.CombinedOutput()
+}
+
+// StartOrFatal is equivalent to Start, but handles the error with a call to ctx.Fatal
+func (c *Cmd) StartOrFatal() {
+ if err := c.Start(); err != nil {
+ c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
+ }
+}
+
+// RunOrFatal is equivalent to Run, but handles the error with a call to ctx.Fatal
+func (c *Cmd) RunOrFatal() {
+ if err := c.Run(); err != nil {
+ if e, ok := err.(*exec.ExitError); ok {
+ c.ctx.Fatalf("%s failed with: %v", c.name, e.ProcessState.String())
+ } else {
+ c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
+ }
+ }
+}
+
+// WaitOrFatal is equivalent to Wait, but handles the error with a call to ctx.Fatal
+func (c *Cmd) WaitOrFatal() {
+ if err := c.Wait(); err != nil {
+ if e, ok := err.(*exec.ExitError); ok {
+ c.ctx.Fatalf("%s failed with: %v", c.name, e.ProcessState.String())
+ } else {
+ c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
+ }
+ }
+}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 218ca698..f29d0c19 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -20,7 +20,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "os/exec"
"path/filepath"
"regexp"
"strconv"
@@ -93,28 +92,17 @@ func runKati(ctx Context, config Config) {
args = append(args, "-j"+strconv.Itoa(config.Parallel()))
}
- cmd := exec.CommandContext(ctx.Context, executable, args...)
- cmd.Env = config.Environment().Environ()
+ cmd := Command(ctx, config, "ckati", executable, args...)
+ cmd.Sandbox = katiSandbox
pipe, err := cmd.StdoutPipe()
if err != nil {
ctx.Fatalln("Error getting output pipe for ckati:", err)
}
cmd.Stderr = cmd.Stdout
- ctx.Verboseln(cmd.Path, cmd.Args)
- if err := cmd.Start(); err != nil {
- ctx.Fatalln("Failed to run ckati:", err)
- }
-
+ cmd.StartOrFatal()
katiRewriteOutput(ctx, pipe)
-
- if err := cmd.Wait(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- ctx.Fatalln("ckati failed with:", e.ProcessState.String())
- } else {
- ctx.Fatalln("Failed to run ckati:", err)
- }
- }
+ cmd.WaitOrFatal()
}
var katiIncludeRe = regexp.MustCompile(`^(\[\d+/\d+] )?including [^ ]+ ...$`)
diff --git a/ui/build/make.go b/ui/build/make.go
index a8d4483b..32dc17b5 100644
--- a/ui/build/make.go
+++ b/ui/build/make.go
@@ -16,7 +16,6 @@ package build
import (
"fmt"
- "os/exec"
"path/filepath"
"strings"
)
@@ -38,7 +37,7 @@ func DumpMakeVars(ctx Context, config Config, goals, extra_targets, vars []strin
ctx.BeginTrace("dumpvars")
defer ctx.EndTrace()
- cmd := exec.CommandContext(ctx.Context,
+ cmd := Command(ctx, config, "make",
"make",
"--no-print-directory",
"-f", "build/core/config.mk",
@@ -48,11 +47,10 @@ func DumpMakeVars(ctx Context, config Config, goals, extra_targets, vars []strin
"MAKECMDGOALS="+strings.Join(goals, " "),
"DUMP_MANY_VARS="+strings.Join(vars, " "),
"OUT_DIR="+config.OutDir())
- cmd.Env = config.Environment().Environ()
cmd.Args = append(cmd.Args, extra_targets...)
+ cmd.Sandbox = makeSandbox
// TODO: error out when Stderr contains any content
cmd.Stderr = ctx.Stderr()
- ctx.Verboseln(cmd.Path, cmd.Args)
output, err := cmd.Output()
if err != nil {
return nil, err
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 054af243..5787a00f 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -15,7 +15,6 @@
package build
import (
- "os/exec"
"path/filepath"
"strconv"
"strings"
@@ -51,35 +50,26 @@ func runNinja(ctx Context, config Config) {
}
args = append(args, "-w", "dupbuild=err")
- env := config.Environment().Copy()
- env.AppendFromKati(config.KatiEnvFile())
+ cmd := Command(ctx, config, "ninja", executable, args...)
+ cmd.Environment.AppendFromKati(config.KatiEnvFile())
// Allow both NINJA_ARGS and NINJA_EXTRA_ARGS, since both have been
// used in the past to specify extra ninja arguments.
- if extra, ok := env.Get("NINJA_ARGS"); ok {
- args = append(args, strings.Fields(extra)...)
+ if extra, ok := cmd.Environment.Get("NINJA_ARGS"); ok {
+ cmd.Args = append(cmd.Args, strings.Fields(extra)...)
}
- if extra, ok := env.Get("NINJA_EXTRA_ARGS"); ok {
- args = append(args, strings.Fields(extra)...)
+ if extra, ok := cmd.Environment.Get("NINJA_EXTRA_ARGS"); ok {
+ cmd.Args = append(cmd.Args, strings.Fields(extra)...)
}
- if _, ok := env.Get("NINJA_STATUS"); !ok {
- env.Set("NINJA_STATUS", "[%p %f/%t] ")
+ if _, ok := cmd.Environment.Get("NINJA_STATUS"); !ok {
+ cmd.Environment.Set("NINJA_STATUS", "[%p %f/%t] ")
}
- cmd := exec.CommandContext(ctx.Context, executable, args...)
- cmd.Env = env.Environ()
cmd.Stdin = ctx.Stdin()
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
- ctx.Verboseln(cmd.Path, cmd.Args)
startTime := time.Now()
defer ctx.ImportNinjaLog(filepath.Join(config.OutDir(), ".ninja_log"), startTime)
- if err := cmd.Run(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- ctx.Fatalln("ninja failed with:", e.ProcessState.String())
- } else {
- ctx.Fatalln("Failed to run ninja:", err)
- }
- }
+ cmd.RunOrFatal()
}
diff --git a/ui/build/sandbox/darwin/global.sb b/ui/build/sandbox/darwin/global.sb
new file mode 100644
index 00000000..47d0c434
--- /dev/null
+++ b/ui/build/sandbox/darwin/global.sb
@@ -0,0 +1,40 @@
+(version 1)
+
+; TODO: (deny default)
+(allow default (with report))
+
+; Import apple-defined rules for bsd daemons
+(import "bsd.sb")
+
+; Allow reading of any file
+(allow file-read*)
+
+; Allow writing to $OUT_DIR and $DIST_DIR
+(allow file-write*
+ (subpath (param "OUT_DIR"))
+ (subpath (param "DIST_DIR")))
+
+; Java attempts to write usage data to ~/.oracle_jre_usage, just ignore
+(deny file-write* (with no-log)
+ (subpath (string-append (param "HOME") "/.oracle_jre_usage")))
+
+; Allow writes to user-specific temp folders (Java stores hsperfdata there)
+(allow file-write*
+ (subpath "/private/var/folders"))
+
+; Allow writing to the terminal
+(allow file-write-data
+ (subpath "/dev/tty"))
+
+; Java
+(allow mach-lookup
+ (global-name "com.apple.SystemConfiguration.configd") ; Java
+ (global-name "com.apple.CoreServices.coreservicesd") ; xcodebuild in Soong
+ (global-name "com.apple.FSEvents") ; xcodebuild in Soong
+ (global-name "com.apple.lsd.mapdb") ; xcodebuild in Soong
+ (global-name-regex #"^com\.apple\.distributed_notifications") ; xcodebuild in Soong
+)
+
+; Allow executing any file
+(allow process-exec*)
+(allow process-fork)
diff --git a/ui/build/sandbox_darwin.go b/ui/build/sandbox_darwin.go
new file mode 100644
index 00000000..54c145c5
--- /dev/null
+++ b/ui/build/sandbox_darwin.go
@@ -0,0 +1,69 @@
+// 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 (
+ "os/exec"
+ "path/filepath"
+)
+
+type Sandbox string
+
+const (
+ noSandbox = ""
+ globalSandbox = "build/soong/ui/build/sandbox/darwin/global.sb"
+ makeSandbox = globalSandbox
+ soongSandbox = globalSandbox
+ katiSandbox = globalSandbox
+)
+
+var sandboxExecPath string
+
+func init() {
+ if p, err := exec.LookPath("sandbox-exec"); err == nil {
+ sandboxExecPath = p
+ }
+}
+
+func (c *Cmd) sandboxSupported() bool {
+ if c.Sandbox == "" {
+ return false
+ } else if sandboxExecPath == "" {
+ c.ctx.Verboseln("sandbox-exec not found, disabling sandboxing")
+ return false
+ }
+ return true
+}
+
+func (c *Cmd) wrapSandbox() {
+ homeDir, _ := c.Environment.Get("HOME")
+ outDir, err := filepath.Abs(c.config.OutDir())
+ if err != nil {
+ c.ctx.Fatalln("Failed to get absolute path of OUT_DIR:", err)
+ }
+ distDir, err := filepath.Abs(c.config.DistDir())
+ if err != nil {
+ c.ctx.Fatalln("Failed to get absolute path of DIST_DIR:", err)
+ }
+
+ c.Args[0] = c.Path
+ c.Path = sandboxExecPath
+ c.Args = append([]string{
+ "sandbox-exec", "-f", string(c.Sandbox),
+ "-D", "HOME=" + homeDir,
+ "-D", "OUT_DIR=" + outDir,
+ "-D", "DIST_DIR=" + distDir,
+ }, c.Args...)
+}
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
new file mode 100644
index 00000000..fb48b9cb
--- /dev/null
+++ b/ui/build/sandbox_linux.go
@@ -0,0 +1,32 @@
+// 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
+
+type Sandbox bool
+
+const (
+ noSandbox = false
+ globalSandbox = false
+ makeSandbox = false
+ soongSandbox = false
+ katiSandbox = false
+)
+
+func (c *Cmd) sandboxSupported() bool {
+ return false
+}
+
+func (c *Cmd) wrapSandbox() {
+}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 6554f1d8..ddfe666c 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,7 +15,6 @@
package build
import (
- "os/exec"
"path/filepath"
)
@@ -23,42 +22,27 @@ func runSoongBootstrap(ctx Context, config Config) {
ctx.BeginTrace("bootstrap soong")
defer ctx.EndTrace()
- cmd := exec.CommandContext(ctx.Context, "./bootstrap.bash")
- env := config.Environment().Copy()
- env.Set("BUILDDIR", config.SoongOutDir())
- cmd.Env = env.Environ()
+ cmd := Command(ctx, config, "soong bootstrap", "./bootstrap.bash")
+ cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
+ cmd.Sandbox = soongSandbox
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
- ctx.Verboseln(cmd.Path, cmd.Args)
- if err := cmd.Run(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- ctx.Fatalln("soong bootstrap failed with:", e.ProcessState.String())
- } else {
- ctx.Fatalln("Failed to run soong bootstrap:", err)
- }
- }
+ cmd.RunOrFatal()
}
func runSoong(ctx Context, config Config) {
ctx.BeginTrace("soong")
defer ctx.EndTrace()
- cmd := exec.CommandContext(ctx.Context, filepath.Join(config.SoongOutDir(), "soong"), "-w", "dupbuild=err")
+ cmd := Command(ctx, config, "soong",
+ filepath.Join(config.SoongOutDir(), "soong"), "-w", "dupbuild=err")
if config.IsVerbose() {
cmd.Args = append(cmd.Args, "-v")
}
- env := config.Environment().Copy()
- env.Set("SKIP_NINJA", "true")
- cmd.Env = env.Environ()
+ cmd.Environment.Set("SKIP_NINJA", "true")
+ cmd.Sandbox = soongSandbox
cmd.Stdin = ctx.Stdin()
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
- ctx.Verboseln(cmd.Path, cmd.Args)
- if err := cmd.Run(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- ctx.Fatalln("soong bootstrap failed with:", e.ProcessState.String())
- } else {
- ctx.Fatalln("Failed to run soong bootstrap:", err)
- }
- }
+ cmd.RunOrFatal()
}