• 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/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