blob: 868b7d7d86140fa03c5dd32fb5b53f74cc66c6af [file] [log] [blame]
Mike Frysinger50e31fa2018-01-19 18:59:49 -05001/* 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 */
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -04007
8#include <errno.h>
9
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070010#include <dirent.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040011#include <fcntl.h>
Allen Webb05af7762021-07-16 12:56:44 -050012#include <sys/mman.h>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070013#include <sys/mount.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040014#include <sys/stat.h>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070015#include <sys/types.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040016#include <sys/wait.h>
Dylan Reid0412dcc2017-08-24 11:33:15 -070017#include <unistd.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040018
19#include <gtest/gtest.h>
20
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070021#include <functional>
22#include <map>
23#include <set>
24#include <string>
25
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040026#include "libminijail-private.h"
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070027#include "libminijail.h"
28#include "scoped_minijail.h"
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040029#include "util.h"
30
Mike Frysingerb2c12d12017-09-29 21:18:59 -040031namespace {
32
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040033#if defined(__ANDROID__)
Mike Frysingerb2c12d12017-09-29 21:18:59 -040034# define ROOT_PREFIX "/system"
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040035#else
Mike Frysingerb2c12d12017-09-29 21:18:59 -040036# define ROOT_PREFIX ""
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040037#endif
38
Luis Hector Chavez9acba452018-10-11 10:13:25 -070039constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
40constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
41constexpr char kPreloadPath[] = "./libminijailpreload.so";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070042constexpr size_t kBufferSize = 128;
43
44std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
45 std::set<pid_t> pids{root_pid};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070046 bool progress = false;
47
48 do {
49 progress = false;
50 DIR* d = opendir("/proc");
51 if (!d)
52 pdie("opendir(\"/proc\")");
53
54 struct dirent* dir_entry;
55 while ((dir_entry = readdir(d)) != nullptr) {
56 if (dir_entry->d_type != DT_DIR)
57 continue;
58 char* end;
59 const int pid = strtol(dir_entry->d_name, &end, 10);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070060 if (*end != '\0')
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070061 continue;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070062 std::string path = "/proc/" + std::to_string(pid) + "/stat";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070063
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070064 FILE* f = fopen(path.c_str(), "re");
Luis Héctor Chávez25214912021-01-03 05:47:09 -080065 if (!f) {
66 if (errno == ENOENT) {
67 // This loop is inherently racy, since PIDs can be reaped in the
68 // middle of this. Not being able to find one /proc/PID/stat file is
69 // completely normal.
70 continue;
71 }
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070072 pdie("fopen(%s)", path.c_str());
Luis Héctor Chávez25214912021-01-03 05:47:09 -080073 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070074 pid_t ppid;
75 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070076 fclose(f);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070077 if (ret != 1) {
78 continue;
79 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070080 if (pids.find(ppid) == pids.end())
81 continue;
82 progress |= pids.insert(pid).second;
83 }
84 closedir(d);
85 } while (progress);
86 return pids;
87}
88
89std::map<std::string, std::string> GetNamespaces(
90 pid_t pid,
91 const std::vector<std::string>& namespace_names) {
92 std::map<std::string, std::string> namespaces;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070093 char buf[kBufferSize];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070094 for (const auto& namespace_name : namespace_names) {
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070095 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
96 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070097 if (len == -1)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070098 pdie("readlink(\"%s\")", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070099 namespaces.emplace(namespace_name, std::string(buf, len));
100 }
101 return namespaces;
102}
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400103
104} // namespace
105
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400106/* Silence unused variable warnings. */
107TEST(silence, silence_unused) {
108 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
109 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
110 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
111}
112
113TEST(consumebytes, zero) {
114 char buf[1024];
115 size_t len = sizeof(buf);
116 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400117 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400118 EXPECT_EQ(&buf[0], pos);
119 EXPECT_EQ(sizeof(buf), len);
120}
121
122TEST(consumebytes, exact) {
123 char buf[1024];
124 size_t len = sizeof(buf);
125 char *pos = &buf[0];
126 /* One past the end since it consumes the whole buffer. */
127 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400128 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400129 EXPECT_EQ((size_t)0, len);
130 EXPECT_EQ(end, pos);
131}
132
133TEST(consumebytes, half) {
134 char buf[1024];
135 size_t len = sizeof(buf);
136 char *pos = &buf[0];
137 /* One past the end since it consumes the whole buffer. */
138 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400139 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400140 EXPECT_EQ(sizeof(buf) / 2, len);
141 EXPECT_EQ(end, pos);
142}
143
144TEST(consumebytes, toolong) {
145 char buf[1024];
146 size_t len = sizeof(buf);
147 char *pos = &buf[0];
148 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400149 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400150 EXPECT_EQ(sizeof(buf), len);
151 EXPECT_EQ(&buf[0], pos);
152}
153
154TEST(consumestr, zero) {
155 char buf[1024];
156 size_t len = 0;
157 char *pos = &buf[0];
158 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400159 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400160 EXPECT_EQ((size_t)0, len);
161 EXPECT_EQ(&buf[0], pos);
162}
163
164TEST(consumestr, nonul) {
165 char buf[1024];
166 size_t len = sizeof(buf);
167 char *pos = &buf[0];
168 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400169 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400170 EXPECT_EQ(sizeof(buf), len);
171 EXPECT_EQ(&buf[0], pos);
172}
173
174TEST(consumestr, full) {
175 char buf[1024];
176 size_t len = sizeof(buf);
177 char *pos = &buf[0];
178 memset(buf, 0xff, sizeof(buf));
179 buf[sizeof(buf)-1] = '\0';
180 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
181 EXPECT_EQ((size_t)0, len);
182 EXPECT_EQ(&buf[sizeof(buf)], pos);
183}
184
185TEST(consumestr, trailing_nul) {
186 char buf[1024];
187 size_t len = sizeof(buf) - 1;
188 char *pos = &buf[0];
189 memset(buf, 0xff, sizeof(buf));
190 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400191 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400192 EXPECT_EQ(sizeof(buf) - 1, len);
193 EXPECT_EQ(&buf[0], pos);
194}
195
196class MarshalTest : public ::testing::Test {
197 protected:
198 virtual void SetUp() {
199 m_ = minijail_new();
200 j_ = minijail_new();
201 size_ = minijail_size(m_);
202 }
203 virtual void TearDown() {
204 minijail_destroy(m_);
205 minijail_destroy(j_);
206 }
207
208 char buf_[4096];
209 struct minijail *m_;
210 struct minijail *j_;
211 size_t size_;
212};
213
214TEST_F(MarshalTest, empty) {
215 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
216 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
217}
218
219TEST_F(MarshalTest, 0xff) {
220 memset(buf_, 0xff, sizeof(buf_));
221 /* Should fail on the first consumestr since a NUL will never be found. */
222 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
223}
224
Dylan Reid6dc224f2021-05-12 17:06:25 -0700225TEST_F(MarshalTest, copy_empty) {
226 ASSERT_EQ(0, minijail_copy_jail(m_, j_));
227}
228
François Degros47e63352019-10-01 13:01:53 +1000229TEST(KillTest, running_process) {
230 const ScopedMinijail j(minijail_new());
231 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
232 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
233 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
234 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
235}
236
237TEST(KillTest, process_already_awaited) {
238 const ScopedMinijail j(minijail_new());
239 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
240 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
241 EXPECT_EQ(minijail_wait(j.get()), 42);
242 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
243}
244
245TEST(KillTest, process_already_finished_but_not_awaited) {
246 int fds[2];
247 const ScopedMinijail j(minijail_new());
248 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
249 ASSERT_EQ(pipe(fds), 0);
250 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
251 ASSERT_EQ(close(fds[1]), 0);
252 // Wait for process to finish.
253 char buf[PIPE_BUF];
254 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
255 EXPECT_EQ(minijail_kill(j.get()), 42);
256 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
257}
258
259TEST(KillTest, process_not_started) {
260 const ScopedMinijail j(minijail_new());
261 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
262}
263
François Degros08b10f72019-10-09 12:44:05 +1100264TEST(WaitTest, return_zero) {
265 const ScopedMinijail j(minijail_new());
266 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
267 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
268 EXPECT_EQ(minijail_wait(j.get()), 0);
269}
270
271TEST(WaitTest, return_max) {
272 const ScopedMinijail j(minijail_new());
273 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
274 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
275 EXPECT_EQ(minijail_wait(j.get()), 255);
276}
277
278TEST(WaitTest, return_modulo) {
279 const ScopedMinijail j(minijail_new());
280 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
281 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
282 EXPECT_EQ(minijail_wait(j.get()), 0);
283}
284
285TEST(WaitTest, killed_by_sigkill) {
286 const ScopedMinijail j(minijail_new());
287 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
288 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
289 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
290}
291
292TEST(WaitTest, killed_by_sigsys) {
293 const ScopedMinijail j(minijail_new());
294 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
295 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
296 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
297}
298
299TEST(WaitTest, command_not_found) {
300 const ScopedMinijail j(minijail_new());
301 char* const argv[] = {"whatever", nullptr};
302 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
303 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
304}
305
306TEST(WaitTest, command_not_run) {
307 const ScopedMinijail j(minijail_new());
308 char* const argv[] = {"whatever", nullptr};
309 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
310 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
311}
312
313TEST(WaitTest, no_process) {
314 const ScopedMinijail j(minijail_new());
315 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
316}
317
318TEST(WaitTest, can_wait_only_once) {
319 const ScopedMinijail j(minijail_new());
320 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
321 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
322 EXPECT_EQ(minijail_wait(j.get()), 0);
323 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
324}
325
François Degros26f8e4e2020-04-17 09:31:02 +1000326TEST(Test, minijail_preserve_fd_no_leak) {
327 const ScopedMinijail j(minijail_new());
328 char* const script = R"(
329 echo Hi >&1;
330 exec 1>&-;
331 read line1;
332 read line2;
333 echo "$line1$line2 and Goodbye" >&2;
334 exit 42;
335 )";
336 char* const argv[] = {"sh", "-c", script, nullptr};
337
338 const int npipes = 3;
339 int fds[npipes][2];
340
341 // Create pipes.
342 for (int i = 0; i < npipes; ++i) {
343 ASSERT_EQ(pipe(fds[i]), 0);
344 }
345
346 // All pipes are output pipes except for the first one which is used as
347 // input pipe.
348 std::swap(fds[0][0], fds[0][1]);
349
350 for (int i = 0; i < npipes; ++i) {
351 const int fd = fds[i][1];
352 minijail_preserve_fd(j.get(), fd, i);
353 }
354
355 minijail_close_open_fds(j.get());
356
357 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
358
359 // Close unused end of pipes.
360 for (int i = 0; i < npipes; ++i) {
361 const int fd = fds[i][1];
362 ASSERT_EQ(close(fd), 0);
363 }
364
365 const int in = fds[0][0];
366 const int out = fds[1][0];
367 const int err = fds[2][0];
368
369 char buf[PIPE_BUF];
370 ssize_t nbytes;
371
372 // Check that stdout pipe works.
373 nbytes = read(out, buf, PIPE_BUF);
374 ASSERT_GT(nbytes, 0);
375 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
376
377 // Check that the write end of stdout pipe got closed by the child process. If
378 // the child process kept other file descriptors connected to stdout, then the
379 // parent process wouldn't be able to detect that all write ends of this pipe
380 // are closed and it would block here.
381 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
382 ASSERT_EQ(close(out), 0);
383
384 // Check that stdin pipe works.
385 const std::string s = "Greetings\n";
386 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
387
388 // Close write end of pipe connected to child's stdin. If there was another
389 // file descriptor connected to this write end, then the child process
390 // wouldn't be able to detect that this write end is closed and it would
391 // block.
392 ASSERT_EQ(close(in), 0);
393
394 // Check that child process continued and ended.
395 nbytes = read(err, buf, PIPE_BUF);
396 ASSERT_GT(nbytes, 0);
397 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
398
399 // Check that the write end of the stderr pipe is closed when the child
400 // process finishes.
401 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
402 ASSERT_EQ(close(err), 0);
403
404 // Check the child process termination status.
405 EXPECT_EQ(minijail_wait(j.get()), 42);
406}
407
François Degrosa8be2c42019-10-01 12:06:42 +1000408TEST(Test, close_original_pipes_after_dup2) {
409 // Pipe used by child process to signal that it continued after reading from
410 // stdin.
411 int to_wait[2];
412 ASSERT_EQ(pipe(to_wait), 0);
413
414 const ScopedMinijail j(minijail_new());
415 char* program;
416 ASSERT_GT(asprintf(&program, R"(
417 echo Hi >&1;
418 echo There >&2;
419 exec 1>&-;
420 exec 2>&-;
421 read line1;
422 read line2;
423 echo "$line1$line2 and Goodbye" >&%d;
424 exit 42;
425 )", to_wait[1]), 0);
François Degros87f0e832019-10-10 10:22:39 +1100426 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000427
428 int in = -1;
429 int out = -1;
430 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400431 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
432 nullptr, &in, &out, &err),
433 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000434 free(program);
435
436 EXPECT_GT(in, 0);
437 EXPECT_GT(out, 0);
438 EXPECT_GT(err, 0);
439
440 char buf[PIPE_BUF];
441 ssize_t n;
442
443 // Check that stdout and stderr pipes work.
444 n = read(out, buf, PIPE_BUF);
445 ASSERT_GT(n, 0);
446 EXPECT_EQ(std::string(buf, n), "Hi\n");
447
448 n = read(err, buf, PIPE_BUF);
449 ASSERT_GT(n, 0);
450 EXPECT_EQ(std::string(buf, n), "There\n");
451
452 // Check that the write ends of stdout and stderr pipes got closed by the
453 // child process. If the child process kept other file descriptors connected
454 // to stdout and stderr, then the parent process wouldn't be able to detect
455 // that all write ends of these pipes are closed and it would block here.
456 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000457 ASSERT_EQ(close(out), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000458 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000459 ASSERT_EQ(close(err), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000460
461 // Check that stdin pipe works.
462 const std::string s = "Greetings\n";
463 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
464
465 // Close write end of pipe connected to child's stdin. If there was another
466 // file descriptor connected to this write end, then the child wouldn't be
467 // able to detect that this write end is closed and it would block.
468 ASSERT_EQ(close(in), 0);
469
470 // Check that child process continued and ended.
471 n = read(to_wait[0], buf, PIPE_BUF);
472 ASSERT_GT(n, 0);
473 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
474 EXPECT_EQ(minijail_wait(j.get()), 42);
475}
476
Allen Webb66417bd2021-07-16 15:07:24 -0700477TEST(Test, minijail_no_clobber_pipe_fd) {
478 const ScopedMinijail j(minijail_new());
479 char* const script = R"(
480 echo Hi >&1;
481 exec 1>&-;
482 exec 4>&-;
483 exec 7>&-;
484 read line1;
485 read line2;
486 echo "$line1$line2 and Goodbye" >&2;
487 exit 42;
488 )";
489 char* const argv[] = {"sh", "-c", script, nullptr};
490
491 const int npipes = 3;
492 int fds[npipes][2];
493
494 // Create pipes.
495 for (int i = 0; i < npipes; ++i) {
496 ASSERT_EQ(pipe(fds[i]), 0);
497 }
498
499 // All pipes are output pipes except for the first one which is used as
500 // input pipe.
501 std::swap(fds[0][0], fds[0][1]);
502
503 // Generate a lot of mappings to try to clobber any file descriptors generated
504 // by libminijail.
505 for (int offset = 0; offset < npipes * 3; offset += npipes) {
506 for (int i = 0 ; i < npipes; ++i) {
507 const int fd = fds[i][1];
508 minijail_preserve_fd(j.get(), fd, i + offset);
509 }
510 }
511
512 minijail_close_open_fds(j.get());
513
514 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
515
516 // Close unused end of pipes.
517 for (int i = 0; i < npipes; ++i) {
518 const int fd = fds[i][1];
519 ASSERT_EQ(close(fd), 0);
520 }
521
522 const int in = fds[0][0];
523 const int out = fds[1][0];
524 const int err = fds[2][0];
525
526 char buf[PIPE_BUF];
527 ssize_t nbytes;
528
529 // Check that stdout pipe works.
530 nbytes = read(out, buf, PIPE_BUF);
531 ASSERT_GT(nbytes, 0);
532 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
533
534 // Check that the write end of stdout pipe got closed by the child process. If
535 // the child process kept other file descriptors connected to stdout, then the
536 // parent process wouldn't be able to detect that all write ends of this pipe
537 // are closed and it would block here.
538 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
539 ASSERT_EQ(close(out), 0);
540
541 // Check that stdin pipe works.
542 const std::string s = "Greetings\n";
543 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
544
545 // Close write end of pipe connected to child's stdin. If there was another
546 // file descriptor connected to this write end, then the child process
547 // wouldn't be able to detect that this write end is closed and it would
548 // block.
549 ASSERT_EQ(close(in), 0);
550
551 // Check that child process continued and ended.
552 nbytes = read(err, buf, PIPE_BUF);
553 ASSERT_GT(nbytes, 0);
554 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
555
556 // Check that the write end of the stderr pipe is closed when the child
557 // process finishes.
558 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
559 ASSERT_EQ(close(err), 0);
560
561 // Check the child process termination status.
562 EXPECT_EQ(minijail_wait(j.get()), 42);
563}
564
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100565TEST(Test, minijail_run_env_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700566 // TODO(crbug.com/895875): The preload library interferes with ASan since they
567 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800568 if (running_with_asan())
569 GTEST_SKIP();
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700570
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700571 ScopedMinijail j(minijail_new());
572 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700573
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100574 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700575 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100576 argv[1] = NULL;
577
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700578 pid_t pid;
579 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100580 int mj_run_ret = minijail_run_pid_pipes(
581 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700582 EXPECT_EQ(mj_run_ret, 0);
583
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100584 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700585 const size_t teststr_len = strlen(teststr);
586 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
587 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
588
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100589 char buf[kBufferSize] = {};
590 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700591 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100592 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700593
594 int status;
595 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100596 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700597 ASSERT_TRUE(WIFSIGNALED(status));
598 EXPECT_EQ(WTERMSIG(status), SIGTERM);
599
600 argv[0] = const_cast<char*>(kShellPath);
601 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100602 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700603 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700604
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500605 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100606 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500607 envp[1] = NULL;
608
609 // Set a canary env var in the parent that should not be present in the child.
610 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
611
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100612 int child_stderr;
613 mj_run_ret =
614 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
615 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500616 EXPECT_EQ(mj_run_ret, 0);
617
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100618 memset(buf, 0, sizeof(buf));
619 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
620 EXPECT_GE(read_ret, 0);
621 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500622
623 EXPECT_EQ(waitpid(pid, &status, 0), pid);
624 ASSERT_TRUE(WIFEXITED(status));
625 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100626}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500627
Allen Webb05af7762021-07-16 12:56:44 -0500628TEST(Test, minijail_run_fd_env_pid_pipes) {
629 // TODO(crbug.com/895875): The preload library interferes with ASan since they
630 // both need to use LD_PRELOAD.
631 if (running_with_asan())
632 GTEST_SKIP();
633
634 ScopedMinijail j(minijail_new());
635 minijail_set_preload_path(j.get(), kPreloadPath);
636
637 char *argv[4];
Allen Webb05af7762021-07-16 12:56:44 -0500638 argv[0] = const_cast<char*>(kShellPath);
639 argv[1] = "-c";
Allen Webb93438ca2021-09-13 15:16:34 -0500640 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2\n";
Allen Webb05af7762021-07-16 12:56:44 -0500641 argv[3] = nullptr;
642
643 char *envp[2];
644 envp[0] = "TEST_VAR=test";
645 envp[1] = nullptr;
646
647 // Set a canary env var in the parent that should not be present in the child.
648 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
649
Allen Webb93438ca2021-09-13 15:16:34 -0500650 int elf_fd = open(const_cast<char*>(kShellPath), O_RDONLY | O_CLOEXEC);
651 ASSERT_NE(elf_fd, -1);
Allen Webb05af7762021-07-16 12:56:44 -0500652
653 int dev_null = open("/dev/null", O_RDONLY);
654 ASSERT_NE(dev_null, -1);
655 // Create a mapping to dev_null that would clobber elf_fd if it is not
656 // relocated.
657 minijail_preserve_fd(j.get(), dev_null, elf_fd);
658
Allen Webb93438ca2021-09-13 15:16:34 -0500659 pid_t pid;
660 int child_stdin, child_stdout, child_stderr;
661 int mj_run_ret =
Allen Webb05af7762021-07-16 12:56:44 -0500662 minijail_run_fd_env_pid_pipes(j.get(), elf_fd, argv, envp, &pid,
663 &child_stdin, &child_stdout, &child_stderr);
664 EXPECT_EQ(mj_run_ret, 0);
665 close(dev_null);
666
Allen Webb93438ca2021-09-13 15:16:34 -0500667 char buf[kBufferSize] = {};
668 ssize_t read_ret = read(child_stderr, buf, sizeof(buf) - 1);
Allen Webb05af7762021-07-16 12:56:44 -0500669 EXPECT_GE(read_ret, 0);
670 EXPECT_STREQ(buf, "|test\n");
671
Allen Webb93438ca2021-09-13 15:16:34 -0500672 int status;
Allen Webb05af7762021-07-16 12:56:44 -0500673 EXPECT_EQ(waitpid(pid, &status, 0), pid);
674 ASSERT_TRUE(WIFEXITED(status));
675 EXPECT_EQ(WEXITSTATUS(status), 0);
676}
677
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800678TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
679 // TODO(crbug.com/895875): The preload library interferes with ASan since they
680 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800681 if (running_with_asan())
682 GTEST_SKIP();
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800683
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100684 ScopedMinijail j(minijail_new());
685
686 char *argv[4];
687 argv[0] = const_cast<char*>(kCatPath);
688 argv[1] = NULL;
689
690 pid_t pid;
691 int child_stdin, child_stdout;
692 int mj_run_ret = minijail_run_pid_pipes(
693 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
694 EXPECT_EQ(mj_run_ret, 0);
695
696 char teststr[] = "test\n";
697 const size_t teststr_len = strlen(teststr);
698 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
699 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
700
701 char buf[kBufferSize] = {};
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800702 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100703 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
704 EXPECT_STREQ(buf, teststr);
705
706 int status;
707 EXPECT_EQ(kill(pid, SIGTERM), 0);
708 EXPECT_EQ(waitpid(pid, &status, 0), pid);
709 ASSERT_TRUE(WIFSIGNALED(status));
710 EXPECT_EQ(WTERMSIG(status), SIGTERM);
711
712 argv[0] = const_cast<char*>(kShellPath);
713 argv[1] = "-c";
714 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
715 argv[3] = nullptr;
716
717 char *envp[2];
718 envp[0] = "TEST_VAR=test";
719 envp[1] = NULL;
720
721 // Set a canary env var in the parent that should not be present in the child.
722 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
723
Dylan Reid83276a02020-06-10 15:17:13 -0700724 // Use the preload library from this test build.
725 ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
726
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100727 int child_stderr;
728 mj_run_ret =
729 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
730 &child_stdin, &child_stdout, &child_stderr);
731 EXPECT_EQ(mj_run_ret, 0);
732
733 memset(buf, 0, sizeof(buf));
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800734 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100735 EXPECT_GE(read_ret, 0);
736 EXPECT_STREQ(buf, "|test\n");
737
738 EXPECT_EQ(waitpid(pid, &status, 0), pid);
739 ASSERT_TRUE(WIFEXITED(status));
740 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500741}
742
Allen Webb66417bd2021-07-16 15:07:24 -0700743TEST(Test, test_minijail_no_clobber_fds) {
744 int dev_null = open("/dev/null", O_RDONLY);
745 ASSERT_NE(dev_null, -1);
746
747 ScopedMinijail j(minijail_new());
748
749 // Keep stderr.
750 minijail_preserve_fd(j.get(), 2, 2);
751 // Create a lot of mappings to dev_null to possibly clobber libminijail.c fds.
752 for (int i = 3; i < 15; ++i) {
753 minijail_preserve_fd(j.get(), dev_null, i);
754 }
755
756 char *argv[4];
757 argv[0] = const_cast<char*>(kShellPath);
758 argv[1] = "-c";
759 argv[2] = "echo Hello; read line1; echo \"${line1}\" >&2";
760 argv[3] = nullptr;
761
762 pid_t pid;
763 int child_stdin;
764 int child_stdout;
765 int child_stderr;
766 int mj_run_ret = minijail_run_pid_pipes_no_preload(
767 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, &child_stderr);
768 EXPECT_EQ(mj_run_ret, 0);
769
770 char buf[kBufferSize];
771 ssize_t read_ret = read(child_stdout, buf, sizeof(buf));
772 EXPECT_GE(read_ret, 0);
773 buf[read_ret] = '\0';
774 EXPECT_STREQ(buf, "Hello\n");
775
776 constexpr char to_write[] = "test in and err\n";
777 ssize_t write_ret = write(child_stdin, to_write, sizeof(to_write));
778 EXPECT_EQ(write_ret, sizeof(to_write));
779
780 read_ret = read(child_stderr, buf, sizeof(buf));
781 EXPECT_GE(read_ret, 0);
782 buf[read_ret] = '\0';
783 EXPECT_STREQ(buf, to_write);
784
785 int status;
786 waitpid(pid, &status, 0);
787 ASSERT_TRUE(WIFEXITED(status));
788 EXPECT_EQ(WEXITSTATUS(status), 0);
789
790 close(dev_null);
791}
792
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400793TEST(Test, test_minijail_no_fd_leaks) {
794 pid_t pid;
795 int child_stdout;
796 int mj_run_ret;
797 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700798 char buf[kBufferSize];
799 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400800 int status;
801 char *argv[4];
802
803 int dev_null = open("/dev/null", O_RDONLY);
804 ASSERT_NE(dev_null, -1);
805 snprintf(script,
806 sizeof(script),
807 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
808 dev_null);
809
810 struct minijail *j = minijail_new();
811
François Degros87f0e832019-10-10 10:22:39 +1100812 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400813 argv[1] = "-c";
814 argv[2] = script;
815 argv[3] = NULL;
816 mj_run_ret = minijail_run_pid_pipes_no_preload(
817 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
818 EXPECT_EQ(mj_run_ret, 0);
819
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700820 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400821 EXPECT_GE(read_ret, 0);
822 buf[read_ret] = '\0';
823 EXPECT_STREQ(buf, "yes\n");
824
825 waitpid(pid, &status, 0);
826 ASSERT_TRUE(WIFEXITED(status));
827 EXPECT_EQ(WEXITSTATUS(status), 0);
828
829 minijail_close_open_fds(j);
830 mj_run_ret = minijail_run_pid_pipes_no_preload(
831 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
832 EXPECT_EQ(mj_run_ret, 0);
833
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700834 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400835 EXPECT_GE(read_ret, 0);
836 buf[read_ret] = '\0';
837 EXPECT_STREQ(buf, "no\n");
838
839 waitpid(pid, &status, 0);
840 ASSERT_TRUE(WIFEXITED(status));
841 EXPECT_EQ(WEXITSTATUS(status), 0);
842
843 minijail_destroy(j);
844
845 close(dev_null);
846}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100847
Dylan Reid0412dcc2017-08-24 11:33:15 -0700848TEST(Test, test_minijail_fork) {
849 pid_t mj_fork_ret;
850 int status;
851 int pipe_fds[2];
852 ssize_t pid_size = sizeof(mj_fork_ret);
853
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700854 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700855
856 ASSERT_EQ(pipe(pipe_fds), 0);
857
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700858 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700859 ASSERT_GE(mj_fork_ret, 0);
860 if (mj_fork_ret == 0) {
861 pid_t pid_in_parent;
862 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700863 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
864 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700865 exit(0);
866 }
867
868 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
869 waitpid(mj_fork_ret, &status, 0);
870 ASSERT_TRUE(WIFEXITED(status));
871 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700872}
873
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700874static int early_exit(void* payload) {
875 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
876}
877
878TEST(Test, test_minijail_callback) {
879 pid_t pid;
880 int mj_run_ret;
881 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700882 char *argv[2];
883 int exit_code = 42;
884
885 struct minijail *j = minijail_new();
886
887 status =
888 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500889 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700890 EXPECT_EQ(status, 0);
891
François Degros87f0e832019-10-10 10:22:39 +1100892 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700893 argv[1] = NULL;
894 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500895 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700896 EXPECT_EQ(mj_run_ret, 0);
897
898 status = minijail_wait(j);
899 EXPECT_EQ(status, exit_code);
900
901 minijail_destroy(j);
902}
903
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700904TEST(Test, test_minijail_preserve_fd) {
905 int mj_run_ret;
906 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700907 char *argv[2];
908 char teststr[] = "test\n";
909 size_t teststr_len = strlen(teststr);
910 int read_pipe[2];
911 int write_pipe[2];
912 char buf[1024];
913
914 struct minijail *j = minijail_new();
915
916 status = pipe(read_pipe);
917 ASSERT_EQ(status, 0);
918 status = pipe(write_pipe);
919 ASSERT_EQ(status, 0);
920
921 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
922 ASSERT_EQ(status, 0);
923 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
924 ASSERT_EQ(status, 0);
925 minijail_close_open_fds(j);
926
François Degros87f0e832019-10-10 10:22:39 +1100927 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700928 argv[1] = NULL;
929 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
930 EXPECT_EQ(mj_run_ret, 0);
931
932 close(write_pipe[0]);
933 status = write(write_pipe[1], teststr, teststr_len);
934 EXPECT_EQ(status, (int)teststr_len);
935 close(write_pipe[1]);
936
937 close(read_pipe[1]);
938 status = read(read_pipe[0], buf, 8);
939 EXPECT_EQ(status, (int)teststr_len);
940 buf[teststr_len] = 0;
941 EXPECT_EQ(strcmp(buf, teststr), 0);
942
943 status = minijail_wait(j);
944 EXPECT_EQ(status, 0);
945
946 minijail_destroy(j);
947}
948
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700949TEST(Test, test_minijail_reset_signal_mask) {
950 struct minijail *j = minijail_new();
951
952 sigset_t original_signal_mask;
953 {
954 sigset_t signal_mask;
955 ASSERT_EQ(0, sigemptyset(&signal_mask));
956 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
957 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
958 }
959
960 minijail_reset_signal_mask(j);
961
962 pid_t mj_fork_ret = minijail_fork(j);
963 ASSERT_GE(mj_fork_ret, 0);
964 if (mj_fork_ret == 0) {
965 sigset_t signal_mask;
966 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
967 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400968 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700969 exit(0);
970 }
971
972 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
973
974 int status;
975 waitpid(mj_fork_ret, &status, 0);
976 ASSERT_TRUE(WIFEXITED(status));
977 EXPECT_EQ(WEXITSTATUS(status), 0);
978
979 minijail_destroy(j);
980}
981
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700982TEST(Test, test_minijail_reset_signal_handlers) {
983 struct minijail *j = minijail_new();
984
985 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
986 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
987 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
988
989 minijail_reset_signal_handlers(j);
990
991 pid_t mj_fork_ret = minijail_fork(j);
992 ASSERT_GE(mj_fork_ret, 0);
993 if (mj_fork_ret == 0) {
994 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400995 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700996 exit(0);
997 }
998
999 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
1000
1001 int status;
1002 waitpid(mj_fork_ret, &status, 0);
1003 ASSERT_TRUE(WIFEXITED(status));
1004 EXPECT_EQ(WEXITSTATUS(status), 0);
1005
1006 minijail_destroy(j);
1007}
1008
Mike Frysinger780aef72017-10-03 01:39:52 -04001009namespace {
1010
1011// Tests that require userns access.
1012// Android unit tests don't currently support entering user namespaces as
1013// unprivileged users due to having an older kernel. Chrome OS unit tests
1014// don't support it either due to being in a chroot environment (see man 2
1015// clone for more information about failure modes with the CLONE_NEWUSER flag).
1016class NamespaceTest : public ::testing::Test {
1017 protected:
1018 static void SetUpTestCase() {
1019 userns_supported_ = UsernsSupported();
1020 }
1021
1022 // Whether userns is supported.
1023 static bool userns_supported_;
1024
1025 static bool UsernsSupported() {
1026 pid_t pid = fork();
1027 if (pid == -1)
1028 pdie("could not fork");
1029
1030 if (pid == 0)
1031 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
1032
1033 int status;
1034 if (waitpid(pid, &status, 0) < 0)
1035 pdie("could not wait");
1036
1037 if (!WIFEXITED(status))
1038 die("child did not exit properly: %#x", status);
1039
1040 bool ret = WEXITSTATUS(status) == 0;
1041 if (!ret)
1042 warn("Skipping userns related tests");
1043 return ret;
1044 }
1045};
1046
1047bool NamespaceTest::userns_supported_;
1048
1049} // namespace
1050
1051TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -07001052 int mj_run_ret;
1053 int status;
1054 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001055 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -07001056 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1057 constexpr gid_t kTargetGid = 1000;
1058
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001059 if (!userns_supported_)
1060 GTEST_SKIP();
Mike Frysinger780aef72017-10-03 01:39:52 -04001061
Luis Hector Chavez71323552017-09-05 09:17:22 -07001062 struct minijail *j = minijail_new();
1063
1064 minijail_namespace_pids(j);
1065 minijail_namespace_vfs(j);
1066 minijail_mount_tmp(j);
1067 minijail_run_as_init(j);
1068
1069 // Perform userns mapping.
1070 minijail_namespace_user(j);
1071 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1072 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1073 minijail_change_uid(j, kTargetUid);
1074 minijail_change_gid(j, kTargetGid);
1075 minijail_uidmap(j, uidmap);
1076 minijail_gidmap(j, gidmap);
1077 minijail_namespace_user_disable_setgroups(j);
1078
François Degros87f0e832019-10-10 10:22:39 +11001079 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -07001080 argv[1] = "-c";
1081 argv[2] = "exec touch /tmp/foo";
1082 argv[3] = NULL;
1083 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
1084 EXPECT_EQ(mj_run_ret, 0);
1085
1086 status = minijail_wait(j);
1087 EXPECT_EQ(status, 0);
1088
1089 minijail_destroy(j);
1090}
1091
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001092TEST_F(NamespaceTest, test_namespaces) {
1093 constexpr char teststr[] = "test\n";
1094
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -07001095 // TODO(crbug.com/895875): The preload library interferes with ASan since they
1096 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001097 if (!userns_supported_ || running_with_asan())
1098 GTEST_SKIP();
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001099
Luis Hector Chavezac0acf32018-10-15 09:45:01 -07001100 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
1101 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001102
Luis Hector Chavez83a44892018-10-12 08:56:20 -07001103 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
1104 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001105 // Grab the set of namespaces outside the container.
1106 std::map<std::string, std::string> init_namespaces =
1107 GetNamespaces(getpid(), namespace_names);
1108 std::function<void(struct minijail*)> test_functions[] = {
1109 [](struct minijail* j attribute_unused) {},
1110 [](struct minijail* j) {
1111 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
1112 minijail_enter_pivot_root(j, "/tmp");
1113 },
1114 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
1115 };
1116
1117 // This test is run with and without the preload library.
1118 for (const auto& run_function :
1119 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
1120 for (const auto& test_function : test_functions) {
1121 ScopedMinijail j(minijail_new());
1122 minijail_set_preload_path(j.get(), kPreloadPath);
1123
1124 // Enter all the namespaces we can.
1125 minijail_namespace_cgroups(j.get());
1126 minijail_namespace_net(j.get());
1127 minijail_namespace_pids(j.get());
1128 minijail_namespace_user(j.get());
1129 minijail_namespace_vfs(j.get());
1130 minijail_namespace_uts(j.get());
1131
Luis Hector Chavezac0acf32018-10-15 09:45:01 -07001132 // Set up the user namespace.
1133 minijail_uidmap(j.get(), uidmap.c_str());
1134 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001135 minijail_namespace_user_disable_setgroups(j.get());
1136
1137 minijail_close_open_fds(j.get());
1138 test_function(j.get());
1139
François Degros87f0e832019-10-10 10:22:39 +11001140 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001141 pid_t container_pid;
1142 int child_stdin, child_stdout;
1143 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +11001144 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001145 &container_pid, &child_stdin, &child_stdout, nullptr);
1146 EXPECT_EQ(mj_run_ret, 0);
1147
1148 // Send some data to stdin and read it back to ensure that the child
1149 // process is running.
1150 const size_t teststr_len = strlen(teststr);
1151 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
1152 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
1153
1154 char buf[kBufferSize];
1155 ssize_t read_ret = read(child_stdout, buf, 8);
1156 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
1157 buf[teststr_len] = 0;
1158 EXPECT_EQ(strcmp(buf, teststr), 0);
1159
1160 // Grab the set of namespaces in every container process. They must not
1161 // match the ones in the init namespace, and they must all match each
1162 // other.
1163 std::map<std::string, std::string> container_namespaces =
1164 GetNamespaces(container_pid, namespace_names);
1165 EXPECT_NE(container_namespaces, init_namespaces);
1166 for (pid_t pid : GetProcessSubtreePids(container_pid))
1167 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
1168
1169 EXPECT_EQ(0, close(child_stdin));
1170
1171 int status = minijail_wait(j.get());
1172 EXPECT_EQ(status, 0);
1173 }
1174 }
1175}
1176
Mike Frysinger902a4492018-12-27 05:22:56 -05001177TEST_F(NamespaceTest, test_enter_ns) {
1178 char uidmap[kBufferSize], gidmap[kBufferSize];
1179
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001180 if (!userns_supported_)
1181 GTEST_SKIP();
Mike Frysinger902a4492018-12-27 05:22:56 -05001182
1183 // We first create a child in a new userns so we have privs to run more tests.
1184 // We can't combine the steps as the kernel disallows many resource sharing
1185 // from outside the userns.
1186 struct minijail *j = minijail_new();
1187
1188 minijail_namespace_vfs(j);
1189 minijail_namespace_pids(j);
1190 minijail_run_as_init(j);
1191
1192 // Perform userns mapping.
1193 minijail_namespace_user(j);
1194 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1195 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1196 minijail_uidmap(j, uidmap);
1197 minijail_gidmap(j, gidmap);
1198 minijail_namespace_user_disable_setgroups(j);
1199
1200 pid_t pid = minijail_fork(j);
1201 if (pid == 0) {
1202 // Child.
1203 minijail_destroy(j);
1204
1205 // Create new namespaces inside this userns which we may enter.
1206 j = minijail_new();
1207 minijail_namespace_net(j);
1208 minijail_namespace_vfs(j);
1209 pid = minijail_fork(j);
1210 if (pid == 0) {
1211 // Child.
1212 minijail_destroy(j);
1213
1214 // Finally enter those namespaces.
1215 j = minijail_new();
1216
1217 // We need to get the absolute path because entering a new mntns will
1218 // implicitly chdir(/) for us.
1219 char *path = realpath(kPreloadPath, nullptr);
1220 ASSERT_NE(nullptr, path);
1221 minijail_set_preload_path(j, path);
1222
1223 minijail_namespace_net(j);
1224 minijail_namespace_vfs(j);
1225
1226 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1227 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1228
1229 char *argv[] = {"/bin/true", nullptr};
1230 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1231 EXPECT_EQ(0, minijail_wait(j));
1232 minijail_destroy(j);
1233 exit(0);
1234 } else {
1235 ASSERT_GT(pid, 0);
1236 EXPECT_EQ(0, minijail_wait(j));
1237 minijail_destroy(j);
1238 exit(0);
1239 }
1240 } else {
1241 ASSERT_GT(pid, 0);
1242 EXPECT_EQ(0, minijail_wait(j));
1243 minijail_destroy(j);
1244 }
1245}
1246
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001247TEST_F(NamespaceTest, test_remount_all_private) {
1248 pid_t pid;
1249 int child_stdout;
1250 int mj_run_ret;
1251 ssize_t read_ret;
1252 char buf[kBufferSize];
1253 int status;
1254 char *argv[4];
1255 char uidmap[kBufferSize], gidmap[kBufferSize];
1256 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1257 constexpr gid_t kTargetGid = 1000;
1258
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001259 if (!userns_supported_)
1260 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001261
1262 struct minijail *j = minijail_new();
1263
1264 minijail_namespace_pids(j);
1265 minijail_namespace_vfs(j);
1266 minijail_run_as_init(j);
1267
1268 // Perform userns mapping.
1269 minijail_namespace_user(j);
1270 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1271 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1272 minijail_change_uid(j, kTargetUid);
1273 minijail_change_gid(j, kTargetGid);
1274 minijail_uidmap(j, uidmap);
1275 minijail_gidmap(j, gidmap);
1276 minijail_namespace_user_disable_setgroups(j);
1277
1278 minijail_namespace_vfs(j);
1279 minijail_remount_mode(j, MS_PRIVATE);
1280
1281 argv[0] = const_cast<char*>(kShellPath);
1282 argv[1] = "-c";
1283 argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
Allen Webb05af7762021-07-16 12:56:44 -05001284 "/proc/self/mountinfo";
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001285 argv[3] = NULL;
1286 mj_run_ret = minijail_run_pid_pipes_no_preload(
1287 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1288 EXPECT_EQ(mj_run_ret, 0);
1289
1290 // There should be no output because all mounts should be remounted as
1291 // private.
1292 read_ret = read(child_stdout, buf, sizeof(buf));
1293 EXPECT_EQ(read_ret, 0);
1294
1295 // grep will exit with 1 if it does not find anything which is what we
1296 // expect.
1297 status = minijail_wait(j);
1298 EXPECT_EQ(status, 1);
1299
1300 minijail_destroy(j);
1301}
1302
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001303TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1304 int status;
1305 char uidmap[kBufferSize], gidmap[kBufferSize];
1306 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1307 constexpr gid_t kTargetGid = 1000;
1308
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001309 if (!userns_supported_)
1310 GTEST_SKIP();
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001311
1312 struct minijail *j = minijail_new();
1313
1314 minijail_namespace_pids(j);
1315 minijail_namespace_vfs(j);
1316 minijail_mount_tmp(j);
1317 minijail_run_as_init(j);
1318
1319 // Perform userns mapping.
1320 minijail_namespace_user(j);
1321 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1322 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1323 minijail_change_uid(j, kTargetUid);
1324 minijail_change_gid(j, kTargetGid);
1325 minijail_uidmap(j, uidmap);
1326 minijail_gidmap(j, gidmap);
1327 minijail_namespace_user_disable_setgroups(j);
1328
1329 minijail_namespace_vfs(j);
1330 minijail_remount_mode(j, MS_SHARED);
1331 minijail_add_remount(j, "/proc", MS_PRIVATE);
1332
1333 char *argv[] = {"/bin/true", nullptr};
1334 minijail_run(j, argv[0], argv);
1335
1336 status = minijail_wait(j);
1337 EXPECT_GT(status, 0);
1338
1339 minijail_destroy(j);
1340}
1341
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001342TEST_F(NamespaceTest, test_remount_one_shared) {
1343 pid_t pid;
1344 int child_stdout;
1345 int mj_run_ret;
1346 ssize_t read_ret;
1347 char buf[kBufferSize * 4];
1348 int status;
1349 char *argv[4];
1350 char uidmap[kBufferSize], gidmap[kBufferSize];
1351 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1352 constexpr gid_t kTargetGid = 1000;
1353
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001354 if (!userns_supported_)
1355 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001356
1357 struct minijail *j = minijail_new();
1358
1359 minijail_namespace_pids(j);
1360 minijail_namespace_vfs(j);
1361 minijail_mount_tmp(j);
1362 minijail_run_as_init(j);
1363
1364 // Perform userns mapping.
1365 minijail_namespace_user(j);
1366 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1367 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1368 minijail_change_uid(j, kTargetUid);
1369 minijail_change_gid(j, kTargetGid);
1370 minijail_uidmap(j, uidmap);
1371 minijail_gidmap(j, gidmap);
1372 minijail_namespace_user_disable_setgroups(j);
1373
1374 minijail_namespace_vfs(j);
1375 minijail_remount_mode(j, MS_PRIVATE);
1376 minijail_add_remount(j, "/proc", MS_SHARED);
1377
1378 argv[0] = const_cast<char*>(kShellPath);
1379 argv[1] = "-c";
1380 argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1381 argv[3] = NULL;
1382 mj_run_ret = minijail_run_pid_pipes_no_preload(
1383 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1384 EXPECT_EQ(mj_run_ret, 0);
1385
1386 // There should be no output because all mounts should be remounted as
1387 // private.
1388 read_ret = read(child_stdout, buf, sizeof(buf));
1389 EXPECT_GE(read_ret, 0);
1390 buf[read_ret] = '\0';
1391 EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1392
1393 status = minijail_wait(j);
1394 EXPECT_EQ(status, 0);
1395
1396 minijail_destroy(j);
1397}
1398
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001399void TestCreateSession(bool create_session) {
1400 int status;
1401 int pipe_fds[2];
1402 pid_t child_pid;
1403 pid_t parent_sid = getsid(0);
1404 ssize_t pid_size = sizeof(pid_t);
1405
1406 ScopedMinijail j(minijail_new());
1407 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1408 // a new session because of that.
1409 minijail_close_open_fds(j.get());
1410
1411 if (create_session)
1412 minijail_create_session(j.get());
1413
1414 ASSERT_EQ(pipe(pipe_fds), 0);
1415 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1416
1417 child_pid = minijail_fork(j.get());
1418 ASSERT_GE(child_pid, 0);
1419 if (child_pid == 0) {
1420 pid_t sid_in_parent;
1421 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1422 if (create_session)
1423 ASSERT_NE(sid_in_parent, getsid(0));
1424 else
1425 ASSERT_EQ(sid_in_parent, getsid(0));
1426 exit(0);
1427 }
1428
1429 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1430 waitpid(child_pid, &status, 0);
1431 ASSERT_TRUE(WIFEXITED(status));
1432 EXPECT_EQ(WEXITSTATUS(status), 0);
1433}
1434
1435TEST(Test, default_no_new_session) {
1436 TestCreateSession(/*create_session=*/false);
1437}
1438
1439TEST(Test, create_new_session) {
1440 TestCreateSession(/*create_session=*/true);
1441}