blob: 496738bdea9e4f5c5952c62e7dd86e85d7620abb [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>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070012#include <sys/mount.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040013#include <sys/stat.h>
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070014#include <sys/types.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040015#include <sys/wait.h>
Dylan Reid0412dcc2017-08-24 11:33:15 -070016#include <unistd.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040017
18#include <gtest/gtest.h>
19
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070020#include <functional>
21#include <map>
22#include <set>
23#include <string>
24
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040025#include "libminijail-private.h"
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070026#include "libminijail.h"
27#include "scoped_minijail.h"
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040028#include "util.h"
29
Mike Frysingerb2c12d12017-09-29 21:18:59 -040030namespace {
31
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040032#if defined(__ANDROID__)
Mike Frysingerb2c12d12017-09-29 21:18:59 -040033# define ROOT_PREFIX "/system"
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040034#else
Mike Frysingerb2c12d12017-09-29 21:18:59 -040035# define ROOT_PREFIX ""
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040036#endif
37
Luis Hector Chavez9acba452018-10-11 10:13:25 -070038constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
39constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
40constexpr char kPreloadPath[] = "./libminijailpreload.so";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070041constexpr size_t kBufferSize = 128;
42
43std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
44 std::set<pid_t> pids{root_pid};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070045 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);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070059 if (*end != '\0')
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070060 continue;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070061 std::string path = "/proc/" + std::to_string(pid) + "/stat";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070062
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070063 FILE* f = fopen(path.c_str(), "re");
Luis Héctor Chávez25214912021-01-03 05:47:09 -080064 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 }
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070071 pdie("fopen(%s)", path.c_str());
Luis Héctor Chávez25214912021-01-03 05:47:09 -080072 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070073 pid_t ppid;
74 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070075 fclose(f);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070076 if (ret != 1) {
77 continue;
78 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070079 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
88std::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;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070092 char buf[kBufferSize];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070093 for (const auto& namespace_name : namespace_names) {
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070094 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
95 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070096 if (len == -1)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070097 pdie("readlink(\"%s\")", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070098 namespaces.emplace(namespace_name, std::string(buf, len));
99 }
100 return namespaces;
101}
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400102
103} // namespace
104
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400105/* Silence unused variable warnings. */
106TEST(silence, silence_unused) {
107 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
108 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
109 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
110}
111
112TEST(consumebytes, zero) {
113 char buf[1024];
114 size_t len = sizeof(buf);
115 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400116 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400117 EXPECT_EQ(&buf[0], pos);
118 EXPECT_EQ(sizeof(buf), len);
119}
120
121TEST(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)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400127 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400128 EXPECT_EQ((size_t)0, len);
129 EXPECT_EQ(end, pos);
130}
131
132TEST(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];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400138 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400139 EXPECT_EQ(sizeof(buf) / 2, len);
140 EXPECT_EQ(end, pos);
141}
142
143TEST(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. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400148 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400149 EXPECT_EQ(sizeof(buf), len);
150 EXPECT_EQ(&buf[0], pos);
151}
152
153TEST(consumestr, zero) {
154 char buf[1024];
155 size_t len = 0;
156 char *pos = &buf[0];
157 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400158 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400159 EXPECT_EQ((size_t)0, len);
160 EXPECT_EQ(&buf[0], pos);
161}
162
163TEST(consumestr, nonul) {
164 char buf[1024];
165 size_t len = sizeof(buf);
166 char *pos = &buf[0];
167 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400168 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400169 EXPECT_EQ(sizeof(buf), len);
170 EXPECT_EQ(&buf[0], pos);
171}
172
173TEST(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
184TEST(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';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400190 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400191 EXPECT_EQ(sizeof(buf) - 1, len);
192 EXPECT_EQ(&buf[0], pos);
193}
194
195class MarshalTest : public ::testing::Test {
196 protected:
197 virtual void SetUp() {
198 m_ = minijail_new();
199 j_ = minijail_new();
200 size_ = minijail_size(m_);
201 }
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
213TEST_F(MarshalTest, empty) {
214 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
215 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
216}
217
218TEST_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
Dylan Reid6dc224f2021-05-12 17:06:25 -0700224TEST_F(MarshalTest, copy_empty) {
225 ASSERT_EQ(0, minijail_copy_jail(m_, j_));
226}
227
François Degros47e63352019-10-01 13:01:53 +1000228TEST(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
236TEST(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
244TEST(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
258TEST(KillTest, process_not_started) {
259 const ScopedMinijail j(minijail_new());
260 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
261}
262
François Degros08b10f72019-10-09 12:44:05 +1100263TEST(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
270TEST(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
277TEST(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
284TEST(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
291TEST(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
298TEST(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
305TEST(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
312TEST(WaitTest, no_process) {
313 const ScopedMinijail j(minijail_new());
314 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
315}
316
317TEST(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
François Degros26f8e4e2020-04-17 09:31:02 +1000325TEST(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
François Degrosa8be2c42019-10-01 12:06:42 +1000407TEST(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);
François Degros87f0e832019-10-10 10:22:39 +1100425 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000426
427 int in = -1;
428 int out = -1;
429 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400430 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
431 nullptr, &in, &out, &err),
432 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000433 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);
François Degros26f8e4e2020-04-17 09:31:02 +1000456 ASSERT_EQ(close(out), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000457 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000458 ASSERT_EQ(close(err), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000459
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
Allen Webb66417bd2021-07-16 15:07:24 -0700476TEST(Test, minijail_no_clobber_pipe_fd) {
477 const ScopedMinijail j(minijail_new());
478 char* const script = R"(
479 echo Hi >&1;
480 exec 1>&-;
481 exec 4>&-;
482 exec 7>&-;
483 read line1;
484 read line2;
485 echo "$line1$line2 and Goodbye" >&2;
486 exit 42;
487 )";
488 char* const argv[] = {"sh", "-c", script, nullptr};
489
490 const int npipes = 3;
491 int fds[npipes][2];
492
493 // Create pipes.
494 for (int i = 0; i < npipes; ++i) {
495 ASSERT_EQ(pipe(fds[i]), 0);
496 }
497
498 // All pipes are output pipes except for the first one which is used as
499 // input pipe.
500 std::swap(fds[0][0], fds[0][1]);
501
502 // Generate a lot of mappings to try to clobber any file descriptors generated
503 // by libminijail.
504 for (int offset = 0; offset < npipes * 3; offset += npipes) {
505 for (int i = 0 ; i < npipes; ++i) {
506 const int fd = fds[i][1];
507 minijail_preserve_fd(j.get(), fd, i + offset);
508 }
509 }
510
511 minijail_close_open_fds(j.get());
512
513 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
514
515 // Close unused end of pipes.
516 for (int i = 0; i < npipes; ++i) {
517 const int fd = fds[i][1];
518 ASSERT_EQ(close(fd), 0);
519 }
520
521 const int in = fds[0][0];
522 const int out = fds[1][0];
523 const int err = fds[2][0];
524
525 char buf[PIPE_BUF];
526 ssize_t nbytes;
527
528 // Check that stdout pipe works.
529 nbytes = read(out, buf, PIPE_BUF);
530 ASSERT_GT(nbytes, 0);
531 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
532
533 // Check that the write end of stdout pipe got closed by the child process. If
534 // the child process kept other file descriptors connected to stdout, then the
535 // parent process wouldn't be able to detect that all write ends of this pipe
536 // are closed and it would block here.
537 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
538 ASSERT_EQ(close(out), 0);
539
540 // Check that stdin pipe works.
541 const std::string s = "Greetings\n";
542 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
543
544 // Close write end of pipe connected to child's stdin. If there was another
545 // file descriptor connected to this write end, then the child process
546 // wouldn't be able to detect that this write end is closed and it would
547 // block.
548 ASSERT_EQ(close(in), 0);
549
550 // Check that child process continued and ended.
551 nbytes = read(err, buf, PIPE_BUF);
552 ASSERT_GT(nbytes, 0);
553 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
554
555 // Check that the write end of the stderr pipe is closed when the child
556 // process finishes.
557 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
558 ASSERT_EQ(close(err), 0);
559
560 // Check the child process termination status.
561 EXPECT_EQ(minijail_wait(j.get()), 42);
562}
563
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100564TEST(Test, minijail_run_env_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700565 // TODO(crbug.com/895875): The preload library interferes with ASan since they
566 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800567 if (running_with_asan())
568 GTEST_SKIP();
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700569
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700570 ScopedMinijail j(minijail_new());
571 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700572
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100573 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700574 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100575 argv[1] = NULL;
576
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700577 pid_t pid;
578 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100579 int mj_run_ret = minijail_run_pid_pipes(
580 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700581 EXPECT_EQ(mj_run_ret, 0);
582
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100583 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700584 const size_t teststr_len = strlen(teststr);
585 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
586 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
587
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100588 char buf[kBufferSize] = {};
589 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700590 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100591 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700592
593 int status;
594 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100595 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700596 ASSERT_TRUE(WIFSIGNALED(status));
597 EXPECT_EQ(WTERMSIG(status), SIGTERM);
598
599 argv[0] = const_cast<char*>(kShellPath);
600 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100601 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700602 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700603
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500604 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100605 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500606 envp[1] = NULL;
607
608 // Set a canary env var in the parent that should not be present in the child.
609 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
610
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100611 int child_stderr;
612 mj_run_ret =
613 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
614 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500615 EXPECT_EQ(mj_run_ret, 0);
616
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100617 memset(buf, 0, sizeof(buf));
618 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
619 EXPECT_GE(read_ret, 0);
620 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500621
622 EXPECT_EQ(waitpid(pid, &status, 0), pid);
623 ASSERT_TRUE(WIFEXITED(status));
624 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100625}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500626
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800627TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
628 // TODO(crbug.com/895875): The preload library interferes with ASan since they
629 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -0800630 if (running_with_asan())
631 GTEST_SKIP();
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800632
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100633 ScopedMinijail j(minijail_new());
634
635 char *argv[4];
636 argv[0] = const_cast<char*>(kCatPath);
637 argv[1] = NULL;
638
639 pid_t pid;
640 int child_stdin, child_stdout;
641 int mj_run_ret = minijail_run_pid_pipes(
642 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
643 EXPECT_EQ(mj_run_ret, 0);
644
645 char teststr[] = "test\n";
646 const size_t teststr_len = strlen(teststr);
647 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
648 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
649
650 char buf[kBufferSize] = {};
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800651 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100652 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
653 EXPECT_STREQ(buf, teststr);
654
655 int status;
656 EXPECT_EQ(kill(pid, SIGTERM), 0);
657 EXPECT_EQ(waitpid(pid, &status, 0), pid);
658 ASSERT_TRUE(WIFSIGNALED(status));
659 EXPECT_EQ(WTERMSIG(status), SIGTERM);
660
661 argv[0] = const_cast<char*>(kShellPath);
662 argv[1] = "-c";
663 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
664 argv[3] = nullptr;
665
666 char *envp[2];
667 envp[0] = "TEST_VAR=test";
668 envp[1] = NULL;
669
670 // Set a canary env var in the parent that should not be present in the child.
671 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
672
Dylan Reid83276a02020-06-10 15:17:13 -0700673 // Use the preload library from this test build.
674 ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
675
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100676 int child_stderr;
677 mj_run_ret =
678 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
679 &child_stdin, &child_stdout, &child_stderr);
680 EXPECT_EQ(mj_run_ret, 0);
681
682 memset(buf, 0, sizeof(buf));
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800683 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100684 EXPECT_GE(read_ret, 0);
685 EXPECT_STREQ(buf, "|test\n");
686
687 EXPECT_EQ(waitpid(pid, &status, 0), pid);
688 ASSERT_TRUE(WIFEXITED(status));
689 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500690}
691
Allen Webb66417bd2021-07-16 15:07:24 -0700692TEST(Test, test_minijail_no_clobber_fds) {
693 int dev_null = open("/dev/null", O_RDONLY);
694 ASSERT_NE(dev_null, -1);
695
696 ScopedMinijail j(minijail_new());
697
698 // Keep stderr.
699 minijail_preserve_fd(j.get(), 2, 2);
700 // Create a lot of mappings to dev_null to possibly clobber libminijail.c fds.
701 for (int i = 3; i < 15; ++i) {
702 minijail_preserve_fd(j.get(), dev_null, i);
703 }
704
705 char *argv[4];
706 argv[0] = const_cast<char*>(kShellPath);
707 argv[1] = "-c";
708 argv[2] = "echo Hello; read line1; echo \"${line1}\" >&2";
709 argv[3] = nullptr;
710
711 pid_t pid;
712 int child_stdin;
713 int child_stdout;
714 int child_stderr;
715 int mj_run_ret = minijail_run_pid_pipes_no_preload(
716 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, &child_stderr);
717 EXPECT_EQ(mj_run_ret, 0);
718
719 char buf[kBufferSize];
720 ssize_t read_ret = read(child_stdout, buf, sizeof(buf));
721 EXPECT_GE(read_ret, 0);
722 buf[read_ret] = '\0';
723 EXPECT_STREQ(buf, "Hello\n");
724
725 constexpr char to_write[] = "test in and err\n";
726 ssize_t write_ret = write(child_stdin, to_write, sizeof(to_write));
727 EXPECT_EQ(write_ret, sizeof(to_write));
728
729 read_ret = read(child_stderr, buf, sizeof(buf));
730 EXPECT_GE(read_ret, 0);
731 buf[read_ret] = '\0';
732 EXPECT_STREQ(buf, to_write);
733
734 int status;
735 waitpid(pid, &status, 0);
736 ASSERT_TRUE(WIFEXITED(status));
737 EXPECT_EQ(WEXITSTATUS(status), 0);
738
739 close(dev_null);
740}
741
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400742TEST(Test, test_minijail_no_fd_leaks) {
743 pid_t pid;
744 int child_stdout;
745 int mj_run_ret;
746 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700747 char buf[kBufferSize];
748 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400749 int status;
750 char *argv[4];
751
752 int dev_null = open("/dev/null", O_RDONLY);
753 ASSERT_NE(dev_null, -1);
754 snprintf(script,
755 sizeof(script),
756 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
757 dev_null);
758
759 struct minijail *j = minijail_new();
760
François Degros87f0e832019-10-10 10:22:39 +1100761 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400762 argv[1] = "-c";
763 argv[2] = script;
764 argv[3] = NULL;
765 mj_run_ret = minijail_run_pid_pipes_no_preload(
766 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
767 EXPECT_EQ(mj_run_ret, 0);
768
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700769 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400770 EXPECT_GE(read_ret, 0);
771 buf[read_ret] = '\0';
772 EXPECT_STREQ(buf, "yes\n");
773
774 waitpid(pid, &status, 0);
775 ASSERT_TRUE(WIFEXITED(status));
776 EXPECT_EQ(WEXITSTATUS(status), 0);
777
778 minijail_close_open_fds(j);
779 mj_run_ret = minijail_run_pid_pipes_no_preload(
780 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
781 EXPECT_EQ(mj_run_ret, 0);
782
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700783 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400784 EXPECT_GE(read_ret, 0);
785 buf[read_ret] = '\0';
786 EXPECT_STREQ(buf, "no\n");
787
788 waitpid(pid, &status, 0);
789 ASSERT_TRUE(WIFEXITED(status));
790 EXPECT_EQ(WEXITSTATUS(status), 0);
791
792 minijail_destroy(j);
793
794 close(dev_null);
795}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100796
Dylan Reid0412dcc2017-08-24 11:33:15 -0700797TEST(Test, test_minijail_fork) {
798 pid_t mj_fork_ret;
799 int status;
800 int pipe_fds[2];
801 ssize_t pid_size = sizeof(mj_fork_ret);
802
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700803 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700804
805 ASSERT_EQ(pipe(pipe_fds), 0);
806
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700807 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700808 ASSERT_GE(mj_fork_ret, 0);
809 if (mj_fork_ret == 0) {
810 pid_t pid_in_parent;
811 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700812 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
813 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700814 exit(0);
815 }
816
817 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
818 waitpid(mj_fork_ret, &status, 0);
819 ASSERT_TRUE(WIFEXITED(status));
820 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700821}
822
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700823static int early_exit(void* payload) {
824 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
825}
826
827TEST(Test, test_minijail_callback) {
828 pid_t pid;
829 int mj_run_ret;
830 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700831 char *argv[2];
832 int exit_code = 42;
833
834 struct minijail *j = minijail_new();
835
836 status =
837 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500838 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700839 EXPECT_EQ(status, 0);
840
François Degros87f0e832019-10-10 10:22:39 +1100841 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700842 argv[1] = NULL;
843 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500844 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700845 EXPECT_EQ(mj_run_ret, 0);
846
847 status = minijail_wait(j);
848 EXPECT_EQ(status, exit_code);
849
850 minijail_destroy(j);
851}
852
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700853TEST(Test, test_minijail_preserve_fd) {
854 int mj_run_ret;
855 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700856 char *argv[2];
857 char teststr[] = "test\n";
858 size_t teststr_len = strlen(teststr);
859 int read_pipe[2];
860 int write_pipe[2];
861 char buf[1024];
862
863 struct minijail *j = minijail_new();
864
865 status = pipe(read_pipe);
866 ASSERT_EQ(status, 0);
867 status = pipe(write_pipe);
868 ASSERT_EQ(status, 0);
869
870 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
871 ASSERT_EQ(status, 0);
872 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
873 ASSERT_EQ(status, 0);
874 minijail_close_open_fds(j);
875
François Degros87f0e832019-10-10 10:22:39 +1100876 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700877 argv[1] = NULL;
878 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
879 EXPECT_EQ(mj_run_ret, 0);
880
881 close(write_pipe[0]);
882 status = write(write_pipe[1], teststr, teststr_len);
883 EXPECT_EQ(status, (int)teststr_len);
884 close(write_pipe[1]);
885
886 close(read_pipe[1]);
887 status = read(read_pipe[0], buf, 8);
888 EXPECT_EQ(status, (int)teststr_len);
889 buf[teststr_len] = 0;
890 EXPECT_EQ(strcmp(buf, teststr), 0);
891
892 status = minijail_wait(j);
893 EXPECT_EQ(status, 0);
894
895 minijail_destroy(j);
896}
897
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700898TEST(Test, test_minijail_reset_signal_mask) {
899 struct minijail *j = minijail_new();
900
901 sigset_t original_signal_mask;
902 {
903 sigset_t signal_mask;
904 ASSERT_EQ(0, sigemptyset(&signal_mask));
905 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
906 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
907 }
908
909 minijail_reset_signal_mask(j);
910
911 pid_t mj_fork_ret = minijail_fork(j);
912 ASSERT_GE(mj_fork_ret, 0);
913 if (mj_fork_ret == 0) {
914 sigset_t signal_mask;
915 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
916 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400917 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700918 exit(0);
919 }
920
921 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
922
923 int status;
924 waitpid(mj_fork_ret, &status, 0);
925 ASSERT_TRUE(WIFEXITED(status));
926 EXPECT_EQ(WEXITSTATUS(status), 0);
927
928 minijail_destroy(j);
929}
930
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700931TEST(Test, test_minijail_reset_signal_handlers) {
932 struct minijail *j = minijail_new();
933
934 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
935 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
936 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
937
938 minijail_reset_signal_handlers(j);
939
940 pid_t mj_fork_ret = minijail_fork(j);
941 ASSERT_GE(mj_fork_ret, 0);
942 if (mj_fork_ret == 0) {
943 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400944 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700945 exit(0);
946 }
947
948 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
949
950 int status;
951 waitpid(mj_fork_ret, &status, 0);
952 ASSERT_TRUE(WIFEXITED(status));
953 EXPECT_EQ(WEXITSTATUS(status), 0);
954
955 minijail_destroy(j);
956}
957
Mike Frysinger780aef72017-10-03 01:39:52 -0400958namespace {
959
960// Tests that require userns access.
961// Android unit tests don't currently support entering user namespaces as
962// unprivileged users due to having an older kernel. Chrome OS unit tests
963// don't support it either due to being in a chroot environment (see man 2
964// clone for more information about failure modes with the CLONE_NEWUSER flag).
965class NamespaceTest : public ::testing::Test {
966 protected:
967 static void SetUpTestCase() {
968 userns_supported_ = UsernsSupported();
969 }
970
971 // Whether userns is supported.
972 static bool userns_supported_;
973
974 static bool UsernsSupported() {
975 pid_t pid = fork();
976 if (pid == -1)
977 pdie("could not fork");
978
979 if (pid == 0)
980 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
981
982 int status;
983 if (waitpid(pid, &status, 0) < 0)
984 pdie("could not wait");
985
986 if (!WIFEXITED(status))
987 die("child did not exit properly: %#x", status);
988
989 bool ret = WEXITSTATUS(status) == 0;
990 if (!ret)
991 warn("Skipping userns related tests");
992 return ret;
993 }
994};
995
996bool NamespaceTest::userns_supported_;
997
998} // namespace
999
1000TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -07001001 int mj_run_ret;
1002 int status;
1003 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001004 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -07001005 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1006 constexpr gid_t kTargetGid = 1000;
1007
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001008 if (!userns_supported_)
1009 GTEST_SKIP();
Mike Frysinger780aef72017-10-03 01:39:52 -04001010
Luis Hector Chavez71323552017-09-05 09:17:22 -07001011 struct minijail *j = minijail_new();
1012
1013 minijail_namespace_pids(j);
1014 minijail_namespace_vfs(j);
1015 minijail_mount_tmp(j);
1016 minijail_run_as_init(j);
1017
1018 // Perform userns mapping.
1019 minijail_namespace_user(j);
1020 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1021 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1022 minijail_change_uid(j, kTargetUid);
1023 minijail_change_gid(j, kTargetGid);
1024 minijail_uidmap(j, uidmap);
1025 minijail_gidmap(j, gidmap);
1026 minijail_namespace_user_disable_setgroups(j);
1027
François Degros87f0e832019-10-10 10:22:39 +11001028 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -07001029 argv[1] = "-c";
1030 argv[2] = "exec touch /tmp/foo";
1031 argv[3] = NULL;
1032 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
1033 EXPECT_EQ(mj_run_ret, 0);
1034
1035 status = minijail_wait(j);
1036 EXPECT_EQ(status, 0);
1037
1038 minijail_destroy(j);
1039}
1040
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001041TEST_F(NamespaceTest, test_namespaces) {
1042 constexpr char teststr[] = "test\n";
1043
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -07001044 // TODO(crbug.com/895875): The preload library interferes with ASan since they
1045 // both need to use LD_PRELOAD.
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001046 if (!userns_supported_ || running_with_asan())
1047 GTEST_SKIP();
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001048
Luis Hector Chavezac0acf32018-10-15 09:45:01 -07001049 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
1050 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001051
Luis Hector Chavez83a44892018-10-12 08:56:20 -07001052 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
1053 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001054 // Grab the set of namespaces outside the container.
1055 std::map<std::string, std::string> init_namespaces =
1056 GetNamespaces(getpid(), namespace_names);
1057 std::function<void(struct minijail*)> test_functions[] = {
1058 [](struct minijail* j attribute_unused) {},
1059 [](struct minijail* j) {
1060 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
1061 minijail_enter_pivot_root(j, "/tmp");
1062 },
1063 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
1064 };
1065
1066 // This test is run with and without the preload library.
1067 for (const auto& run_function :
1068 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
1069 for (const auto& test_function : test_functions) {
1070 ScopedMinijail j(minijail_new());
1071 minijail_set_preload_path(j.get(), kPreloadPath);
1072
1073 // Enter all the namespaces we can.
1074 minijail_namespace_cgroups(j.get());
1075 minijail_namespace_net(j.get());
1076 minijail_namespace_pids(j.get());
1077 minijail_namespace_user(j.get());
1078 minijail_namespace_vfs(j.get());
1079 minijail_namespace_uts(j.get());
1080
Luis Hector Chavezac0acf32018-10-15 09:45:01 -07001081 // Set up the user namespace.
1082 minijail_uidmap(j.get(), uidmap.c_str());
1083 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001084 minijail_namespace_user_disable_setgroups(j.get());
1085
1086 minijail_close_open_fds(j.get());
1087 test_function(j.get());
1088
François Degros87f0e832019-10-10 10:22:39 +11001089 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001090 pid_t container_pid;
1091 int child_stdin, child_stdout;
1092 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +11001093 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -07001094 &container_pid, &child_stdin, &child_stdout, nullptr);
1095 EXPECT_EQ(mj_run_ret, 0);
1096
1097 // Send some data to stdin and read it back to ensure that the child
1098 // process is running.
1099 const size_t teststr_len = strlen(teststr);
1100 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
1101 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
1102
1103 char buf[kBufferSize];
1104 ssize_t read_ret = read(child_stdout, buf, 8);
1105 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
1106 buf[teststr_len] = 0;
1107 EXPECT_EQ(strcmp(buf, teststr), 0);
1108
1109 // Grab the set of namespaces in every container process. They must not
1110 // match the ones in the init namespace, and they must all match each
1111 // other.
1112 std::map<std::string, std::string> container_namespaces =
1113 GetNamespaces(container_pid, namespace_names);
1114 EXPECT_NE(container_namespaces, init_namespaces);
1115 for (pid_t pid : GetProcessSubtreePids(container_pid))
1116 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
1117
1118 EXPECT_EQ(0, close(child_stdin));
1119
1120 int status = minijail_wait(j.get());
1121 EXPECT_EQ(status, 0);
1122 }
1123 }
1124}
1125
Mike Frysinger902a4492018-12-27 05:22:56 -05001126TEST_F(NamespaceTest, test_enter_ns) {
1127 char uidmap[kBufferSize], gidmap[kBufferSize];
1128
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001129 if (!userns_supported_)
1130 GTEST_SKIP();
Mike Frysinger902a4492018-12-27 05:22:56 -05001131
1132 // We first create a child in a new userns so we have privs to run more tests.
1133 // We can't combine the steps as the kernel disallows many resource sharing
1134 // from outside the userns.
1135 struct minijail *j = minijail_new();
1136
1137 minijail_namespace_vfs(j);
1138 minijail_namespace_pids(j);
1139 minijail_run_as_init(j);
1140
1141 // Perform userns mapping.
1142 minijail_namespace_user(j);
1143 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1144 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1145 minijail_uidmap(j, uidmap);
1146 minijail_gidmap(j, gidmap);
1147 minijail_namespace_user_disable_setgroups(j);
1148
1149 pid_t pid = minijail_fork(j);
1150 if (pid == 0) {
1151 // Child.
1152 minijail_destroy(j);
1153
1154 // Create new namespaces inside this userns which we may enter.
1155 j = minijail_new();
1156 minijail_namespace_net(j);
1157 minijail_namespace_vfs(j);
1158 pid = minijail_fork(j);
1159 if (pid == 0) {
1160 // Child.
1161 minijail_destroy(j);
1162
1163 // Finally enter those namespaces.
1164 j = minijail_new();
1165
1166 // We need to get the absolute path because entering a new mntns will
1167 // implicitly chdir(/) for us.
1168 char *path = realpath(kPreloadPath, nullptr);
1169 ASSERT_NE(nullptr, path);
1170 minijail_set_preload_path(j, path);
1171
1172 minijail_namespace_net(j);
1173 minijail_namespace_vfs(j);
1174
1175 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1176 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1177
1178 char *argv[] = {"/bin/true", nullptr};
1179 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1180 EXPECT_EQ(0, minijail_wait(j));
1181 minijail_destroy(j);
1182 exit(0);
1183 } else {
1184 ASSERT_GT(pid, 0);
1185 EXPECT_EQ(0, minijail_wait(j));
1186 minijail_destroy(j);
1187 exit(0);
1188 }
1189 } else {
1190 ASSERT_GT(pid, 0);
1191 EXPECT_EQ(0, minijail_wait(j));
1192 minijail_destroy(j);
1193 }
1194}
1195
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001196TEST_F(NamespaceTest, test_remount_all_private) {
1197 pid_t pid;
1198 int child_stdout;
1199 int mj_run_ret;
1200 ssize_t read_ret;
1201 char buf[kBufferSize];
1202 int status;
1203 char *argv[4];
1204 char uidmap[kBufferSize], gidmap[kBufferSize];
1205 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1206 constexpr gid_t kTargetGid = 1000;
1207
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001208 if (!userns_supported_)
1209 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001210
1211 struct minijail *j = minijail_new();
1212
1213 minijail_namespace_pids(j);
1214 minijail_namespace_vfs(j);
1215 minijail_run_as_init(j);
1216
1217 // Perform userns mapping.
1218 minijail_namespace_user(j);
1219 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1220 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1221 minijail_change_uid(j, kTargetUid);
1222 minijail_change_gid(j, kTargetGid);
1223 minijail_uidmap(j, uidmap);
1224 minijail_gidmap(j, gidmap);
1225 minijail_namespace_user_disable_setgroups(j);
1226
1227 minijail_namespace_vfs(j);
1228 minijail_remount_mode(j, MS_PRIVATE);
1229
1230 argv[0] = const_cast<char*>(kShellPath);
1231 argv[1] = "-c";
1232 argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
1233 "/proc/self/mountinfo";
1234 argv[3] = NULL;
1235 mj_run_ret = minijail_run_pid_pipes_no_preload(
1236 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1237 EXPECT_EQ(mj_run_ret, 0);
1238
1239 // There should be no output because all mounts should be remounted as
1240 // private.
1241 read_ret = read(child_stdout, buf, sizeof(buf));
1242 EXPECT_EQ(read_ret, 0);
1243
1244 // grep will exit with 1 if it does not find anything which is what we
1245 // expect.
1246 status = minijail_wait(j);
1247 EXPECT_EQ(status, 1);
1248
1249 minijail_destroy(j);
1250}
1251
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001252TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1253 int status;
1254 char uidmap[kBufferSize], gidmap[kBufferSize];
1255 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1256 constexpr gid_t kTargetGid = 1000;
1257
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001258 if (!userns_supported_)
1259 GTEST_SKIP();
Nicole Anderson-Aue119bbb2021-02-04 23:12:12 +00001260
1261 struct minijail *j = minijail_new();
1262
1263 minijail_namespace_pids(j);
1264 minijail_namespace_vfs(j);
1265 minijail_mount_tmp(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_SHARED);
1280 minijail_add_remount(j, "/proc", MS_PRIVATE);
1281
1282 char *argv[] = {"/bin/true", nullptr};
1283 minijail_run(j, argv[0], argv);
1284
1285 status = minijail_wait(j);
1286 EXPECT_GT(status, 0);
1287
1288 minijail_destroy(j);
1289}
1290
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001291TEST_F(NamespaceTest, test_remount_one_shared) {
1292 pid_t pid;
1293 int child_stdout;
1294 int mj_run_ret;
1295 ssize_t read_ret;
1296 char buf[kBufferSize * 4];
1297 int status;
1298 char *argv[4];
1299 char uidmap[kBufferSize], gidmap[kBufferSize];
1300 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1301 constexpr gid_t kTargetGid = 1000;
1302
Luis Héctor Chávez4f830bd2021-01-03 05:47:11 -08001303 if (!userns_supported_)
1304 GTEST_SKIP();
Nicole Anderson-Au835f7172021-01-13 21:18:13 +00001305
1306 struct minijail *j = minijail_new();
1307
1308 minijail_namespace_pids(j);
1309 minijail_namespace_vfs(j);
1310 minijail_mount_tmp(j);
1311 minijail_run_as_init(j);
1312
1313 // Perform userns mapping.
1314 minijail_namespace_user(j);
1315 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1316 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1317 minijail_change_uid(j, kTargetUid);
1318 minijail_change_gid(j, kTargetGid);
1319 minijail_uidmap(j, uidmap);
1320 minijail_gidmap(j, gidmap);
1321 minijail_namespace_user_disable_setgroups(j);
1322
1323 minijail_namespace_vfs(j);
1324 minijail_remount_mode(j, MS_PRIVATE);
1325 minijail_add_remount(j, "/proc", MS_SHARED);
1326
1327 argv[0] = const_cast<char*>(kShellPath);
1328 argv[1] = "-c";
1329 argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1330 argv[3] = NULL;
1331 mj_run_ret = minijail_run_pid_pipes_no_preload(
1332 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1333 EXPECT_EQ(mj_run_ret, 0);
1334
1335 // There should be no output because all mounts should be remounted as
1336 // private.
1337 read_ret = read(child_stdout, buf, sizeof(buf));
1338 EXPECT_GE(read_ret, 0);
1339 buf[read_ret] = '\0';
1340 EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1341
1342 status = minijail_wait(j);
1343 EXPECT_EQ(status, 0);
1344
1345 minijail_destroy(j);
1346}
1347
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001348void TestCreateSession(bool create_session) {
1349 int status;
1350 int pipe_fds[2];
1351 pid_t child_pid;
1352 pid_t parent_sid = getsid(0);
1353 ssize_t pid_size = sizeof(pid_t);
1354
1355 ScopedMinijail j(minijail_new());
1356 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1357 // a new session because of that.
1358 minijail_close_open_fds(j.get());
1359
1360 if (create_session)
1361 minijail_create_session(j.get());
1362
1363 ASSERT_EQ(pipe(pipe_fds), 0);
1364 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1365
1366 child_pid = minijail_fork(j.get());
1367 ASSERT_GE(child_pid, 0);
1368 if (child_pid == 0) {
1369 pid_t sid_in_parent;
1370 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1371 if (create_session)
1372 ASSERT_NE(sid_in_parent, getsid(0));
1373 else
1374 ASSERT_EQ(sid_in_parent, getsid(0));
1375 exit(0);
1376 }
1377
1378 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1379 waitpid(child_pid, &status, 0);
1380 ASSERT_TRUE(WIFEXITED(status));
1381 EXPECT_EQ(WEXITSTATUS(status), 0);
1382}
1383
1384TEST(Test, default_no_new_session) {
1385 TestCreateSession(/*create_session=*/false);
1386}
1387
1388TEST(Test, create_new_session) {
1389 TestCreateSession(/*create_session=*/true);
1390}