blob: b94db7448d051a9eb6b1ff69bfae6d126dd62f15 [file] [log] [blame]
Dan Willemsen269a8c72017-05-03 17:15:47 -07001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package build
16
Dan Willemsen63663c62019-01-02 12:24:44 -080017import (
18 "bytes"
19 "os"
20 "os/exec"
21 "os/user"
22 "strings"
23 "sync"
Dan Willemsen269a8c72017-05-03 17:15:47 -070024)
25
Dan Willemsen63663c62019-01-02 12:24:44 -080026type Sandbox struct {
27 Enabled bool
28 DisableWhenUsingGoma bool
Dan Willemsen25e6f092019-04-09 10:22:43 -070029
30 AllowBuildBrokenUsesNetwork bool
Dan Willemsen63663c62019-01-02 12:24:44 -080031}
32
33var (
34 noSandbox = Sandbox{}
35 basicSandbox = Sandbox{
36 Enabled: true,
37 }
38
39 dumpvarsSandbox = basicSandbox
40 katiSandbox = basicSandbox
41 soongSandbox = basicSandbox
42 ninjaSandbox = Sandbox{
43 Enabled: true,
44 DisableWhenUsingGoma: true,
Dan Willemsen25e6f092019-04-09 10:22:43 -070045
46 AllowBuildBrokenUsesNetwork: true,
Dan Willemsen63663c62019-01-02 12:24:44 -080047 }
48)
49
50const nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
51
52var sandboxConfig struct {
53 once sync.Once
54
55 working bool
56 group string
57}
58
Dan Willemsen269a8c72017-05-03 17:15:47 -070059func (c *Cmd) sandboxSupported() bool {
Dan Willemsen63663c62019-01-02 12:24:44 -080060 if !c.Sandbox.Enabled {
61 return false
62 }
63
64 // Goma is incompatible with PID namespaces and Mount namespaces. b/122767582
65 if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() {
66 return false
67 }
68
69 sandboxConfig.once.Do(func() {
70 sandboxConfig.group = "nogroup"
71 if _, err := user.LookupGroup(sandboxConfig.group); err != nil {
72 sandboxConfig.group = "nobody"
73 }
74
75 cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
76 "-H", "android-build",
77 "-e",
78 "-u", "nobody",
79 "-g", sandboxConfig.group,
80 "-B", "/",
81 "--disable_clone_newcgroup",
82 "--",
83 "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
84 cmd.Env = c.config.Environment().Environ()
85
86 c.ctx.Verboseln(cmd.Args)
87 data, err := cmd.CombinedOutput()
88 if err == nil && bytes.Contains(data, []byte("Android Success")) {
89 sandboxConfig.working = true
90 return
91 }
92
93 c.ctx.Println("Build sandboxing disabled due to nsjail error. This may become fatal in the future.")
94 c.ctx.Println("Please let us know why nsjail doesn't work in your environment at:")
95 c.ctx.Println(" https://groups.google.com/forum/#!forum/android-building")
96 c.ctx.Println(" https://issuetracker.google.com/issues/new?component=381517")
97
98 for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
99 c.ctx.Verboseln(line)
100 }
101
102 if err == nil {
103 c.ctx.Verboseln("nsjail exited successfully, but without the correct output")
104 } else if e, ok := err.(*exec.ExitError); ok {
105 c.ctx.Verbosef("nsjail failed with %v", e.ProcessState.String())
106 } else {
107 c.ctx.Verbosef("nsjail failed with %v", err)
108 }
109 })
110
111 return sandboxConfig.working
Dan Willemsen269a8c72017-05-03 17:15:47 -0700112}
113
114func (c *Cmd) wrapSandbox() {
Dan Willemsen63663c62019-01-02 12:24:44 -0800115 wd, _ := os.Getwd()
116
117 sandboxArgs := []string{
118 // The executable to run
119 "-x", c.Path,
120
121 // Set the hostname to something consistent
122 "-H", "android-build",
123
124 // Use the current working dir
125 "--cwd", wd,
126
127 // No time limit
128 "-t", "0",
129
130 // Keep all environment variables, we already filter them out
131 // in soong_ui
132 "-e",
133
Dan Willemsen3a4dbd62019-01-16 23:02:24 -0800134 // Mount /proc read-write, necessary to run a nested nsjail or minijail0
135 "--proc_rw",
136
Dan Willemsen63663c62019-01-02 12:24:44 -0800137 // Use a consistent user & group.
138 // Note that these are mapped back to the real UID/GID when
139 // doing filesystem operations, so they're rather arbitrary.
140 "-u", "nobody",
141 "-g", sandboxConfig.group,
142
143 // Set high values, as nsjail uses low defaults.
144 "--rlimit_as", "soft",
145 "--rlimit_core", "soft",
146 "--rlimit_cpu", "soft",
147 "--rlimit_fsize", "soft",
148 "--rlimit_nofile", "soft",
149
150 // For now, just map everything. Eventually we should limit this, especially to make most things readonly.
151 "-B", "/",
152
Dan Willemsen63663c62019-01-02 12:24:44 -0800153 // Disable newcgroup for now, since it may require newer kernels
154 // TODO: try out cgroups
155 "--disable_clone_newcgroup",
156
157 // Only log important warnings / errors
158 "-q",
Dan Willemsen63663c62019-01-02 12:24:44 -0800159 }
Dan Willemsen25e6f092019-04-09 10:22:43 -0700160
161 if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
162 c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
163 c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
164 sandboxArgs = append(sandboxArgs, "-N")
165 }
166
167 // Stop nsjail from parsing arguments
168 sandboxArgs = append(sandboxArgs, "--")
169
Dan Willemsen63663c62019-01-02 12:24:44 -0800170 c.Args = append(sandboxArgs, c.Args[1:]...)
171 c.Path = nsjailPath
172
173 env := Environment(c.Env)
174 if _, hasUser := env.Get("USER"); hasUser {
175 env.Set("USER", "nobody")
176 }
177 c.Env = []string(env)
Dan Willemsen269a8c72017-05-03 17:15:47 -0700178}