blob: 98eb028a84f03be4ef44f5cac47003bc2015989b [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
51const nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
52
53var sandboxConfig struct {
54 once sync.Once
55
56 working bool
57 group string
Diego Wilsona22240b2020-04-02 18:11:28 +000058 srcDir string
59 outDir string
60 distDir string
Dan Willemsen63663c62019-01-02 12:24:44 -080061}
62
Dan Willemsen269a8c72017-05-03 17:15:47 -070063func (c *Cmd) sandboxSupported() bool {
Dan Willemsen63663c62019-01-02 12:24:44 -080064 if !c.Sandbox.Enabled {
65 return false
66 }
67
68 // Goma is incompatible with PID namespaces and Mount namespaces. b/122767582
69 if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() {
70 return false
71 }
72
73 sandboxConfig.once.Do(func() {
74 sandboxConfig.group = "nogroup"
75 if _, err := user.LookupGroup(sandboxConfig.group); err != nil {
76 sandboxConfig.group = "nobody"
77 }
78
Diego Wilson10e564a2020-04-15 17:42:59 +000079 // These directories will be bind mounted
80 // so we need full non-symlink paths
Diego Wilsona22240b2020-04-02 18:11:28 +000081 sandboxConfig.srcDir = absPath(c.ctx, ".")
Diego Wilson10e564a2020-04-15 17:42:59 +000082 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
83 sandboxConfig.srcDir = absPath(c.ctx, derefPath)
84 }
Diego Wilsona22240b2020-04-02 18:11:28 +000085 sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
Diego Wilson10e564a2020-04-15 17:42:59 +000086 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
87 sandboxConfig.outDir = absPath(c.ctx, derefPath)
88 }
Diego Wilsona22240b2020-04-02 18:11:28 +000089 sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
Diego Wilson10e564a2020-04-15 17:42:59 +000090 if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
91 sandboxConfig.distDir = absPath(c.ctx, derefPath)
92 }
Diego Wilsona22240b2020-04-02 18:11:28 +000093
Diego Wilsona5d96532020-04-06 22:02:38 +000094 sandboxArgs := []string{
Dan Willemsen63663c62019-01-02 12:24:44 -080095 "-H", "android-build",
96 "-e",
97 "-u", "nobody",
98 "-g", sandboxConfig.group,
Diego Wilsona22240b2020-04-02 18:11:28 +000099 "-R", "/",
100 "-B", sandboxConfig.srcDir,
101 "-B", "/tmp",
102 "-B", sandboxConfig.outDir,
Diego Wilsona5d96532020-04-06 22:02:38 +0000103 }
104
105 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
106 //Mount dist dir as read-write if it already exists
107 sandboxArgs = append(sandboxArgs, "-B",
108 sandboxConfig.distDir)
109 }
110
111 sandboxArgs = append(sandboxArgs,
Dan Willemsen63663c62019-01-02 12:24:44 -0800112 "--disable_clone_newcgroup",
113 "--",
114 "/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
Diego Wilsona5d96532020-04-06 22:02:38 +0000115
116 cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
117
Dan Willemsen63663c62019-01-02 12:24:44 -0800118 cmd.Env = c.config.Environment().Environ()
119
120 c.ctx.Verboseln(cmd.Args)
121 data, err := cmd.CombinedOutput()
122 if err == nil && bytes.Contains(data, []byte("Android Success")) {
123 sandboxConfig.working = true
124 return
125 }
126
Dan Willemsen1871d882020-03-02 20:36:04 +0000127 c.ctx.Println("Build sandboxing disabled due to nsjail error.")
Dan Willemsen63663c62019-01-02 12:24:44 -0800128
129 for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
130 c.ctx.Verboseln(line)
131 }
132
133 if err == nil {
134 c.ctx.Verboseln("nsjail exited successfully, but without the correct output")
135 } else if e, ok := err.(*exec.ExitError); ok {
136 c.ctx.Verbosef("nsjail failed with %v", e.ProcessState.String())
137 } else {
138 c.ctx.Verbosef("nsjail failed with %v", err)
139 }
140 })
141
142 return sandboxConfig.working
Dan Willemsen269a8c72017-05-03 17:15:47 -0700143}
144
145func (c *Cmd) wrapSandbox() {
Dan Willemsen63663c62019-01-02 12:24:44 -0800146 wd, _ := os.Getwd()
147
148 sandboxArgs := []string{
149 // The executable to run
150 "-x", c.Path,
151
152 // Set the hostname to something consistent
153 "-H", "android-build",
154
155 // Use the current working dir
156 "--cwd", wd,
157
158 // No time limit
159 "-t", "0",
160
161 // Keep all environment variables, we already filter them out
162 // in soong_ui
163 "-e",
164
Dan Willemsen3a4dbd62019-01-16 23:02:24 -0800165 // Mount /proc read-write, necessary to run a nested nsjail or minijail0
166 "--proc_rw",
167
Dan Willemsen63663c62019-01-02 12:24:44 -0800168 // Use a consistent user & group.
169 // Note that these are mapped back to the real UID/GID when
170 // doing filesystem operations, so they're rather arbitrary.
171 "-u", "nobody",
172 "-g", sandboxConfig.group,
173
174 // Set high values, as nsjail uses low defaults.
175 "--rlimit_as", "soft",
176 "--rlimit_core", "soft",
177 "--rlimit_cpu", "soft",
178 "--rlimit_fsize", "soft",
179 "--rlimit_nofile", "soft",
180
Diego Wilsona22240b2020-04-02 18:11:28 +0000181 // For now, just map everything. Make most things readonly.
182 "-R", "/",
183
184 // Mount source are read-write
185 "-B", sandboxConfig.srcDir,
186
187 //Mount out dir as read-write
188 "-B", sandboxConfig.outDir,
189
Diego Wilsona22240b2020-04-02 18:11:28 +0000190 // Mount a writable tmp dir
191 "-B", "/tmp",
Dan Willemsen63663c62019-01-02 12:24:44 -0800192
Dan Willemsen63663c62019-01-02 12:24:44 -0800193 // Disable newcgroup for now, since it may require newer kernels
194 // TODO: try out cgroups
195 "--disable_clone_newcgroup",
196
197 // Only log important warnings / errors
198 "-q",
Dan Willemsen63663c62019-01-02 12:24:44 -0800199 }
Dan Willemsen25e6f092019-04-09 10:22:43 -0700200
Diego Wilsona5d96532020-04-06 22:02:38 +0000201 if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
202 //Mount dist dir as read-write if it already exists
203 sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
204 }
205
Dan Willemsen25e6f092019-04-09 10:22:43 -0700206 if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
207 c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
208 c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
209 sandboxArgs = append(sandboxArgs, "-N")
Colin Crossaa812d12019-06-19 13:33:24 -0700210 } else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
211 // The debugger is enabled and soong_build will pause until a remote delve process connects, allow
212 // network connections.
213 sandboxArgs = append(sandboxArgs, "-N")
Dan Willemsen25e6f092019-04-09 10:22:43 -0700214 }
215
216 // Stop nsjail from parsing arguments
217 sandboxArgs = append(sandboxArgs, "--")
218
Dan Willemsen63663c62019-01-02 12:24:44 -0800219 c.Args = append(sandboxArgs, c.Args[1:]...)
220 c.Path = nsjailPath
221
222 env := Environment(c.Env)
223 if _, hasUser := env.Get("USER"); hasUser {
224 env.Set("USER", "nobody")
225 }
226 c.Env = []string(env)
Dan Willemsen269a8c72017-05-03 17:15:47 -0700227}