blob: 78e3cfb1bf8d471aab946d6a6e45c3f08d7d9bb8 [file] [log] [blame]
Mike Frysinger50e31fa2018-01-19 18:59:49 -05001/* Copyright 2016 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Test platform independent logic of Minijail using gtest.
6 */
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -04007
8#include <errno.h>
9
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070010#include <dirent.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040011#include <fcntl.h>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070012#include <sys/mount.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040013#include <sys/stat.h>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070014#include <sys/types.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040015#include <sys/wait.h>
Dylan Reid0412dcc2017-08-24 11:33:15 -070016#include <unistd.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040017
18#include <gtest/gtest.h>
19
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070020#include <functional>
21#include <map>
22#include <set>
23#include <string>
24
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040025#include "libminijail-private.h"
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070026#include "libminijail.h"
27#include "scoped_minijail.h"
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040028#include "util.h"
29
Mike Frysingerb2c12d12017-09-29 21:18:59 -040030namespace {
31
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040032#if defined(__ANDROID__)
Mike Frysingerb2c12d12017-09-29 21:18:59 -040033# define ROOT_PREFIX "/system"
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040034#else
Mike Frysingerb2c12d12017-09-29 21:18:59 -040035# define ROOT_PREFIX ""
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040036#endif
37
Luis Hector Chavez9acba452018-10-11 10:13:25 -070038constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
39constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
40constexpr char kPreloadPath[] = "./libminijailpreload.so";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070041constexpr size_t kBufferSize = 128;
42
43std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
44 std::set<pid_t> pids{root_pid};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070045 bool progress = false;
46
47 do {
48 progress = false;
49 DIR* d = opendir("/proc");
50 if (!d)
51 pdie("opendir(\"/proc\")");
52
53 struct dirent* dir_entry;
54 while ((dir_entry = readdir(d)) != nullptr) {
55 if (dir_entry->d_type != DT_DIR)
56 continue;
57 char* end;
58 const int pid = strtol(dir_entry->d_name, &end, 10);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070059 if (*end != '\0')
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070060 continue;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070061 std::string path = "/proc/" + std::to_string(pid) + "/stat";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070062
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070063 FILE* f = fopen(path.c_str(), "re");
Luis Héctor Chávez25214912021-01-03 05:47:09 -080064 if (!f) {
65 if (errno == ENOENT) {
66 // This loop is inherently racy, since PIDs can be reaped in the
67 // middle of this. Not being able to find one /proc/PID/stat file is
68 // completely normal.
69 continue;
70 }
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070071 pdie("fopen(%s)", path.c_str());
Luis Héctor Chávez25214912021-01-03 05:47:09 -080072 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070073 pid_t ppid;
74 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070075 fclose(f);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070076 if (ret != 1) {
77 continue;
78 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070079 if (pids.find(ppid) == pids.end())
80 continue;
81 progress |= pids.insert(pid).second;
82 }
83 closedir(d);
84 } while (progress);
85 return pids;
86}
87
88std::map<std::string, std::string> GetNamespaces(
89 pid_t pid,
90 const std::vector<std::string>& namespace_names) {
91 std::map<std::string, std::string> namespaces;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070092 char buf[kBufferSize];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070093 for (const auto& namespace_name : namespace_names) {
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070094 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
95 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070096 if (len == -1)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070097 pdie("readlink(\"%s\")", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070098 namespaces.emplace(namespace_name, std::string(buf, len));
99 }
100 return namespaces;
101}
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400102
103} // namespace
104
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400105/* Silence unused variable warnings. */
106TEST(silence, silence_unused) {
107 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
108 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
109 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
110}
111
112TEST(consumebytes, zero) {
113 char buf[1024];
114 size_t len = sizeof(buf);
115 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400116 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400117 EXPECT_EQ(&buf[0], pos);
118 EXPECT_EQ(sizeof(buf), len);
119}
120
121TEST(consumebytes, exact) {
122 char buf[1024];
123 size_t len = sizeof(buf);
124 char *pos = &buf[0];
125 /* One past the end since it consumes the whole buffer. */
126 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400127 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400128 EXPECT_EQ((size_t)0, len);
129 EXPECT_EQ(end, pos);
130}
131
132TEST(consumebytes, half) {
133 char buf[1024];
134 size_t len = sizeof(buf);
135 char *pos = &buf[0];
136 /* One past the end since it consumes the whole buffer. */
137 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400138 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400139 EXPECT_EQ(sizeof(buf) / 2, len);
140 EXPECT_EQ(end, pos);
141}
142
143TEST(consumebytes, toolong) {
144 char buf[1024];
145 size_t len = sizeof(buf);
146 char *pos = &buf[0];
147 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400148 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400149 EXPECT_EQ(sizeof(buf), len);
150 EXPECT_EQ(&buf[0], pos);
151}
152
153TEST(consumestr, zero) {
154 char buf[1024];
155 size_t len = 0;
156 char *pos = &buf[0];
157 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400158 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400159 EXPECT_EQ((size_t)0, len);
160 EXPECT_EQ(&buf[0], pos);
161}
162
163TEST(consumestr, nonul) {
164 char buf[1024];
165 size_t len = sizeof(buf);
166 char *pos = &buf[0];
167 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400168 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400169 EXPECT_EQ(sizeof(buf), len);
170 EXPECT_EQ(&buf[0], pos);
171}
172
173TEST(consumestr, full) {
174 char buf[1024];
175 size_t len = sizeof(buf);
176 char *pos = &buf[0];
177 memset(buf, 0xff, sizeof(buf));
178 buf[sizeof(buf)-1] = '\0';
179 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
180 EXPECT_EQ((size_t)0, len);
181 EXPECT_EQ(&buf[sizeof(buf)], pos);
182}
183
184TEST(consumestr, trailing_nul) {
185 char buf[1024];
186 size_t len = sizeof(buf) - 1;
187 char *pos = &buf[0];
188 memset(buf, 0xff, sizeof(buf));
189 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400190 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400191 EXPECT_EQ(sizeof(buf) - 1, len);
192 EXPECT_EQ(&buf[0], pos);
193}
194
195class MarshalTest : public ::testing::Test {
196 protected:
197 virtual void SetUp() {
198 m_ = minijail_new();
199 j_ = minijail_new();
200 size_ = minijail_size(m_);
201 }
202 virtual void TearDown() {
203 minijail_destroy(m_);
204 minijail_destroy(j_);
205 }
206
207 char buf_[4096];
208 struct minijail *m_;
209 struct minijail *j_;
210 size_t size_;
211};
212
213TEST_F(MarshalTest, empty) {
214 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
215 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
216}
217
218TEST_F(MarshalTest, 0xff) {
219 memset(buf_, 0xff, sizeof(buf_));
220 /* Should fail on the first consumestr since a NUL will never be found. */
221 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
222}
223
Dylan Reid6dc224f2021-05-12 17:06:25 -0700224TEST_F(MarshalTest, copy_empty) {
225 ASSERT_EQ(0, minijail_copy_jail(m_, j_));
226}
227
François Degros47e63352019-10-01 13:01:53 +1000228TEST(KillTest, running_process) {
229 const ScopedMinijail j(minijail_new());
230 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
231 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
232 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
233 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
234}
235
236TEST(KillTest, process_already_awaited) {
237 const ScopedMinijail j(minijail_new());
238 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
239 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
240 EXPECT_EQ(minijail_wait(j.get()), 42);
241 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
242}
243
244TEST(KillTest, process_already_finished_but_not_awaited) {
245 int fds[2];
246 const ScopedMinijail j(minijail_new());
247 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
248 ASSERT_EQ(pipe(fds), 0);
249 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
250 ASSERT_EQ(close(fds[1]), 0);
251 // Wait for process to finish.
252 char buf[PIPE_BUF];
253 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
254 EXPECT_EQ(minijail_kill(j.get()), 42);
255 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
256}
257
258TEST(KillTest, process_not_started) {
259 const ScopedMinijail j(minijail_new());
260 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
261}
262
François Degros08b10f72019-10-09 12:44:05 +1100263TEST(WaitTest, return_zero) {
264 const ScopedMinijail j(minijail_new());
265 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
266 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
267 EXPECT_EQ(minijail_wait(j.get()), 0);
268}
269
270TEST(WaitTest, return_max) {
271 const ScopedMinijail j(minijail_new());
272 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
273 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
274 EXPECT_EQ(minijail_wait(j.get()), 255);
275}
276
277TEST(WaitTest, return_modulo) {
278 const ScopedMinijail j(minijail_new());
279 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
280 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
281 EXPECT_EQ(minijail_wait(j.get()), 0);
282}
283
284TEST(WaitTest, killed_by_sigkill) {
285 const ScopedMinijail j(minijail_new());
286 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
287 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
288 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
289}
290
291TEST(WaitTest, killed_by_sigsys) {
292 const ScopedMinijail j(minijail_new());
293 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
294 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
295 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
296}
297
298TEST(WaitTest, command_not_found) {
299 const ScopedMinijail j(minijail_new());
300 char* const argv[] = {"whatever", nullptr};
301 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
302 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
303}
304
305TEST(WaitTest, command_not_run) {
306 const ScopedMinijail j(minijail_new());
307 char* const argv[] = {"whatever", nullptr};
308 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
309 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
310}
311
312TEST(WaitTest, no_process) {
313 const ScopedMinijail j(minijail_new());
314 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
315}
316
317TEST(WaitTest, can_wait_only_once) {
318 const ScopedMinijail j(minijail_new());
319 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
320 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
321 EXPECT_EQ(minijail_wait(j.get()), 0);
322 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
323}
324
François Degros26f8e4e2020-04-17 09:31:02 +1000325TEST(Test, minijail_preserve_fd_no_leak) {
326 const ScopedMinijail j(minijail_new());
327 char* const script = R"(
328 echo Hi >&1;
329 exec 1>&-;
330 read line1;
331 read line2;
332 echo "$line1$line2 and Goodbye" >&2;
333 exit 42;
334 )";
335 char* const argv[] = {"sh", "-c", script, nullptr};
336
337 const int npipes = 3;
338 int fds[npipes][2];
339
340 // Create pipes.
341 for (int i = 0; i < npipes; ++i) {
342 ASSERT_EQ(pipe(fds[i]), 0);
343 }
344
345 // All pipes are output pipes except for the first one which is used as
346 // input pipe.
347 std::swap(fds[0][0], fds[0][1]);
348
349 for (int i = 0; i < npipes; ++i) {
350 const int fd = fds[i][1];
351 minijail_preserve_fd(j.get(), fd, i);
352 }
353
354 minijail_close_open_fds(j.get());
355
356 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
357
358 // Close unused end of pipes.
359 for (int i = 0; i < npipes; ++i) {
360 const int fd = fds[i][1];
361 ASSERT_EQ(close(fd), 0);
362 }
363
364 const int in = fds[0][0];
365 const int out = fds[1][0];
366 const int err = fds[2][0];
367
368 char buf[PIPE_BUF];
369 ssize_t nbytes;
370
371 // Check that stdout pipe works.
372 nbytes = read(out, buf, PIPE_BUF);
373 ASSERT_GT(nbytes, 0);
374 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
375
376 // Check that the write end of stdout pipe got closed by the child process. If
377 // the child process kept other file descriptors connected to stdout, then the
378 // parent process wouldn't be able to detect that all write ends of this pipe
379 // are closed and it would block here.
380 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
381 ASSERT_EQ(close(out), 0);
382
383 // Check that stdin pipe works.
384 const std::string s = "Greetings\n";
385 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
386
387 // Close write end of pipe connected to child's stdin. If there was another
388 // file descriptor connected to this write end, then the child process
389 // wouldn't be able to detect that this write end is closed and it would
390 // block.
391 ASSERT_EQ(close(in), 0);
392
393 // Check that child process continued and ended.
394 nbytes = read(err, buf, PIPE_BUF);
395 ASSERT_GT(nbytes, 0);
396 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
397
398 // Check that the write end of the stderr pipe is closed when the child
399 // process finishes.
400 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
401 ASSERT_EQ(close(err), 0);
402
403 // Check the child process termination status.
404 EXPECT_EQ(minijail_wait(j.get()), 42);
405}
406
François Degrosa8be2c42019-10-01 12:06:42 +1000407TEST(Test, close_original_pipes_after_dup2) {
408 // Pipe used by child process to signal that it continued after reading from
409 // stdin.
410 int to_wait[2];
411 ASSERT_EQ(pipe(to_wait), 0);
412
413 const ScopedMinijail j(minijail_new());
414 char* program;
415 ASSERT_GT(asprintf(&program, R"(
416 echo Hi >&1;
417 echo There >&2;
418 exec 1>&-;
419 exec 2>&-;
420 read line1;
421 read line2;
422 echo "$line1$line2 and Goodbye" >&%d;
423 exit 42;
424 )", to_wait[1]), 0);
François Degros87f0e832019-10-10 10:22:39 +1100425 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000426
427 int in = -1;
428 int out = -1;
429 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400430 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
431 nullptr, &in, &out, &err),
432 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000433 free(program);
434
435 EXPECT_GT(in, 0);
436 EXPECT_GT(out, 0);
437 EXPECT_GT(err, 0);
438
439 char buf[PIPE_BUF];
440 ssize_t n;
441
442 // Check that stdout and stderr pipes work.
443 n = read(out, buf, PIPE_BUF);
444 ASSERT_GT(n, 0);
445 EXPECT_EQ(std::string(buf, n), "Hi\n");
446
447 n = read(err, buf, PIPE_BUF);
448 ASSERT_GT(n, 0);
449 EXPECT_EQ(std::string(buf, n), "There\n");
450
451 // Check that the write ends of stdout and stderr pipes got closed by the
452 // child process. If the child process kept other file descriptors connected
453 // to stdout and stderr, then the parent process wouldn't be able to detect
454 // that all write ends of these pipes are closed and it would block here.
455 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000456 ASSERT_EQ(close(out), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000457 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000458 ASSERT_EQ(close(err), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000459
460 // Check that stdin pipe works.
461 const std::string s = "Greetings\n";
462 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
463
464 // Close write end of pipe connected to child's stdin. If there was another
465 // file descriptor connected to this write end, then the child wouldn't be
466 // able to detect that this write end is closed and it would block.
467 ASSERT_EQ(close(in), 0);
468
469 // Check that child process continued and ended.
470 n = read(to_wait[0], buf, PIPE_BUF);
471 ASSERT_GT(n, 0);
472 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
473 EXPECT_EQ(minijail_wait(j.get()), 42);
474}
475
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100476TEST(Test, minijail_run_env_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700477 // TODO(crbug.com/895875): The preload library interferes with ASan since they
478 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800479 if (running_with_asan())
480 GTEST_SKIP();
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700481
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700482 ScopedMinijail j(minijail_new());
483 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700484
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100485 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700486 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100487 argv[1] = NULL;
488
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700489 pid_t pid;
490 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100491 int mj_run_ret = minijail_run_pid_pipes(
492 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700493 EXPECT_EQ(mj_run_ret, 0);
494
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100495 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700496 const size_t teststr_len = strlen(teststr);
497 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
498 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
499
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100500 char buf[kBufferSize] = {};
501 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700502 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100503 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700504
505 int status;
506 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100507 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700508 ASSERT_TRUE(WIFSIGNALED(status));
509 EXPECT_EQ(WTERMSIG(status), SIGTERM);
510
511 argv[0] = const_cast<char*>(kShellPath);
512 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100513 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700514 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700515
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500516 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100517 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500518 envp[1] = NULL;
519
520 // Set a canary env var in the parent that should not be present in the child.
521 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
522
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100523 int child_stderr;
524 mj_run_ret =
525 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
526 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500527 EXPECT_EQ(mj_run_ret, 0);
528
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100529 memset(buf, 0, sizeof(buf));
530 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
531 EXPECT_GE(read_ret, 0);
532 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500533
534 EXPECT_EQ(waitpid(pid, &status, 0), pid);
535 ASSERT_TRUE(WIFEXITED(status));
536 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100537}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500538
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800539TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
540 // TODO(crbug.com/895875): The preload library interferes with ASan since they
541 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800542 if (running_with_asan())
543 GTEST_SKIP();
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800544
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100545 ScopedMinijail j(minijail_new());
546
547 char *argv[4];
548 argv[0] = const_cast<char*>(kCatPath);
549 argv[1] = NULL;
550
551 pid_t pid;
552 int child_stdin, child_stdout;
553 int mj_run_ret = minijail_run_pid_pipes(
554 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
555 EXPECT_EQ(mj_run_ret, 0);
556
557 char teststr[] = "test\n";
558 const size_t teststr_len = strlen(teststr);
559 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
560 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
561
562 char buf[kBufferSize] = {};
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800563 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100564 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
565 EXPECT_STREQ(buf, teststr);
566
567 int status;
568 EXPECT_EQ(kill(pid, SIGTERM), 0);
569 EXPECT_EQ(waitpid(pid, &status, 0), pid);
570 ASSERT_TRUE(WIFSIGNALED(status));
571 EXPECT_EQ(WTERMSIG(status), SIGTERM);
572
573 argv[0] = const_cast<char*>(kShellPath);
574 argv[1] = "-c";
575 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
576 argv[3] = nullptr;
577
578 char *envp[2];
579 envp[0] = "TEST_VAR=test";
580 envp[1] = NULL;
581
582 // Set a canary env var in the parent that should not be present in the child.
583 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
584
Dylan Reid83276a02020-06-10 15:17:13 -0700585 // Use the preload library from this test build.
586 ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
587
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100588 int child_stderr;
589 mj_run_ret =
590 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
591 &child_stdin, &child_stdout, &child_stderr);
592 EXPECT_EQ(mj_run_ret, 0);
593
594 memset(buf, 0, sizeof(buf));
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800595 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100596 EXPECT_GE(read_ret, 0);
597 EXPECT_STREQ(buf, "|test\n");
598
599 EXPECT_EQ(waitpid(pid, &status, 0), pid);
600 ASSERT_TRUE(WIFEXITED(status));
601 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500602}
603
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400604TEST(Test, test_minijail_no_fd_leaks) {
605 pid_t pid;
606 int child_stdout;
607 int mj_run_ret;
608 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700609 char buf[kBufferSize];
610 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400611 int status;
612 char *argv[4];
613
614 int dev_null = open("/dev/null", O_RDONLY);
615 ASSERT_NE(dev_null, -1);
616 snprintf(script,
617 sizeof(script),
618 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
619 dev_null);
620
621 struct minijail *j = minijail_new();
622
François Degros87f0e832019-10-10 10:22:39 +1100623 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400624 argv[1] = "-c";
625 argv[2] = script;
626 argv[3] = NULL;
627 mj_run_ret = minijail_run_pid_pipes_no_preload(
628 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
629 EXPECT_EQ(mj_run_ret, 0);
630
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700631 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400632 EXPECT_GE(read_ret, 0);
633 buf[read_ret] = '\0';
634 EXPECT_STREQ(buf, "yes\n");
635
636 waitpid(pid, &status, 0);
637 ASSERT_TRUE(WIFEXITED(status));
638 EXPECT_EQ(WEXITSTATUS(status), 0);
639
640 minijail_close_open_fds(j);
641 mj_run_ret = minijail_run_pid_pipes_no_preload(
642 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
643 EXPECT_EQ(mj_run_ret, 0);
644
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700645 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400646 EXPECT_GE(read_ret, 0);
647 buf[read_ret] = '\0';
648 EXPECT_STREQ(buf, "no\n");
649
650 waitpid(pid, &status, 0);
651 ASSERT_TRUE(WIFEXITED(status));
652 EXPECT_EQ(WEXITSTATUS(status), 0);
653
654 minijail_destroy(j);
655
656 close(dev_null);
657}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100658
Dylan Reid0412dcc2017-08-24 11:33:15 -0700659TEST(Test, test_minijail_fork) {
660 pid_t mj_fork_ret;
661 int status;
662 int pipe_fds[2];
663 ssize_t pid_size = sizeof(mj_fork_ret);
664
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700665 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700666
667 ASSERT_EQ(pipe(pipe_fds), 0);
668
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700669 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700670 ASSERT_GE(mj_fork_ret, 0);
671 if (mj_fork_ret == 0) {
672 pid_t pid_in_parent;
673 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700674 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
675 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700676 exit(0);
677 }
678
679 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
680 waitpid(mj_fork_ret, &status, 0);
681 ASSERT_TRUE(WIFEXITED(status));
682 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700683}
684
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700685static int early_exit(void* payload) {
686 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
687}
688
689TEST(Test, test_minijail_callback) {
690 pid_t pid;
691 int mj_run_ret;
692 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700693 char *argv[2];
694 int exit_code = 42;
695
696 struct minijail *j = minijail_new();
697
698 status =
699 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500700 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700701 EXPECT_EQ(status, 0);
702
François Degros87f0e832019-10-10 10:22:39 +1100703 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700704 argv[1] = NULL;
705 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500706 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700707 EXPECT_EQ(mj_run_ret, 0);
708
709 status = minijail_wait(j);
710 EXPECT_EQ(status, exit_code);
711
712 minijail_destroy(j);
713}
714
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700715TEST(Test, test_minijail_preserve_fd) {
716 int mj_run_ret;
717 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700718 char *argv[2];
719 char teststr[] = "test\n";
720 size_t teststr_len = strlen(teststr);
721 int read_pipe[2];
722 int write_pipe[2];
723 char buf[1024];
724
725 struct minijail *j = minijail_new();
726
727 status = pipe(read_pipe);
728 ASSERT_EQ(status, 0);
729 status = pipe(write_pipe);
730 ASSERT_EQ(status, 0);
731
732 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
733 ASSERT_EQ(status, 0);
734 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
735 ASSERT_EQ(status, 0);
736 minijail_close_open_fds(j);
737
François Degros87f0e832019-10-10 10:22:39 +1100738 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700739 argv[1] = NULL;
740 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
741 EXPECT_EQ(mj_run_ret, 0);
742
743 close(write_pipe[0]);
744 status = write(write_pipe[1], teststr, teststr_len);
745 EXPECT_EQ(status, (int)teststr_len);
746 close(write_pipe[1]);
747
748 close(read_pipe[1]);
749 status = read(read_pipe[0], buf, 8);
750 EXPECT_EQ(status, (int)teststr_len);
751 buf[teststr_len] = 0;
752 EXPECT_EQ(strcmp(buf, teststr), 0);
753
754 status = minijail_wait(j);
755 EXPECT_EQ(status, 0);
756
757 minijail_destroy(j);
758}
759
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700760TEST(Test, test_minijail_reset_signal_mask) {
761 struct minijail *j = minijail_new();
762
763 sigset_t original_signal_mask;
764 {
765 sigset_t signal_mask;
766 ASSERT_EQ(0, sigemptyset(&signal_mask));
767 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
768 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
769 }
770
771 minijail_reset_signal_mask(j);
772
773 pid_t mj_fork_ret = minijail_fork(j);
774 ASSERT_GE(mj_fork_ret, 0);
775 if (mj_fork_ret == 0) {
776 sigset_t signal_mask;
777 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
778 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400779 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700780 exit(0);
781 }
782
783 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
784
785 int status;
786 waitpid(mj_fork_ret, &status, 0);
787 ASSERT_TRUE(WIFEXITED(status));
788 EXPECT_EQ(WEXITSTATUS(status), 0);
789
790 minijail_destroy(j);
791}
792
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700793TEST(Test, test_minijail_reset_signal_handlers) {
794 struct minijail *j = minijail_new();
795
796 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
797 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
798 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
799
800 minijail_reset_signal_handlers(j);
801
802 pid_t mj_fork_ret = minijail_fork(j);
803 ASSERT_GE(mj_fork_ret, 0);
804 if (mj_fork_ret == 0) {
805 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400806 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700807 exit(0);
808 }
809
810 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
811
812 int status;
813 waitpid(mj_fork_ret, &status, 0);
814 ASSERT_TRUE(WIFEXITED(status));
815 EXPECT_EQ(WEXITSTATUS(status), 0);
816
817 minijail_destroy(j);
818}
819
Mike Frysinger780aef72017-10-03 01:39:52 -0400820namespace {
821
822// Tests that require userns access.
823// Android unit tests don't currently support entering user namespaces as
824// unprivileged users due to having an older kernel. Chrome OS unit tests
825// don't support it either due to being in a chroot environment (see man 2
826// clone for more information about failure modes with the CLONE_NEWUSER flag).
827class NamespaceTest : public ::testing::Test {
828 protected:
829 static void SetUpTestCase() {
830 userns_supported_ = UsernsSupported();
831 }
832
833 // Whether userns is supported.
834 static bool userns_supported_;
835
836 static bool UsernsSupported() {
837 pid_t pid = fork();
838 if (pid == -1)
839 pdie("could not fork");
840
841 if (pid == 0)
842 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
843
844 int status;
845 if (waitpid(pid, &status, 0) < 0)
846 pdie("could not wait");
847
848 if (!WIFEXITED(status))
849 die("child did not exit properly: %#x", status);
850
851 bool ret = WEXITSTATUS(status) == 0;
852 if (!ret)
853 warn("Skipping userns related tests");
854 return ret;
855 }
856};
857
858bool NamespaceTest::userns_supported_;
859
860} // namespace
861
862TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700863 int mj_run_ret;
864 int status;
865 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700866 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700867 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
868 constexpr gid_t kTargetGid = 1000;
869
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800870 if (!userns_supported_)
871 GTEST_SKIP();
Mike Frysinger780aef72017-10-03 01:39:52 -0400872
Luis Hector Chavez71323552017-09-05 09:17:22 -0700873 struct minijail *j = minijail_new();
874
875 minijail_namespace_pids(j);
876 minijail_namespace_vfs(j);
877 minijail_mount_tmp(j);
878 minijail_run_as_init(j);
879
880 // Perform userns mapping.
881 minijail_namespace_user(j);
882 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
883 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
884 minijail_change_uid(j, kTargetUid);
885 minijail_change_gid(j, kTargetGid);
886 minijail_uidmap(j, uidmap);
887 minijail_gidmap(j, gidmap);
888 minijail_namespace_user_disable_setgroups(j);
889
François Degros87f0e832019-10-10 10:22:39 +1100890 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -0700891 argv[1] = "-c";
892 argv[2] = "exec touch /tmp/foo";
893 argv[3] = NULL;
894 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
895 EXPECT_EQ(mj_run_ret, 0);
896
897 status = minijail_wait(j);
898 EXPECT_EQ(status, 0);
899
900 minijail_destroy(j);
901}
902
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700903TEST_F(NamespaceTest, test_namespaces) {
904 constexpr char teststr[] = "test\n";
905
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700906 // TODO(crbug.com/895875): The preload library interferes with ASan since they
907 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800908 if (!userns_supported_ || running_with_asan())
909 GTEST_SKIP();
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700910
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700911 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
912 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700913
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700914 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
915 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700916 // Grab the set of namespaces outside the container.
917 std::map<std::string, std::string> init_namespaces =
918 GetNamespaces(getpid(), namespace_names);
919 std::function<void(struct minijail*)> test_functions[] = {
920 [](struct minijail* j attribute_unused) {},
921 [](struct minijail* j) {
922 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
923 minijail_enter_pivot_root(j, "/tmp");
924 },
925 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
926 };
927
928 // This test is run with and without the preload library.
929 for (const auto& run_function :
930 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
931 for (const auto& test_function : test_functions) {
932 ScopedMinijail j(minijail_new());
933 minijail_set_preload_path(j.get(), kPreloadPath);
934
935 // Enter all the namespaces we can.
936 minijail_namespace_cgroups(j.get());
937 minijail_namespace_net(j.get());
938 minijail_namespace_pids(j.get());
939 minijail_namespace_user(j.get());
940 minijail_namespace_vfs(j.get());
941 minijail_namespace_uts(j.get());
942
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700943 // Set up the user namespace.
944 minijail_uidmap(j.get(), uidmap.c_str());
945 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700946 minijail_namespace_user_disable_setgroups(j.get());
947
948 minijail_close_open_fds(j.get());
949 test_function(j.get());
950
François Degros87f0e832019-10-10 10:22:39 +1100951 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700952 pid_t container_pid;
953 int child_stdin, child_stdout;
954 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +1100955 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700956 &container_pid, &child_stdin, &child_stdout, nullptr);
957 EXPECT_EQ(mj_run_ret, 0);
958
959 // Send some data to stdin and read it back to ensure that the child
960 // process is running.
961 const size_t teststr_len = strlen(teststr);
962 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
963 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
964
965 char buf[kBufferSize];
966 ssize_t read_ret = read(child_stdout, buf, 8);
967 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
968 buf[teststr_len] = 0;
969 EXPECT_EQ(strcmp(buf, teststr), 0);
970
971 // Grab the set of namespaces in every container process. They must not
972 // match the ones in the init namespace, and they must all match each
973 // other.
974 std::map<std::string, std::string> container_namespaces =
975 GetNamespaces(container_pid, namespace_names);
976 EXPECT_NE(container_namespaces, init_namespaces);
977 for (pid_t pid : GetProcessSubtreePids(container_pid))
978 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
979
980 EXPECT_EQ(0, close(child_stdin));
981
982 int status = minijail_wait(j.get());
983 EXPECT_EQ(status, 0);
984 }
985 }
986}
987
Mike Frysinger902a4492018-12-27 05:22:56 -0500988TEST_F(NamespaceTest, test_enter_ns) {
989 char uidmap[kBufferSize], gidmap[kBufferSize];
990
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800991 if (!userns_supported_)
992 GTEST_SKIP();
Mike Frysinger902a4492018-12-27 05:22:56 -0500993
994 // We first create a child in a new userns so we have privs to run more tests.
995 // We can't combine the steps as the kernel disallows many resource sharing
996 // from outside the userns.
997 struct minijail *j = minijail_new();
998
999 minijail_namespace_vfs(j);
1000 minijail_namespace_pids(j);
1001 minijail_run_as_init(j);
1002
1003 // Perform userns mapping.
1004 minijail_namespace_user(j);
1005 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1006 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1007 minijail_uidmap(j, uidmap);
1008 minijail_gidmap(j, gidmap);
1009 minijail_namespace_user_disable_setgroups(j);
1010
1011 pid_t pid = minijail_fork(j);
1012 if (pid == 0) {
1013 // Child.
1014 minijail_destroy(j);
1015
1016 // Create new namespaces inside this userns which we may enter.
1017 j = minijail_new();
1018 minijail_namespace_net(j);
1019 minijail_namespace_vfs(j);
1020 pid = minijail_fork(j);
1021 if (pid == 0) {
1022 // Child.
1023 minijail_destroy(j);
1024
1025 // Finally enter those namespaces.
1026 j = minijail_new();
1027
1028 // We need to get the absolute path because entering a new mntns will
1029 // implicitly chdir(/) for us.
1030 char *path = realpath(kPreloadPath, nullptr);
1031 ASSERT_NE(nullptr, path);
1032 minijail_set_preload_path(j, path);
1033
1034 minijail_namespace_net(j);
1035 minijail_namespace_vfs(j);
1036
1037 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1038 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1039
1040 char *argv[] = {"/bin/true", nullptr};
1041 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1042 EXPECT_EQ(0, minijail_wait(j));
1043 minijail_destroy(j);
1044 exit(0);
1045 } else {
1046 ASSERT_GT(pid, 0);
1047 EXPECT_EQ(0, minijail_wait(j));
1048 minijail_destroy(j);
1049 exit(0);
1050 }
1051 } else {
1052 ASSERT_GT(pid, 0);
1053 EXPECT_EQ(0, minijail_wait(j));
1054 minijail_destroy(j);
1055 }
1056}
1057
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001058TEST_F(NamespaceTest, test_remount_all_private) {
1059 pid_t pid;
1060 int child_stdout;
1061 int mj_run_ret;
1062 ssize_t read_ret;
1063 char buf[kBufferSize];
1064 int status;
1065 char *argv[4];
1066 char uidmap[kBufferSize], gidmap[kBufferSize];
1067 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1068 constexpr gid_t kTargetGid = 1000;
1069
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001070 if (!userns_supported_)
1071 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001072
1073 struct minijail *j = minijail_new();
1074
1075 minijail_namespace_pids(j);
1076 minijail_namespace_vfs(j);
1077 minijail_run_as_init(j);
1078
1079 // Perform userns mapping.
1080 minijail_namespace_user(j);
1081 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1082 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1083 minijail_change_uid(j, kTargetUid);
1084 minijail_change_gid(j, kTargetGid);
1085 minijail_uidmap(j, uidmap);
1086 minijail_gidmap(j, gidmap);
1087 minijail_namespace_user_disable_setgroups(j);
1088
1089 minijail_namespace_vfs(j);
1090 minijail_remount_mode(j, MS_PRIVATE);
1091
1092 argv[0] = const_cast<char*>(kShellPath);
1093 argv[1] = "-c";
1094 argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
1095 "/proc/self/mountinfo";
1096 argv[3] = NULL;
1097 mj_run_ret = minijail_run_pid_pipes_no_preload(
1098 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1099 EXPECT_EQ(mj_run_ret, 0);
1100
1101 // There should be no output because all mounts should be remounted as
1102 // private.
1103 read_ret = read(child_stdout, buf, sizeof(buf));
1104 EXPECT_EQ(read_ret, 0);
1105
1106 // grep will exit with 1 if it does not find anything which is what we
1107 // expect.
1108 status = minijail_wait(j);
1109 EXPECT_EQ(status, 1);
1110
1111 minijail_destroy(j);
1112}
1113
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001114TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1115 int status;
1116 char uidmap[kBufferSize], gidmap[kBufferSize];
1117 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1118 constexpr gid_t kTargetGid = 1000;
1119
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001120 if (!userns_supported_)
1121 GTEST_SKIP();
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001122
1123 struct minijail *j = minijail_new();
1124
1125 minijail_namespace_pids(j);
1126 minijail_namespace_vfs(j);
1127 minijail_mount_tmp(j);
1128 minijail_run_as_init(j);
1129
1130 // Perform userns mapping.
1131 minijail_namespace_user(j);
1132 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1133 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1134 minijail_change_uid(j, kTargetUid);
1135 minijail_change_gid(j, kTargetGid);
1136 minijail_uidmap(j, uidmap);
1137 minijail_gidmap(j, gidmap);
1138 minijail_namespace_user_disable_setgroups(j);
1139
1140 minijail_namespace_vfs(j);
1141 minijail_remount_mode(j, MS_SHARED);
1142 minijail_add_remount(j, "/proc", MS_PRIVATE);
1143
1144 char *argv[] = {"/bin/true", nullptr};
1145 minijail_run(j, argv[0], argv);
1146
1147 status = minijail_wait(j);
1148 EXPECT_GT(status, 0);
1149
1150 minijail_destroy(j);
1151}
1152
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001153TEST_F(NamespaceTest, test_remount_one_shared) {
1154 pid_t pid;
1155 int child_stdout;
1156 int mj_run_ret;
1157 ssize_t read_ret;
1158 char buf[kBufferSize * 4];
1159 int status;
1160 char *argv[4];
1161 char uidmap[kBufferSize], gidmap[kBufferSize];
1162 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1163 constexpr gid_t kTargetGid = 1000;
1164
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001165 if (!userns_supported_)
1166 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001167
1168 struct minijail *j = minijail_new();
1169
1170 minijail_namespace_pids(j);
1171 minijail_namespace_vfs(j);
1172 minijail_mount_tmp(j);
1173 minijail_run_as_init(j);
1174
1175 // Perform userns mapping.
1176 minijail_namespace_user(j);
1177 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1178 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1179 minijail_change_uid(j, kTargetUid);
1180 minijail_change_gid(j, kTargetGid);
1181 minijail_uidmap(j, uidmap);
1182 minijail_gidmap(j, gidmap);
1183 minijail_namespace_user_disable_setgroups(j);
1184
1185 minijail_namespace_vfs(j);
1186 minijail_remount_mode(j, MS_PRIVATE);
1187 minijail_add_remount(j, "/proc", MS_SHARED);
1188
1189 argv[0] = const_cast<char*>(kShellPath);
1190 argv[1] = "-c";
1191 argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1192 argv[3] = NULL;
1193 mj_run_ret = minijail_run_pid_pipes_no_preload(
1194 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1195 EXPECT_EQ(mj_run_ret, 0);
1196
1197 // There should be no output because all mounts should be remounted as
1198 // private.
1199 read_ret = read(child_stdout, buf, sizeof(buf));
1200 EXPECT_GE(read_ret, 0);
1201 buf[read_ret] = '\0';
1202 EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1203
1204 status = minijail_wait(j);
1205 EXPECT_EQ(status, 0);
1206
1207 minijail_destroy(j);
1208}
1209
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001210void TestCreateSession(bool create_session) {
1211 int status;
1212 int pipe_fds[2];
1213 pid_t child_pid;
1214 pid_t parent_sid = getsid(0);
1215 ssize_t pid_size = sizeof(pid_t);
1216
1217 ScopedMinijail j(minijail_new());
1218 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1219 // a new session because of that.
1220 minijail_close_open_fds(j.get());
1221
1222 if (create_session)
1223 minijail_create_session(j.get());
1224
1225 ASSERT_EQ(pipe(pipe_fds), 0);
1226 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1227
1228 child_pid = minijail_fork(j.get());
1229 ASSERT_GE(child_pid, 0);
1230 if (child_pid == 0) {
1231 pid_t sid_in_parent;
1232 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1233 if (create_session)
1234 ASSERT_NE(sid_in_parent, getsid(0));
1235 else
1236 ASSERT_EQ(sid_in_parent, getsid(0));
1237 exit(0);
1238 }
1239
1240 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1241 waitpid(child_pid, &status, 0);
1242 ASSERT_TRUE(WIFEXITED(status));
1243 EXPECT_EQ(WEXITSTATUS(status), 0);
1244}
1245
1246TEST(Test, default_no_new_session) {
1247 TestCreateSession(/*create_session=*/false);
1248}
1249
1250TEST(Test, create_new_session) {
1251 TestCreateSession(/*create_session=*/true);
1252}