blob: 4c3bac307ced66d6191a7df71b474f23ca1e9474 [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
Diego Wilsona22240b2020-04-02 18:11:28 +000057 srcDir string
58 outDir string
59 distDir string
Dan Willemsen63663c62019-01-02 12:24:44 -080060}
61
Dan Willemsen269a8c72017-05-03 17:15:47 -070062func (c *Cmd) sandboxSupported() bool {
Dan Willemsen63663c62019-01-02 12:24:44 -080063 if !c.Sandbox.Enabled {
64 return false
65 }
66
67 // Goma is incompatible with PID namespaces and Mount namespaces. b/122767582
68 if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() {
69 return false
70 }
71
72 sandboxConfig.once.Do(func() {
73 sandboxConfig.group = "nogroup"
74 if _, err := user.LookupGroup(sandboxConfig.group); err != nil {
75 sandboxConfig.group = "nobody"
76 }
77
Diego Wilsona22240b2020-04-02 18:11:28 +000078 sandboxConfig.srcDir = absPath(c.ctx, ".")
79 sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
80 sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
81
Diego Wilsona5d96532020-04-06 22:02:38 +000082 sandboxArgs := []string{
Dan Willemsen63663c62019-01-02 12:24:44 -080083 "-H", "android-build",
84 "-e",
85 "-u", "nobody",
86 "-g", sandboxConfig.group,
Diego Wilsona22240b2020-04-02 18:11:28 +000087 "-R", "/",
88 "-B", sandboxConfig.srcDir,
89 "-B", "/tmp",
90 "-B", sandboxConfig.outDir,
Diego Wilsona5d96532020-04-06 22:02:38 +000091 }
92
93 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
94 //Mount dist dir as read-write if it already exists
95 sandboxArgs = append(sandboxArgs, "-B",
96 sandboxConfig.distDir)
97 }
98
99 sandboxArgs = append(sandboxArgs,
Dan Willemsen63663c62019-01-02 12:24:44 -0800100 "--disable_clone_newcgroup",
101 "--",
102 "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
Diego Wilsona5d96532020-04-06 22:02:38 +0000103
104 cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
105
Dan Willemsen63663c62019-01-02 12:24:44 -0800106 cmd.Env = c.config.Environment().Environ()
107
108 c.ctx.Verboseln(cmd.Args)
109 data, err := cmd.CombinedOutput()
110 if err == nil && bytes.Contains(data, []byte("Android Success")) {
111 sandboxConfig.working = true
112 return
113 }
114
Dan Willemsen1871d882020-03-02 20:36:04 +0000115 c.ctx.Println("Build sandboxing disabled due to nsjail error.")
Dan Willemsen63663c62019-01-02 12:24:44 -0800116
117 for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
118 c.ctx.Verboseln(line)
119 }
120
121 if err == nil {
122 c.ctx.Verboseln("nsjail exited successfully, but without the correct output")
123 } else if e, ok := err.(*exec.ExitError); ok {
124 c.ctx.Verbosef("nsjail failed with %v", e.ProcessState.String())
125 } else {
126 c.ctx.Verbosef("nsjail failed with %v", err)
127 }
128 })
129
130 return sandboxConfig.working
Dan Willemsen269a8c72017-05-03 17:15:47 -0700131}
132
133func (c *Cmd) wrapSandbox() {
Dan Willemsen63663c62019-01-02 12:24:44 -0800134 wd, _ := os.Getwd()
135
136 sandboxArgs := []string{
137 // The executable to run
138 "-x", c.Path,
139
140 // Set the hostname to something consistent
141 "-H", "android-build",
142
143 // Use the current working dir
144 "--cwd", wd,
145
146 // No time limit
147 "-t", "0",
148
149 // Keep all environment variables, we already filter them out
150 // in soong_ui
151 "-e",
152
Dan Willemsen3a4dbd62019-01-16 23:02:24 -0800153 // Mount /proc read-write, necessary to run a nested nsjail or minijail0
154 "--proc_rw",
155
Dan Willemsen63663c62019-01-02 12:24:44 -0800156 // Use a consistent user & group.
157 // Note that these are mapped back to the real UID/GID when
158 // doing filesystem operations, so they're rather arbitrary.
159 "-u", "nobody",
160 "-g", sandboxConfig.group,
161
162 // Set high values, as nsjail uses low defaults.
163 "--rlimit_as", "soft",
164 "--rlimit_core", "soft",
165 "--rlimit_cpu", "soft",
166 "--rlimit_fsize", "soft",
167 "--rlimit_nofile", "soft",
168
Diego Wilsona22240b2020-04-02 18:11:28 +0000169 // For now, just map everything. Make most things readonly.
170 "-R", "/",
171
172 // Mount source are read-write
173 "-B", sandboxConfig.srcDir,
174
175 //Mount out dir as read-write
176 "-B", sandboxConfig.outDir,
177
Diego Wilsona22240b2020-04-02 18:11:28 +0000178 // Mount a writable tmp dir
179 "-B", "/tmp",
Dan Willemsen63663c62019-01-02 12:24:44 -0800180
Dan Willemsen63663c62019-01-02 12:24:44 -0800181 // Disable newcgroup for now, since it may require newer kernels
182 // TODO: try out cgroups
183 "--disable_clone_newcgroup",
184
185 // Only log important warnings / errors
186 "-q",
Dan Willemsen63663c62019-01-02 12:24:44 -0800187 }
Dan Willemsen25e6f092019-04-09 10:22:43 -0700188
Diego Wilsona5d96532020-04-06 22:02:38 +0000189 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
190 //Mount dist dir as read-write if it already exists
191 sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
192 }
193
Dan Willemsen25e6f092019-04-09 10:22:43 -0700194 if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
195 c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
196 c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
197 sandboxArgs = append(sandboxArgs, "-N")
Colin Crossaa812d12019-06-19 13:33:24 -0700198 } else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
199 // The debugger is enabled and soong_build will pause until a remote delve process connects, allow
200 // network connections.
201 sandboxArgs = append(sandboxArgs, "-N")
Dan Willemsen25e6f092019-04-09 10:22:43 -0700202 }
203
204 // Stop nsjail from parsing arguments
205 sandboxArgs = append(sandboxArgs, "--")
206
Dan Willemsen63663c62019-01-02 12:24:44 -0800207 c.Args = append(sandboxArgs, c.Args[1:]...)
208 c.Path = nsjailPath
209
210 env := Environment(c.Env)
211 if _, hasUser := env.Get("USER"); hasUser {
212 env.Set("USER", "nobody")
213 }
214 c.Env = []string(env)
Dan Willemsen269a8c72017-05-03 17:15:47 -0700215}