1 /* 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 */
7
8 #include <errno.h>
9
10 #include <dirent.h>
11 #include <fcntl.h>
12 #include <sys/mount.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17
18 #include <gtest/gtest.h>
19
20 #include <functional>
21 #include <map>
22 #include <set>
23 #include <string>
24
25 #include "libminijail-private.h"
26 #include "libminijail.h"
27 #include "scoped_minijail.h"
28 #include "util.h"
29
30 namespace {
31
32 #if defined(__ANDROID__)
33 # define ROOT_PREFIX "/system"
34 #else
35 # define ROOT_PREFIX ""
36 #endif
37
38 constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
39 constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
40 constexpr char kPreloadPath[] = "./libminijailpreload.so";
41 constexpr size_t kBufferSize = 128;
42
GetProcessSubtreePids(pid_t root_pid)43 std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
44 std::set<pid_t> pids{root_pid};
45 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);
59 if (*end != '\0')
60 continue;
61 std::string path = "/proc/" + std::to_string(pid) + "/stat";
62
63 FILE* f = fopen(path.c_str(), "re");
64 if (!f)
65 pdie("fopen(%s)", path.c_str());
66 pid_t ppid;
67 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
68 fclose(f);
69 if (ret != 1) {
70 continue;
71 }
72 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
GetNamespaces(pid_t pid,const std::vector<std::string> & namespace_names)81 std::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;
85 char buf[kBufferSize];
86 for (const auto& namespace_name : namespace_names) {
87 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
88 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
89 if (len == -1)
90 pdie("readlink(\"%s\")", path.c_str());
91 namespaces.emplace(namespace_name, std::string(buf, len));
92 }
93 return namespaces;
94 }
95
96 } // namespace
97
98 /* Prototypes needed only by test. */
99 size_t minijail_get_tmpfs_size(const struct minijail *);
100
101 /* Silence unused variable warnings. */
TEST(silence,silence_unused)102 TEST(silence, silence_unused) {
103 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
104 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
105 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
106 }
107
TEST(consumebytes,zero)108 TEST(consumebytes, zero) {
109 char buf[1024];
110 size_t len = sizeof(buf);
111 char *pos = &buf[0];
112 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
113 EXPECT_EQ(&buf[0], pos);
114 EXPECT_EQ(sizeof(buf), len);
115 }
116
TEST(consumebytes,exact)117 TEST(consumebytes, exact) {
118 char buf[1024];
119 size_t len = sizeof(buf);
120 char *pos = &buf[0];
121 /* One past the end since it consumes the whole buffer. */
122 char *end = &buf[sizeof(buf)];
123 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
124 EXPECT_EQ((size_t)0, len);
125 EXPECT_EQ(end, pos);
126 }
127
TEST(consumebytes,half)128 TEST(consumebytes, half) {
129 char buf[1024];
130 size_t len = sizeof(buf);
131 char *pos = &buf[0];
132 /* One past the end since it consumes the whole buffer. */
133 char *end = &buf[sizeof(buf) / 2];
134 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
135 EXPECT_EQ(sizeof(buf) / 2, len);
136 EXPECT_EQ(end, pos);
137 }
138
TEST(consumebytes,toolong)139 TEST(consumebytes, toolong) {
140 char buf[1024];
141 size_t len = sizeof(buf);
142 char *pos = &buf[0];
143 /* One past the end since it consumes the whole buffer. */
144 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
145 EXPECT_EQ(sizeof(buf), len);
146 EXPECT_EQ(&buf[0], pos);
147 }
148
TEST(consumestr,zero)149 TEST(consumestr, zero) {
150 char buf[1024];
151 size_t len = 0;
152 char *pos = &buf[0];
153 memset(buf, 0xff, sizeof(buf));
154 EXPECT_EQ(nullptr, consumestr(&pos, &len));
155 EXPECT_EQ((size_t)0, len);
156 EXPECT_EQ(&buf[0], pos);
157 }
158
TEST(consumestr,nonul)159 TEST(consumestr, nonul) {
160 char buf[1024];
161 size_t len = sizeof(buf);
162 char *pos = &buf[0];
163 memset(buf, 0xff, sizeof(buf));
164 EXPECT_EQ(nullptr, consumestr(&pos, &len));
165 EXPECT_EQ(sizeof(buf), len);
166 EXPECT_EQ(&buf[0], pos);
167 }
168
TEST(consumestr,full)169 TEST(consumestr, full) {
170 char buf[1024];
171 size_t len = sizeof(buf);
172 char *pos = &buf[0];
173 memset(buf, 0xff, sizeof(buf));
174 buf[sizeof(buf)-1] = '\0';
175 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
176 EXPECT_EQ((size_t)0, len);
177 EXPECT_EQ(&buf[sizeof(buf)], pos);
178 }
179
TEST(consumestr,trailing_nul)180 TEST(consumestr, trailing_nul) {
181 char buf[1024];
182 size_t len = sizeof(buf) - 1;
183 char *pos = &buf[0];
184 memset(buf, 0xff, sizeof(buf));
185 buf[sizeof(buf)-1] = '\0';
186 EXPECT_EQ(nullptr, consumestr(&pos, &len));
187 EXPECT_EQ(sizeof(buf) - 1, len);
188 EXPECT_EQ(&buf[0], pos);
189 }
190
191 class MarshalTest : public ::testing::Test {
192 protected:
SetUp()193 virtual void SetUp() {
194 m_ = minijail_new();
195 j_ = minijail_new();
196 size_ = minijail_size(m_);
197 }
TearDown()198 virtual void TearDown() {
199 minijail_destroy(m_);
200 minijail_destroy(j_);
201 }
202
203 char buf_[4096];
204 struct minijail *m_;
205 struct minijail *j_;
206 size_t size_;
207 };
208
TEST_F(MarshalTest,empty)209 TEST_F(MarshalTest, empty) {
210 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
211 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
212 }
213
214 TEST_F(MarshalTest, 0xff) {
215 memset(buf_, 0xff, sizeof(buf_));
216 /* Should fail on the first consumestr since a NUL will never be found. */
217 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
218 }
219
TEST(Test,minijail_run_pid_pipes)220 TEST(Test, minijail_run_pid_pipes) {
221 constexpr char teststr[] = "test\n";
222
223 struct minijail* j = minijail_new();
224 minijail_set_preload_path(j, kPreloadPath);
225
226 char* argv[4];
227 argv[0] = const_cast<char*>(kCatPath);
228 argv[1] = nullptr;
229 pid_t pid;
230 int child_stdin, child_stdout;
231 int mj_run_ret = minijail_run_pid_pipes(j, argv[0], argv, &pid, &child_stdin,
232 &child_stdout, nullptr);
233 EXPECT_EQ(mj_run_ret, 0);
234
235 const size_t teststr_len = strlen(teststr);
236 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
237 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
238
239 char buf[kBufferSize];
240 ssize_t read_ret = read(child_stdout, buf, 8);
241 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
242 buf[teststr_len] = 0;
243 EXPECT_EQ(strcmp(buf, teststr), 0);
244
245 int status;
246 EXPECT_EQ(kill(pid, SIGTERM), 0);
247 waitpid(pid, &status, 0);
248 ASSERT_TRUE(WIFSIGNALED(status));
249 EXPECT_EQ(WTERMSIG(status), SIGTERM);
250
251 argv[0] = const_cast<char*>(kShellPath);
252 argv[1] = "-c";
253 argv[2] = "echo test >&2";
254 argv[3] = nullptr;
255 int child_stderr;
256 mj_run_ret = minijail_run_pid_pipes(j, argv[0], argv, &pid, &child_stdin,
257 &child_stdout, &child_stderr);
258 EXPECT_EQ(mj_run_ret, 0);
259
260 read_ret = read(child_stderr, buf, sizeof(buf));
261 EXPECT_GE(read_ret, static_cast<ssize_t>(teststr_len));
262
263 waitpid(pid, &status, 0);
264 ASSERT_TRUE(WIFEXITED(status));
265 EXPECT_EQ(WEXITSTATUS(status), 0);
266
267 minijail_destroy(j);
268 }
269
TEST(Test,minijail_run_pid_pipes_no_preload)270 TEST(Test, minijail_run_pid_pipes_no_preload) {
271 pid_t pid;
272 int child_stdin, child_stdout, child_stderr;
273 int mj_run_ret;
274 ssize_t write_ret, read_ret;
275 char buf[kBufferSize];
276 int status;
277 char teststr[] = "test\n";
278 size_t teststr_len = strlen(teststr);
279 char *argv[4];
280
281 struct minijail *j = minijail_new();
282
283 argv[0] = (char*)kCatPath;
284 argv[1] = NULL;
285 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
286 &pid,
287 &child_stdin, &child_stdout,
288 NULL);
289 EXPECT_EQ(mj_run_ret, 0);
290
291 write_ret = write(child_stdin, teststr, teststr_len);
292 EXPECT_EQ(write_ret, (int)teststr_len);
293
294 read_ret = read(child_stdout, buf, 8);
295 EXPECT_EQ(read_ret, (int)teststr_len);
296 buf[teststr_len] = 0;
297 EXPECT_EQ(strcmp(buf, teststr), 0);
298
299 EXPECT_EQ(kill(pid, SIGTERM), 0);
300 waitpid(pid, &status, 0);
301 ASSERT_TRUE(WIFSIGNALED(status));
302 EXPECT_EQ(WTERMSIG(status), SIGTERM);
303
304 argv[0] = (char*)kShellPath;
305 argv[1] = "-c";
306 argv[2] = "echo test >&2";
307 argv[3] = NULL;
308 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
309 &child_stdin, &child_stdout,
310 &child_stderr);
311 EXPECT_EQ(mj_run_ret, 0);
312
313 read_ret = read(child_stderr, buf, sizeof(buf));
314 EXPECT_GE(read_ret, (int)teststr_len);
315
316 waitpid(pid, &status, 0);
317 ASSERT_TRUE(WIFEXITED(status));
318 EXPECT_EQ(WEXITSTATUS(status), 0);
319
320 minijail_destroy(j);
321 }
322
TEST(Test,minijail_run_env_pid_pipes_no_preload)323 TEST(Test, minijail_run_env_pid_pipes_no_preload) {
324 pid_t pid;
325 int child_stdin, child_stdout, child_stderr;
326 int mj_run_ret;
327 ssize_t read_ret;
328 char buf[kBufferSize];
329 int status;
330 char test_envvar[] = "TEST_VAR=test";
331 size_t testvar_len = strlen("test");
332 char *argv[4];
333 char *envp[2];
334
335 struct minijail *j = minijail_new();
336
337 argv[0] = (char*)kShellPath;
338 argv[1] = "-c";
339 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\"";
340 argv[3] = NULL;
341
342 envp[0] = test_envvar;
343 envp[1] = NULL;
344
345 // Set a canary env var in the parent that should not be present in the child.
346 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
347
348 mj_run_ret = minijail_run_env_pid_pipes_no_preload(
349 j, argv[0], argv, envp, &pid, &child_stdin, &child_stdout, &child_stderr);
350 EXPECT_EQ(mj_run_ret, 0);
351
352 read_ret = read(child_stdout, buf, sizeof(buf));
353 EXPECT_GE(read_ret, (int)testvar_len);
354
355 EXPECT_EQ("|test\n", std::string(buf));
356
357 EXPECT_EQ(waitpid(pid, &status, 0), pid);
358 ASSERT_TRUE(WIFEXITED(status));
359 EXPECT_EQ(WEXITSTATUS(status), 0);
360
361 minijail_destroy(j);
362 }
363
TEST(Test,test_minijail_no_fd_leaks)364 TEST(Test, test_minijail_no_fd_leaks) {
365 pid_t pid;
366 int child_stdout;
367 int mj_run_ret;
368 ssize_t read_ret;
369 char buf[kBufferSize];
370 char script[kBufferSize];
371 int status;
372 char *argv[4];
373
374 int dev_null = open("/dev/null", O_RDONLY);
375 ASSERT_NE(dev_null, -1);
376 snprintf(script,
377 sizeof(script),
378 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
379 dev_null);
380
381 struct minijail *j = minijail_new();
382
383 argv[0] = (char*)kShellPath;
384 argv[1] = "-c";
385 argv[2] = script;
386 argv[3] = NULL;
387 mj_run_ret = minijail_run_pid_pipes_no_preload(
388 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
389 EXPECT_EQ(mj_run_ret, 0);
390
391 read_ret = read(child_stdout, buf, sizeof(buf));
392 EXPECT_GE(read_ret, 0);
393 buf[read_ret] = '\0';
394 EXPECT_STREQ(buf, "yes\n");
395
396 waitpid(pid, &status, 0);
397 ASSERT_TRUE(WIFEXITED(status));
398 EXPECT_EQ(WEXITSTATUS(status), 0);
399
400 minijail_close_open_fds(j);
401 mj_run_ret = minijail_run_pid_pipes_no_preload(
402 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
403 EXPECT_EQ(mj_run_ret, 0);
404
405 read_ret = read(child_stdout, buf, sizeof(buf));
406 EXPECT_GE(read_ret, 0);
407 buf[read_ret] = '\0';
408 EXPECT_STREQ(buf, "no\n");
409
410 waitpid(pid, &status, 0);
411 ASSERT_TRUE(WIFEXITED(status));
412 EXPECT_EQ(WEXITSTATUS(status), 0);
413
414 minijail_destroy(j);
415
416 close(dev_null);
417 }
418
TEST(Test,test_minijail_fork)419 TEST(Test, test_minijail_fork) {
420 pid_t mj_fork_ret;
421 int status;
422 int pipe_fds[2];
423 ssize_t pid_size = sizeof(mj_fork_ret);
424
425 struct minijail *j = minijail_new();
426
427 ASSERT_EQ(pipe(pipe_fds), 0);
428
429 mj_fork_ret = minijail_fork(j);
430 ASSERT_GE(mj_fork_ret, 0);
431 if (mj_fork_ret == 0) {
432 pid_t pid_in_parent;
433 // Wait for the parent to tell us the pid in the parent namespace.
434 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
435 ASSERT_EQ(pid_in_parent, getpid());
436 minijail_destroy(j);
437 exit(0);
438 }
439
440 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
441 waitpid(mj_fork_ret, &status, 0);
442 ASSERT_TRUE(WIFEXITED(status));
443 EXPECT_EQ(WEXITSTATUS(status), 0);
444
445 minijail_destroy(j);
446 }
447
early_exit(void * payload)448 static int early_exit(void* payload) {
449 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
450 }
451
TEST(Test,test_minijail_callback)452 TEST(Test, test_minijail_callback) {
453 pid_t pid;
454 int mj_run_ret;
455 int status;
456 char *argv[2];
457 int exit_code = 42;
458
459 struct minijail *j = minijail_new();
460
461 status =
462 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
463 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
464 EXPECT_EQ(status, 0);
465
466 argv[0] = (char*)kCatPath;
467 argv[1] = NULL;
468 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
469 NULL, NULL);
470 EXPECT_EQ(mj_run_ret, 0);
471
472 status = minijail_wait(j);
473 EXPECT_EQ(status, exit_code);
474
475 minijail_destroy(j);
476 }
477
TEST(Test,test_minijail_preserve_fd)478 TEST(Test, test_minijail_preserve_fd) {
479 int mj_run_ret;
480 int status;
481 char *argv[2];
482 char teststr[] = "test\n";
483 size_t teststr_len = strlen(teststr);
484 int read_pipe[2];
485 int write_pipe[2];
486 char buf[1024];
487
488 struct minijail *j = minijail_new();
489
490 status = pipe(read_pipe);
491 ASSERT_EQ(status, 0);
492 status = pipe(write_pipe);
493 ASSERT_EQ(status, 0);
494
495 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
496 ASSERT_EQ(status, 0);
497 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
498 ASSERT_EQ(status, 0);
499 minijail_close_open_fds(j);
500
501 argv[0] = (char*)kCatPath;
502 argv[1] = NULL;
503 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
504 EXPECT_EQ(mj_run_ret, 0);
505
506 close(write_pipe[0]);
507 status = write(write_pipe[1], teststr, teststr_len);
508 EXPECT_EQ(status, (int)teststr_len);
509 close(write_pipe[1]);
510
511 close(read_pipe[1]);
512 status = read(read_pipe[0], buf, 8);
513 EXPECT_EQ(status, (int)teststr_len);
514 buf[teststr_len] = 0;
515 EXPECT_EQ(strcmp(buf, teststr), 0);
516
517 status = minijail_wait(j);
518 EXPECT_EQ(status, 0);
519
520 minijail_destroy(j);
521 }
522
TEST(Test,test_minijail_reset_signal_mask)523 TEST(Test, test_minijail_reset_signal_mask) {
524 struct minijail *j = minijail_new();
525
526 sigset_t original_signal_mask;
527 {
528 sigset_t signal_mask;
529 ASSERT_EQ(0, sigemptyset(&signal_mask));
530 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
531 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
532 }
533
534 minijail_reset_signal_mask(j);
535
536 pid_t mj_fork_ret = minijail_fork(j);
537 ASSERT_GE(mj_fork_ret, 0);
538 if (mj_fork_ret == 0) {
539 sigset_t signal_mask;
540 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
541 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
542 minijail_destroy(j);
543 exit(0);
544 }
545
546 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
547
548 int status;
549 waitpid(mj_fork_ret, &status, 0);
550 ASSERT_TRUE(WIFEXITED(status));
551 EXPECT_EQ(WEXITSTATUS(status), 0);
552
553 minijail_destroy(j);
554 }
555
TEST(Test,test_minijail_reset_signal_handlers)556 TEST(Test, test_minijail_reset_signal_handlers) {
557 struct minijail *j = minijail_new();
558
559 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
560 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
561 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
562
563 minijail_reset_signal_handlers(j);
564
565 pid_t mj_fork_ret = minijail_fork(j);
566 ASSERT_GE(mj_fork_ret, 0);
567 if (mj_fork_ret == 0) {
568 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
569 minijail_destroy(j);
570 exit(0);
571 }
572
573 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
574
575 int status;
576 waitpid(mj_fork_ret, &status, 0);
577 ASSERT_TRUE(WIFEXITED(status));
578 EXPECT_EQ(WEXITSTATUS(status), 0);
579
580 minijail_destroy(j);
581 }
582
583 namespace {
584
585 // Tests that require userns access.
586 // Android unit tests don't currently support entering user namespaces as
587 // unprivileged users due to having an older kernel. Chrome OS unit tests
588 // don't support it either due to being in a chroot environment (see man 2
589 // clone for more information about failure modes with the CLONE_NEWUSER flag).
590 class NamespaceTest : public ::testing::Test {
591 protected:
SetUpTestCase()592 static void SetUpTestCase() {
593 userns_supported_ = UsernsSupported();
594 }
595
596 // Whether userns is supported.
597 static bool userns_supported_;
598
UsernsSupported()599 static bool UsernsSupported() {
600 pid_t pid = fork();
601 if (pid == -1)
602 pdie("could not fork");
603
604 if (pid == 0)
605 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
606
607 int status;
608 if (waitpid(pid, &status, 0) < 0)
609 pdie("could not wait");
610
611 if (!WIFEXITED(status))
612 die("child did not exit properly: %#x", status);
613
614 bool ret = WEXITSTATUS(status) == 0;
615 if (!ret)
616 warn("Skipping userns related tests");
617 return ret;
618 }
619 };
620
621 bool NamespaceTest::userns_supported_;
622
623 } // namespace
624
TEST_F(NamespaceTest,test_tmpfs_userns)625 TEST_F(NamespaceTest, test_tmpfs_userns) {
626 int mj_run_ret;
627 int status;
628 char *argv[4];
629 char uidmap[kBufferSize], gidmap[kBufferSize];
630 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
631 constexpr gid_t kTargetGid = 1000;
632
633 if (!userns_supported_) {
634 SUCCEED();
635 return;
636 }
637
638 struct minijail *j = minijail_new();
639
640 minijail_namespace_pids(j);
641 minijail_namespace_vfs(j);
642 minijail_mount_tmp(j);
643 minijail_run_as_init(j);
644
645 // Perform userns mapping.
646 minijail_namespace_user(j);
647 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
648 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
649 minijail_change_uid(j, kTargetUid);
650 minijail_change_gid(j, kTargetGid);
651 minijail_uidmap(j, uidmap);
652 minijail_gidmap(j, gidmap);
653 minijail_namespace_user_disable_setgroups(j);
654
655 argv[0] = (char*)kShellPath;
656 argv[1] = "-c";
657 argv[2] = "exec touch /tmp/foo";
658 argv[3] = NULL;
659 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
660 EXPECT_EQ(mj_run_ret, 0);
661
662 status = minijail_wait(j);
663 EXPECT_EQ(status, 0);
664
665 minijail_destroy(j);
666 }
667
TEST_F(NamespaceTest,test_namespaces)668 TEST_F(NamespaceTest, test_namespaces) {
669 constexpr char teststr[] = "test\n";
670
671 if (!userns_supported_) {
672 SUCCEED();
673 return;
674 }
675
676 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
677 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
678
679 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
680 "net", "cgroup", "uts"};
681 // Grab the set of namespaces outside the container.
682 std::map<std::string, std::string> init_namespaces =
683 GetNamespaces(getpid(), namespace_names);
684 std::function<void(struct minijail*)> test_functions[] = {
685 [](struct minijail* j attribute_unused) {},
686 [](struct minijail* j) {
687 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
688 minijail_enter_pivot_root(j, "/tmp");
689 },
690 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
691 };
692
693 // This test is run with and without the preload library.
694 for (const auto& run_function :
695 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
696 for (const auto& test_function : test_functions) {
697 ScopedMinijail j(minijail_new());
698 minijail_set_preload_path(j.get(), kPreloadPath);
699
700 // Enter all the namespaces we can.
701 minijail_namespace_cgroups(j.get());
702 minijail_namespace_net(j.get());
703 minijail_namespace_pids(j.get());
704 minijail_namespace_user(j.get());
705 minijail_namespace_vfs(j.get());
706 minijail_namespace_uts(j.get());
707
708 // Set up the user namespace.
709 minijail_uidmap(j.get(), uidmap.c_str());
710 minijail_gidmap(j.get(), gidmap.c_str());
711 minijail_namespace_user_disable_setgroups(j.get());
712
713 minijail_close_open_fds(j.get());
714 test_function(j.get());
715
716 const char* argv[] = {kCatPath, nullptr};
717 pid_t container_pid;
718 int child_stdin, child_stdout;
719 int mj_run_ret =
720 run_function(j.get(), argv[0], const_cast<char* const*>(argv),
721 &container_pid, &child_stdin, &child_stdout, nullptr);
722 EXPECT_EQ(mj_run_ret, 0);
723
724 // Send some data to stdin and read it back to ensure that the child
725 // process is running.
726 const size_t teststr_len = strlen(teststr);
727 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
728 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
729
730 char buf[kBufferSize];
731 ssize_t read_ret = read(child_stdout, buf, 8);
732 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
733 buf[teststr_len] = 0;
734 EXPECT_EQ(strcmp(buf, teststr), 0);
735
736 // Grab the set of namespaces in every container process. They must not
737 // match the ones in the init namespace, and they must all match each
738 // other.
739 std::map<std::string, std::string> container_namespaces =
740 GetNamespaces(container_pid, namespace_names);
741 EXPECT_NE(container_namespaces, init_namespaces);
742 for (pid_t pid : GetProcessSubtreePids(container_pid))
743 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
744
745 EXPECT_EQ(0, close(child_stdin));
746
747 int status = minijail_wait(j.get());
748 EXPECT_EQ(status, 0);
749 }
750 }
751 }
752
TEST_F(NamespaceTest,test_enter_ns)753 TEST_F(NamespaceTest, test_enter_ns) {
754 char uidmap[kBufferSize], gidmap[kBufferSize];
755
756 if (!userns_supported_) {
757 SUCCEED();
758 return;
759 }
760
761 // We first create a child in a new userns so we have privs to run more tests.
762 // We can't combine the steps as the kernel disallows many resource sharing
763 // from outside the userns.
764 struct minijail *j = minijail_new();
765
766 minijail_namespace_vfs(j);
767 minijail_namespace_pids(j);
768 minijail_run_as_init(j);
769
770 // Perform userns mapping.
771 minijail_namespace_user(j);
772 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
773 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
774 minijail_uidmap(j, uidmap);
775 minijail_gidmap(j, gidmap);
776 minijail_namespace_user_disable_setgroups(j);
777
778 pid_t pid = minijail_fork(j);
779 if (pid == 0) {
780 // Child.
781 minijail_destroy(j);
782
783 // Create new namespaces inside this userns which we may enter.
784 j = minijail_new();
785 minijail_namespace_net(j);
786 minijail_namespace_vfs(j);
787 pid = minijail_fork(j);
788 if (pid == 0) {
789 // Child.
790 minijail_destroy(j);
791
792 // Finally enter those namespaces.
793 j = minijail_new();
794
795 // We need to get the absolute path because entering a new mntns will
796 // implicitly chdir(/) for us.
797 char *path = realpath(kPreloadPath, nullptr);
798 ASSERT_NE(nullptr, path);
799 minijail_set_preload_path(j, path);
800
801 minijail_namespace_net(j);
802 minijail_namespace_vfs(j);
803
804 minijail_namespace_enter_net(j, "/proc/self/ns/net");
805 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
806
807 char *argv[] = {"/bin/true", nullptr};
808 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
809 EXPECT_EQ(0, minijail_wait(j));
810 minijail_destroy(j);
811 exit(0);
812 } else {
813 ASSERT_GT(pid, 0);
814 EXPECT_EQ(0, minijail_wait(j));
815 minijail_destroy(j);
816 exit(0);
817 }
818 } else {
819 ASSERT_GT(pid, 0);
820 EXPECT_EQ(0, minijail_wait(j));
821 minijail_destroy(j);
822 }
823 }
824
TEST(Test,parse_size)825 TEST(Test, parse_size) {
826 size_t size;
827
828 ASSERT_EQ(0, parse_size(&size, "42"));
829 ASSERT_EQ(42U, size);
830
831 ASSERT_EQ(0, parse_size(&size, "16K"));
832 ASSERT_EQ(16384U, size);
833
834 ASSERT_EQ(0, parse_size(&size, "1M"));
835 ASSERT_EQ(1024U * 1024, size);
836
837 uint64_t gigabyte = 1024ULL * 1024 * 1024;
838 ASSERT_EQ(0, parse_size(&size, "3G"));
839 ASSERT_EQ(3U, size / gigabyte);
840 ASSERT_EQ(0U, size % gigabyte);
841
842 ASSERT_EQ(0, parse_size(&size, "4294967294"));
843 ASSERT_EQ(3U, size / gigabyte);
844 ASSERT_EQ(gigabyte - 2, size % gigabyte);
845
846 #if __WORDSIZE == 64
847 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
848 ASSERT_EQ(0, parse_size(&size, "9E"));
849 ASSERT_EQ(9U, size / exabyte);
850 ASSERT_EQ(0U, size % exabyte);
851
852 ASSERT_EQ(0, parse_size(&size, "15E"));
853 ASSERT_EQ(15U, size / exabyte);
854 ASSERT_EQ(0U, size % exabyte);
855
856 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
857 ASSERT_EQ(15U, size / exabyte);
858 ASSERT_EQ(exabyte - 2, size % exabyte);
859
860 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
861 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
862 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
863 #elif __WORDSIZE == 32
864 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
865 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
866 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
867 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
868 #endif
869
870 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
871 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
872 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
873 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
874 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
875 }
876