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