blob: 57c5b97caf79b4fa8ed63dbef3801ff1ec41ed58 [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 Hector Chavez86e10d32018-10-11 20:36:48 -070064 if (!f)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070065 pdie("fopen(%s)", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070066 pid_t ppid;
67 int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070068 fclose(f);
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070069 if (ret != 1) {
70 continue;
71 }
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070072 if (pids.find(ppid) == pids.end())
73 continue;
74 progress |= pids.insert(pid).second;
75 }
76 closedir(d);
77 } while (progress);
78 return pids;
79}
80
81std::map<std::string, std::string> GetNamespaces(
82 pid_t pid,
83 const std::vector<std::string>& namespace_names) {
84 std::map<std::string, std::string> namespaces;
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070085 char buf[kBufferSize];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070086 for (const auto& namespace_name : namespace_names) {
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070087 std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
88 ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070089 if (len == -1)
Luis Hector Chavezac0acf32018-10-15 09:45:01 -070090 pdie("readlink(\"%s\")", path.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -070091 namespaces.emplace(namespace_name, std::string(buf, len));
92 }
93 return namespaces;
94}
Mike Frysingerb2c12d12017-09-29 21:18:59 -040095
96} // namespace
97
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040098/* Silence unused variable warnings. */
99TEST(silence, silence_unused) {
100 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
101 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
102 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
103}
104
105TEST(consumebytes, zero) {
106 char buf[1024];
107 size_t len = sizeof(buf);
108 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400109 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400110 EXPECT_EQ(&buf[0], pos);
111 EXPECT_EQ(sizeof(buf), len);
112}
113
114TEST(consumebytes, exact) {
115 char buf[1024];
116 size_t len = sizeof(buf);
117 char *pos = &buf[0];
118 /* One past the end since it consumes the whole buffer. */
119 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400120 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400121 EXPECT_EQ((size_t)0, len);
122 EXPECT_EQ(end, pos);
123}
124
125TEST(consumebytes, half) {
126 char buf[1024];
127 size_t len = sizeof(buf);
128 char *pos = &buf[0];
129 /* One past the end since it consumes the whole buffer. */
130 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400131 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400132 EXPECT_EQ(sizeof(buf) / 2, len);
133 EXPECT_EQ(end, pos);
134}
135
136TEST(consumebytes, toolong) {
137 char buf[1024];
138 size_t len = sizeof(buf);
139 char *pos = &buf[0];
140 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400141 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400142 EXPECT_EQ(sizeof(buf), len);
143 EXPECT_EQ(&buf[0], pos);
144}
145
146TEST(consumestr, zero) {
147 char buf[1024];
148 size_t len = 0;
149 char *pos = &buf[0];
150 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400151 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400152 EXPECT_EQ((size_t)0, len);
153 EXPECT_EQ(&buf[0], pos);
154}
155
156TEST(consumestr, nonul) {
157 char buf[1024];
158 size_t len = sizeof(buf);
159 char *pos = &buf[0];
160 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400161 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400162 EXPECT_EQ(sizeof(buf), len);
163 EXPECT_EQ(&buf[0], pos);
164}
165
166TEST(consumestr, full) {
167 char buf[1024];
168 size_t len = sizeof(buf);
169 char *pos = &buf[0];
170 memset(buf, 0xff, sizeof(buf));
171 buf[sizeof(buf)-1] = '\0';
172 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
173 EXPECT_EQ((size_t)0, len);
174 EXPECT_EQ(&buf[sizeof(buf)], pos);
175}
176
177TEST(consumestr, trailing_nul) {
178 char buf[1024];
179 size_t len = sizeof(buf) - 1;
180 char *pos = &buf[0];
181 memset(buf, 0xff, sizeof(buf));
182 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400183 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400184 EXPECT_EQ(sizeof(buf) - 1, len);
185 EXPECT_EQ(&buf[0], pos);
186}
187
188class MarshalTest : public ::testing::Test {
189 protected:
190 virtual void SetUp() {
191 m_ = minijail_new();
192 j_ = minijail_new();
193 size_ = minijail_size(m_);
194 }
195 virtual void TearDown() {
196 minijail_destroy(m_);
197 minijail_destroy(j_);
198 }
199
200 char buf_[4096];
201 struct minijail *m_;
202 struct minijail *j_;
203 size_t size_;
204};
205
206TEST_F(MarshalTest, empty) {
207 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
208 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
209}
210
211TEST_F(MarshalTest, 0xff) {
212 memset(buf_, 0xff, sizeof(buf_));
213 /* Should fail on the first consumestr since a NUL will never be found. */
214 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
215}
216
François Degros47e63352019-10-01 13:01:53 +1000217TEST(KillTest, running_process) {
218 const ScopedMinijail j(minijail_new());
219 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
220 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
221 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
222 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
223}
224
225TEST(KillTest, process_already_awaited) {
226 const ScopedMinijail j(minijail_new());
227 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
228 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
229 EXPECT_EQ(minijail_wait(j.get()), 42);
230 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
231}
232
233TEST(KillTest, process_already_finished_but_not_awaited) {
234 int fds[2];
235 const ScopedMinijail j(minijail_new());
236 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
237 ASSERT_EQ(pipe(fds), 0);
238 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
239 ASSERT_EQ(close(fds[1]), 0);
240 // Wait for process to finish.
241 char buf[PIPE_BUF];
242 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
243 EXPECT_EQ(minijail_kill(j.get()), 42);
244 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
245}
246
247TEST(KillTest, process_not_started) {
248 const ScopedMinijail j(minijail_new());
249 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
250}
251
François Degros08b10f72019-10-09 12:44:05 +1100252TEST(WaitTest, return_zero) {
253 const ScopedMinijail j(minijail_new());
254 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
255 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
256 EXPECT_EQ(minijail_wait(j.get()), 0);
257}
258
259TEST(WaitTest, return_max) {
260 const ScopedMinijail j(minijail_new());
261 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
262 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
263 EXPECT_EQ(minijail_wait(j.get()), 255);
264}
265
266TEST(WaitTest, return_modulo) {
267 const ScopedMinijail j(minijail_new());
268 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
269 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
270 EXPECT_EQ(minijail_wait(j.get()), 0);
271}
272
273TEST(WaitTest, killed_by_sigkill) {
274 const ScopedMinijail j(minijail_new());
275 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
276 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
277 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
278}
279
280TEST(WaitTest, killed_by_sigsys) {
281 const ScopedMinijail j(minijail_new());
282 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
283 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
284 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
285}
286
287TEST(WaitTest, command_not_found) {
288 const ScopedMinijail j(minijail_new());
289 char* const argv[] = {"whatever", nullptr};
290 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
291 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
292}
293
294TEST(WaitTest, command_not_run) {
295 const ScopedMinijail j(minijail_new());
296 char* const argv[] = {"whatever", nullptr};
297 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
298 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
299}
300
301TEST(WaitTest, no_process) {
302 const ScopedMinijail j(minijail_new());
303 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
304}
305
306TEST(WaitTest, can_wait_only_once) {
307 const ScopedMinijail j(minijail_new());
308 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
309 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
310 EXPECT_EQ(minijail_wait(j.get()), 0);
311 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
312}
313
François Degros26f8e4e2020-04-17 09:31:02 +1000314TEST(Test, minijail_preserve_fd_no_leak) {
315 const ScopedMinijail j(minijail_new());
316 char* const script = R"(
317 echo Hi >&1;
318 exec 1>&-;
319 read line1;
320 read line2;
321 echo "$line1$line2 and Goodbye" >&2;
322 exit 42;
323 )";
324 char* const argv[] = {"sh", "-c", script, nullptr};
325
326 const int npipes = 3;
327 int fds[npipes][2];
328
329 // Create pipes.
330 for (int i = 0; i < npipes; ++i) {
331 ASSERT_EQ(pipe(fds[i]), 0);
332 }
333
334 // All pipes are output pipes except for the first one which is used as
335 // input pipe.
336 std::swap(fds[0][0], fds[0][1]);
337
338 for (int i = 0; i < npipes; ++i) {
339 const int fd = fds[i][1];
340 minijail_preserve_fd(j.get(), fd, i);
341 }
342
343 minijail_close_open_fds(j.get());
344
345 EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
346
347 // Close unused end of pipes.
348 for (int i = 0; i < npipes; ++i) {
349 const int fd = fds[i][1];
350 ASSERT_EQ(close(fd), 0);
351 }
352
353 const int in = fds[0][0];
354 const int out = fds[1][0];
355 const int err = fds[2][0];
356
357 char buf[PIPE_BUF];
358 ssize_t nbytes;
359
360 // Check that stdout pipe works.
361 nbytes = read(out, buf, PIPE_BUF);
362 ASSERT_GT(nbytes, 0);
363 EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
364
365 // Check that the write end of stdout pipe got closed by the child process. If
366 // the child process kept other file descriptors connected to stdout, then the
367 // parent process wouldn't be able to detect that all write ends of this pipe
368 // are closed and it would block here.
369 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
370 ASSERT_EQ(close(out), 0);
371
372 // Check that stdin pipe works.
373 const std::string s = "Greetings\n";
374 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
375
376 // Close write end of pipe connected to child's stdin. If there was another
377 // file descriptor connected to this write end, then the child process
378 // wouldn't be able to detect that this write end is closed and it would
379 // block.
380 ASSERT_EQ(close(in), 0);
381
382 // Check that child process continued and ended.
383 nbytes = read(err, buf, PIPE_BUF);
384 ASSERT_GT(nbytes, 0);
385 EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
386
387 // Check that the write end of the stderr pipe is closed when the child
388 // process finishes.
389 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
390 ASSERT_EQ(close(err), 0);
391
392 // Check the child process termination status.
393 EXPECT_EQ(minijail_wait(j.get()), 42);
394}
395
François Degrosa8be2c42019-10-01 12:06:42 +1000396TEST(Test, close_original_pipes_after_dup2) {
397 // Pipe used by child process to signal that it continued after reading from
398 // stdin.
399 int to_wait[2];
400 ASSERT_EQ(pipe(to_wait), 0);
401
402 const ScopedMinijail j(minijail_new());
403 char* program;
404 ASSERT_GT(asprintf(&program, R"(
405 echo Hi >&1;
406 echo There >&2;
407 exec 1>&-;
408 exec 2>&-;
409 read line1;
410 read line2;
411 echo "$line1$line2 and Goodbye" >&%d;
412 exit 42;
413 )", to_wait[1]), 0);
François Degros87f0e832019-10-10 10:22:39 +1100414 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000415
416 int in = -1;
417 int out = -1;
418 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400419 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
420 nullptr, &in, &out, &err),
421 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000422 free(program);
423
424 EXPECT_GT(in, 0);
425 EXPECT_GT(out, 0);
426 EXPECT_GT(err, 0);
427
428 char buf[PIPE_BUF];
429 ssize_t n;
430
431 // Check that stdout and stderr pipes work.
432 n = read(out, buf, PIPE_BUF);
433 ASSERT_GT(n, 0);
434 EXPECT_EQ(std::string(buf, n), "Hi\n");
435
436 n = read(err, buf, PIPE_BUF);
437 ASSERT_GT(n, 0);
438 EXPECT_EQ(std::string(buf, n), "There\n");
439
440 // Check that the write ends of stdout and stderr pipes got closed by the
441 // child process. If the child process kept other file descriptors connected
442 // to stdout and stderr, then the parent process wouldn't be able to detect
443 // that all write ends of these pipes are closed and it would block here.
444 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000445 ASSERT_EQ(close(out), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000446 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
François Degros26f8e4e2020-04-17 09:31:02 +1000447 ASSERT_EQ(close(err), 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000448
449 // Check that stdin pipe works.
450 const std::string s = "Greetings\n";
451 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
452
453 // Close write end of pipe connected to child's stdin. If there was another
454 // file descriptor connected to this write end, then the child wouldn't be
455 // able to detect that this write end is closed and it would block.
456 ASSERT_EQ(close(in), 0);
457
458 // Check that child process continued and ended.
459 n = read(to_wait[0], buf, PIPE_BUF);
460 ASSERT_GT(n, 0);
461 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
462 EXPECT_EQ(minijail_wait(j.get()), 42);
463}
464
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100465TEST(Test, minijail_run_env_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700466 // TODO(crbug.com/895875): The preload library interferes with ASan since they
467 // both need to use LD_PRELOAD.
468 if (running_with_asan()) {
469 SUCCEED();
470 return;
471 }
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700472
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700473 ScopedMinijail j(minijail_new());
474 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700475
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100476 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700477 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100478 argv[1] = NULL;
479
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700480 pid_t pid;
481 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100482 int mj_run_ret = minijail_run_pid_pipes(
483 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700484 EXPECT_EQ(mj_run_ret, 0);
485
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100486 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700487 const size_t teststr_len = strlen(teststr);
488 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
489 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
490
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100491 char buf[kBufferSize] = {};
492 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700493 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100494 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700495
496 int status;
497 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100498 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700499 ASSERT_TRUE(WIFSIGNALED(status));
500 EXPECT_EQ(WTERMSIG(status), SIGTERM);
501
502 argv[0] = const_cast<char*>(kShellPath);
503 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100504 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700505 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700506
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500507 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100508 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500509 envp[1] = NULL;
510
511 // Set a canary env var in the parent that should not be present in the child.
512 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
513
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100514 int child_stderr;
515 mj_run_ret =
516 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
517 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500518 EXPECT_EQ(mj_run_ret, 0);
519
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100520 memset(buf, 0, sizeof(buf));
521 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
522 EXPECT_GE(read_ret, 0);
523 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500524
525 EXPECT_EQ(waitpid(pid, &status, 0), pid);
526 ASSERT_TRUE(WIFEXITED(status));
527 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100528}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500529
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800530TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
531 // TODO(crbug.com/895875): The preload library interferes with ASan since they
532 // both need to use LD_PRELOAD.
533 if (running_with_asan()) {
534 SUCCEED();
535 return;
536 }
537
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100538 ScopedMinijail j(minijail_new());
539
540 char *argv[4];
541 argv[0] = const_cast<char*>(kCatPath);
542 argv[1] = NULL;
543
544 pid_t pid;
545 int child_stdin, child_stdout;
546 int mj_run_ret = minijail_run_pid_pipes(
547 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
548 EXPECT_EQ(mj_run_ret, 0);
549
550 char teststr[] = "test\n";
551 const size_t teststr_len = strlen(teststr);
552 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
553 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
554
555 char buf[kBufferSize] = {};
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800556 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100557 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
558 EXPECT_STREQ(buf, teststr);
559
560 int status;
561 EXPECT_EQ(kill(pid, SIGTERM), 0);
562 EXPECT_EQ(waitpid(pid, &status, 0), pid);
563 ASSERT_TRUE(WIFSIGNALED(status));
564 EXPECT_EQ(WTERMSIG(status), SIGTERM);
565
566 argv[0] = const_cast<char*>(kShellPath);
567 argv[1] = "-c";
568 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
569 argv[3] = nullptr;
570
571 char *envp[2];
572 envp[0] = "TEST_VAR=test";
573 envp[1] = NULL;
574
575 // Set a canary env var in the parent that should not be present in the child.
576 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
577
Dylan Reid83276a02020-06-10 15:17:13 -0700578 // Use the preload library from this test build.
579 ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
580
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100581 int child_stderr;
582 mj_run_ret =
583 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
584 &child_stdin, &child_stdout, &child_stderr);
585 EXPECT_EQ(mj_run_ret, 0);
586
587 memset(buf, 0, sizeof(buf));
Luis Héctor Chávez4baeafa2021-01-03 05:47:13 -0800588 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100589 EXPECT_GE(read_ret, 0);
590 EXPECT_STREQ(buf, "|test\n");
591
592 EXPECT_EQ(waitpid(pid, &status, 0), pid);
593 ASSERT_TRUE(WIFEXITED(status));
594 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500595}
596
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400597TEST(Test, test_minijail_no_fd_leaks) {
598 pid_t pid;
599 int child_stdout;
600 int mj_run_ret;
601 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700602 char buf[kBufferSize];
603 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400604 int status;
605 char *argv[4];
606
607 int dev_null = open("/dev/null", O_RDONLY);
608 ASSERT_NE(dev_null, -1);
609 snprintf(script,
610 sizeof(script),
611 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
612 dev_null);
613
614 struct minijail *j = minijail_new();
615
François Degros87f0e832019-10-10 10:22:39 +1100616 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400617 argv[1] = "-c";
618 argv[2] = script;
619 argv[3] = NULL;
620 mj_run_ret = minijail_run_pid_pipes_no_preload(
621 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
622 EXPECT_EQ(mj_run_ret, 0);
623
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700624 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400625 EXPECT_GE(read_ret, 0);
626 buf[read_ret] = '\0';
627 EXPECT_STREQ(buf, "yes\n");
628
629 waitpid(pid, &status, 0);
630 ASSERT_TRUE(WIFEXITED(status));
631 EXPECT_EQ(WEXITSTATUS(status), 0);
632
633 minijail_close_open_fds(j);
634 mj_run_ret = minijail_run_pid_pipes_no_preload(
635 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
636 EXPECT_EQ(mj_run_ret, 0);
637
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700638 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400639 EXPECT_GE(read_ret, 0);
640 buf[read_ret] = '\0';
641 EXPECT_STREQ(buf, "no\n");
642
643 waitpid(pid, &status, 0);
644 ASSERT_TRUE(WIFEXITED(status));
645 EXPECT_EQ(WEXITSTATUS(status), 0);
646
647 minijail_destroy(j);
648
649 close(dev_null);
650}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100651
Dylan Reid0412dcc2017-08-24 11:33:15 -0700652TEST(Test, test_minijail_fork) {
653 pid_t mj_fork_ret;
654 int status;
655 int pipe_fds[2];
656 ssize_t pid_size = sizeof(mj_fork_ret);
657
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700658 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700659
660 ASSERT_EQ(pipe(pipe_fds), 0);
661
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700662 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700663 ASSERT_GE(mj_fork_ret, 0);
664 if (mj_fork_ret == 0) {
665 pid_t pid_in_parent;
666 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700667 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
668 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700669 exit(0);
670 }
671
672 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
673 waitpid(mj_fork_ret, &status, 0);
674 ASSERT_TRUE(WIFEXITED(status));
675 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700676}
677
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700678static int early_exit(void* payload) {
679 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
680}
681
682TEST(Test, test_minijail_callback) {
683 pid_t pid;
684 int mj_run_ret;
685 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700686 char *argv[2];
687 int exit_code = 42;
688
689 struct minijail *j = minijail_new();
690
691 status =
692 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500693 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700694 EXPECT_EQ(status, 0);
695
François Degros87f0e832019-10-10 10:22:39 +1100696 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700697 argv[1] = NULL;
698 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500699 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700700 EXPECT_EQ(mj_run_ret, 0);
701
702 status = minijail_wait(j);
703 EXPECT_EQ(status, exit_code);
704
705 minijail_destroy(j);
706}
707
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700708TEST(Test, test_minijail_preserve_fd) {
709 int mj_run_ret;
710 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700711 char *argv[2];
712 char teststr[] = "test\n";
713 size_t teststr_len = strlen(teststr);
714 int read_pipe[2];
715 int write_pipe[2];
716 char buf[1024];
717
718 struct minijail *j = minijail_new();
719
720 status = pipe(read_pipe);
721 ASSERT_EQ(status, 0);
722 status = pipe(write_pipe);
723 ASSERT_EQ(status, 0);
724
725 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
726 ASSERT_EQ(status, 0);
727 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
728 ASSERT_EQ(status, 0);
729 minijail_close_open_fds(j);
730
François Degros87f0e832019-10-10 10:22:39 +1100731 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700732 argv[1] = NULL;
733 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
734 EXPECT_EQ(mj_run_ret, 0);
735
736 close(write_pipe[0]);
737 status = write(write_pipe[1], teststr, teststr_len);
738 EXPECT_EQ(status, (int)teststr_len);
739 close(write_pipe[1]);
740
741 close(read_pipe[1]);
742 status = read(read_pipe[0], buf, 8);
743 EXPECT_EQ(status, (int)teststr_len);
744 buf[teststr_len] = 0;
745 EXPECT_EQ(strcmp(buf, teststr), 0);
746
747 status = minijail_wait(j);
748 EXPECT_EQ(status, 0);
749
750 minijail_destroy(j);
751}
752
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700753TEST(Test, test_minijail_reset_signal_mask) {
754 struct minijail *j = minijail_new();
755
756 sigset_t original_signal_mask;
757 {
758 sigset_t signal_mask;
759 ASSERT_EQ(0, sigemptyset(&signal_mask));
760 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
761 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
762 }
763
764 minijail_reset_signal_mask(j);
765
766 pid_t mj_fork_ret = minijail_fork(j);
767 ASSERT_GE(mj_fork_ret, 0);
768 if (mj_fork_ret == 0) {
769 sigset_t signal_mask;
770 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
771 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400772 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700773 exit(0);
774 }
775
776 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
777
778 int status;
779 waitpid(mj_fork_ret, &status, 0);
780 ASSERT_TRUE(WIFEXITED(status));
781 EXPECT_EQ(WEXITSTATUS(status), 0);
782
783 minijail_destroy(j);
784}
785
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700786TEST(Test, test_minijail_reset_signal_handlers) {
787 struct minijail *j = minijail_new();
788
789 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
790 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
791 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
792
793 minijail_reset_signal_handlers(j);
794
795 pid_t mj_fork_ret = minijail_fork(j);
796 ASSERT_GE(mj_fork_ret, 0);
797 if (mj_fork_ret == 0) {
798 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400799 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700800 exit(0);
801 }
802
803 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
804
805 int status;
806 waitpid(mj_fork_ret, &status, 0);
807 ASSERT_TRUE(WIFEXITED(status));
808 EXPECT_EQ(WEXITSTATUS(status), 0);
809
810 minijail_destroy(j);
811}
812
Mike Frysinger780aef72017-10-03 01:39:52 -0400813namespace {
814
815// Tests that require userns access.
816// Android unit tests don't currently support entering user namespaces as
817// unprivileged users due to having an older kernel. Chrome OS unit tests
818// don't support it either due to being in a chroot environment (see man 2
819// clone for more information about failure modes with the CLONE_NEWUSER flag).
820class NamespaceTest : public ::testing::Test {
821 protected:
822 static void SetUpTestCase() {
823 userns_supported_ = UsernsSupported();
824 }
825
826 // Whether userns is supported.
827 static bool userns_supported_;
828
829 static bool UsernsSupported() {
830 pid_t pid = fork();
831 if (pid == -1)
832 pdie("could not fork");
833
834 if (pid == 0)
835 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
836
837 int status;
838 if (waitpid(pid, &status, 0) < 0)
839 pdie("could not wait");
840
841 if (!WIFEXITED(status))
842 die("child did not exit properly: %#x", status);
843
844 bool ret = WEXITSTATUS(status) == 0;
845 if (!ret)
846 warn("Skipping userns related tests");
847 return ret;
848 }
849};
850
851bool NamespaceTest::userns_supported_;
852
853} // namespace
854
855TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700856 int mj_run_ret;
857 int status;
858 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700859 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700860 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
861 constexpr gid_t kTargetGid = 1000;
862
Mike Frysinger780aef72017-10-03 01:39:52 -0400863 if (!userns_supported_) {
864 SUCCEED();
865 return;
866 }
867
Luis Hector Chavez71323552017-09-05 09:17:22 -0700868 struct minijail *j = minijail_new();
869
870 minijail_namespace_pids(j);
871 minijail_namespace_vfs(j);
872 minijail_mount_tmp(j);
873 minijail_run_as_init(j);
874
875 // Perform userns mapping.
876 minijail_namespace_user(j);
877 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
878 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
879 minijail_change_uid(j, kTargetUid);
880 minijail_change_gid(j, kTargetGid);
881 minijail_uidmap(j, uidmap);
882 minijail_gidmap(j, gidmap);
883 minijail_namespace_user_disable_setgroups(j);
884
François Degros87f0e832019-10-10 10:22:39 +1100885 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -0700886 argv[1] = "-c";
887 argv[2] = "exec touch /tmp/foo";
888 argv[3] = NULL;
889 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
890 EXPECT_EQ(mj_run_ret, 0);
891
892 status = minijail_wait(j);
893 EXPECT_EQ(status, 0);
894
895 minijail_destroy(j);
896}
897
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700898TEST_F(NamespaceTest, test_namespaces) {
899 constexpr char teststr[] = "test\n";
900
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700901 // TODO(crbug.com/895875): The preload library interferes with ASan since they
902 // both need to use LD_PRELOAD.
903 if (!userns_supported_ || running_with_asan()) {
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700904 SUCCEED();
905 return;
906 }
907
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700908 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
909 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700910
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700911 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
912 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700913 // Grab the set of namespaces outside the container.
914 std::map<std::string, std::string> init_namespaces =
915 GetNamespaces(getpid(), namespace_names);
916 std::function<void(struct minijail*)> test_functions[] = {
917 [](struct minijail* j attribute_unused) {},
918 [](struct minijail* j) {
919 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
920 minijail_enter_pivot_root(j, "/tmp");
921 },
922 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
923 };
924
925 // This test is run with and without the preload library.
926 for (const auto& run_function :
927 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
928 for (const auto& test_function : test_functions) {
929 ScopedMinijail j(minijail_new());
930 minijail_set_preload_path(j.get(), kPreloadPath);
931
932 // Enter all the namespaces we can.
933 minijail_namespace_cgroups(j.get());
934 minijail_namespace_net(j.get());
935 minijail_namespace_pids(j.get());
936 minijail_namespace_user(j.get());
937 minijail_namespace_vfs(j.get());
938 minijail_namespace_uts(j.get());
939
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700940 // Set up the user namespace.
941 minijail_uidmap(j.get(), uidmap.c_str());
942 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700943 minijail_namespace_user_disable_setgroups(j.get());
944
945 minijail_close_open_fds(j.get());
946 test_function(j.get());
947
François Degros87f0e832019-10-10 10:22:39 +1100948 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700949 pid_t container_pid;
950 int child_stdin, child_stdout;
951 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +1100952 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700953 &container_pid, &child_stdin, &child_stdout, nullptr);
954 EXPECT_EQ(mj_run_ret, 0);
955
956 // Send some data to stdin and read it back to ensure that the child
957 // process is running.
958 const size_t teststr_len = strlen(teststr);
959 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
960 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
961
962 char buf[kBufferSize];
963 ssize_t read_ret = read(child_stdout, buf, 8);
964 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
965 buf[teststr_len] = 0;
966 EXPECT_EQ(strcmp(buf, teststr), 0);
967
968 // Grab the set of namespaces in every container process. They must not
969 // match the ones in the init namespace, and they must all match each
970 // other.
971 std::map<std::string, std::string> container_namespaces =
972 GetNamespaces(container_pid, namespace_names);
973 EXPECT_NE(container_namespaces, init_namespaces);
974 for (pid_t pid : GetProcessSubtreePids(container_pid))
975 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
976
977 EXPECT_EQ(0, close(child_stdin));
978
979 int status = minijail_wait(j.get());
980 EXPECT_EQ(status, 0);
981 }
982 }
983}
984
Mike Frysinger902a4492018-12-27 05:22:56 -0500985TEST_F(NamespaceTest, test_enter_ns) {
986 char uidmap[kBufferSize], gidmap[kBufferSize];
987
988 if (!userns_supported_) {
989 SUCCEED();
990 return;
991 }
992
993 // We first create a child in a new userns so we have privs to run more tests.
994 // We can't combine the steps as the kernel disallows many resource sharing
995 // from outside the userns.
996 struct minijail *j = minijail_new();
997
998 minijail_namespace_vfs(j);
999 minijail_namespace_pids(j);
1000 minijail_run_as_init(j);
1001
1002 // Perform userns mapping.
1003 minijail_namespace_user(j);
1004 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1005 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1006 minijail_uidmap(j, uidmap);
1007 minijail_gidmap(j, gidmap);
1008 minijail_namespace_user_disable_setgroups(j);
1009
1010 pid_t pid = minijail_fork(j);
1011 if (pid == 0) {
1012 // Child.
1013 minijail_destroy(j);
1014
1015 // Create new namespaces inside this userns which we may enter.
1016 j = minijail_new();
1017 minijail_namespace_net(j);
1018 minijail_namespace_vfs(j);
1019 pid = minijail_fork(j);
1020 if (pid == 0) {
1021 // Child.
1022 minijail_destroy(j);
1023
1024 // Finally enter those namespaces.
1025 j = minijail_new();
1026
1027 // We need to get the absolute path because entering a new mntns will
1028 // implicitly chdir(/) for us.
1029 char *path = realpath(kPreloadPath, nullptr);
1030 ASSERT_NE(nullptr, path);
1031 minijail_set_preload_path(j, path);
1032
1033 minijail_namespace_net(j);
1034 minijail_namespace_vfs(j);
1035
1036 minijail_namespace_enter_net(j, "/proc/self/ns/net");
1037 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1038
1039 char *argv[] = {"/bin/true", nullptr};
1040 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1041 EXPECT_EQ(0, minijail_wait(j));
1042 minijail_destroy(j);
1043 exit(0);
1044 } else {
1045 ASSERT_GT(pid, 0);
1046 EXPECT_EQ(0, minijail_wait(j));
1047 minijail_destroy(j);
1048 exit(0);
1049 }
1050 } else {
1051 ASSERT_GT(pid, 0);
1052 EXPECT_EQ(0, minijail_wait(j));
1053 minijail_destroy(j);
1054 }
1055}
1056
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001057void TestCreateSession(bool create_session) {
1058 int status;
1059 int pipe_fds[2];
1060 pid_t child_pid;
1061 pid_t parent_sid = getsid(0);
1062 ssize_t pid_size = sizeof(pid_t);
1063
1064 ScopedMinijail j(minijail_new());
1065 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1066 // a new session because of that.
1067 minijail_close_open_fds(j.get());
1068
1069 if (create_session)
1070 minijail_create_session(j.get());
1071
1072 ASSERT_EQ(pipe(pipe_fds), 0);
1073 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1074
1075 child_pid = minijail_fork(j.get());
1076 ASSERT_GE(child_pid, 0);
1077 if (child_pid == 0) {
1078 pid_t sid_in_parent;
1079 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1080 if (create_session)
1081 ASSERT_NE(sid_in_parent, getsid(0));
1082 else
1083 ASSERT_EQ(sid_in_parent, getsid(0));
1084 exit(0);
1085 }
1086
1087 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1088 waitpid(child_pid, &status, 0);
1089 ASSERT_TRUE(WIFEXITED(status));
1090 EXPECT_EQ(WEXITSTATUS(status), 0);
1091}
1092
1093TEST(Test, default_no_new_session) {
1094 TestCreateSession(/*create_session=*/false);
1095}
1096
1097TEST(Test, create_new_session) {
1098 TestCreateSession(/*create_session=*/true);
1099}