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