• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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