blob: d9ca854174a4d5c59f5761a8b1610506b09aa128 [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"
Diego Wilson10e564a2020-04-15 17:42:59 +000022 "path/filepath"
Dan Willemsen63663c62019-01-02 12:24:44 -080023 "strings"
24 "sync"
Dan Willemsen269a8c72017-05-03 17:15:47 -070025)
26
Dan Willemsen63663c62019-01-02 12:24:44 -080027type Sandbox struct {
28 Enabled bool
29 DisableWhenUsingGoma bool
Dan Willemsen25e6f092019-04-09 10:22:43 -070030
31 AllowBuildBrokenUsesNetwork bool
Dan Willemsen63663c62019-01-02 12:24:44 -080032}
33
34var (
35 noSandbox = Sandbox{}
36 basicSandbox = Sandbox{
37 Enabled: true,
38 }
39
40 dumpvarsSandbox = basicSandbox
41 katiSandbox = basicSandbox
42 soongSandbox = basicSandbox
43 ninjaSandbox = Sandbox{
44 Enabled: true,
45 DisableWhenUsingGoma: true,
Dan Willemsen25e6f092019-04-09 10:22:43 -070046
47 AllowBuildBrokenUsesNetwork: true,
Dan Willemsen63663c62019-01-02 12:24:44 -080048 }
49)
50
Taylor Santiagoca30e082024-07-30 13:48:43 -070051const (
52 nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
53 abfsSrcDir = "/src"
Taylor Santiagoca30e082024-07-30 13:48:43 -070054)
Dan Willemsen63663c62019-01-02 12:24:44 -080055
56var sandboxConfig struct {
57 once sync.Once
58
59 working bool
60 group string
Diego Wilsona22240b2020-04-02 18:11:28 +000061 srcDir string
62 outDir string
63 distDir string
Dan Willemsen63663c62019-01-02 12:24:44 -080064}
65
Dan Willemsen269a8c72017-05-03 17:15:47 -070066func (c *Cmd) sandboxSupported() bool {
Dan Willemsen63663c62019-01-02 12:24:44 -080067 if !c.Sandbox.Enabled {
68 return false
69 }
70
71 // Goma is incompatible with PID namespaces and Mount namespaces. b/122767582
72 if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() {
73 return false
74 }
75
76 sandboxConfig.once.Do(func() {
77 sandboxConfig.group = "nogroup"
78 if _, err := user.LookupGroup(sandboxConfig.group); err != nil {
79 sandboxConfig.group = "nobody"
80 }
81
Diego Wilson10e564a2020-04-15 17:42:59 +000082 // These directories will be bind mounted
83 // so we need full non-symlink paths
Diego Wilsona22240b2020-04-02 18:11:28 +000084 sandboxConfig.srcDir = absPath(c.ctx, ".")
Diego Wilson10e564a2020-04-15 17:42:59 +000085 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
86 sandboxConfig.srcDir = absPath(c.ctx, derefPath)
87 }
Diego Wilsona22240b2020-04-02 18:11:28 +000088 sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
Diego Wilson10e564a2020-04-15 17:42:59 +000089 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
90 sandboxConfig.outDir = absPath(c.ctx, derefPath)
91 }
Diego Wilsona22240b2020-04-02 18:11:28 +000092 sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
Diego Wilson10e564a2020-04-15 17:42:59 +000093 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
94 sandboxConfig.distDir = absPath(c.ctx, derefPath)
95 }
Diego Wilsona22240b2020-04-02 18:11:28 +000096
Diego Wilsona5d96532020-04-06 22:02:38 +000097 sandboxArgs := []string{
Dan Willemsen63663c62019-01-02 12:24:44 -080098 "-H", "android-build",
99 "-e",
100 "-u", "nobody",
101 "-g", sandboxConfig.group,
Diego Wilsona22240b2020-04-02 18:11:28 +0000102 "-R", "/",
Spandan Das05063612021-06-25 01:39:04 +0000103 // Mount tmp before srcDir
104 // srcDir is /tmp/.* in integration tests, which is a child dir of /tmp
105 // nsjail throws an error if a child dir is mounted before its parent
Diego Wilsona22240b2020-04-02 18:11:28 +0000106 "-B", "/tmp",
Spandan Das2d997042022-11-04 20:58:18 +0000107 c.config.sandboxConfig.SrcDirMountFlag(), sandboxConfig.srcDir,
Diego Wilsona22240b2020-04-02 18:11:28 +0000108 "-B", sandboxConfig.outDir,
Diego Wilsona5d96532020-04-06 22:02:38 +0000109 }
110
111 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
112 //Mount dist dir as read-write if it already exists
113 sandboxArgs = append(sandboxArgs, "-B",
114 sandboxConfig.distDir)
115 }
116
117 sandboxArgs = append(sandboxArgs,
Dan Willemsen63663c62019-01-02 12:24:44 -0800118 "--disable_clone_newcgroup",
119 "--",
120 "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
Diego Wilsona5d96532020-04-06 22:02:38 +0000121
122 cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
123
Dan Willemsen63663c62019-01-02 12:24:44 -0800124 cmd.Env = c.config.Environment().Environ()
125
126 c.ctx.Verboseln(cmd.Args)
127 data, err := cmd.CombinedOutput()
128 if err == nil && bytes.Contains(data, []byte("Android Success")) {
129 sandboxConfig.working = true
130 return
131 }
132
Dan Willemsen1871d882020-03-02 20:36:04 +0000133 c.ctx.Println("Build sandboxing disabled due to nsjail error.")
Dan Willemsen63663c62019-01-02 12:24:44 -0800134
135 for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
136 c.ctx.Verboseln(line)
137 }
138
139 if err == nil {
140 c.ctx.Verboseln("nsjail exited successfully, but without the correct output")
141 } else if e, ok := err.(*exec.ExitError); ok {
142 c.ctx.Verbosef("nsjail failed with %v", e.ProcessState.String())
143 } else {
144 c.ctx.Verbosef("nsjail failed with %v", err)
145 }
146 })
147
148 return sandboxConfig.working
Dan Willemsen269a8c72017-05-03 17:15:47 -0700149}
150
Taylor Santiagoca30e082024-07-30 13:48:43 -0700151func (c *Cmd) srcDirArg() string {
152 if !c.config.UseABFS() {
153 return sandboxConfig.srcDir
154 }
155
156 return sandboxConfig.srcDir + ":" + abfsSrcDir
157}
158
159func (c *Cmd) outDirArg() string {
160 if !c.config.UseABFS() {
161 return sandboxConfig.outDir
162 }
163
Taylor Santiago26118512024-08-05 19:52:41 -0700164 return sandboxConfig.outDir + ":" + filepath.Join(abfsSrcDir, sandboxConfig.outDir)
165}
166
167// When configured to use ABFS, we need to allow the creation of the /src
168// directory. Therefore, we cannot mount the root "/" directory as read-only.
169// Instead, we individually mount the children of "/" as RO.
170func (c *Cmd) readMountArgs() []string {
171 if !c.config.UseABFS() {
172 // For now, just map everything. Make most things readonly.
173 return []string{"-R", "/"}
174 }
175
176 entries, err := os.ReadDir("/")
177 if err != nil {
178 // If we can't read "/", just use the default non-ABFS behavior.
179 return []string{"-R", "/"}
180 }
181
182 args := make([]string, 0, 2*len(entries))
183 for _, ent := range entries {
184 args = append(args, "-R", "/"+ent.Name())
185 }
186
187 return args
Taylor Santiagoca30e082024-07-30 13:48:43 -0700188}
189
Dan Willemsen269a8c72017-05-03 17:15:47 -0700190func (c *Cmd) wrapSandbox() {
PODISHETTY KUMAR (xWF)9543d192024-09-02 03:54:36 +0000191 wd, _ := os.Getwd()
Dan Willemsen63663c62019-01-02 12:24:44 -0800192
Taylor Santiago26118512024-08-05 19:52:41 -0700193 var sandboxArgs []string
194 sandboxArgs = append(sandboxArgs,
Dan Willemsen63663c62019-01-02 12:24:44 -0800195 // The executable to run
196 "-x", c.Path,
197
198 // Set the hostname to something consistent
199 "-H", "android-build",
200
201 // Use the current working dir
202 "--cwd", wd,
203
204 // No time limit
205 "-t", "0",
206
207 // Keep all environment variables, we already filter them out
208 // in soong_ui
209 "-e",
210
Dan Willemsen3a4dbd62019-01-16 23:02:24 -0800211 // Mount /proc read-write, necessary to run a nested nsjail or minijail0
212 "--proc_rw",
213
Dan Willemsen63663c62019-01-02 12:24:44 -0800214 // Use a consistent user & group.
215 // Note that these are mapped back to the real UID/GID when
216 // doing filesystem operations, so they're rather arbitrary.
217 "-u", "nobody",
218 "-g", sandboxConfig.group,
219
220 // Set high values, as nsjail uses low defaults.
221 "--rlimit_as", "soft",
222 "--rlimit_core", "soft",
223 "--rlimit_cpu", "soft",
224 "--rlimit_fsize", "soft",
225 "--rlimit_nofile", "soft",
Taylor Santiago26118512024-08-05 19:52:41 -0700226 )
Dan Willemsen63663c62019-01-02 12:24:44 -0800227
Taylor Santiago26118512024-08-05 19:52:41 -0700228 sandboxArgs = append(sandboxArgs,
PODISHETTY KUMAR (xWF)9543d192024-09-02 03:54:36 +0000229 c.readMountArgs()...
Taylor Santiago26118512024-08-05 19:52:41 -0700230 )
Diego Wilsona22240b2020-04-02 18:11:28 +0000231
Taylor Santiago26118512024-08-05 19:52:41 -0700232 sandboxArgs = append(sandboxArgs,
Dan Willemsen1612e262020-05-01 16:26:56 -0700233 // Mount a writable tmp dir
234 "-B", "/tmp",
235
Spandan Dasa3639e62021-05-25 19:14:02 +0000236 // Mount source
Taylor Santiagoca30e082024-07-30 13:48:43 -0700237 c.config.sandboxConfig.SrcDirMountFlag(), c.srcDirArg(),
Diego Wilsona22240b2020-04-02 18:11:28 +0000238
239 //Mount out dir as read-write
Taylor Santiagoca30e082024-07-30 13:48:43 -0700240 "-B", c.outDirArg(),
Diego Wilsona22240b2020-04-02 18:11:28 +0000241
Dan Willemsen63663c62019-01-02 12:24:44 -0800242 // Disable newcgroup for now, since it may require newer kernels
243 // TODO: try out cgroups
244 "--disable_clone_newcgroup",
245
246 // Only log important warnings / errors
247 "-q",
Taylor Santiago26118512024-08-05 19:52:41 -0700248 )
Taylor Santiago3c16e612024-05-30 14:41:31 -0700249 if c.config.UseABFS() {
250 sandboxArgs = append(sandboxArgs, "-B", "{ABFS_DIR}")
251 }
Dan Willemsen25e6f092019-04-09 10:22:43 -0700252
Spandan Dasa3639e62021-05-25 19:14:02 +0000253 // Mount srcDir RW allowlists as Read-Write
254 if len(c.config.sandboxConfig.SrcDirRWAllowlist()) > 0 && !c.config.sandboxConfig.SrcDirIsRO() {
255 errMsg := `Product source tree has been set as ReadWrite, RW allowlist not necessary.
256 To recover, either
257 1. Unset BUILD_BROKEN_SRC_DIR_IS_WRITABLE #or
258 2. Unset BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST`
259 c.ctx.Fatalln(errMsg)
260 }
261 for _, srcDirChild := range c.config.sandboxConfig.SrcDirRWAllowlist() {
262 sandboxArgs = append(sandboxArgs, "-B", srcDirChild)
263 }
264
Diego Wilsona5d96532020-04-06 22:02:38 +0000265 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
266 //Mount dist dir as read-write if it already exists
267 sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
268 }
269
Dan Willemsen25e6f092019-04-09 10:22:43 -0700270 if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
271 c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
272 c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
273 sandboxArgs = append(sandboxArgs, "-N")
Colin Crossaa812d12019-06-19 13:33:24 -0700274 } else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
275 // The debugger is enabled and soong_build will pause until a remote delve process connects, allow
276 // network connections.
277 sandboxArgs = append(sandboxArgs, "-N")
Dan Willemsen25e6f092019-04-09 10:22:43 -0700278 }
279
280 // Stop nsjail from parsing arguments
281 sandboxArgs = append(sandboxArgs, "--")
282
Dan Willemsen63663c62019-01-02 12:24:44 -0800283 c.Args = append(sandboxArgs, c.Args[1:]...)
284 c.Path = nsjailPath
285
286 env := Environment(c.Env)
287 if _, hasUser := env.Get("USER"); hasUser {
288 env.Set("USER", "nobody")
289 }
290 c.Env = []string(env)
Dan Willemsen269a8c72017-05-03 17:15:47 -0700291}