blob: 23a30b75e3755d7020b9bc66fc66ae68b54551d6 [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 Hector Chavez86e10d32018-10-11 20:36:48 -070064 if (!f)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070065 pdie("fopen(%s)", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070066 pid_t ppid;
67 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070068 fclose(f);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070069 if (ret != 1) {
70 continue;
71 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070072 if (pids.find(ppid) == pids.end())
73 continue;
74 progress |= pids.insert(pid).second;
75 }
76 closedir(d);
77 } while (progress);
78 return pids;
79}
80
81std::map<std::string, std::string> GetNamespaces(
82 pid_t pid,
83 const std::vector<std::string>& namespace_names) {
84 std::map<std::string, std::string> namespaces;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070085 char buf[kBufferSize];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070086 for (const auto& namespace_name : namespace_names) {
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070087 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
88 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070089 if (len == -1)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070090 pdie("readlink(\"%s\")", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070091 namespaces.emplace(namespace_name, std::string(buf, len));
92 }
93 return namespaces;
94}
Mike Frysingerb2c12d12017-09-29 21:18:59 -040095
96} // namespace
97
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040098/* Silence unused variable warnings. */
99TEST(silence, silence_unused) {
100 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
101 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
102 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
103}
104
105TEST(consumebytes, zero) {
106 char buf[1024];
107 size_t len = sizeof(buf);
108 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400109 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400110 EXPECT_EQ(&buf[0], pos);
111 EXPECT_EQ(sizeof(buf), len);
112}
113
114TEST(consumebytes, exact) {
115 char buf[1024];
116 size_t len = sizeof(buf);
117 char *pos = &buf[0];
118 /* One past the end since it consumes the whole buffer. */
119 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400120 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400121 EXPECT_EQ((size_t)0, len);
122 EXPECT_EQ(end, pos);
123}
124
125TEST(consumebytes, half) {
126 char buf[1024];
127 size_t len = sizeof(buf);
128 char *pos = &buf[0];
129 /* One past the end since it consumes the whole buffer. */
130 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400131 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400132 EXPECT_EQ(sizeof(buf) / 2, len);
133 EXPECT_EQ(end, pos);
134}
135
136TEST(consumebytes, toolong) {
137 char buf[1024];
138 size_t len = sizeof(buf);
139 char *pos = &buf[0];
140 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400141 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400142 EXPECT_EQ(sizeof(buf), len);
143 EXPECT_EQ(&buf[0], pos);
144}
145
146TEST(consumestr, zero) {
147 char buf[1024];
148 size_t len = 0;
149 char *pos = &buf[0];
150 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400151 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400152 EXPECT_EQ((size_t)0, len);
153 EXPECT_EQ(&buf[0], pos);
154}
155
156TEST(consumestr, nonul) {
157 char buf[1024];
158 size_t len = sizeof(buf);
159 char *pos = &buf[0];
160 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400161 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400162 EXPECT_EQ(sizeof(buf), len);
163 EXPECT_EQ(&buf[0], pos);
164}
165
166TEST(consumestr, full) {
167 char buf[1024];
168 size_t len = sizeof(buf);
169 char *pos = &buf[0];
170 memset(buf, 0xff, sizeof(buf));
171 buf[sizeof(buf)-1] = '\0';
172 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
173 EXPECT_EQ((size_t)0, len);
174 EXPECT_EQ(&buf[sizeof(buf)], pos);
175}
176
177TEST(consumestr, trailing_nul) {
178 char buf[1024];
179 size_t len = sizeof(buf) - 1;
180 char *pos = &buf[0];
181 memset(buf, 0xff, sizeof(buf));
182 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400183 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400184 EXPECT_EQ(sizeof(buf) - 1, len);
185 EXPECT_EQ(&buf[0], pos);
186}
187
188class MarshalTest : public ::testing::Test {
189 protected:
190 virtual void SetUp() {
191 m_ = minijail_new();
192 j_ = minijail_new();
193 size_ = minijail_size(m_);
194 }
195 virtual void TearDown() {
196 minijail_destroy(m_);
197 minijail_destroy(j_);
198 }
199
200 char buf_[4096];
201 struct minijail *m_;
202 struct minijail *j_;
203 size_t size_;
204};
205
206TEST_F(MarshalTest, empty) {
207 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
208 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
209}
210
211TEST_F(MarshalTest, 0xff) {
212 memset(buf_, 0xff, sizeof(buf_));
213 /* Should fail on the first consumestr since a NUL will never be found. */
214 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
215}
216
François Degros47e63352019-10-01 13:01:53 +1000217TEST(KillTest, running_process) {
218 const ScopedMinijail j(minijail_new());
219 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
220 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
221 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
222 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
223}
224
225TEST(KillTest, process_already_awaited) {
226 const ScopedMinijail j(minijail_new());
227 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
228 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
229 EXPECT_EQ(minijail_wait(j.get()), 42);
230 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
231}
232
233TEST(KillTest, process_already_finished_but_not_awaited) {
234 int fds[2];
235 const ScopedMinijail j(minijail_new());
236 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
237 ASSERT_EQ(pipe(fds), 0);
238 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
239 ASSERT_EQ(close(fds[1]), 0);
240 // Wait for process to finish.
241 char buf[PIPE_BUF];
242 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
243 EXPECT_EQ(minijail_kill(j.get()), 42);
244 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
245}
246
247TEST(KillTest, process_not_started) {
248 const ScopedMinijail j(minijail_new());
249 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
250}
251
François Degros08b10f72019-10-09 12:44:05 +1100252TEST(WaitTest, return_zero) {
253 const ScopedMinijail j(minijail_new());
254 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
255 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
256 EXPECT_EQ(minijail_wait(j.get()), 0);
257}
258
259TEST(WaitTest, return_max) {
260 const ScopedMinijail j(minijail_new());
261 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
262 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
263 EXPECT_EQ(minijail_wait(j.get()), 255);
264}
265
266TEST(WaitTest, return_modulo) {
267 const ScopedMinijail j(minijail_new());
268 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
269 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
270 EXPECT_EQ(minijail_wait(j.get()), 0);
271}
272
273TEST(WaitTest, killed_by_sigkill) {
274 const ScopedMinijail j(minijail_new());
275 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
276 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
277 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
278}
279
280TEST(WaitTest, killed_by_sigsys) {
281 const ScopedMinijail j(minijail_new());
282 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
283 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
284 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
285}
286
287TEST(WaitTest, command_not_found) {
288 const ScopedMinijail j(minijail_new());
289 char* const argv[] = {"whatever", nullptr};
290 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
291 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
292}
293
294TEST(WaitTest, command_not_run) {
295 const ScopedMinijail j(minijail_new());
296 char* const argv[] = {"whatever", nullptr};
297 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
298 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
299}
300
301TEST(WaitTest, no_process) {
302 const ScopedMinijail j(minijail_new());
303 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
304}
305
306TEST(WaitTest, can_wait_only_once) {
307 const ScopedMinijail j(minijail_new());
308 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
309 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
310 EXPECT_EQ(minijail_wait(j.get()), 0);
311 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
312}
313
François Degros26f8e4e2020-04-17 09:31:02 +1000314TEST(Test, minijail_preserve_fd_no_leak) {
315 const ScopedMinijail j(minijail_new());
316 char* const script = R"(
317 echo Hi >&1;
318 exec 1>&-;
319 read line1;
320 read line2;
321 echo "$line1$line2 and Goodbye" >&2;
322 exit 42;
323 )";
324 char* const argv[] = {"sh", "-c", script, nullptr};
325
326 const int npipes = 3;
327 int fds[npipes][2];
328
329 // Create pipes.
330 for (int i = 0; i < npipes; ++i) {
331 ASSERT_EQ(pipe(fds[i]), 0);
332 }
333
334 // All pipes are output pipes except for the first one which is used as
335 // input pipe.
336 std::swap(fds[0][0], fds[0][1]);
337
338 for (int i = 0; i < npipes; ++i) {
339 const int fd = fds[i][1];
340 minijail_preserve_fd(j.get(), fd, i);
341 }
342
343 minijail_close_open_fds(j.get());
344
345 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
346
347 // Close unused end of pipes.
348 for (int i = 0; i < npipes; ++i) {
349 const int fd = fds[i][1];
350 ASSERT_EQ(close(fd), 0);
351 }
352
353 const int in = fds[0][0];
354 const int out = fds[1][0];
355 const int err = fds[2][0];
356
357 char buf[PIPE_BUF];
358 ssize_t nbytes;
359
360 // Check that stdout pipe works.
361 nbytes = read(out, buf, PIPE_BUF);
362 ASSERT_GT(nbytes, 0);
363 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
364
365 // Check that the write end of stdout pipe got closed by the child process. If
366 // the child process kept other file descriptors connected to stdout, then the
367 // parent process wouldn't be able to detect that all write ends of this pipe
368 // are closed and it would block here.
369 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
370 ASSERT_EQ(close(out), 0);
371
372 // Check that stdin pipe works.
373 const std::string s = "Greetings\n";
374 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
375
376 // Close write end of pipe connected to child's stdin. If there was another
377 // file descriptor connected to this write end, then the child process
378 // wouldn't be able to detect that this write end is closed and it would
379 // block.
380 ASSERT_EQ(close(in), 0);
381
382 // Check that child process continued and ended.
383 nbytes = read(err, buf, PIPE_BUF);
384 ASSERT_GT(nbytes, 0);
385 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
386
387 // Check that the write end of the stderr pipe is closed when the child
388 // process finishes.
389 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
390 ASSERT_EQ(close(err), 0);
391
392 // Check the child process termination status.
393 EXPECT_EQ(minijail_wait(j.get()), 42);
394}
395
François Degrosa8be2c42019-10-01 12:06:42 +1000396TEST(Test, close_original_pipes_after_dup2) {
397 // Pipe used by child process to signal that it continued after reading from
398 // stdin.
399 int to_wait[2];
400 ASSERT_EQ(pipe(to_wait), 0);
401
402 const ScopedMinijail j(minijail_new());
403 char* program;
404 ASSERT_GT(asprintf(&program, R"(
405 echo Hi >&1;
406 echo There >&2;
407 exec 1>&-;
408 exec 2>&-;
409 read line1;
410 read line2;
411 echo "$line1$line2 and Goodbye" >&%d;
412 exit 42;
413 )", to_wait[1]), 0);
François Degros87f0e832019-10-10 10:22:39 +1100414 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000415
416 int in = -1;
417 int out = -1;
418 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400419 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
420 nullptr, &in, &out, &err),
421 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000422 free(program);
423
424 EXPECT_GT(in, 0);
425 EXPECT_GT(out, 0);
426 EXPECT_GT(err, 0);
427
428 char buf[PIPE_BUF];
429 ssize_t n;
430
431 // Check that stdout and stderr pipes work.
432 n = read(out, buf, PIPE_BUF);
433 ASSERT_GT(n, 0);
434 EXPECT_EQ(std::string(buf, n), "Hi\n");
435
436 n = read(err, buf, PIPE_BUF);
437 ASSERT_GT(n, 0);
438 EXPECT_EQ(std::string(buf, n), "There\n");
439
440 // Check that the write ends of stdout and stderr pipes got closed by the
441 // child process. If the child process kept other file descriptors connected
442 // to stdout and stderr, then the parent process wouldn't be able to detect
443 // that all write ends of these pipes are closed and it would block here.
444 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000445 ASSERT_EQ(close(out), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000446 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000447 ASSERT_EQ(close(err), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000448
449 // Check that stdin pipe works.
450 const std::string s = "Greetings\n";
451 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
452
453 // Close write end of pipe connected to child's stdin. If there was another
454 // file descriptor connected to this write end, then the child wouldn't be
455 // able to detect that this write end is closed and it would block.
456 ASSERT_EQ(close(in), 0);
457
458 // Check that child process continued and ended.
459 n = read(to_wait[0], buf, PIPE_BUF);
460 ASSERT_GT(n, 0);
461 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
462 EXPECT_EQ(minijail_wait(j.get()), 42);
463}
464
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100465TEST(Test, minijail_run_env_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700466 // TODO(crbug.com/895875): The preload library interferes with ASan since they
467 // both need to use LD_PRELOAD.
468 if (running_with_asan()) {
469 SUCCEED();
470 return;
471 }
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700472
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700473 ScopedMinijail j(minijail_new());
474 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700475
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100476 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700477 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100478 argv[1] = NULL;
479
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700480 pid_t pid;
481 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100482 int mj_run_ret = minijail_run_pid_pipes(
483 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700484 EXPECT_EQ(mj_run_ret, 0);
485
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100486 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700487 const size_t teststr_len = strlen(teststr);
488 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
489 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
490
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100491 char buf[kBufferSize] = {};
492 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700493 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100494 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700495
496 int status;
497 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100498 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700499 ASSERT_TRUE(WIFSIGNALED(status));
500 EXPECT_EQ(WTERMSIG(status), SIGTERM);
501
502 argv[0] = const_cast<char*>(kShellPath);
503 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100504 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700505 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700506
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500507 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100508 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500509 envp[1] = NULL;
510
511 // Set a canary env var in the parent that should not be present in the child.
512 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
513
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100514 int child_stderr;
515 mj_run_ret =
516 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
517 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500518 EXPECT_EQ(mj_run_ret, 0);
519
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100520 memset(buf, 0, sizeof(buf));
521 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
522 EXPECT_GE(read_ret, 0);
523 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500524
525 EXPECT_EQ(waitpid(pid, &status, 0), pid);
526 ASSERT_TRUE(WIFEXITED(status));
527 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100528}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500529
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100530TEST(Test, minijail_run_env_pid_pipes_no_preload) {
531 ScopedMinijail j(minijail_new());
532
533 char *argv[4];
534 argv[0] = const_cast<char*>(kCatPath);
535 argv[1] = NULL;
536
537 pid_t pid;
538 int child_stdin, child_stdout;
539 int mj_run_ret = minijail_run_pid_pipes(
540 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
541 EXPECT_EQ(mj_run_ret, 0);
542
543 char teststr[] = "test\n";
544 const size_t teststr_len = strlen(teststr);
545 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
546 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
547
548 char buf[kBufferSize] = {};
549 ssize_t read_ret = read(child_stdout, buf, 8);
550 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
551 EXPECT_STREQ(buf, teststr);
552
553 int status;
554 EXPECT_EQ(kill(pid, SIGTERM), 0);
555 EXPECT_EQ(waitpid(pid, &status, 0), pid);
556 ASSERT_TRUE(WIFSIGNALED(status));
557 EXPECT_EQ(WTERMSIG(status), SIGTERM);
558
559 argv[0] = const_cast<char*>(kShellPath);
560 argv[1] = "-c";
561 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
562 argv[3] = nullptr;
563
564 char *envp[2];
565 envp[0] = "TEST_VAR=test";
566 envp[1] = NULL;
567
568 // Set a canary env var in the parent that should not be present in the child.
569 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
570
Dylan Reid83276a02020-06-10 15:17:13 -0700571 // Use the preload library from this test build.
572 ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
573
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100574 int child_stderr;
575 mj_run_ret =
576 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
577 &child_stdin, &child_stdout, &child_stderr);
578 EXPECT_EQ(mj_run_ret, 0);
579
580 memset(buf, 0, sizeof(buf));
581 read_ret = read(child_stderr, buf, sizeof(buf));
582 EXPECT_GE(read_ret, 0);
583 EXPECT_STREQ(buf, "|test\n");
584
585 EXPECT_EQ(waitpid(pid, &status, 0), pid);
586 ASSERT_TRUE(WIFEXITED(status));
587 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500588}
589
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400590TEST(Test, test_minijail_no_fd_leaks) {
591 pid_t pid;
592 int child_stdout;
593 int mj_run_ret;
594 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700595 char buf[kBufferSize];
596 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400597 int status;
598 char *argv[4];
599
600 int dev_null = open("/dev/null", O_RDONLY);
601 ASSERT_NE(dev_null, -1);
602 snprintf(script,
603 sizeof(script),
604 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
605 dev_null);
606
607 struct minijail *j = minijail_new();
608
François Degros87f0e832019-10-10 10:22:39 +1100609 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400610 argv[1] = "-c";
611 argv[2] = script;
612 argv[3] = NULL;
613 mj_run_ret = minijail_run_pid_pipes_no_preload(
614 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
615 EXPECT_EQ(mj_run_ret, 0);
616
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700617 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400618 EXPECT_GE(read_ret, 0);
619 buf[read_ret] = '\0';
620 EXPECT_STREQ(buf, "yes\n");
621
622 waitpid(pid, &status, 0);
623 ASSERT_TRUE(WIFEXITED(status));
624 EXPECT_EQ(WEXITSTATUS(status), 0);
625
626 minijail_close_open_fds(j);
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, "no\n");
635
636 waitpid(pid, &status, 0);
637 ASSERT_TRUE(WIFEXITED(status));
638 EXPECT_EQ(WEXITSTATUS(status), 0);
639
640 minijail_destroy(j);
641
642 close(dev_null);
643}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100644
Dylan Reid0412dcc2017-08-24 11:33:15 -0700645TEST(Test, test_minijail_fork) {
646 pid_t mj_fork_ret;
647 int status;
648 int pipe_fds[2];
649 ssize_t pid_size = sizeof(mj_fork_ret);
650
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700651 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700652
653 ASSERT_EQ(pipe(pipe_fds), 0);
654
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700655 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700656 ASSERT_GE(mj_fork_ret, 0);
657 if (mj_fork_ret == 0) {
658 pid_t pid_in_parent;
659 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700660 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
661 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700662 exit(0);
663 }
664
665 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
666 waitpid(mj_fork_ret, &status, 0);
667 ASSERT_TRUE(WIFEXITED(status));
668 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700669}
670
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700671static int early_exit(void* payload) {
672 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
673}
674
675TEST(Test, test_minijail_callback) {
676 pid_t pid;
677 int mj_run_ret;
678 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700679 char *argv[2];
680 int exit_code = 42;
681
682 struct minijail *j = minijail_new();
683
684 status =
685 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500686 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700687 EXPECT_EQ(status, 0);
688
François Degros87f0e832019-10-10 10:22:39 +1100689 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700690 argv[1] = NULL;
691 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500692 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700693 EXPECT_EQ(mj_run_ret, 0);
694
695 status = minijail_wait(j);
696 EXPECT_EQ(status, exit_code);
697
698 minijail_destroy(j);
699}
700
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700701TEST(Test, test_minijail_preserve_fd) {
702 int mj_run_ret;
703 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700704 char *argv[2];
705 char teststr[] = "test\n";
706 size_t teststr_len = strlen(teststr);
707 int read_pipe[2];
708 int write_pipe[2];
709 char buf[1024];
710
711 struct minijail *j = minijail_new();
712
713 status = pipe(read_pipe);
714 ASSERT_EQ(status, 0);
715 status = pipe(write_pipe);
716 ASSERT_EQ(status, 0);
717
718 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
719 ASSERT_EQ(status, 0);
720 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
721 ASSERT_EQ(status, 0);
722 minijail_close_open_fds(j);
723
François Degros87f0e832019-10-10 10:22:39 +1100724 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700725 argv[1] = NULL;
726 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
727 EXPECT_EQ(mj_run_ret, 0);
728
729 close(write_pipe[0]);
730 status = write(write_pipe[1], teststr, teststr_len);
731 EXPECT_EQ(status, (int)teststr_len);
732 close(write_pipe[1]);
733
734 close(read_pipe[1]);
735 status = read(read_pipe[0], buf, 8);
736 EXPECT_EQ(status, (int)teststr_len);
737 buf[teststr_len] = 0;
738 EXPECT_EQ(strcmp(buf, teststr), 0);
739
740 status = minijail_wait(j);
741 EXPECT_EQ(status, 0);
742
743 minijail_destroy(j);
744}
745
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700746TEST(Test, test_minijail_reset_signal_mask) {
747 struct minijail *j = minijail_new();
748
749 sigset_t original_signal_mask;
750 {
751 sigset_t signal_mask;
752 ASSERT_EQ(0, sigemptyset(&signal_mask));
753 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
754 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
755 }
756
757 minijail_reset_signal_mask(j);
758
759 pid_t mj_fork_ret = minijail_fork(j);
760 ASSERT_GE(mj_fork_ret, 0);
761 if (mj_fork_ret == 0) {
762 sigset_t signal_mask;
763 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
764 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400765 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700766 exit(0);
767 }
768
769 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
770
771 int status;
772 waitpid(mj_fork_ret, &status, 0);
773 ASSERT_TRUE(WIFEXITED(status));
774 EXPECT_EQ(WEXITSTATUS(status), 0);
775
776 minijail_destroy(j);
777}
778
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700779TEST(Test, test_minijail_reset_signal_handlers) {
780 struct minijail *j = minijail_new();
781
782 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
783 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
784 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
785
786 minijail_reset_signal_handlers(j);
787
788 pid_t mj_fork_ret = minijail_fork(j);
789 ASSERT_GE(mj_fork_ret, 0);
790 if (mj_fork_ret == 0) {
791 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400792 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700793 exit(0);
794 }
795
796 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
797
798 int status;
799 waitpid(mj_fork_ret, &status, 0);
800 ASSERT_TRUE(WIFEXITED(status));
801 EXPECT_EQ(WEXITSTATUS(status), 0);
802
803 minijail_destroy(j);
804}
805
Mike Frysinger780aef72017-10-03 01:39:52 -0400806namespace {
807
808// Tests that require userns access.
809// Android unit tests don't currently support entering user namespaces as
810// unprivileged users due to having an older kernel. Chrome OS unit tests
811// don't support it either due to being in a chroot environment (see man 2
812// clone for more information about failure modes with the CLONE_NEWUSER flag).
813class NamespaceTest : public ::testing::Test {
814 protected:
815 static void SetUpTestCase() {
816 userns_supported_ = UsernsSupported();
817 }
818
819 // Whether userns is supported.
820 static bool userns_supported_;
821
822 static bool UsernsSupported() {
823 pid_t pid = fork();
824 if (pid == -1)
825 pdie("could not fork");
826
827 if (pid == 0)
828 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
829
830 int status;
831 if (waitpid(pid, &status, 0) < 0)
832 pdie("could not wait");
833
834 if (!WIFEXITED(status))
835 die("child did not exit properly: %#x", status);
836
837 bool ret = WEXITSTATUS(status) == 0;
838 if (!ret)
839 warn("Skipping userns related tests");
840 return ret;
841 }
842};
843
844bool NamespaceTest::userns_supported_;
845
846} // namespace
847
848TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700849 int mj_run_ret;
850 int status;
851 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700852 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700853 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
854 constexpr gid_t kTargetGid = 1000;
855
Mike Frysinger780aef72017-10-03 01:39:52 -0400856 if (!userns_supported_) {
857 SUCCEED();
858 return;
859 }
860
Luis Hector Chavez71323552017-09-05 09:17:22 -0700861 struct minijail *j = minijail_new();
862
863 minijail_namespace_pids(j);
864 minijail_namespace_vfs(j);
865 minijail_mount_tmp(j);
866 minijail_run_as_init(j);
867
868 // Perform userns mapping.
869 minijail_namespace_user(j);
870 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
871 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
872 minijail_change_uid(j, kTargetUid);
873 minijail_change_gid(j, kTargetGid);
874 minijail_uidmap(j, uidmap);
875 minijail_gidmap(j, gidmap);
876 minijail_namespace_user_disable_setgroups(j);
877
François Degros87f0e832019-10-10 10:22:39 +1100878 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -0700879 argv[1] = "-c";
880 argv[2] = "exec touch /tmp/foo";
881 argv[3] = NULL;
882 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
883 EXPECT_EQ(mj_run_ret, 0);
884
885 status = minijail_wait(j);
886 EXPECT_EQ(status, 0);
887
888 minijail_destroy(j);
889}
890
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700891TEST_F(NamespaceTest, test_namespaces) {
892 constexpr char teststr[] = "test\n";
893
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700894 // TODO(crbug.com/895875): The preload library interferes with ASan since they
895 // both need to use LD_PRELOAD.
896 if (!userns_supported_ || running_with_asan()) {
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700897 SUCCEED();
898 return;
899 }
900
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700901 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
902 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700903
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700904 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
905 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700906 // Grab the set of namespaces outside the container.
907 std::map<std::string, std::string> init_namespaces =
908 GetNamespaces(getpid(), namespace_names);
909 std::function<void(struct minijail*)> test_functions[] = {
910 [](struct minijail* j attribute_unused) {},
911 [](struct minijail* j) {
912 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
913 minijail_enter_pivot_root(j, "/tmp");
914 },
915 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
916 };
917
918 // This test is run with and without the preload library.
919 for (const auto& run_function :
920 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
921 for (const auto& test_function : test_functions) {
922 ScopedMinijail j(minijail_new());
923 minijail_set_preload_path(j.get(), kPreloadPath);
924
925 // Enter all the namespaces we can.
926 minijail_namespace_cgroups(j.get());
927 minijail_namespace_net(j.get());
928 minijail_namespace_pids(j.get());
929 minijail_namespace_user(j.get());
930 minijail_namespace_vfs(j.get());
931 minijail_namespace_uts(j.get());
932
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700933 // Set up the user namespace.
934 minijail_uidmap(j.get(), uidmap.c_str());
935 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700936 minijail_namespace_user_disable_setgroups(j.get());
937
938 minijail_close_open_fds(j.get());
939 test_function(j.get());
940
François Degros87f0e832019-10-10 10:22:39 +1100941 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700942 pid_t container_pid;
943 int child_stdin, child_stdout;
944 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +1100945 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700946 &container_pid, &child_stdin, &child_stdout, nullptr);
947 EXPECT_EQ(mj_run_ret, 0);
948
949 // Send some data to stdin and read it back to ensure that the child
950 // process is running.
951 const size_t teststr_len = strlen(teststr);
952 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
953 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
954
955 char buf[kBufferSize];
956 ssize_t read_ret = read(child_stdout, buf, 8);
957 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
958 buf[teststr_len] = 0;
959 EXPECT_EQ(strcmp(buf, teststr), 0);
960
961 // Grab the set of namespaces in every container process. They must not
962 // match the ones in the init namespace, and they must all match each
963 // other.
964 std::map<std::string, std::string> container_namespaces =
965 GetNamespaces(container_pid, namespace_names);
966 EXPECT_NE(container_namespaces, init_namespaces);
967 for (pid_t pid : GetProcessSubtreePids(container_pid))
968 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
969
970 EXPECT_EQ(0, close(child_stdin));
971
972 int status = minijail_wait(j.get());
973 EXPECT_EQ(status, 0);
974 }
975 }
976}
977
Mike Frysinger902a4492018-12-27 05:22:56 -0500978TEST_F(NamespaceTest, test_enter_ns) {
979 char uidmap[kBufferSize], gidmap[kBufferSize];
980
981 if (!userns_supported_) {
982 SUCCEED();
983 return;
984 }
985
986 // We first create a child in a new userns so we have privs to run more tests.
987 // We can't combine the steps as the kernel disallows many resource sharing
988 // from outside the userns.
989 struct minijail *j = minijail_new();
990
991 minijail_namespace_vfs(j);
992 minijail_namespace_pids(j);
993 minijail_run_as_init(j);
994
995 // Perform userns mapping.
996 minijail_namespace_user(j);
997 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
998 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
999 minijail_uidmap(j, uidmap);
1000 minijail_gidmap(j, gidmap);
1001 minijail_namespace_user_disable_setgroups(j);
1002
1003 pid_t pid = minijail_fork(j);
1004 if (pid == 0) {
1005 // Child.
1006 minijail_destroy(j);
1007
1008 // Create new namespaces inside this userns which we may enter.
1009 j = minijail_new();
1010 minijail_namespace_net(j);
1011 minijail_namespace_vfs(j);
1012 pid = minijail_fork(j);
1013 if (pid == 0) {
1014 // Child.
1015 minijail_destroy(j);
1016
1017 // Finally enter those namespaces.
1018 j = minijail_new();
1019
1020 // We need to get the absolute path because entering a new mntns will
1021 // implicitly chdir(/) for us.
1022 char *path = realpath(kPreloadPath, nullptr);
1023 ASSERT_NE(nullptr, path);
1024 minijail_set_preload_path(j, path);
1025
1026 minijail_namespace_net(j);
1027 minijail_namespace_vfs(j);
1028
1029 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1030 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1031
1032 char *argv[] = {"/bin/true", nullptr};
1033 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1034 EXPECT_EQ(0, minijail_wait(j));
1035 minijail_destroy(j);
1036 exit(0);
1037 } else {
1038 ASSERT_GT(pid, 0);
1039 EXPECT_EQ(0, minijail_wait(j));
1040 minijail_destroy(j);
1041 exit(0);
1042 }
1043 } else {
1044 ASSERT_GT(pid, 0);
1045 EXPECT_EQ(0, minijail_wait(j));
1046 minijail_destroy(j);
1047 }
1048}
1049
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001050void TestCreateSession(bool create_session) {
1051 int status;
1052 int pipe_fds[2];
1053 pid_t child_pid;
1054 pid_t parent_sid = getsid(0);
1055 ssize_t pid_size = sizeof(pid_t);
1056
1057 ScopedMinijail j(minijail_new());
1058 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1059 // a new session because of that.
1060 minijail_close_open_fds(j.get());
1061
1062 if (create_session)
1063 minijail_create_session(j.get());
1064
1065 ASSERT_EQ(pipe(pipe_fds), 0);
1066 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1067
1068 child_pid = minijail_fork(j.get());
1069 ASSERT_GE(child_pid, 0);
1070 if (child_pid == 0) {
1071 pid_t sid_in_parent;
1072 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1073 if (create_session)
1074 ASSERT_NE(sid_in_parent, getsid(0));
1075 else
1076 ASSERT_EQ(sid_in_parent, getsid(0));
1077 exit(0);
1078 }
1079
1080 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1081 waitpid(child_pid, &status, 0);
1082 ASSERT_TRUE(WIFEXITED(status));
1083 EXPECT_EQ(WEXITSTATUS(status), 0);
1084}
1085
1086TEST(Test, default_no_new_session) {
1087 TestCreateSession(/*create_session=*/false);
1088}
1089
1090TEST(Test, create_new_session) {
1091 TestCreateSession(/*create_session=*/true);
1092}