• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2016 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Test platform independent logic of Minijail using gtest.
6  */
7 
8 #include <errno.h>
9 
10 #include <dirent.h>
11 #include <fcntl.h>
12 #include <sys/mount.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 
18 #include <gtest/gtest.h>
19 
20 #include <functional>
21 #include <map>
22 #include <set>
23 #include <string>
24 
25 #include "libminijail-private.h"
26 #include "libminijail.h"
27 #include "scoped_minijail.h"
28 #include "util.h"
29 
30 namespace {
31 
32 #if defined(__ANDROID__)
33 # define ROOT_PREFIX "/system"
34 #else
35 # define ROOT_PREFIX ""
36 #endif
37 
38 constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
39 constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
40 constexpr char kPreloadPath[] = "./libminijailpreload.so";
41 constexpr size_t kBufferSize = 128;
42 
GetProcessSubtreePids(pid_t root_pid)43 std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
44   std::set<pid_t> pids{root_pid};
45   bool progress = false;
46 
47   do {
48     progress = false;
49     DIR* d = opendir("/proc");
50     if (!d)
51       pdie("opendir(\"/proc\")");
52 
53     struct dirent* dir_entry;
54     while ((dir_entry = readdir(d)) != nullptr) {
55       if (dir_entry->d_type != DT_DIR)
56         continue;
57       char* end;
58       const int pid = strtol(dir_entry->d_name, &end, 10);
59       if (*end != '\0')
60         continue;
61       std::string path = "/proc/" + std::to_string(pid) + "/stat";
62 
63       FILE* f = fopen(path.c_str(), "re");
64       if (!f) {
65         if (errno == ENOENT) {
66           // This loop is inherently racy, since PIDs can be reaped in the
67           // middle of this. Not being able to find one /proc/PID/stat file is
68           // completely normal.
69           continue;
70         }
71         pdie("fopen(%s)", path.c_str());
72       }
73       pid_t ppid;
74       int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
75       fclose(f);
76       if (ret != 1) {
77         continue;
78       }
79       if (pids.find(ppid) == pids.end())
80         continue;
81       progress |= pids.insert(pid).second;
82     }
83     closedir(d);
84   } while (progress);
85   return pids;
86 }
87 
GetNamespaces(pid_t pid,const std::vector<std::string> & namespace_names)88 std::map<std::string, std::string> GetNamespaces(
89     pid_t pid,
90     const std::vector<std::string>& namespace_names) {
91   std::map<std::string, std::string> namespaces;
92   char buf[kBufferSize];
93   for (const auto& namespace_name : namespace_names) {
94     std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
95     ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
96     if (len == -1)
97       pdie("readlink(\"%s\")", path.c_str());
98     namespaces.emplace(namespace_name, std::string(buf, len));
99   }
100   return namespaces;
101 }
102 
103 }  // namespace
104 
105 /* Silence unused variable warnings. */
TEST(silence,silence_unused)106 TEST(silence, silence_unused) {
107   EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
108   EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
109   EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
110 }
111 
TEST(consumebytes,zero)112 TEST(consumebytes, zero) {
113   char buf[1024];
114   size_t len = sizeof(buf);
115   char *pos = &buf[0];
116   EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
117   EXPECT_EQ(&buf[0], pos);
118   EXPECT_EQ(sizeof(buf), len);
119 }
120 
TEST(consumebytes,exact)121 TEST(consumebytes, exact) {
122   char buf[1024];
123   size_t len = sizeof(buf);
124   char *pos = &buf[0];
125   /* One past the end since it consumes the whole buffer. */
126   char *end = &buf[sizeof(buf)];
127   EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
128   EXPECT_EQ((size_t)0, len);
129   EXPECT_EQ(end, pos);
130 }
131 
TEST(consumebytes,half)132 TEST(consumebytes, half) {
133   char buf[1024];
134   size_t len = sizeof(buf);
135   char *pos = &buf[0];
136   /* One past the end since it consumes the whole buffer. */
137   char *end = &buf[sizeof(buf) / 2];
138   EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
139   EXPECT_EQ(sizeof(buf) / 2, len);
140   EXPECT_EQ(end, pos);
141 }
142 
TEST(consumebytes,toolong)143 TEST(consumebytes, toolong) {
144   char buf[1024];
145   size_t len = sizeof(buf);
146   char *pos = &buf[0];
147   /* One past the end since it consumes the whole buffer. */
148   EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
149   EXPECT_EQ(sizeof(buf), len);
150   EXPECT_EQ(&buf[0], pos);
151 }
152 
TEST(consumestr,zero)153 TEST(consumestr, zero) {
154   char buf[1024];
155   size_t len = 0;
156   char *pos = &buf[0];
157   memset(buf, 0xff, sizeof(buf));
158   EXPECT_EQ(nullptr, consumestr(&pos, &len));
159   EXPECT_EQ((size_t)0, len);
160   EXPECT_EQ(&buf[0], pos);
161 }
162 
TEST(consumestr,nonul)163 TEST(consumestr, nonul) {
164   char buf[1024];
165   size_t len = sizeof(buf);
166   char *pos = &buf[0];
167   memset(buf, 0xff, sizeof(buf));
168   EXPECT_EQ(nullptr, consumestr(&pos, &len));
169   EXPECT_EQ(sizeof(buf), len);
170   EXPECT_EQ(&buf[0], pos);
171 }
172 
TEST(consumestr,full)173 TEST(consumestr, full) {
174   char buf[1024];
175   size_t len = sizeof(buf);
176   char *pos = &buf[0];
177   memset(buf, 0xff, sizeof(buf));
178   buf[sizeof(buf)-1] = '\0';
179   EXPECT_EQ((void *)buf, consumestr(&pos, &len));
180   EXPECT_EQ((size_t)0, len);
181   EXPECT_EQ(&buf[sizeof(buf)], pos);
182 }
183 
TEST(consumestr,trailing_nul)184 TEST(consumestr, trailing_nul) {
185   char buf[1024];
186   size_t len = sizeof(buf) - 1;
187   char *pos = &buf[0];
188   memset(buf, 0xff, sizeof(buf));
189   buf[sizeof(buf)-1] = '\0';
190   EXPECT_EQ(nullptr, consumestr(&pos, &len));
191   EXPECT_EQ(sizeof(buf) - 1, len);
192   EXPECT_EQ(&buf[0], pos);
193 }
194 
195 class MarshalTest : public ::testing::Test {
196  protected:
SetUp()197   virtual void SetUp() {
198     m_ = minijail_new();
199     j_ = minijail_new();
200     size_ = minijail_size(m_);
201   }
TearDown()202   virtual void TearDown() {
203     minijail_destroy(m_);
204     minijail_destroy(j_);
205   }
206 
207   char buf_[4096];
208   struct minijail *m_;
209   struct minijail *j_;
210   size_t size_;
211 };
212 
TEST_F(MarshalTest,empty)213 TEST_F(MarshalTest, empty) {
214   ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
215   EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
216 }
217 
218 TEST_F(MarshalTest, 0xff) {
219   memset(buf_, 0xff, sizeof(buf_));
220   /* Should fail on the first consumestr since a NUL will never be found. */
221   EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
222 }
223 
TEST_F(MarshalTest,copy_empty)224 TEST_F(MarshalTest, copy_empty) {
225   ASSERT_EQ(0, minijail_copy_jail(m_, j_));
226 }
227 
TEST(KillTest,running_process)228 TEST(KillTest, running_process) {
229   const ScopedMinijail j(minijail_new());
230   char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
231   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
232   EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
233   EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
234 }
235 
TEST(KillTest,process_already_awaited)236 TEST(KillTest, process_already_awaited) {
237   const ScopedMinijail j(minijail_new());
238   char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
239   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
240   EXPECT_EQ(minijail_wait(j.get()), 42);
241   EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
242 }
243 
TEST(KillTest,process_already_finished_but_not_awaited)244 TEST(KillTest, process_already_finished_but_not_awaited) {
245   int fds[2];
246   const ScopedMinijail j(minijail_new());
247   char* const argv[] = {"sh", "-c", "exit 42", nullptr};
248   ASSERT_EQ(pipe(fds), 0);
249   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
250   ASSERT_EQ(close(fds[1]), 0);
251   // Wait for process to finish.
252   char buf[PIPE_BUF];
253   EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
254   EXPECT_EQ(minijail_kill(j.get()), 42);
255   EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
256 }
257 
TEST(KillTest,process_not_started)258 TEST(KillTest, process_not_started) {
259   const ScopedMinijail j(minijail_new());
260   EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
261 }
262 
TEST(WaitTest,return_zero)263 TEST(WaitTest, return_zero) {
264   const ScopedMinijail j(minijail_new());
265   char* const argv[] = {"sh", "-c", "exit 0", nullptr};
266   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
267   EXPECT_EQ(minijail_wait(j.get()), 0);
268 }
269 
TEST(WaitTest,return_max)270 TEST(WaitTest, return_max) {
271   const ScopedMinijail j(minijail_new());
272   char* const argv[] = {"sh", "-c", "exit 255", nullptr};
273   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
274   EXPECT_EQ(minijail_wait(j.get()), 255);
275 }
276 
TEST(WaitTest,return_modulo)277 TEST(WaitTest, return_modulo) {
278   const ScopedMinijail j(minijail_new());
279   char* const argv[] = {"sh", "-c", "exit 256", nullptr};
280   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
281   EXPECT_EQ(minijail_wait(j.get()), 0);
282 }
283 
TEST(WaitTest,killed_by_sigkill)284 TEST(WaitTest, killed_by_sigkill) {
285   const ScopedMinijail j(minijail_new());
286   char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
287   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
288   EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE  + SIGKILL);
289 }
290 
TEST(WaitTest,killed_by_sigsys)291 TEST(WaitTest, killed_by_sigsys) {
292   const ScopedMinijail j(minijail_new());
293   char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
294   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
295   EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
296 }
297 
TEST(WaitTest,command_not_found)298 TEST(WaitTest, command_not_found) {
299   const ScopedMinijail j(minijail_new());
300   char* const argv[] = {"whatever", nullptr};
301   EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
302   EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
303 }
304 
TEST(WaitTest,command_not_run)305 TEST(WaitTest, command_not_run) {
306   const ScopedMinijail j(minijail_new());
307   char* const argv[] = {"whatever", nullptr};
308   EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
309   EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
310 }
311 
TEST(WaitTest,no_process)312 TEST(WaitTest, no_process) {
313   const ScopedMinijail j(minijail_new());
314   EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
315 }
316 
TEST(WaitTest,can_wait_only_once)317 TEST(WaitTest, can_wait_only_once) {
318   const ScopedMinijail j(minijail_new());
319   char* const argv[] = {"sh", "-c", "exit 0", nullptr};
320   EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
321   EXPECT_EQ(minijail_wait(j.get()), 0);
322   EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
323 }
324 
TEST(Test,minijail_preserve_fd_no_leak)325 TEST(Test, minijail_preserve_fd_no_leak) {
326   const ScopedMinijail j(minijail_new());
327   char* const script = R"(
328       echo Hi >&1;
329       exec 1>&-;
330       read line1;
331       read line2;
332       echo "$line1$line2 and Goodbye" >&2;
333       exit 42;
334     )";
335   char* const argv[] = {"sh", "-c", script, nullptr};
336 
337   const int npipes = 3;
338   int fds[npipes][2];
339 
340   // Create pipes.
341   for (int i = 0; i < npipes; ++i) {
342     ASSERT_EQ(pipe(fds[i]), 0);
343   }
344 
345   // All pipes are output pipes except for the first one which is used as
346   // input pipe.
347   std::swap(fds[0][0], fds[0][1]);
348 
349   for (int i = 0; i < npipes; ++i) {
350     const int fd = fds[i][1];
351     minijail_preserve_fd(j.get(), fd, i);
352   }
353 
354   minijail_close_open_fds(j.get());
355 
356   EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
357 
358   // Close unused end of pipes.
359   for (int i = 0; i < npipes; ++i) {
360     const int fd = fds[i][1];
361     ASSERT_EQ(close(fd), 0);
362   }
363 
364   const int in = fds[0][0];
365   const int out = fds[1][0];
366   const int err = fds[2][0];
367 
368   char buf[PIPE_BUF];
369   ssize_t nbytes;
370 
371   // Check that stdout pipe works.
372   nbytes = read(out, buf, PIPE_BUF);
373   ASSERT_GT(nbytes, 0);
374   EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
375 
376   // Check that the write end of stdout pipe got closed by the child process. If
377   // the child process kept other file descriptors connected to stdout, then the
378   // parent process wouldn't be able to detect that all write ends of this pipe
379   // are closed and it would block here.
380   EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
381   ASSERT_EQ(close(out), 0);
382 
383   // Check that stdin pipe works.
384   const std::string s = "Greetings\n";
385   EXPECT_EQ(write(in, s.data(), s.size()), s.size());
386 
387   // Close write end of pipe connected to child's stdin. If there was another
388   // file descriptor connected to this write end, then the child process
389   // wouldn't be able to detect that this write end is closed and it would
390   // block.
391   ASSERT_EQ(close(in), 0);
392 
393   // Check that child process continued and ended.
394   nbytes = read(err, buf, PIPE_BUF);
395   ASSERT_GT(nbytes, 0);
396   EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
397 
398   // Check that the write end of the stderr pipe is closed when the child
399   // process finishes.
400   EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
401   ASSERT_EQ(close(err), 0);
402 
403   // Check the child process termination status.
404   EXPECT_EQ(minijail_wait(j.get()), 42);
405 }
406 
TEST(Test,close_original_pipes_after_dup2)407 TEST(Test, close_original_pipes_after_dup2) {
408   // Pipe used by child process to signal that it continued after reading from
409   // stdin.
410   int to_wait[2];
411   ASSERT_EQ(pipe(to_wait), 0);
412 
413   const ScopedMinijail j(minijail_new());
414   char* program;
415   ASSERT_GT(asprintf(&program, R"(
416       echo Hi >&1;
417       echo There >&2;
418       exec 1>&-;
419       exec 2>&-;
420       read line1;
421       read line2;
422       echo "$line1$line2 and Goodbye" >&%d;
423       exit 42;
424     )", to_wait[1]), 0);
425   char* const argv[] = {"sh", "-c", program, nullptr};
426 
427   int in = -1;
428   int out = -1;
429   int err = -1;
430   EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
431                                               nullptr, &in, &out, &err),
432             0);
433   free(program);
434 
435   EXPECT_GT(in, 0);
436   EXPECT_GT(out, 0);
437   EXPECT_GT(err, 0);
438 
439   char buf[PIPE_BUF];
440   ssize_t n;
441 
442   // Check that stdout and stderr pipes work.
443   n = read(out, buf, PIPE_BUF);
444   ASSERT_GT(n, 0);
445   EXPECT_EQ(std::string(buf, n), "Hi\n");
446 
447   n = read(err, buf, PIPE_BUF);
448   ASSERT_GT(n, 0);
449   EXPECT_EQ(std::string(buf, n), "There\n");
450 
451   // Check that the write ends of stdout and stderr pipes got closed by the
452   // child process. If the child process kept other file descriptors connected
453   // to stdout and stderr, then the parent process wouldn't be able to detect
454   // that all write ends of these pipes are closed and it would block here.
455   EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
456   ASSERT_EQ(close(out), 0);
457   EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
458   ASSERT_EQ(close(err), 0);
459 
460   // Check that stdin pipe works.
461   const std::string s = "Greetings\n";
462   EXPECT_EQ(write(in, s.data(), s.size()), s.size());
463 
464   // Close write end of pipe connected to child's stdin. If there was another
465   // file descriptor connected to this write end, then the child wouldn't be
466   // able to detect that this write end is closed and it would block.
467   ASSERT_EQ(close(in), 0);
468 
469   // Check that child process continued and ended.
470   n = read(to_wait[0], buf, PIPE_BUF);
471   ASSERT_GT(n, 0);
472   EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
473   EXPECT_EQ(minijail_wait(j.get()), 42);
474 }
475 
TEST(Test,minijail_run_env_pid_pipes)476 TEST(Test, minijail_run_env_pid_pipes) {
477   // TODO(crbug.com/895875): The preload library interferes with ASan since they
478   // both need to use LD_PRELOAD.
479   if (running_with_asan())
480     GTEST_SKIP();
481 
482   ScopedMinijail j(minijail_new());
483   minijail_set_preload_path(j.get(), kPreloadPath);
484 
485   char *argv[4];
486   argv[0] = const_cast<char*>(kCatPath);
487   argv[1] = NULL;
488 
489   pid_t pid;
490   int child_stdin, child_stdout;
491   int mj_run_ret = minijail_run_pid_pipes(
492       j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
493   EXPECT_EQ(mj_run_ret, 0);
494 
495   char teststr[] = "test\n";
496   const size_t teststr_len = strlen(teststr);
497   ssize_t write_ret = write(child_stdin, teststr, teststr_len);
498   EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
499 
500   char buf[kBufferSize] = {};
501   ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
502   EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
503   EXPECT_STREQ(buf, teststr);
504 
505   int status;
506   EXPECT_EQ(kill(pid, SIGTERM), 0);
507   EXPECT_EQ(waitpid(pid, &status, 0), pid);
508   ASSERT_TRUE(WIFSIGNALED(status));
509   EXPECT_EQ(WTERMSIG(status), SIGTERM);
510 
511   argv[0] = const_cast<char*>(kShellPath);
512   argv[1] = "-c";
513   argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
514   argv[3] = nullptr;
515 
516   char *envp[2];
517   envp[0] = "TEST_VAR=test";
518   envp[1] = NULL;
519 
520   // Set a canary env var in the parent that should not be present in the child.
521   ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
522 
523   int child_stderr;
524   mj_run_ret =
525       minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
526                                  &child_stdin, &child_stdout, &child_stderr);
527   EXPECT_EQ(mj_run_ret, 0);
528 
529   memset(buf, 0, sizeof(buf));
530   read_ret = read(child_stderr, buf, sizeof(buf) - 1);
531   EXPECT_GE(read_ret, 0);
532   EXPECT_STREQ(buf, "|test\n");
533 
534   EXPECT_EQ(waitpid(pid, &status, 0), pid);
535   ASSERT_TRUE(WIFEXITED(status));
536   EXPECT_EQ(WEXITSTATUS(status), 0);
537 }
538 
TEST(Test,minijail_run_env_pid_pipes_with_local_preload)539 TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
540   // TODO(crbug.com/895875): The preload library interferes with ASan since they
541   // both need to use LD_PRELOAD.
542   if (running_with_asan())
543     GTEST_SKIP();
544 
545   ScopedMinijail j(minijail_new());
546 
547   char *argv[4];
548   argv[0] = const_cast<char*>(kCatPath);
549   argv[1] = NULL;
550 
551   pid_t pid;
552   int child_stdin, child_stdout;
553   int mj_run_ret = minijail_run_pid_pipes(
554       j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
555   EXPECT_EQ(mj_run_ret, 0);
556 
557   char teststr[] = "test\n";
558   const size_t teststr_len = strlen(teststr);
559   ssize_t write_ret = write(child_stdin, teststr, teststr_len);
560   EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
561 
562   char buf[kBufferSize] = {};
563   ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
564   EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
565   EXPECT_STREQ(buf, teststr);
566 
567   int status;
568   EXPECT_EQ(kill(pid, SIGTERM), 0);
569   EXPECT_EQ(waitpid(pid, &status, 0), pid);
570   ASSERT_TRUE(WIFSIGNALED(status));
571   EXPECT_EQ(WTERMSIG(status), SIGTERM);
572 
573   argv[0] = const_cast<char*>(kShellPath);
574   argv[1] = "-c";
575   argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
576   argv[3] = nullptr;
577 
578   char *envp[2];
579   envp[0] = "TEST_VAR=test";
580   envp[1] = NULL;
581 
582   // Set a canary env var in the parent that should not be present in the child.
583   ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
584 
585   // Use the preload library from this test build.
586   ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
587 
588   int child_stderr;
589   mj_run_ret =
590       minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
591                                  &child_stdin, &child_stdout, &child_stderr);
592   EXPECT_EQ(mj_run_ret, 0);
593 
594   memset(buf, 0, sizeof(buf));
595   read_ret = read(child_stderr, buf, sizeof(buf) - 1);
596   EXPECT_GE(read_ret, 0);
597   EXPECT_STREQ(buf, "|test\n");
598 
599   EXPECT_EQ(waitpid(pid, &status, 0), pid);
600   ASSERT_TRUE(WIFEXITED(status));
601   EXPECT_EQ(WEXITSTATUS(status), 0);
602 }
603 
TEST(Test,test_minijail_no_fd_leaks)604 TEST(Test, test_minijail_no_fd_leaks) {
605   pid_t pid;
606   int child_stdout;
607   int mj_run_ret;
608   ssize_t read_ret;
609   char buf[kBufferSize];
610   char script[kBufferSize];
611   int status;
612   char *argv[4];
613 
614   int dev_null = open("/dev/null", O_RDONLY);
615   ASSERT_NE(dev_null, -1);
616   snprintf(script,
617            sizeof(script),
618            "[ -e /proc/self/fd/%d ] && echo yes || echo no",
619            dev_null);
620 
621   struct minijail *j = minijail_new();
622 
623   argv[0] = const_cast<char*>(kShellPath);
624   argv[1] = "-c";
625   argv[2] = script;
626   argv[3] = NULL;
627   mj_run_ret = minijail_run_pid_pipes_no_preload(
628       j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
629   EXPECT_EQ(mj_run_ret, 0);
630 
631   read_ret = read(child_stdout, buf, sizeof(buf));
632   EXPECT_GE(read_ret, 0);
633   buf[read_ret] = '\0';
634   EXPECT_STREQ(buf, "yes\n");
635 
636   waitpid(pid, &status, 0);
637   ASSERT_TRUE(WIFEXITED(status));
638   EXPECT_EQ(WEXITSTATUS(status), 0);
639 
640   minijail_close_open_fds(j);
641   mj_run_ret = minijail_run_pid_pipes_no_preload(
642       j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
643   EXPECT_EQ(mj_run_ret, 0);
644 
645   read_ret = read(child_stdout, buf, sizeof(buf));
646   EXPECT_GE(read_ret, 0);
647   buf[read_ret] = '\0';
648   EXPECT_STREQ(buf, "no\n");
649 
650   waitpid(pid, &status, 0);
651   ASSERT_TRUE(WIFEXITED(status));
652   EXPECT_EQ(WEXITSTATUS(status), 0);
653 
654   minijail_destroy(j);
655 
656   close(dev_null);
657 }
658 
TEST(Test,test_minijail_fork)659 TEST(Test, test_minijail_fork) {
660   pid_t mj_fork_ret;
661   int status;
662   int pipe_fds[2];
663   ssize_t pid_size = sizeof(mj_fork_ret);
664 
665   ScopedMinijail j(minijail_new());
666 
667   ASSERT_EQ(pipe(pipe_fds), 0);
668 
669   mj_fork_ret = minijail_fork(j.get());
670   ASSERT_GE(mj_fork_ret, 0);
671   if (mj_fork_ret == 0) {
672     pid_t pid_in_parent;
673     // Wait for the parent to tell us the pid in the parent namespace.
674     ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
675     ASSERT_EQ(pid_in_parent, getpid());
676     exit(0);
677   }
678 
679   EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
680   waitpid(mj_fork_ret, &status, 0);
681   ASSERT_TRUE(WIFEXITED(status));
682   EXPECT_EQ(WEXITSTATUS(status), 0);
683 }
684 
early_exit(void * payload)685 static int early_exit(void* payload) {
686   exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
687 }
688 
TEST(Test,test_minijail_callback)689 TEST(Test, test_minijail_callback) {
690   pid_t pid;
691   int mj_run_ret;
692   int status;
693   char *argv[2];
694   int exit_code = 42;
695 
696   struct minijail *j = minijail_new();
697 
698   status =
699       minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
700                         MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
701   EXPECT_EQ(status, 0);
702 
703   argv[0] = const_cast<char*>(kCatPath);
704   argv[1] = NULL;
705   mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
706                                                  NULL, NULL);
707   EXPECT_EQ(mj_run_ret, 0);
708 
709   status = minijail_wait(j);
710   EXPECT_EQ(status, exit_code);
711 
712   minijail_destroy(j);
713 }
714 
TEST(Test,test_minijail_preserve_fd)715 TEST(Test, test_minijail_preserve_fd) {
716   int mj_run_ret;
717   int status;
718   char *argv[2];
719   char teststr[] = "test\n";
720   size_t teststr_len = strlen(teststr);
721   int read_pipe[2];
722   int write_pipe[2];
723   char buf[1024];
724 
725   struct minijail *j = minijail_new();
726 
727   status = pipe(read_pipe);
728   ASSERT_EQ(status, 0);
729   status = pipe(write_pipe);
730   ASSERT_EQ(status, 0);
731 
732   status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
733   ASSERT_EQ(status, 0);
734   status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
735   ASSERT_EQ(status, 0);
736   minijail_close_open_fds(j);
737 
738   argv[0] = const_cast<char*>(kCatPath);
739   argv[1] = NULL;
740   mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
741   EXPECT_EQ(mj_run_ret, 0);
742 
743   close(write_pipe[0]);
744   status = write(write_pipe[1], teststr, teststr_len);
745   EXPECT_EQ(status, (int)teststr_len);
746   close(write_pipe[1]);
747 
748   close(read_pipe[1]);
749   status = read(read_pipe[0], buf, 8);
750   EXPECT_EQ(status, (int)teststr_len);
751   buf[teststr_len] = 0;
752   EXPECT_EQ(strcmp(buf, teststr), 0);
753 
754   status = minijail_wait(j);
755   EXPECT_EQ(status, 0);
756 
757   minijail_destroy(j);
758 }
759 
TEST(Test,test_minijail_reset_signal_mask)760 TEST(Test, test_minijail_reset_signal_mask) {
761   struct minijail *j = minijail_new();
762 
763   sigset_t original_signal_mask;
764   {
765     sigset_t signal_mask;
766     ASSERT_EQ(0, sigemptyset(&signal_mask));
767     ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
768     ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
769   }
770 
771   minijail_reset_signal_mask(j);
772 
773   pid_t mj_fork_ret = minijail_fork(j);
774   ASSERT_GE(mj_fork_ret, 0);
775   if (mj_fork_ret == 0) {
776     sigset_t signal_mask;
777     ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
778     ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
779     minijail_destroy(j);
780     exit(0);
781   }
782 
783   ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
784 
785   int status;
786   waitpid(mj_fork_ret, &status, 0);
787   ASSERT_TRUE(WIFEXITED(status));
788   EXPECT_EQ(WEXITSTATUS(status), 0);
789 
790   minijail_destroy(j);
791 }
792 
TEST(Test,test_minijail_reset_signal_handlers)793 TEST(Test, test_minijail_reset_signal_handlers) {
794   struct minijail *j = minijail_new();
795 
796   ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
797   ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
798   ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
799 
800   minijail_reset_signal_handlers(j);
801 
802   pid_t mj_fork_ret = minijail_fork(j);
803   ASSERT_GE(mj_fork_ret, 0);
804   if (mj_fork_ret == 0) {
805     ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
806     minijail_destroy(j);
807     exit(0);
808   }
809 
810   ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
811 
812   int status;
813   waitpid(mj_fork_ret, &status, 0);
814   ASSERT_TRUE(WIFEXITED(status));
815   EXPECT_EQ(WEXITSTATUS(status), 0);
816 
817   minijail_destroy(j);
818 }
819 
820 namespace {
821 
822 // Tests that require userns access.
823 // Android unit tests don't currently support entering user namespaces as
824 // unprivileged users due to having an older kernel.  Chrome OS unit tests
825 // don't support it either due to being in a chroot environment (see man 2
826 // clone for more information about failure modes with the CLONE_NEWUSER flag).
827 class NamespaceTest : public ::testing::Test {
828  protected:
SetUpTestCase()829   static void SetUpTestCase() {
830     userns_supported_ = UsernsSupported();
831   }
832 
833   // Whether userns is supported.
834   static bool userns_supported_;
835 
UsernsSupported()836   static bool UsernsSupported() {
837     pid_t pid = fork();
838     if (pid == -1)
839       pdie("could not fork");
840 
841     if (pid == 0)
842       _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
843 
844     int status;
845     if (waitpid(pid, &status, 0) < 0)
846       pdie("could not wait");
847 
848     if (!WIFEXITED(status))
849       die("child did not exit properly: %#x", status);
850 
851     bool ret = WEXITSTATUS(status) == 0;
852     if (!ret)
853       warn("Skipping userns related tests");
854     return ret;
855   }
856 };
857 
858 bool NamespaceTest::userns_supported_;
859 
860 }  // namespace
861 
TEST_F(NamespaceTest,test_tmpfs_userns)862 TEST_F(NamespaceTest, test_tmpfs_userns) {
863   int mj_run_ret;
864   int status;
865   char *argv[4];
866   char uidmap[kBufferSize], gidmap[kBufferSize];
867   constexpr uid_t kTargetUid = 1000;  // Any non-zero value will do.
868   constexpr gid_t kTargetGid = 1000;
869 
870   if (!userns_supported_)
871     GTEST_SKIP();
872 
873   struct minijail *j = minijail_new();
874 
875   minijail_namespace_pids(j);
876   minijail_namespace_vfs(j);
877   minijail_mount_tmp(j);
878   minijail_run_as_init(j);
879 
880   // Perform userns mapping.
881   minijail_namespace_user(j);
882   snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
883   snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
884   minijail_change_uid(j, kTargetUid);
885   minijail_change_gid(j, kTargetGid);
886   minijail_uidmap(j, uidmap);
887   minijail_gidmap(j, gidmap);
888   minijail_namespace_user_disable_setgroups(j);
889 
890   argv[0] = const_cast<char*>(kShellPath);
891   argv[1] = "-c";
892   argv[2] = "exec touch /tmp/foo";
893   argv[3] = NULL;
894   mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
895   EXPECT_EQ(mj_run_ret, 0);
896 
897   status = minijail_wait(j);
898   EXPECT_EQ(status, 0);
899 
900   minijail_destroy(j);
901 }
902 
TEST_F(NamespaceTest,test_namespaces)903 TEST_F(NamespaceTest, test_namespaces) {
904   constexpr char teststr[] = "test\n";
905 
906   // TODO(crbug.com/895875): The preload library interferes with ASan since they
907   // both need to use LD_PRELOAD.
908   if (!userns_supported_ || running_with_asan())
909     GTEST_SKIP();
910 
911   std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
912   std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
913 
914   const std::vector<std::string> namespace_names = {"pid", "mnt",    "user",
915                                                     "net", "cgroup", "uts"};
916   // Grab the set of namespaces outside the container.
917   std::map<std::string, std::string> init_namespaces =
918       GetNamespaces(getpid(), namespace_names);
919   std::function<void(struct minijail*)> test_functions[] = {
920       [](struct minijail* j attribute_unused) {},
921       [](struct minijail* j) {
922         minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
923         minijail_enter_pivot_root(j, "/tmp");
924       },
925       [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
926   };
927 
928   // This test is run with and without the preload library.
929   for (const auto& run_function :
930        {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
931     for (const auto& test_function : test_functions) {
932       ScopedMinijail j(minijail_new());
933       minijail_set_preload_path(j.get(), kPreloadPath);
934 
935       // Enter all the namespaces we can.
936       minijail_namespace_cgroups(j.get());
937       minijail_namespace_net(j.get());
938       minijail_namespace_pids(j.get());
939       minijail_namespace_user(j.get());
940       minijail_namespace_vfs(j.get());
941       minijail_namespace_uts(j.get());
942 
943       // Set up the user namespace.
944       minijail_uidmap(j.get(), uidmap.c_str());
945       minijail_gidmap(j.get(), gidmap.c_str());
946       minijail_namespace_user_disable_setgroups(j.get());
947 
948       minijail_close_open_fds(j.get());
949       test_function(j.get());
950 
951       char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
952       pid_t container_pid;
953       int child_stdin, child_stdout;
954       int mj_run_ret =
955           run_function(j.get(), argv[0], argv,
956                        &container_pid, &child_stdin, &child_stdout, nullptr);
957       EXPECT_EQ(mj_run_ret, 0);
958 
959       // Send some data to stdin and read it back to ensure that the child
960       // process is running.
961       const size_t teststr_len = strlen(teststr);
962       ssize_t write_ret = write(child_stdin, teststr, teststr_len);
963       EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
964 
965       char buf[kBufferSize];
966       ssize_t read_ret = read(child_stdout, buf, 8);
967       EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
968       buf[teststr_len] = 0;
969       EXPECT_EQ(strcmp(buf, teststr), 0);
970 
971       // Grab the set of namespaces in every container process. They must not
972       // match the ones in the init namespace, and they must all match each
973       // other.
974       std::map<std::string, std::string> container_namespaces =
975           GetNamespaces(container_pid, namespace_names);
976       EXPECT_NE(container_namespaces, init_namespaces);
977       for (pid_t pid : GetProcessSubtreePids(container_pid))
978         EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
979 
980       EXPECT_EQ(0, close(child_stdin));
981 
982       int status = minijail_wait(j.get());
983       EXPECT_EQ(status, 0);
984     }
985   }
986 }
987 
TEST_F(NamespaceTest,test_enter_ns)988 TEST_F(NamespaceTest, test_enter_ns) {
989   char uidmap[kBufferSize], gidmap[kBufferSize];
990 
991   if (!userns_supported_)
992     GTEST_SKIP();
993 
994   // We first create a child in a new userns so we have privs to run more tests.
995   // We can't combine the steps as the kernel disallows many resource sharing
996   // from outside the userns.
997   struct minijail *j = minijail_new();
998 
999   minijail_namespace_vfs(j);
1000   minijail_namespace_pids(j);
1001   minijail_run_as_init(j);
1002 
1003   // Perform userns mapping.
1004   minijail_namespace_user(j);
1005   snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1006   snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1007   minijail_uidmap(j, uidmap);
1008   minijail_gidmap(j, gidmap);
1009   minijail_namespace_user_disable_setgroups(j);
1010 
1011   pid_t pid = minijail_fork(j);
1012   if (pid == 0) {
1013     // Child.
1014     minijail_destroy(j);
1015 
1016     // Create new namespaces inside this userns which we may enter.
1017     j = minijail_new();
1018     minijail_namespace_net(j);
1019     minijail_namespace_vfs(j);
1020     pid = minijail_fork(j);
1021     if (pid == 0) {
1022       // Child.
1023       minijail_destroy(j);
1024 
1025       // Finally enter those namespaces.
1026       j = minijail_new();
1027 
1028       // We need to get the absolute path because entering a new mntns will
1029       // implicitly chdir(/) for us.
1030       char *path = realpath(kPreloadPath, nullptr);
1031       ASSERT_NE(nullptr, path);
1032       minijail_set_preload_path(j, path);
1033 
1034       minijail_namespace_net(j);
1035       minijail_namespace_vfs(j);
1036 
1037       minijail_namespace_enter_net(j, "/proc/self/ns/net");
1038       minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1039 
1040       char *argv[] = {"/bin/true", nullptr};
1041       EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1042       EXPECT_EQ(0, minijail_wait(j));
1043       minijail_destroy(j);
1044       exit(0);
1045     } else {
1046       ASSERT_GT(pid, 0);
1047       EXPECT_EQ(0, minijail_wait(j));
1048       minijail_destroy(j);
1049       exit(0);
1050     }
1051   } else {
1052     ASSERT_GT(pid, 0);
1053     EXPECT_EQ(0, minijail_wait(j));
1054     minijail_destroy(j);
1055   }
1056 }
1057 
TEST_F(NamespaceTest,test_remount_all_private)1058 TEST_F(NamespaceTest, test_remount_all_private) {
1059   pid_t pid;
1060   int child_stdout;
1061   int mj_run_ret;
1062   ssize_t read_ret;
1063   char buf[kBufferSize];
1064   int status;
1065   char *argv[4];
1066   char uidmap[kBufferSize], gidmap[kBufferSize];
1067   constexpr uid_t kTargetUid = 1000;  // Any non-zero value will do.
1068   constexpr gid_t kTargetGid = 1000;
1069 
1070   if (!userns_supported_)
1071     GTEST_SKIP();
1072 
1073   struct minijail *j = minijail_new();
1074 
1075   minijail_namespace_pids(j);
1076   minijail_namespace_vfs(j);
1077   minijail_run_as_init(j);
1078 
1079   // Perform userns mapping.
1080   minijail_namespace_user(j);
1081   snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1082   snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1083   minijail_change_uid(j, kTargetUid);
1084   minijail_change_gid(j, kTargetGid);
1085   minijail_uidmap(j, uidmap);
1086   minijail_gidmap(j, gidmap);
1087   minijail_namespace_user_disable_setgroups(j);
1088 
1089   minijail_namespace_vfs(j);
1090   minijail_remount_mode(j, MS_PRIVATE);
1091 
1092   argv[0] = const_cast<char*>(kShellPath);
1093   argv[1] = "-c";
1094   argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
1095 	    "/proc/self/mountinfo";
1096   argv[3] = NULL;
1097   mj_run_ret = minijail_run_pid_pipes_no_preload(
1098       j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1099   EXPECT_EQ(mj_run_ret, 0);
1100 
1101   // There should be no output because all mounts should be remounted as
1102   // private.
1103   read_ret = read(child_stdout, buf, sizeof(buf));
1104   EXPECT_EQ(read_ret, 0);
1105 
1106   // grep will exit with 1 if it does not find anything which is what we
1107   // expect.
1108   status = minijail_wait(j);
1109   EXPECT_EQ(status, 1);
1110 
1111   minijail_destroy(j);
1112 }
1113 
TEST_F(NamespaceTest,test_fail_to_remount_one_private)1114 TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1115   int status;
1116   char uidmap[kBufferSize], gidmap[kBufferSize];
1117   constexpr uid_t kTargetUid = 1000;  // Any non-zero value will do.
1118   constexpr gid_t kTargetGid = 1000;
1119 
1120   if (!userns_supported_)
1121     GTEST_SKIP();
1122 
1123   struct minijail *j = minijail_new();
1124 
1125   minijail_namespace_pids(j);
1126   minijail_namespace_vfs(j);
1127   minijail_mount_tmp(j);
1128   minijail_run_as_init(j);
1129 
1130   // Perform userns mapping.
1131   minijail_namespace_user(j);
1132   snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1133   snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1134   minijail_change_uid(j, kTargetUid);
1135   minijail_change_gid(j, kTargetGid);
1136   minijail_uidmap(j, uidmap);
1137   minijail_gidmap(j, gidmap);
1138   minijail_namespace_user_disable_setgroups(j);
1139 
1140   minijail_namespace_vfs(j);
1141   minijail_remount_mode(j, MS_SHARED);
1142   minijail_add_remount(j, "/proc", MS_PRIVATE);
1143 
1144   char *argv[] = {"/bin/true", nullptr};
1145   minijail_run(j, argv[0], argv);
1146 
1147   status = minijail_wait(j);
1148   EXPECT_GT(status, 0);
1149 
1150   minijail_destroy(j);
1151 }
1152 
TEST_F(NamespaceTest,test_remount_one_shared)1153 TEST_F(NamespaceTest, test_remount_one_shared) {
1154   pid_t pid;
1155   int child_stdout;
1156   int mj_run_ret;
1157   ssize_t read_ret;
1158   char buf[kBufferSize * 4];
1159   int status;
1160   char *argv[4];
1161   char uidmap[kBufferSize], gidmap[kBufferSize];
1162   constexpr uid_t kTargetUid = 1000;  // Any non-zero value will do.
1163   constexpr gid_t kTargetGid = 1000;
1164 
1165   if (!userns_supported_)
1166     GTEST_SKIP();
1167 
1168   struct minijail *j = minijail_new();
1169 
1170   minijail_namespace_pids(j);
1171   minijail_namespace_vfs(j);
1172   minijail_mount_tmp(j);
1173   minijail_run_as_init(j);
1174 
1175   // Perform userns mapping.
1176   minijail_namespace_user(j);
1177   snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1178   snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1179   minijail_change_uid(j, kTargetUid);
1180   minijail_change_gid(j, kTargetGid);
1181   minijail_uidmap(j, uidmap);
1182   minijail_gidmap(j, gidmap);
1183   minijail_namespace_user_disable_setgroups(j);
1184 
1185   minijail_namespace_vfs(j);
1186   minijail_remount_mode(j, MS_PRIVATE);
1187   minijail_add_remount(j, "/proc", MS_SHARED);
1188 
1189   argv[0] = const_cast<char*>(kShellPath);
1190   argv[1] = "-c";
1191   argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1192   argv[3] = NULL;
1193   mj_run_ret = minijail_run_pid_pipes_no_preload(
1194       j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1195   EXPECT_EQ(mj_run_ret, 0);
1196 
1197   // There should be no output because all mounts should be remounted as
1198   // private.
1199   read_ret = read(child_stdout, buf, sizeof(buf));
1200   EXPECT_GE(read_ret, 0);
1201   buf[read_ret] = '\0';
1202   EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1203 
1204   status = minijail_wait(j);
1205   EXPECT_EQ(status, 0);
1206 
1207   minijail_destroy(j);
1208 }
1209 
TestCreateSession(bool create_session)1210 void TestCreateSession(bool create_session) {
1211   int status;
1212   int pipe_fds[2];
1213   pid_t child_pid;
1214   pid_t parent_sid = getsid(0);
1215   ssize_t pid_size = sizeof(pid_t);
1216 
1217   ScopedMinijail j(minijail_new());
1218   // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1219   // a new session because of that.
1220   minijail_close_open_fds(j.get());
1221 
1222   if (create_session)
1223     minijail_create_session(j.get());
1224 
1225   ASSERT_EQ(pipe(pipe_fds), 0);
1226   minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1227 
1228   child_pid = minijail_fork(j.get());
1229   ASSERT_GE(child_pid, 0);
1230   if (child_pid == 0) {
1231     pid_t sid_in_parent;
1232     ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1233     if (create_session)
1234       ASSERT_NE(sid_in_parent, getsid(0));
1235     else
1236       ASSERT_EQ(sid_in_parent, getsid(0));
1237     exit(0);
1238   }
1239 
1240   EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1241   waitpid(child_pid, &status, 0);
1242   ASSERT_TRUE(WIFEXITED(status));
1243   EXPECT_EQ(WEXITSTATUS(status), 0);
1244 }
1245 
TEST(Test,default_no_new_session)1246 TEST(Test, default_no_new_session) {
1247   TestCreateSession(/*create_session=*/false);
1248 }
1249 
TEST(Test,create_new_session)1250 TEST(Test, create_new_session) {
1251   TestCreateSession(/*create_session=*/true);
1252 }
1253