1 /* Copyright 2016 The ChromiumOS Authors
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/mman.h>
13 #include <sys/mount.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <unistd.h>
18
19 #include <gtest/gtest.h>
20
21 #include <functional>
22 #include <map>
23 #include <set>
24 #include <string>
25
26 #include "landlock_util.h"
27 #include "libminijail-private.h"
28 #include "libminijail.h"
29 #include "scoped_minijail.h"
30 #include "unittest_util.h"
31 #include "util.h"
32
33 namespace {
34
35 #if defined(__ANDROID__)
36 # define ROOT_PREFIX "/system"
37 #else
38 # define ROOT_PREFIX ""
39 #endif
40
41 constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
42 constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
43 constexpr char kPreloadPath[] = "./libminijailpreload.so";
44 constexpr size_t kBufferSize = 128;
45
GetProcessSubtreePids(pid_t root_pid)46 std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
47 std::set<pid_t> pids{root_pid};
48 bool progress = false;
49
50 do {
51 progress = false;
52 DIR* d = opendir("/proc");
53 if (!d)
54 pdie("opendir(\"/proc\")");
55
56 struct dirent* dir_entry;
57 while ((dir_entry = readdir(d)) != nullptr) {
58 if (dir_entry->d_type != DT_DIR)
59 continue;
60 char* end;
61 const int pid = strtol(dir_entry->d_name, &end, 10);
62 if (*end != '\0')
63 continue;
64 std::string path = "/proc/" + std::to_string(pid) + "/stat";
65
66 FILE* f = fopen(path.c_str(), "re");
67 if (!f) {
68 if (errno == ENOENT) {
69 // This loop is inherently racy, since PIDs can be reaped in the
70 // middle of this. Not being able to find one /proc/PID/stat file is
71 // completely normal.
72 continue;
73 }
74 pdie("fopen(%s)", path.c_str());
75 }
76 pid_t ppid;
77 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
78 fclose(f);
79 if (ret != 1) {
80 continue;
81 }
82 if (pids.find(ppid) == pids.end())
83 continue;
84 progress |= pids.insert(pid).second;
85 }
86 closedir(d);
87 } while (progress);
88 return pids;
89 }
90
GetNamespaces(pid_t pid,const std::vector<std::string> & namespace_names)91 std::map<std::string, std::string> GetNamespaces(
92 pid_t pid,
93 const std::vector<std::string>& namespace_names) {
94 std::map<std::string, std::string> namespaces;
95 char buf[kBufferSize];
96 for (const auto& namespace_name : namespace_names) {
97 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
98 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
99 if (len == -1)
100 pdie("readlink(\"%s\")", path.c_str());
101 namespaces.emplace(namespace_name, std::string(buf, len));
102 }
103 return namespaces;
104 }
105
set_preload_path(minijail * j)106 void set_preload_path(minijail *j) {
107 #if defined(__ANDROID__)
108 // libminijailpreload.so isn't available in android, so skip trying to load
109 // it. Even without the preload, all the test cases either pass or are skipped
110 // for other reasons.
111 return;
112 #endif
113 // We need to get the absolute path because entering a new mntns will
114 // implicitly chdir(/) for us.
115 char *preload_path = realpath(kPreloadPath, nullptr);
116 ASSERT_NE(preload_path, nullptr);
117 minijail_set_preload_path(j, preload_path);
118 free(preload_path);
119 }
120
121 } // namespace
122
123 /* Silence unused variable warnings. */
TEST(silence,silence_unused)124 TEST(silence, silence_unused) {
125 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
126 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
127 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
128 }
129
TEST(consumebytes,zero)130 TEST(consumebytes, zero) {
131 char buf[1024];
132 size_t len = sizeof(buf);
133 char *pos = &buf[0];
134 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
135 EXPECT_EQ(&buf[0], pos);
136 EXPECT_EQ(sizeof(buf), len);
137 }
138
TEST(consumebytes,exact)139 TEST(consumebytes, exact) {
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 char *end = &buf[sizeof(buf)];
145 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
146 EXPECT_EQ((size_t)0, len);
147 EXPECT_EQ(end, pos);
148 }
149
TEST(consumebytes,half)150 TEST(consumebytes, half) {
151 char buf[1024];
152 size_t len = sizeof(buf);
153 char *pos = &buf[0];
154 /* One past the end since it consumes the whole buffer. */
155 char *end = &buf[sizeof(buf) / 2];
156 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
157 EXPECT_EQ(sizeof(buf) / 2, len);
158 EXPECT_EQ(end, pos);
159 }
160
TEST(consumebytes,toolong)161 TEST(consumebytes, toolong) {
162 char buf[1024];
163 size_t len = sizeof(buf);
164 char *pos = &buf[0];
165 /* One past the end since it consumes the whole buffer. */
166 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
167 EXPECT_EQ(sizeof(buf), len);
168 EXPECT_EQ(&buf[0], pos);
169 }
170
TEST(consumestr,zero)171 TEST(consumestr, zero) {
172 char buf[1024];
173 size_t len = 0;
174 char *pos = &buf[0];
175 memset(buf, 0xff, sizeof(buf));
176 EXPECT_EQ(nullptr, consumestr(&pos, &len));
177 EXPECT_EQ((size_t)0, len);
178 EXPECT_EQ(&buf[0], pos);
179 }
180
TEST(consumestr,nonul)181 TEST(consumestr, nonul) {
182 char buf[1024];
183 size_t len = sizeof(buf);
184 char *pos = &buf[0];
185 memset(buf, 0xff, sizeof(buf));
186 EXPECT_EQ(nullptr, consumestr(&pos, &len));
187 EXPECT_EQ(sizeof(buf), len);
188 EXPECT_EQ(&buf[0], pos);
189 }
190
TEST(consumestr,full)191 TEST(consumestr, full) {
192 char buf[1024];
193 size_t len = sizeof(buf);
194 char *pos = &buf[0];
195 memset(buf, 0xff, sizeof(buf));
196 buf[sizeof(buf)-1] = '\0';
197 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
198 EXPECT_EQ((size_t)0, len);
199 EXPECT_EQ(&buf[sizeof(buf)], pos);
200 }
201
TEST(consumestr,trailing_nul)202 TEST(consumestr, trailing_nul) {
203 char buf[1024];
204 size_t len = sizeof(buf) - 1;
205 char *pos = &buf[0];
206 memset(buf, 0xff, sizeof(buf));
207 buf[sizeof(buf)-1] = '\0';
208 EXPECT_EQ(nullptr, consumestr(&pos, &len));
209 EXPECT_EQ(sizeof(buf) - 1, len);
210 EXPECT_EQ(&buf[0], pos);
211 }
212
213 class MarshalTest : public ::testing::Test {
214 protected:
SetUp()215 virtual void SetUp() {
216 m_ = minijail_new();
217 j_ = minijail_new();
218 size_ = minijail_size(m_);
219 }
TearDown()220 virtual void TearDown() {
221 minijail_destroy(m_);
222 minijail_destroy(j_);
223 }
224
225 char buf_[4096];
226 struct minijail *m_;
227 struct minijail *j_;
228 size_t size_;
229 };
230
TEST_F(MarshalTest,empty)231 TEST_F(MarshalTest, empty) {
232 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
233 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
234 }
235
236 TEST_F(MarshalTest, 0xff) {
237 memset(buf_, 0xff, sizeof(buf_));
238 /* Should fail on the first consumestr since a NUL will never be found. */
239 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
240 }
241
TEST_F(MarshalTest,copy_empty)242 TEST_F(MarshalTest, copy_empty) {
243 ASSERT_EQ(0, minijail_copy_jail(m_, j_));
244 }
245
TEST(KillTest,running_process)246 TEST(KillTest, running_process) {
247 const ScopedMinijail j(minijail_new());
248 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
249 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
250 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
251 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
252 }
253
TEST(KillTest,process_already_awaited)254 TEST(KillTest, process_already_awaited) {
255 const ScopedMinijail j(minijail_new());
256 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
257 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
258 EXPECT_EQ(minijail_wait(j.get()), 42);
259 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
260 }
261
TEST(KillTest,process_already_finished_but_not_awaited)262 TEST(KillTest, process_already_finished_but_not_awaited) {
263 int fds[2];
264 const ScopedMinijail j(minijail_new());
265 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
266 ASSERT_EQ(pipe(fds), 0);
267 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
268 ASSERT_EQ(close(fds[1]), 0);
269 // Wait for process to finish.
270 char buf[PIPE_BUF];
271 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
272 EXPECT_EQ(minijail_kill(j.get()), 42);
273 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
274 }
275
TEST(KillTest,process_not_started)276 TEST(KillTest, process_not_started) {
277 const ScopedMinijail j(minijail_new());
278 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
279 }
280
TEST(WaitTest,return_zero)281 TEST(WaitTest, return_zero) {
282 const ScopedMinijail j(minijail_new());
283 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
284 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
285 EXPECT_EQ(minijail_wait(j.get()), 0);
286 }
287
TEST(WaitTest,return_max)288 TEST(WaitTest, return_max) {
289 const ScopedMinijail j(minijail_new());
290 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
291 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
292 EXPECT_EQ(minijail_wait(j.get()), 255);
293 }
294
TEST(WaitTest,return_modulo)295 TEST(WaitTest, return_modulo) {
296 const ScopedMinijail j(minijail_new());
297 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
298 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
299 EXPECT_EQ(minijail_wait(j.get()), 0);
300 }
301
TEST(WaitTest,killed_by_sigkill)302 TEST(WaitTest, killed_by_sigkill) {
303 const ScopedMinijail j(minijail_new());
304 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
305 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
306 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
307 }
308
TEST(WaitTest,killed_by_sigsys)309 TEST(WaitTest, killed_by_sigsys) {
310 const ScopedMinijail j(minijail_new());
311 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
312 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
313 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
314 }
315
TEST(WaitTest,command_not_found)316 TEST(WaitTest, command_not_found) {
317 const ScopedMinijail j(minijail_new());
318 char* const argv[] = {"whatever", nullptr};
319 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
320 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
321 }
322
TEST(WaitTest,command_not_run)323 TEST(WaitTest, command_not_run) {
324 const ScopedMinijail j(minijail_new());
325 char* const argv[] = {"whatever", nullptr};
326 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
327 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
328 }
329
TEST(WaitTest,no_process)330 TEST(WaitTest, no_process) {
331 const ScopedMinijail j(minijail_new());
332 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
333 }
334
TEST(WaitTest,can_wait_only_once)335 TEST(WaitTest, can_wait_only_once) {
336 const ScopedMinijail j(minijail_new());
337 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
338 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
339 EXPECT_EQ(minijail_wait(j.get()), 0);
340 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
341 }
342
TEST(Test,minijail_preserve_fd_no_leak)343 TEST(Test, minijail_preserve_fd_no_leak) {
344 const ScopedMinijail j(minijail_new());
345 char* const script = R"(
346 echo Hi >&1;
347 exec 1>&-;
348 read line1;
349 read line2;
350 echo "$line1$line2 and Goodbye" >&2;
351 exit 42;
352 )";
353 char* const argv[] = {"sh", "-c", script, nullptr};
354
355 const int npipes = 3;
356 int fds[npipes][2];
357
358 // Create pipes.
359 for (int i = 0; i < npipes; ++i) {
360 ASSERT_EQ(pipe(fds[i]), 0);
361 }
362
363 // All pipes are output pipes except for the first one which is used as
364 // input pipe.
365 std::swap(fds[0][0], fds[0][1]);
366
367 for (int i = 0; i < npipes; ++i) {
368 const int fd = fds[i][1];
369 minijail_preserve_fd(j.get(), fd, i);
370 }
371
372 minijail_close_open_fds(j.get());
373
374 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
375
376 // Close unused end of pipes.
377 for (int i = 0; i < npipes; ++i) {
378 const int fd = fds[i][1];
379 ASSERT_EQ(close(fd), 0);
380 }
381
382 const int in = fds[0][0];
383 const int out = fds[1][0];
384 const int err = fds[2][0];
385
386 char buf[PIPE_BUF];
387 ssize_t nbytes;
388
389 // Check that stdout pipe works.
390 nbytes = read(out, buf, PIPE_BUF);
391 ASSERT_GT(nbytes, 0);
392 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
393
394 // Check that the write end of stdout pipe got closed by the child process. If
395 // the child process kept other file descriptors connected to stdout, then the
396 // parent process wouldn't be able to detect that all write ends of this pipe
397 // are closed and it would block here.
398 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
399 ASSERT_EQ(close(out), 0);
400
401 // Check that stdin pipe works.
402 const std::string s = "Greetings\n";
403 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
404
405 // Close write end of pipe connected to child's stdin. If there was another
406 // file descriptor connected to this write end, then the child process
407 // wouldn't be able to detect that this write end is closed and it would
408 // block.
409 ASSERT_EQ(close(in), 0);
410
411 // Check that child process continued and ended.
412 nbytes = read(err, buf, PIPE_BUF);
413 ASSERT_GT(nbytes, 0);
414 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
415
416 // Check that the write end of the stderr pipe is closed when the child
417 // process finishes.
418 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
419 ASSERT_EQ(close(err), 0);
420
421 // Check the child process termination status.
422 EXPECT_EQ(minijail_wait(j.get()), 42);
423 }
424
TEST(Test,close_original_pipes_after_dup2)425 TEST(Test, close_original_pipes_after_dup2) {
426 // Pipe used by child process to signal that it continued after reading from
427 // stdin.
428 int to_wait[2];
429 ASSERT_EQ(pipe(to_wait), 0);
430
431 const ScopedMinijail j(minijail_new());
432 char* program;
433 ASSERT_GT(asprintf(&program, R"(
434 echo Hi >&1;
435 echo There >&2;
436 exec 1>&-;
437 exec 2>&-;
438 read line1;
439 read line2;
440 echo "$line1$line2 and Goodbye" >&%d;
441 exit 42;
442 )", to_wait[1]), 0);
443 char* const argv[] = {"sh", "-c", program, nullptr};
444
445 int in = -1;
446 int out = -1;
447 int err = -1;
448 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
449 nullptr, &in, &out, &err),
450 0);
451 free(program);
452
453 EXPECT_GT(in, 0);
454 EXPECT_GT(out, 0);
455 EXPECT_GT(err, 0);
456
457 char buf[PIPE_BUF];
458 ssize_t n;
459
460 // Check that stdout and stderr pipes work.
461 n = read(out, buf, PIPE_BUF);
462 ASSERT_GT(n, 0);
463 EXPECT_EQ(std::string(buf, n), "Hi\n");
464
465 n = read(err, buf, PIPE_BUF);
466 ASSERT_GT(n, 0);
467 EXPECT_EQ(std::string(buf, n), "There\n");
468
469 // Check that the write ends of stdout and stderr pipes got closed by the
470 // child process. If the child process kept other file descriptors connected
471 // to stdout and stderr, then the parent process wouldn't be able to detect
472 // that all write ends of these pipes are closed and it would block here.
473 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
474 ASSERT_EQ(close(out), 0);
475 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
476 ASSERT_EQ(close(err), 0);
477
478 // Check that stdin pipe works.
479 const std::string s = "Greetings\n";
480 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
481
482 // Close write end of pipe connected to child's stdin. If there was another
483 // file descriptor connected to this write end, then the child wouldn't be
484 // able to detect that this write end is closed and it would block.
485 ASSERT_EQ(close(in), 0);
486
487 // Check that child process continued and ended.
488 n = read(to_wait[0], buf, PIPE_BUF);
489 ASSERT_GT(n, 0);
490 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
491 EXPECT_EQ(minijail_wait(j.get()), 42);
492 }
493
TEST(Test,minijail_no_clobber_pipe_fd)494 TEST(Test, minijail_no_clobber_pipe_fd) {
495 const ScopedMinijail j(minijail_new());
496 char* const script = R"(
497 echo Hi >&1;
498 exec 1>&-;
499 exec 4>&-;
500 exec 7>&-;
501 read line1;
502 read line2;
503 echo "$line1$line2 and Goodbye" >&2;
504 exit 42;
505 )";
506 char* const argv[] = {"sh", "-c", script, nullptr};
507
508 const int npipes = 3;
509 int fds[npipes][2];
510
511 // Create pipes.
512 for (int i = 0; i < npipes; ++i) {
513 ASSERT_EQ(pipe(fds[i]), 0);
514 }
515
516 // All pipes are output pipes except for the first one which is used as
517 // input pipe.
518 std::swap(fds[0][0], fds[0][1]);
519
520 // Generate a lot of mappings to try to clobber any file descriptors generated
521 // by libminijail.
522 for (int offset = 0; offset < npipes * 3; offset += npipes) {
523 for (int i = 0 ; i < npipes; ++i) {
524 const int fd = fds[i][1];
525 minijail_preserve_fd(j.get(), fd, i + offset);
526 }
527 }
528
529 minijail_close_open_fds(j.get());
530
531 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
532
533 // Close unused end of pipes.
534 for (int i = 0; i < npipes; ++i) {
535 const int fd = fds[i][1];
536 ASSERT_EQ(close(fd), 0);
537 }
538
539 const int in = fds[0][0];
540 const int out = fds[1][0];
541 const int err = fds[2][0];
542
543 char buf[PIPE_BUF];
544 ssize_t nbytes;
545
546 // Check that stdout pipe works.
547 nbytes = read(out, buf, PIPE_BUF);
548 ASSERT_GT(nbytes, 0);
549 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
550
551 // Check that the write end of stdout pipe got closed by the child process. If
552 // the child process kept other file descriptors connected to stdout, then the
553 // parent process wouldn't be able to detect that all write ends of this pipe
554 // are closed and it would block here.
555 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
556 ASSERT_EQ(close(out), 0);
557
558 // Check that stdin pipe works.
559 const std::string s = "Greetings\n";
560 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
561
562 // Close write end of pipe connected to child's stdin. If there was another
563 // file descriptor connected to this write end, then the child process
564 // wouldn't be able to detect that this write end is closed and it would
565 // block.
566 ASSERT_EQ(close(in), 0);
567
568 // Check that child process continued and ended.
569 nbytes = read(err, buf, PIPE_BUF);
570 ASSERT_GT(nbytes, 0);
571 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
572
573 // Check that the write end of the stderr pipe is closed when the child
574 // process finishes.
575 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
576 ASSERT_EQ(close(err), 0);
577
578 // Check the child process termination status.
579 EXPECT_EQ(minijail_wait(j.get()), 42);
580 }
581
TEST(Test,minijail_run_env_pid_pipes)582 TEST(Test, minijail_run_env_pid_pipes) {
583 // TODO(crbug.com/895875): The preload library interferes with ASan since they
584 // both need to use LD_PRELOAD.
585 if (running_with_asan())
586 GTEST_SKIP();
587
588 ScopedMinijail j(minijail_new());
589 set_preload_path(j.get());
590
591 char *argv[4];
592 argv[0] = const_cast<char*>(kCatPath);
593 argv[1] = NULL;
594
595 pid_t pid;
596 int child_stdin, child_stdout;
597 int mj_run_ret = minijail_run_pid_pipes(
598 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
599 EXPECT_EQ(mj_run_ret, 0);
600
601 char teststr[] = "test\n";
602 const size_t teststr_len = strlen(teststr);
603 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
604 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
605
606 char buf[kBufferSize] = {};
607 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
608 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
609 EXPECT_STREQ(buf, teststr);
610
611 int status;
612 EXPECT_EQ(kill(pid, SIGTERM), 0);
613 EXPECT_EQ(waitpid(pid, &status, 0), pid);
614 ASSERT_TRUE(WIFSIGNALED(status));
615 EXPECT_EQ(WTERMSIG(status), SIGTERM);
616
617 argv[0] = const_cast<char*>(kShellPath);
618 argv[1] = "-c";
619 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
620 argv[3] = nullptr;
621
622 char *envp[2];
623 envp[0] = "TEST_VAR=test";
624 envp[1] = NULL;
625
626 // Set a canary env var in the parent that should not be present in the child.
627 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
628
629 int child_stderr;
630 mj_run_ret =
631 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
632 &child_stdin, &child_stdout, &child_stderr);
633 EXPECT_EQ(mj_run_ret, 0);
634
635 memset(buf, 0, sizeof(buf));
636 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
637 EXPECT_GE(read_ret, 0);
638 EXPECT_STREQ(buf, "|test\n");
639
640 EXPECT_EQ(waitpid(pid, &status, 0), pid);
641 ASSERT_TRUE(WIFEXITED(status));
642 EXPECT_EQ(WEXITSTATUS(status), 0);
643 }
644
TEST(Test,minijail_run_fd_env_pid_pipes)645 TEST(Test, minijail_run_fd_env_pid_pipes) {
646 // TODO(crbug.com/895875): The preload library interferes with ASan since they
647 // both need to use LD_PRELOAD.
648 if (running_with_asan())
649 GTEST_SKIP();
650
651 ScopedMinijail j(minijail_new());
652 set_preload_path(j.get());
653
654 char *argv[4];
655 argv[0] = const_cast<char*>(kShellPath);
656 argv[1] = "-c";
657 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2\n";
658 argv[3] = nullptr;
659
660 char *envp[2];
661 envp[0] = "TEST_VAR=test";
662 envp[1] = nullptr;
663
664 // Set a canary env var in the parent that should not be present in the child.
665 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
666
667 int elf_fd = open(const_cast<char*>(kShellPath), O_RDONLY | O_CLOEXEC);
668 ASSERT_NE(elf_fd, -1);
669
670 int dev_null = open("/dev/null", O_RDONLY);
671 ASSERT_NE(dev_null, -1);
672 // Create a mapping to dev_null that would clobber elf_fd if it is not
673 // relocated.
674 minijail_preserve_fd(j.get(), dev_null, elf_fd);
675
676 pid_t pid;
677 int child_stdin, child_stdout, child_stderr;
678 int mj_run_ret =
679 minijail_run_fd_env_pid_pipes(j.get(), elf_fd, argv, envp, &pid,
680 &child_stdin, &child_stdout, &child_stderr);
681 EXPECT_EQ(mj_run_ret, 0);
682 close(dev_null);
683
684 char buf[kBufferSize] = {};
685 ssize_t read_ret = read(child_stderr, buf, sizeof(buf) - 1);
686 EXPECT_GE(read_ret, 0);
687 EXPECT_STREQ(buf, "|test\n");
688
689 int status;
690 EXPECT_EQ(waitpid(pid, &status, 0), pid);
691 ASSERT_TRUE(WIFEXITED(status));
692 EXPECT_EQ(WEXITSTATUS(status), 0);
693 }
694
TEST(Test,minijail_run_env_pid_pipes_with_local_preload)695 TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
696 // TODO(crbug.com/895875): The preload library interferes with ASan since they
697 // both need to use LD_PRELOAD.
698 if (running_with_asan())
699 GTEST_SKIP();
700
701 ScopedMinijail j(minijail_new());
702
703 char *argv[4];
704 argv[0] = const_cast<char*>(kCatPath);
705 argv[1] = NULL;
706
707 pid_t pid;
708 int child_stdin, child_stdout;
709 int mj_run_ret = minijail_run_pid_pipes(
710 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
711 EXPECT_EQ(mj_run_ret, 0);
712
713 char teststr[] = "test\n";
714 const size_t teststr_len = strlen(teststr);
715 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
716 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
717
718 char buf[kBufferSize] = {};
719 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
720 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
721 EXPECT_STREQ(buf, teststr);
722
723 int status;
724 EXPECT_EQ(kill(pid, SIGTERM), 0);
725 EXPECT_EQ(waitpid(pid, &status, 0), pid);
726 ASSERT_TRUE(WIFSIGNALED(status));
727 EXPECT_EQ(WTERMSIG(status), SIGTERM);
728
729 argv[0] = const_cast<char*>(kShellPath);
730 argv[1] = "-c";
731 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
732 argv[3] = nullptr;
733
734 char *envp[2];
735 envp[0] = "TEST_VAR=test";
736 envp[1] = NULL;
737
738 // Set a canary env var in the parent that should not be present in the child.
739 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
740
741 // Use the preload library from this test build.
742 set_preload_path(j.get());
743
744 int child_stderr;
745 mj_run_ret =
746 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
747 &child_stdin, &child_stdout, &child_stderr);
748 EXPECT_EQ(mj_run_ret, 0);
749
750 memset(buf, 0, sizeof(buf));
751 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
752 EXPECT_GE(read_ret, 0);
753 EXPECT_STREQ(buf, "|test\n");
754
755 EXPECT_EQ(waitpid(pid, &status, 0), pid);
756 ASSERT_TRUE(WIFEXITED(status));
757 EXPECT_EQ(WEXITSTATUS(status), 0);
758 }
759
TEST(Test,test_minijail_no_clobber_fds)760 TEST(Test, test_minijail_no_clobber_fds) {
761 int dev_null = open("/dev/null", O_RDONLY);
762 ASSERT_NE(dev_null, -1);
763
764 ScopedMinijail j(minijail_new());
765
766 // Keep stderr.
767 minijail_preserve_fd(j.get(), 2, 2);
768 // Create a lot of mappings to dev_null to possibly clobber libminijail.c fds.
769 for (int i = 3; i < 15; ++i) {
770 minijail_preserve_fd(j.get(), dev_null, i);
771 }
772
773 char *argv[4];
774 argv[0] = const_cast<char*>(kShellPath);
775 argv[1] = "-c";
776 argv[2] = "echo Hello; read line1; echo \"${line1}\" >&2";
777 argv[3] = nullptr;
778
779 pid_t pid;
780 int child_stdin;
781 int child_stdout;
782 int child_stderr;
783 int mj_run_ret = minijail_run_pid_pipes_no_preload(
784 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, &child_stderr);
785 EXPECT_EQ(mj_run_ret, 0);
786
787 char buf[kBufferSize];
788 ssize_t read_ret = read(child_stdout, buf, sizeof(buf));
789 EXPECT_GE(read_ret, 0);
790 buf[read_ret] = '\0';
791 EXPECT_STREQ(buf, "Hello\n");
792
793 constexpr char to_write[] = "test in and err\n";
794 ssize_t write_ret = write(child_stdin, to_write, sizeof(to_write));
795 EXPECT_EQ(write_ret, sizeof(to_write));
796
797 read_ret = read(child_stderr, buf, sizeof(buf));
798 EXPECT_GE(read_ret, 0);
799 buf[read_ret] = '\0';
800 EXPECT_STREQ(buf, to_write);
801
802 int status;
803 waitpid(pid, &status, 0);
804 ASSERT_TRUE(WIFEXITED(status));
805 EXPECT_EQ(WEXITSTATUS(status), 0);
806
807 close(dev_null);
808 }
809
TEST(Test,test_minijail_no_fd_leaks)810 TEST(Test, test_minijail_no_fd_leaks) {
811 pid_t pid;
812 int child_stdout;
813 int mj_run_ret;
814 ssize_t read_ret;
815 char buf[kBufferSize];
816 char script[kBufferSize];
817 int status;
818 char *argv[4];
819
820 int dev_null = open("/dev/null", O_RDONLY);
821 ASSERT_NE(dev_null, -1);
822 snprintf(script,
823 sizeof(script),
824 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
825 dev_null);
826
827 struct minijail *j = minijail_new();
828
829 argv[0] = const_cast<char*>(kShellPath);
830 argv[1] = "-c";
831 argv[2] = script;
832 argv[3] = NULL;
833 mj_run_ret = minijail_run_pid_pipes_no_preload(
834 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
835 EXPECT_EQ(mj_run_ret, 0);
836
837 read_ret = read(child_stdout, buf, sizeof(buf));
838 EXPECT_GE(read_ret, 0);
839 buf[read_ret] = '\0';
840 EXPECT_STREQ(buf, "yes\n");
841
842 waitpid(pid, &status, 0);
843 ASSERT_TRUE(WIFEXITED(status));
844 EXPECT_EQ(WEXITSTATUS(status), 0);
845
846 minijail_close_open_fds(j);
847 mj_run_ret = minijail_run_pid_pipes_no_preload(
848 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
849 EXPECT_EQ(mj_run_ret, 0);
850
851 read_ret = read(child_stdout, buf, sizeof(buf));
852 EXPECT_GE(read_ret, 0);
853 buf[read_ret] = '\0';
854 EXPECT_STREQ(buf, "no\n");
855
856 waitpid(pid, &status, 0);
857 ASSERT_TRUE(WIFEXITED(status));
858 EXPECT_EQ(WEXITSTATUS(status), 0);
859
860 minijail_destroy(j);
861
862 close(dev_null);
863 }
864
TEST(Test,test_minijail_fork)865 TEST(Test, test_minijail_fork) {
866 pid_t mj_fork_ret;
867 int status;
868 int pipe_fds[2];
869 ssize_t pid_size = sizeof(mj_fork_ret);
870
871 ScopedMinijail j(minijail_new());
872
873 ASSERT_EQ(pipe(pipe_fds), 0);
874
875 mj_fork_ret = minijail_fork(j.get());
876 ASSERT_GE(mj_fork_ret, 0);
877 if (mj_fork_ret == 0) {
878 pid_t pid_in_parent;
879 // Wait for the parent to tell us the pid in the parent namespace.
880 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
881 ASSERT_EQ(pid_in_parent, getpid());
882 exit(0);
883 }
884
885 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
886 waitpid(mj_fork_ret, &status, 0);
887 ASSERT_TRUE(WIFEXITED(status));
888 EXPECT_EQ(WEXITSTATUS(status), 0);
889 }
890
early_exit(void * payload)891 static int early_exit(void* payload) {
892 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
893 }
894
TEST(Test,test_minijail_callback)895 TEST(Test, test_minijail_callback) {
896 pid_t pid;
897 int mj_run_ret;
898 int status;
899 char *argv[2];
900 int exit_code = 42;
901
902 struct minijail *j = minijail_new();
903
904 status =
905 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
906 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
907 EXPECT_EQ(status, 0);
908
909 argv[0] = const_cast<char*>(kCatPath);
910 argv[1] = NULL;
911 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
912 NULL, NULL);
913 EXPECT_EQ(mj_run_ret, 0);
914
915 status = minijail_wait(j);
916 EXPECT_EQ(status, exit_code);
917
918 minijail_destroy(j);
919 }
920
TEST(Test,test_minijail_preserve_fd)921 TEST(Test, test_minijail_preserve_fd) {
922 int mj_run_ret;
923 int status;
924 char *argv[2];
925 char teststr[] = "test\n";
926 size_t teststr_len = strlen(teststr);
927 int read_pipe[2];
928 int write_pipe[2];
929 char buf[1024];
930
931 struct minijail *j = minijail_new();
932
933 status = pipe(read_pipe);
934 ASSERT_EQ(status, 0);
935 status = pipe(write_pipe);
936 ASSERT_EQ(status, 0);
937
938 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
939 ASSERT_EQ(status, 0);
940 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
941 ASSERT_EQ(status, 0);
942 minijail_close_open_fds(j);
943
944 argv[0] = const_cast<char*>(kCatPath);
945 argv[1] = NULL;
946 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
947 EXPECT_EQ(mj_run_ret, 0);
948
949 close(write_pipe[0]);
950 status = write(write_pipe[1], teststr, teststr_len);
951 EXPECT_EQ(status, (int)teststr_len);
952 close(write_pipe[1]);
953
954 close(read_pipe[1]);
955 status = read(read_pipe[0], buf, 8);
956 EXPECT_EQ(status, (int)teststr_len);
957 buf[teststr_len] = 0;
958 EXPECT_STREQ(buf, teststr);
959
960 status = minijail_wait(j);
961 EXPECT_EQ(status, 0);
962
963 minijail_destroy(j);
964 }
965
TEST(Test,test_minijail_reset_signal_mask)966 TEST(Test, test_minijail_reset_signal_mask) {
967 struct minijail *j = minijail_new();
968
969 sigset_t original_signal_mask;
970 {
971 sigset_t signal_mask;
972 ASSERT_EQ(0, sigemptyset(&signal_mask));
973 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
974 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
975 }
976
977 minijail_reset_signal_mask(j);
978
979 pid_t mj_fork_ret = minijail_fork(j);
980 ASSERT_GE(mj_fork_ret, 0);
981 if (mj_fork_ret == 0) {
982 sigset_t signal_mask;
983 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
984 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
985 minijail_destroy(j);
986 exit(0);
987 }
988
989 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
990
991 int status;
992 waitpid(mj_fork_ret, &status, 0);
993 ASSERT_TRUE(WIFEXITED(status));
994 EXPECT_EQ(WEXITSTATUS(status), 0);
995
996 minijail_destroy(j);
997 }
998
TEST(Test,test_minijail_reset_signal_handlers)999 TEST(Test, test_minijail_reset_signal_handlers) {
1000 struct minijail *j = minijail_new();
1001
1002 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
1003 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
1004 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
1005
1006 minijail_reset_signal_handlers(j);
1007
1008 pid_t mj_fork_ret = minijail_fork(j);
1009 ASSERT_GE(mj_fork_ret, 0);
1010 if (mj_fork_ret == 0) {
1011 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
1012 minijail_destroy(j);
1013 exit(0);
1014 }
1015
1016 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
1017
1018 int status;
1019 waitpid(mj_fork_ret, &status, 0);
1020 ASSERT_TRUE(WIFEXITED(status));
1021 EXPECT_EQ(WEXITSTATUS(status), 0);
1022
1023 minijail_destroy(j);
1024 }
1025
1026 // Test that bind mounting onto a non-existing location works.
TEST(Test,test_bind_mount_nonexistent_dest)1027 TEST(Test, test_bind_mount_nonexistent_dest) {
1028 TemporaryDir dir;
1029 ASSERT_TRUE(dir.is_valid());
1030
1031 // minijail_bind() expects absolute paths, but TemporaryDir::path can return
1032 // relative paths on Linux.
1033 std::string path = dir.path;
1034 if (!is_android()) {
1035 std::string cwd(getcwd(NULL, 0));
1036 path = cwd + "/" + path;
1037 }
1038
1039 std::string path_src = path + "/src";
1040 std::string path_dest = path + "/dest";
1041
1042 EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
1043
1044 ScopedMinijail j(minijail_new());
1045 int bind_res = minijail_bind(j.get(), path_src.c_str(), path_dest.c_str(),
1046 0 /*writable*/);
1047 EXPECT_EQ(bind_res, 0);
1048 }
1049
1050 // Test that bind mounting with a symlink behaves according to build-time
1051 // configuration.
TEST(Test,test_bind_mount_symlink)1052 TEST(Test, test_bind_mount_symlink) {
1053 TemporaryDir dir;
1054 ASSERT_TRUE(dir.is_valid());
1055
1056 // minijail_bind() expects absolute paths, but TemporaryDir::path can return
1057 // relative paths on Linux.
1058 std::string path = dir.path;
1059 if (!is_android()) {
1060 std::string cwd(getcwd(NULL, 0));
1061 path = cwd + "/" + path;
1062 }
1063
1064 std::string path_src = path + "/src";
1065 std::string path_dest = path + "/dest";
1066 std::string path_sym = path + "/symlink";
1067
1068 EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
1069 EXPECT_EQ(mkdir(path_dest.c_str(), 0700), 0);
1070 EXPECT_EQ(symlink(path_src.c_str(), path_sym.c_str()), 0);
1071
1072 ScopedMinijail j(minijail_new());
1073 int bind_res = minijail_bind(j.get(), path_sym.c_str(), path_dest.c_str(),
1074 0 /*writable*/);
1075 if (block_symlinks_in_bindmount_paths()) {
1076 EXPECT_NE(bind_res, 0);
1077 } else {
1078 EXPECT_EQ(bind_res, 0);
1079 }
1080 EXPECT_EQ(unlink(path_sym.c_str()), 0);
1081 }
1082
1083 namespace {
1084
1085 // Tests that require userns access.
1086 // Android unit tests don't currently support entering user namespaces as
1087 // unprivileged users due to having an older kernel. ChromeOS unit tests
1088 // don't support it either due to being in a chroot environment (see man 2
1089 // clone for more information about failure modes with the CLONE_NEWUSER flag).
1090 class NamespaceTest : public ::testing::Test {
1091 protected:
SetUpTestCase()1092 static void SetUpTestCase() {
1093 userns_supported_ = UsernsSupported();
1094 }
1095
1096 // Whether userns is supported.
1097 static bool userns_supported_;
1098
UsernsSupported()1099 static bool UsernsSupported() {
1100 pid_t pid = fork();
1101 if (pid == -1)
1102 pdie("could not fork");
1103
1104 if (pid == 0)
1105 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
1106
1107 int status;
1108 if (waitpid(pid, &status, 0) < 0)
1109 pdie("could not wait");
1110
1111 if (!WIFEXITED(status))
1112 die("child did not exit properly: %#x", status);
1113
1114 bool ret = WEXITSTATUS(status) == 0;
1115 if (!ret)
1116 warn("Skipping userns related tests");
1117 return ret;
1118 }
1119 };
1120
1121 bool NamespaceTest::userns_supported_;
1122
1123 } // namespace
1124
TEST_F(NamespaceTest,test_tmpfs_userns)1125 TEST_F(NamespaceTest, test_tmpfs_userns) {
1126 int mj_run_ret;
1127 int status;
1128 char *argv[4];
1129 char uidmap[kBufferSize], gidmap[kBufferSize];
1130 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1131 constexpr gid_t kTargetGid = 1000;
1132
1133 if (!userns_supported_)
1134 GTEST_SKIP();
1135
1136 struct minijail *j = minijail_new();
1137
1138 minijail_namespace_pids(j);
1139 minijail_namespace_vfs(j);
1140 minijail_mount_tmp(j);
1141 minijail_run_as_init(j);
1142
1143 // Perform userns mapping.
1144 minijail_namespace_user(j);
1145 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1146 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1147 minijail_change_uid(j, kTargetUid);
1148 minijail_change_gid(j, kTargetGid);
1149 minijail_uidmap(j, uidmap);
1150 minijail_gidmap(j, gidmap);
1151 minijail_namespace_user_disable_setgroups(j);
1152
1153 argv[0] = const_cast<char*>(kShellPath);
1154 argv[1] = "-c";
1155 argv[2] = "exec touch /tmp/foo";
1156 argv[3] = NULL;
1157 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
1158 EXPECT_EQ(mj_run_ret, 0);
1159
1160 status = minijail_wait(j);
1161 EXPECT_EQ(status, 0);
1162
1163 minijail_destroy(j);
1164 }
1165
TEST_F(NamespaceTest,test_namespaces)1166 TEST_F(NamespaceTest, test_namespaces) {
1167 constexpr char teststr[] = "test\n";
1168
1169 // TODO(crbug.com/895875): The preload library interferes with ASan since they
1170 // both need to use LD_PRELOAD.
1171 if (!userns_supported_ || running_with_asan())
1172 GTEST_SKIP();
1173
1174 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
1175 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
1176
1177 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
1178 "net", "cgroup", "uts"};
1179 // Grab the set of namespaces outside the container.
1180 std::map<std::string, std::string> init_namespaces =
1181 GetNamespaces(getpid(), namespace_names);
1182 std::function<void(struct minijail*)> test_functions[] = {
1183 [](struct minijail* j attribute_unused) {},
1184 [](struct minijail* j) {
1185 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
1186 minijail_enter_pivot_root(j, "/tmp");
1187 },
1188 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
1189 };
1190
1191 // This test is run with and without the preload library.
1192 for (const auto& run_function :
1193 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
1194 for (const auto& test_function : test_functions) {
1195 ScopedMinijail j(minijail_new());
1196 set_preload_path(j.get());
1197
1198 // Enter all the namespaces we can.
1199 minijail_namespace_cgroups(j.get());
1200 minijail_namespace_net(j.get());
1201 minijail_namespace_pids(j.get());
1202 minijail_namespace_user(j.get());
1203 minijail_namespace_vfs(j.get());
1204 minijail_namespace_uts(j.get());
1205
1206 // Set up the user namespace.
1207 minijail_uidmap(j.get(), uidmap.c_str());
1208 minijail_gidmap(j.get(), gidmap.c_str());
1209 minijail_namespace_user_disable_setgroups(j.get());
1210
1211 minijail_close_open_fds(j.get());
1212 test_function(j.get());
1213
1214 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
1215 pid_t container_pid;
1216 int child_stdin, child_stdout;
1217 int mj_run_ret =
1218 run_function(j.get(), argv[0], argv,
1219 &container_pid, &child_stdin, &child_stdout, nullptr);
1220 EXPECT_EQ(mj_run_ret, 0);
1221
1222 // Send some data to stdin and read it back to ensure that the child
1223 // process is running.
1224 const size_t teststr_len = strlen(teststr);
1225 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
1226 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
1227
1228 char buf[kBufferSize];
1229 ssize_t read_ret = read(child_stdout, buf, 8);
1230 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
1231 buf[teststr_len] = 0;
1232 EXPECT_STREQ(buf, teststr);
1233
1234 // Grab the set of namespaces in every container process. They must not
1235 // match the ones in the init namespace, and they must all match each
1236 // other.
1237 std::map<std::string, std::string> container_namespaces =
1238 GetNamespaces(container_pid, namespace_names);
1239 EXPECT_NE(container_namespaces, init_namespaces);
1240 for (pid_t pid : GetProcessSubtreePids(container_pid))
1241 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
1242
1243 EXPECT_EQ(0, close(child_stdin));
1244
1245 int status = minijail_wait(j.get());
1246 EXPECT_EQ(status, 0);
1247 }
1248 }
1249 }
1250
TEST_F(NamespaceTest,test_enter_ns)1251 TEST_F(NamespaceTest, test_enter_ns) {
1252 char uidmap[kBufferSize], gidmap[kBufferSize];
1253
1254 if (!userns_supported_)
1255 GTEST_SKIP();
1256
1257 // We first create a child in a new userns so we have privs to run more tests.
1258 // We can't combine the steps as the kernel disallows many resource sharing
1259 // from outside the userns.
1260 struct minijail *j = minijail_new();
1261
1262 minijail_namespace_vfs(j);
1263 minijail_namespace_pids(j);
1264 minijail_run_as_init(j);
1265
1266 // Perform userns mapping.
1267 minijail_namespace_user(j);
1268 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1269 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1270 minijail_uidmap(j, uidmap);
1271 minijail_gidmap(j, gidmap);
1272 minijail_namespace_user_disable_setgroups(j);
1273
1274 pid_t pid = minijail_fork(j);
1275 if (pid == 0) {
1276 // Child.
1277 minijail_destroy(j);
1278
1279 // Create new namespaces inside this userns which we may enter.
1280 j = minijail_new();
1281 minijail_namespace_net(j);
1282 minijail_namespace_vfs(j);
1283 pid = minijail_fork(j);
1284 if (pid == 0) {
1285 // Child.
1286 minijail_destroy(j);
1287
1288 // Finally enter those namespaces.
1289 j = minijail_new();
1290
1291 set_preload_path(j);
1292
1293 minijail_namespace_net(j);
1294 minijail_namespace_vfs(j);
1295
1296 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1297 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1298
1299 char *argv[] = {"/bin/true", nullptr};
1300 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1301 EXPECT_EQ(0, minijail_wait(j));
1302 minijail_destroy(j);
1303 exit(0);
1304 } else {
1305 ASSERT_GT(pid, 0);
1306 EXPECT_EQ(0, minijail_wait(j));
1307 minijail_destroy(j);
1308 exit(0);
1309 }
1310 } else {
1311 ASSERT_GT(pid, 0);
1312 EXPECT_EQ(0, minijail_wait(j));
1313 minijail_destroy(j);
1314 }
1315 }
1316
TEST_F(NamespaceTest,test_remount_all_private)1317 TEST_F(NamespaceTest, test_remount_all_private) {
1318 pid_t pid;
1319 int child_stdout;
1320 int mj_run_ret;
1321 ssize_t read_ret;
1322 char buf[kBufferSize];
1323 int status;
1324 char *argv[4];
1325 char uidmap[kBufferSize], gidmap[kBufferSize];
1326 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1327 constexpr gid_t kTargetGid = 1000;
1328
1329 if (!userns_supported_)
1330 GTEST_SKIP();
1331
1332 struct minijail *j = minijail_new();
1333
1334 minijail_namespace_pids(j);
1335 minijail_namespace_vfs(j);
1336 minijail_run_as_init(j);
1337
1338 // Perform userns mapping.
1339 minijail_namespace_user(j);
1340 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1341 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1342 minijail_change_uid(j, kTargetUid);
1343 minijail_change_gid(j, kTargetGid);
1344 minijail_uidmap(j, uidmap);
1345 minijail_gidmap(j, gidmap);
1346 minijail_namespace_user_disable_setgroups(j);
1347
1348 minijail_namespace_vfs(j);
1349 minijail_remount_mode(j, MS_PRIVATE);
1350
1351 argv[0] = const_cast<char*>(kShellPath);
1352 argv[1] = "-c";
1353 argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
1354 "/proc/self/mountinfo";
1355 argv[3] = NULL;
1356 mj_run_ret = minijail_run_pid_pipes_no_preload(
1357 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1358 EXPECT_EQ(mj_run_ret, 0);
1359
1360 // There should be no output because all mounts should be remounted as
1361 // private.
1362 read_ret = read(child_stdout, buf, sizeof(buf));
1363 EXPECT_EQ(read_ret, 0);
1364
1365 // grep will exit with 1 if it does not find anything which is what we
1366 // expect.
1367 status = minijail_wait(j);
1368 EXPECT_EQ(status, 1);
1369
1370 minijail_destroy(j);
1371 }
1372
TEST_F(NamespaceTest,test_fail_to_remount_one_private)1373 TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1374 int status;
1375 char uidmap[kBufferSize], gidmap[kBufferSize];
1376 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1377 constexpr gid_t kTargetGid = 1000;
1378
1379 if (!userns_supported_)
1380 GTEST_SKIP();
1381
1382 struct minijail *j = minijail_new();
1383
1384 minijail_namespace_pids(j);
1385 minijail_namespace_vfs(j);
1386 minijail_mount_tmp(j);
1387 minijail_run_as_init(j);
1388
1389 // Perform userns mapping.
1390 minijail_namespace_user(j);
1391 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1392 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1393 minijail_change_uid(j, kTargetUid);
1394 minijail_change_gid(j, kTargetGid);
1395 minijail_uidmap(j, uidmap);
1396 minijail_gidmap(j, gidmap);
1397 minijail_namespace_user_disable_setgroups(j);
1398
1399 minijail_namespace_vfs(j);
1400 minijail_remount_mode(j, MS_SHARED);
1401 minijail_add_remount(j, "/proc", MS_PRIVATE);
1402
1403 char *argv[] = {"/bin/true", nullptr};
1404 minijail_run(j, argv[0], argv);
1405
1406 status = minijail_wait(j);
1407 EXPECT_GT(status, 0);
1408
1409 minijail_destroy(j);
1410 }
1411
TEST_F(NamespaceTest,test_remount_one_shared)1412 TEST_F(NamespaceTest, test_remount_one_shared) {
1413 pid_t pid;
1414 int child_stdout;
1415 int mj_run_ret;
1416 ssize_t read_ret;
1417 char buf[kBufferSize * 4];
1418 int status;
1419 char *argv[4];
1420 char uidmap[kBufferSize], gidmap[kBufferSize];
1421 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1422 constexpr gid_t kTargetGid = 1000;
1423
1424 if (!userns_supported_)
1425 GTEST_SKIP();
1426
1427 struct minijail *j = minijail_new();
1428
1429 minijail_namespace_pids(j);
1430 minijail_namespace_vfs(j);
1431 minijail_mount_tmp(j);
1432 minijail_run_as_init(j);
1433
1434 // Perform userns mapping.
1435 minijail_namespace_user(j);
1436 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1437 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1438 minijail_change_uid(j, kTargetUid);
1439 minijail_change_gid(j, kTargetGid);
1440 minijail_uidmap(j, uidmap);
1441 minijail_gidmap(j, gidmap);
1442 minijail_namespace_user_disable_setgroups(j);
1443
1444 minijail_namespace_vfs(j);
1445 minijail_remount_mode(j, MS_PRIVATE);
1446 minijail_add_remount(j, "/proc", MS_SHARED);
1447
1448 argv[0] = const_cast<char*>(kShellPath);
1449 argv[1] = "-c";
1450 argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1451 argv[3] = NULL;
1452 mj_run_ret = minijail_run_pid_pipes_no_preload(
1453 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1454 EXPECT_EQ(mj_run_ret, 0);
1455
1456 // There should be no output because all mounts should be remounted as
1457 // private.
1458 read_ret = read(child_stdout, buf, sizeof(buf));
1459 EXPECT_GE(read_ret, 0);
1460 buf[read_ret] = '\0';
1461 EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1462
1463 status = minijail_wait(j);
1464 EXPECT_EQ(status, 0);
1465
1466 minijail_destroy(j);
1467 }
1468
1469 // Test that using minijail_mount() for bind mounts works.
TEST_F(NamespaceTest,test_remount_ro_using_mount)1470 TEST_F(NamespaceTest, test_remount_ro_using_mount) {
1471 int status;
1472 char uidmap[kBufferSize], gidmap[kBufferSize];
1473 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1474 constexpr gid_t kTargetGid = 1000;
1475
1476 if (!userns_supported_)
1477 GTEST_SKIP();
1478
1479 struct minijail *j = minijail_new();
1480
1481 minijail_namespace_pids(j);
1482 minijail_namespace_vfs(j);
1483 minijail_mount_tmp(j);
1484 minijail_run_as_init(j);
1485
1486 // Perform userns mapping.
1487 minijail_namespace_user(j);
1488 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1489 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1490 minijail_change_uid(j, kTargetUid);
1491 minijail_change_gid(j, kTargetGid);
1492 minijail_uidmap(j, uidmap);
1493 minijail_gidmap(j, gidmap);
1494 minijail_namespace_user_disable_setgroups(j);
1495
1496 // Perform a RO remount using minijail_mount().
1497 minijail_mount(j, "none", "/", "none", MS_REMOUNT | MS_BIND | MS_RDONLY);
1498
1499 char *argv[] = {"/bin/true", nullptr};
1500 minijail_run_no_preload(j, argv[0], argv);
1501
1502 status = minijail_wait(j);
1503 EXPECT_EQ(status, 0);
1504
1505 minijail_destroy(j);
1506 }
1507
1508 namespace {
1509
1510 // Tests that require Landlock support.
1511 //
1512 // These subclass NamespaceTest because they also require userns access.
1513 // TODO(akhna): ideally, Landlock unit tests should be able to run w/o
1514 // namespace_pids or namespace_user.
1515 class LandlockTest : public NamespaceTest {
1516 protected:
SetUpTestCase()1517 static void SetUpTestCase() {
1518 run_landlock_tests_ = LandlockSupported() && UsernsSupported();
1519 }
1520
1521 // Whether Landlock tests should be run.
1522 static bool run_landlock_tests_;
1523
LandlockSupported()1524 static bool LandlockSupported() {
1525 // Check the Landlock version w/o creating a ruleset file descriptor.
1526 int landlock_version = landlock_create_ruleset(
1527 NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
1528 if (landlock_version <= 0) {
1529 const int err = errno;
1530 warn("Skipping Landlock tests");
1531 switch (err) {
1532 case ENOSYS:
1533 warn("Landlock not supported by the current kernel.");
1534 break;
1535 case EOPNOTSUPP:
1536 warn("Landlock is currently disabled.");
1537 break;
1538 }
1539 return false;
1540 }
1541 return true;
1542 }
1543
1544 // Sets up a minijail to make Landlock syscalls and child processes.
SetupLandlockTestingNamespaces(struct minijail * j)1545 void SetupLandlockTestingNamespaces(struct minijail *j) {
1546 minijail_namespace_pids(j);
1547 minijail_namespace_user(j);
1548 }
1549 };
1550
1551 bool LandlockTest::run_landlock_tests_;
1552
1553 // Constants used in Landlock tests.
1554 constexpr char kBinPath[] = "/bin";
1555 constexpr char kEtcPath[] = "/etc";
1556 constexpr char kLibPath[] = "/lib";
1557 constexpr char kLib64Path[] = "/lib64";
1558 constexpr char kTmpPath[] = "/tmp";
1559 constexpr char kLsPath[] = "/bin/ls";
1560 constexpr char kTestSymlinkScript[] = R"(
1561 unlink /tmp/test-sym-link-1;
1562 ln -s /bin /tmp/test-sym-link-1
1563 )";
1564
1565 } // namespace
1566
TEST_F(LandlockTest,test_rule_rx_allow)1567 TEST_F(LandlockTest, test_rule_rx_allow) {
1568 int mj_run_ret;
1569 int status;
1570 char *argv[3];
1571 if (!run_landlock_tests_)
1572 GTEST_SKIP();
1573 ScopedMinijail j(minijail_new());
1574 SetupLandlockTestingNamespaces(j.get());
1575 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1576 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1577 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1578 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1579
1580 argv[0] = const_cast<char*>(kLsPath);
1581 argv[1] = const_cast<char*>(kCatPath);
1582 argv[2] = NULL;
1583
1584 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1585 EXPECT_EQ(mj_run_ret, 0);
1586 status = minijail_wait(j.get());
1587 EXPECT_EQ(status, 0);
1588 }
1589
TEST_F(LandlockTest,test_rule_rx_deny)1590 TEST_F(LandlockTest, test_rule_rx_deny) {
1591 int mj_run_ret;
1592 int status;
1593 char *argv[3];
1594 if (!run_landlock_tests_)
1595 GTEST_SKIP();
1596 ScopedMinijail j(minijail_new());
1597 SetupLandlockTestingNamespaces(j.get());
1598 // Add irrelevant Landlock rule.
1599 minijail_add_fs_restriction_rx(j.get(), "/var");
1600
1601 argv[0] = const_cast<char*>(kLsPath);
1602 argv[1] = const_cast<char*>(kCatPath);
1603 argv[2] = NULL;
1604
1605 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1606 EXPECT_EQ(mj_run_ret, 0);
1607 status = minijail_wait(j.get());
1608 EXPECT_NE(status, 0);
1609 }
1610
TEST_F(LandlockTest,test_rule_ro_allow)1611 TEST_F(LandlockTest, test_rule_ro_allow) {
1612 int mj_run_ret;
1613 int status;
1614 char *argv[3];
1615 if (!run_landlock_tests_)
1616 GTEST_SKIP();
1617 ScopedMinijail j(minijail_new());
1618 SetupLandlockTestingNamespaces(j.get());
1619 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1620 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1621 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1622 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1623 // Add RO rule.
1624 minijail_add_fs_restriction_ro(j.get(), "/var");
1625
1626 argv[0] = const_cast<char*>(kLsPath);
1627 argv[1] = "/var";
1628 argv[2] = NULL;
1629
1630 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1631 EXPECT_EQ(mj_run_ret, 0);
1632 status = minijail_wait(j.get());
1633 EXPECT_EQ(status, 0);
1634 }
1635
TEST_F(LandlockTest,test_rule_ro_deny)1636 TEST_F(LandlockTest, test_rule_ro_deny) {
1637 int mj_run_ret;
1638 int status;
1639 char *argv[3];
1640 if (!run_landlock_tests_)
1641 GTEST_SKIP();
1642 ScopedMinijail j(minijail_new());
1643 SetupLandlockTestingNamespaces(j.get());
1644 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1645 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1646 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1647 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1648 // No RO rule for /var, because we want the cmd to fail.
1649
1650 argv[0] = const_cast<char*>(kLsPath);
1651 argv[1] = "/var";
1652 argv[2] = NULL;
1653
1654 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1655 EXPECT_EQ(mj_run_ret, 0);
1656 status = minijail_wait(j.get());
1657 EXPECT_NE(status, 0);
1658 }
1659
TEST_F(LandlockTest,test_rule_rw_allow)1660 TEST_F(LandlockTest, test_rule_rw_allow) {
1661 int mj_run_ret;
1662 int status;
1663 char *argv[4];
1664 if (!run_landlock_tests_)
1665 GTEST_SKIP();
1666 ScopedMinijail j(minijail_new());
1667 SetupLandlockTestingNamespaces(j.get());
1668 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1669 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1670 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1671 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1672 // Add RW Landlock rule.
1673 minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1674
1675 argv[0] = const_cast<char*>(kShellPath);
1676 argv[1] = "-c";
1677 argv[2] = "exec echo 'bar' > /tmp/baz";
1678 argv[3] = NULL;
1679
1680 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1681 EXPECT_EQ(mj_run_ret, 0);
1682 status = minijail_wait(j.get());
1683 EXPECT_EQ(status, 0);
1684 }
1685
TEST_F(LandlockTest,test_rule_rw_deny)1686 TEST_F(LandlockTest, test_rule_rw_deny) {
1687 int mj_run_ret;
1688 int status;
1689 char *argv[4];
1690 if (!run_landlock_tests_)
1691 GTEST_SKIP();
1692 ScopedMinijail j(minijail_new());
1693 SetupLandlockTestingNamespaces(j.get());
1694 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1695 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1696 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1697 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1698 // No RW rule, because we want the cmd to fail.
1699
1700 argv[0] = const_cast<char*>(kShellPath);
1701 argv[1] = "-c";
1702 argv[2] = "exec echo 'bar' > /tmp/baz";
1703 argv[3] = NULL;
1704
1705 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1706 EXPECT_EQ(mj_run_ret, 0);
1707 status = minijail_wait(j.get());
1708 EXPECT_NE(status, 0);
1709 }
1710
TEST_F(LandlockTest,test_rule_allow_symlinks_advanced_rw)1711 TEST_F(LandlockTest, test_rule_allow_symlinks_advanced_rw) {
1712 int mj_run_ret;
1713 int status;
1714 if (!run_landlock_tests_)
1715 GTEST_SKIP();
1716 ScopedMinijail j(minijail_new());
1717 SetupLandlockTestingNamespaces(j.get());
1718 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1719 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1720 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1721 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1722 minijail_add_fs_restriction_advanced_rw(j.get(), kTmpPath);
1723
1724 char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
1725 nullptr};
1726
1727 mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
1728 EXPECT_EQ(mj_run_ret, 0);
1729 status = minijail_wait(j.get());
1730 EXPECT_EQ(status, 0);
1731 }
1732
TEST_F(LandlockTest,test_rule_deny_symlinks_basic_rw)1733 TEST_F(LandlockTest, test_rule_deny_symlinks_basic_rw) {
1734 int mj_run_ret;
1735 int status;
1736 if (!run_landlock_tests_)
1737 GTEST_SKIP();
1738 ScopedMinijail j(minijail_new());
1739 SetupLandlockTestingNamespaces(j.get());
1740 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1741 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1742 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1743 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1744 minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1745
1746 char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
1747 nullptr};
1748
1749 mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
1750 EXPECT_EQ(mj_run_ret, 0);
1751 status = minijail_wait(j.get());
1752 EXPECT_NE(status, 0);
1753 }
1754
TEST_F(LandlockTest,test_rule_rx_cannot_write)1755 TEST_F(LandlockTest, test_rule_rx_cannot_write) {
1756 int mj_run_ret;
1757 int status;
1758 char *argv[4];
1759 if (!run_landlock_tests_)
1760 GTEST_SKIP();
1761 ScopedMinijail j(minijail_new());
1762 SetupLandlockTestingNamespaces(j.get());
1763 minijail_add_fs_restriction_rx(j.get(), kBinPath);
1764 minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1765 minijail_add_fs_restriction_rx(j.get(), kLibPath);
1766 minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1767 minijail_add_fs_restriction_rx(j.get(), kTmpPath);
1768
1769 argv[0] = const_cast<char*>(kShellPath);
1770 argv[1] = "-c";
1771 argv[2] = "exec echo 'bar' > /tmp/baz";
1772 argv[3] = NULL;
1773
1774 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1775 EXPECT_EQ(mj_run_ret, 0);
1776 status = minijail_wait(j.get());
1777 EXPECT_NE(status, 0);
1778 }
1779
TEST_F(LandlockTest,test_rule_ro_cannot_wx)1780 TEST_F(LandlockTest, test_rule_ro_cannot_wx) {
1781 int mj_run_ret;
1782 int status;
1783 char *argv[4];
1784 if (!run_landlock_tests_)
1785 GTEST_SKIP();
1786 ScopedMinijail j(minijail_new());
1787 SetupLandlockTestingNamespaces(j.get());
1788 minijail_add_fs_restriction_ro(j.get(), kBinPath);
1789 minijail_add_fs_restriction_ro(j.get(), kEtcPath);
1790 minijail_add_fs_restriction_ro(j.get(), kLibPath);
1791 minijail_add_fs_restriction_ro(j.get(), kLib64Path);
1792 minijail_add_fs_restriction_ro(j.get(), kTmpPath);
1793
1794 argv[0] = const_cast<char*>(kShellPath);
1795 argv[1] = "-c";
1796 argv[2] = "exec echo 'bar' > /tmp/baz";
1797 argv[3] = NULL;
1798
1799 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1800 EXPECT_EQ(mj_run_ret, 0);
1801 status = minijail_wait(j.get());
1802 EXPECT_NE(status, 0);
1803 }
1804
TEST_F(LandlockTest,test_rule_rw_cannot_exec)1805 TEST_F(LandlockTest, test_rule_rw_cannot_exec) {
1806 int mj_run_ret;
1807 int status;
1808 char *argv[4];
1809 if (!run_landlock_tests_)
1810 GTEST_SKIP();
1811 ScopedMinijail j(minijail_new());
1812 SetupLandlockTestingNamespaces(j.get());
1813 minijail_add_fs_restriction_rw(j.get(), kBinPath);
1814 minijail_add_fs_restriction_rw(j.get(), kEtcPath);
1815 minijail_add_fs_restriction_rw(j.get(), kLibPath);
1816 minijail_add_fs_restriction_rw(j.get(), kLib64Path);
1817 minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1818
1819 argv[0] = const_cast<char*>(kShellPath);
1820 argv[1] = "-c";
1821 argv[2] = "exec echo 'bar' > /tmp/baz";
1822 argv[3] = NULL;
1823
1824 mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1825 EXPECT_EQ(mj_run_ret, 0);
1826 status = minijail_wait(j.get());
1827 EXPECT_NE(status, 0);
1828 }
1829
TestCreateSession(bool create_session)1830 void TestCreateSession(bool create_session) {
1831 int status;
1832 int pipe_fds[2];
1833 pid_t child_pid;
1834 pid_t parent_sid = getsid(0);
1835 ssize_t pid_size = sizeof(pid_t);
1836
1837 ScopedMinijail j(minijail_new());
1838 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1839 // a new session because of that.
1840 minijail_close_open_fds(j.get());
1841
1842 if (create_session)
1843 minijail_create_session(j.get());
1844
1845 ASSERT_EQ(pipe(pipe_fds), 0);
1846 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1847
1848 child_pid = minijail_fork(j.get());
1849 ASSERT_GE(child_pid, 0);
1850 if (child_pid == 0) {
1851 pid_t sid_in_parent;
1852 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1853 if (create_session)
1854 ASSERT_NE(sid_in_parent, getsid(0));
1855 else
1856 ASSERT_EQ(sid_in_parent, getsid(0));
1857 exit(0);
1858 }
1859
1860 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1861 waitpid(child_pid, &status, 0);
1862 ASSERT_TRUE(WIFEXITED(status));
1863 EXPECT_EQ(WEXITSTATUS(status), 0);
1864 }
1865
TEST(Test,default_no_new_session)1866 TEST(Test, default_no_new_session) {
1867 TestCreateSession(/*create_session=*/false);
1868 }
1869
TEST(Test,create_new_session)1870 TEST(Test, create_new_session) {
1871 TestCreateSession(/*create_session=*/true);
1872 }
1873