blob: d8ffc3819440afc1dff905b1ef0175d2932dc4b2 [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/* Prototypes needed only by test. */
Martin Pelikánab9eb442017-01-25 11:53:58 +110099size_t minijail_get_tmpfs_size(const struct minijail *);
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400100
101/* Silence unused variable warnings. */
102TEST(silence, silence_unused) {
103 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
104 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
105 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
106}
107
108TEST(consumebytes, zero) {
109 char buf[1024];
110 size_t len = sizeof(buf);
111 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400112 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400113 EXPECT_EQ(&buf[0], pos);
114 EXPECT_EQ(sizeof(buf), len);
115}
116
117TEST(consumebytes, exact) {
118 char buf[1024];
119 size_t len = sizeof(buf);
120 char *pos = &buf[0];
121 /* One past the end since it consumes the whole buffer. */
122 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400123 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400124 EXPECT_EQ((size_t)0, len);
125 EXPECT_EQ(end, pos);
126}
127
128TEST(consumebytes, half) {
129 char buf[1024];
130 size_t len = sizeof(buf);
131 char *pos = &buf[0];
132 /* One past the end since it consumes the whole buffer. */
133 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400134 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400135 EXPECT_EQ(sizeof(buf) / 2, len);
136 EXPECT_EQ(end, pos);
137}
138
139TEST(consumebytes, toolong) {
140 char buf[1024];
141 size_t len = sizeof(buf);
142 char *pos = &buf[0];
143 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400144 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400145 EXPECT_EQ(sizeof(buf), len);
146 EXPECT_EQ(&buf[0], pos);
147}
148
149TEST(consumestr, zero) {
150 char buf[1024];
151 size_t len = 0;
152 char *pos = &buf[0];
153 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400154 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400155 EXPECT_EQ((size_t)0, len);
156 EXPECT_EQ(&buf[0], pos);
157}
158
159TEST(consumestr, nonul) {
160 char buf[1024];
161 size_t len = sizeof(buf);
162 char *pos = &buf[0];
163 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400164 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400165 EXPECT_EQ(sizeof(buf), len);
166 EXPECT_EQ(&buf[0], pos);
167}
168
169TEST(consumestr, full) {
170 char buf[1024];
171 size_t len = sizeof(buf);
172 char *pos = &buf[0];
173 memset(buf, 0xff, sizeof(buf));
174 buf[sizeof(buf)-1] = '\0';
175 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
176 EXPECT_EQ((size_t)0, len);
177 EXPECT_EQ(&buf[sizeof(buf)], pos);
178}
179
180TEST(consumestr, trailing_nul) {
181 char buf[1024];
182 size_t len = sizeof(buf) - 1;
183 char *pos = &buf[0];
184 memset(buf, 0xff, sizeof(buf));
185 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400186 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400187 EXPECT_EQ(sizeof(buf) - 1, len);
188 EXPECT_EQ(&buf[0], pos);
189}
190
191class MarshalTest : public ::testing::Test {
192 protected:
193 virtual void SetUp() {
194 m_ = minijail_new();
195 j_ = minijail_new();
196 size_ = minijail_size(m_);
197 }
198 virtual void TearDown() {
199 minijail_destroy(m_);
200 minijail_destroy(j_);
201 }
202
203 char buf_[4096];
204 struct minijail *m_;
205 struct minijail *j_;
206 size_t size_;
207};
208
209TEST_F(MarshalTest, empty) {
210 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
211 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
212}
213
214TEST_F(MarshalTest, 0xff) {
215 memset(buf_, 0xff, sizeof(buf_));
216 /* Should fail on the first consumestr since a NUL will never be found. */
217 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
218}
219
François Degros47e63352019-10-01 13:01:53 +1000220TEST(KillTest, running_process) {
221 const ScopedMinijail j(minijail_new());
222 char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
223 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
224 EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
225 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
226}
227
228TEST(KillTest, process_already_awaited) {
229 const ScopedMinijail j(minijail_new());
230 char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
231 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
232 EXPECT_EQ(minijail_wait(j.get()), 42);
233 EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
234}
235
236TEST(KillTest, process_already_finished_but_not_awaited) {
237 int fds[2];
238 const ScopedMinijail j(minijail_new());
239 char* const argv[] = {"sh", "-c", "exit 42", nullptr};
240 ASSERT_EQ(pipe(fds), 0);
241 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
242 ASSERT_EQ(close(fds[1]), 0);
243 // Wait for process to finish.
244 char buf[PIPE_BUF];
245 EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
246 EXPECT_EQ(minijail_kill(j.get()), 42);
247 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
248}
249
250TEST(KillTest, process_not_started) {
251 const ScopedMinijail j(minijail_new());
252 EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
253}
254
François Degros08b10f72019-10-09 12:44:05 +1100255TEST(WaitTest, return_zero) {
256 const ScopedMinijail j(minijail_new());
257 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
258 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
259 EXPECT_EQ(minijail_wait(j.get()), 0);
260}
261
262TEST(WaitTest, return_max) {
263 const ScopedMinijail j(minijail_new());
264 char* const argv[] = {"sh", "-c", "exit 255", nullptr};
265 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
266 EXPECT_EQ(minijail_wait(j.get()), 255);
267}
268
269TEST(WaitTest, return_modulo) {
270 const ScopedMinijail j(minijail_new());
271 char* const argv[] = {"sh", "-c", "exit 256", nullptr};
272 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
273 EXPECT_EQ(minijail_wait(j.get()), 0);
274}
275
276TEST(WaitTest, killed_by_sigkill) {
277 const ScopedMinijail j(minijail_new());
278 char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
279 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
280 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
281}
282
283TEST(WaitTest, killed_by_sigsys) {
284 const ScopedMinijail j(minijail_new());
285 char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
286 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
287 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
288}
289
290TEST(WaitTest, command_not_found) {
291 const ScopedMinijail j(minijail_new());
292 char* const argv[] = {"whatever", nullptr};
293 EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
294 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
295}
296
297TEST(WaitTest, command_not_run) {
298 const ScopedMinijail j(minijail_new());
299 char* const argv[] = {"whatever", nullptr};
300 EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
301 EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
302}
303
304TEST(WaitTest, no_process) {
305 const ScopedMinijail j(minijail_new());
306 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
307}
308
309TEST(WaitTest, can_wait_only_once) {
310 const ScopedMinijail j(minijail_new());
311 char* const argv[] = {"sh", "-c", "exit 0", nullptr};
312 EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
313 EXPECT_EQ(minijail_wait(j.get()), 0);
314 EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
315}
316
François Degrosa8be2c42019-10-01 12:06:42 +1000317TEST(Test, close_original_pipes_after_dup2) {
318 // Pipe used by child process to signal that it continued after reading from
319 // stdin.
320 int to_wait[2];
321 ASSERT_EQ(pipe(to_wait), 0);
322
323 const ScopedMinijail j(minijail_new());
324 char* program;
325 ASSERT_GT(asprintf(&program, R"(
326 echo Hi >&1;
327 echo There >&2;
328 exec 1>&-;
329 exec 2>&-;
330 read line1;
331 read line2;
332 echo "$line1$line2 and Goodbye" >&%d;
333 exit 42;
334 )", to_wait[1]), 0);
François Degros87f0e832019-10-10 10:22:39 +1100335 char* const argv[] = {"sh", "-c", program, nullptr};
François Degrosa8be2c42019-10-01 12:06:42 +1000336
337 int in = -1;
338 int out = -1;
339 int err = -1;
Jorge Lucangeli Obes7c696e42019-10-24 11:19:51 -0400340 EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
341 nullptr, &in, &out, &err),
342 0);
François Degrosa8be2c42019-10-01 12:06:42 +1000343 free(program);
344
345 EXPECT_GT(in, 0);
346 EXPECT_GT(out, 0);
347 EXPECT_GT(err, 0);
348
349 char buf[PIPE_BUF];
350 ssize_t n;
351
352 // Check that stdout and stderr pipes work.
353 n = read(out, buf, PIPE_BUF);
354 ASSERT_GT(n, 0);
355 EXPECT_EQ(std::string(buf, n), "Hi\n");
356
357 n = read(err, buf, PIPE_BUF);
358 ASSERT_GT(n, 0);
359 EXPECT_EQ(std::string(buf, n), "There\n");
360
361 // Check that the write ends of stdout and stderr pipes got closed by the
362 // child process. If the child process kept other file descriptors connected
363 // to stdout and stderr, then the parent process wouldn't be able to detect
364 // that all write ends of these pipes are closed and it would block here.
365 EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
366 EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
367
368 // Check that stdin pipe works.
369 const std::string s = "Greetings\n";
370 EXPECT_EQ(write(in, s.data(), s.size()), s.size());
371
372 // Close write end of pipe connected to child's stdin. If there was another
373 // file descriptor connected to this write end, then the child wouldn't be
374 // able to detect that this write end is closed and it would block.
375 ASSERT_EQ(close(in), 0);
376
377 // Check that child process continued and ended.
378 n = read(to_wait[0], buf, PIPE_BUF);
379 ASSERT_GT(n, 0);
380 EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
381 EXPECT_EQ(minijail_wait(j.get()), 42);
382}
383
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700384TEST(Test, minijail_run_pid_pipes) {
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700385 // TODO(crbug.com/895875): The preload library interferes with ASan since they
386 // both need to use LD_PRELOAD.
387 if (running_with_asan()) {
388 SUCCEED();
389 return;
390 }
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700391 constexpr char teststr[] = "test\n";
392
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700393 ScopedMinijail j(minijail_new());
394 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700395
396 char* argv[4];
397 argv[0] = const_cast<char*>(kCatPath);
398 argv[1] = nullptr;
399 pid_t pid;
400 int child_stdin, child_stdout;
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700401 int mj_run_ret = minijail_run_pid_pipes(j.get(), argv[0], argv, &pid,
402 &child_stdin, &child_stdout, nullptr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700403 EXPECT_EQ(mj_run_ret, 0);
404
405 const size_t teststr_len = strlen(teststr);
406 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
407 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
408
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700409 char buf[kBufferSize];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700410 ssize_t read_ret = read(child_stdout, buf, 8);
411 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
412 buf[teststr_len] = 0;
413 EXPECT_EQ(strcmp(buf, teststr), 0);
414
415 int status;
416 EXPECT_EQ(kill(pid, SIGTERM), 0);
417 waitpid(pid, &status, 0);
418 ASSERT_TRUE(WIFSIGNALED(status));
419 EXPECT_EQ(WTERMSIG(status), SIGTERM);
420
421 argv[0] = const_cast<char*>(kShellPath);
422 argv[1] = "-c";
423 argv[2] = "echo test >&2";
424 argv[3] = nullptr;
425 int child_stderr;
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700426 mj_run_ret = minijail_run_pid_pipes(j.get(), argv[0], argv, &pid,
427 &child_stdin, &child_stdout,
428 &child_stderr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700429 EXPECT_EQ(mj_run_ret, 0);
430
431 read_ret = read(child_stderr, buf, sizeof(buf));
432 EXPECT_GE(read_ret, static_cast<ssize_t>(teststr_len));
433
434 waitpid(pid, &status, 0);
435 ASSERT_TRUE(WIFEXITED(status));
436 EXPECT_EQ(WEXITSTATUS(status), 0);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700437}
438
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400439TEST(Test, minijail_run_pid_pipes_no_preload) {
440 pid_t pid;
441 int child_stdin, child_stdout, child_stderr;
442 int mj_run_ret;
443 ssize_t write_ret, read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700444 char buf[kBufferSize];
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400445 int status;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400446 char teststr[] = "test\n";
447 size_t teststr_len = strlen(teststr);
448 char *argv[4];
449
450 struct minijail *j = minijail_new();
451
François Degros87f0e832019-10-10 10:22:39 +1100452 argv[0] = const_cast<char*>(kCatPath);
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400453 argv[1] = NULL;
454 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
455 &pid,
456 &child_stdin, &child_stdout,
457 NULL);
458 EXPECT_EQ(mj_run_ret, 0);
459
460 write_ret = write(child_stdin, teststr, teststr_len);
461 EXPECT_EQ(write_ret, (int)teststr_len);
462
463 read_ret = read(child_stdout, buf, 8);
464 EXPECT_EQ(read_ret, (int)teststr_len);
465 buf[teststr_len] = 0;
466 EXPECT_EQ(strcmp(buf, teststr), 0);
467
468 EXPECT_EQ(kill(pid, SIGTERM), 0);
469 waitpid(pid, &status, 0);
470 ASSERT_TRUE(WIFSIGNALED(status));
471 EXPECT_EQ(WTERMSIG(status), SIGTERM);
472
François Degros87f0e832019-10-10 10:22:39 +1100473 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400474 argv[1] = "-c";
475 argv[2] = "echo test >&2";
476 argv[3] = NULL;
477 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
478 &child_stdin, &child_stdout,
479 &child_stderr);
480 EXPECT_EQ(mj_run_ret, 0);
481
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700482 read_ret = read(child_stderr, buf, sizeof(buf));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400483 EXPECT_GE(read_ret, (int)teststr_len);
484
485 waitpid(pid, &status, 0);
486 ASSERT_TRUE(WIFEXITED(status));
487 EXPECT_EQ(WEXITSTATUS(status), 0);
488
489 minijail_destroy(j);
490}
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400491
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500492TEST(Test, minijail_run_env_pid_pipes_no_preload) {
493 pid_t pid;
494 int child_stdin, child_stdout, child_stderr;
495 int mj_run_ret;
496 ssize_t read_ret;
497 char buf[kBufferSize];
498 int status;
499 char test_envvar[] = "TEST_VAR=test";
500 size_t testvar_len = strlen("test");
501 char *argv[4];
502 char *envp[2];
503
504 struct minijail *j = minijail_new();
505
François Degros87f0e832019-10-10 10:22:39 +1100506 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500507 argv[1] = "-c";
508 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\"";
509 argv[3] = NULL;
510
511 envp[0] = test_envvar;
512 envp[1] = NULL;
513
514 // Set a canary env var in the parent that should not be present in the child.
515 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
516
517 mj_run_ret = minijail_run_env_pid_pipes_no_preload(
518 j, argv[0], argv, envp, &pid, &child_stdin, &child_stdout, &child_stderr);
519 EXPECT_EQ(mj_run_ret, 0);
520
521 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obes8b285412019-06-03 16:28:16 -0400522 EXPECT_EQ(read_ret, (int)testvar_len + 2);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500523
Jorge Lucangeli Obes8b285412019-06-03 16:28:16 -0400524 EXPECT_EQ("|test\n", std::string(buf, 0, testvar_len + 2));
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500525
526 EXPECT_EQ(waitpid(pid, &status, 0), pid);
527 ASSERT_TRUE(WIFEXITED(status));
528 EXPECT_EQ(WEXITSTATUS(status), 0);
529
530 minijail_destroy(j);
531}
532
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400533TEST(Test, test_minijail_no_fd_leaks) {
534 pid_t pid;
535 int child_stdout;
536 int mj_run_ret;
537 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700538 char buf[kBufferSize];
539 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400540 int status;
541 char *argv[4];
542
543 int dev_null = open("/dev/null", O_RDONLY);
544 ASSERT_NE(dev_null, -1);
545 snprintf(script,
546 sizeof(script),
547 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
548 dev_null);
549
550 struct minijail *j = minijail_new();
551
François Degros87f0e832019-10-10 10:22:39 +1100552 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400553 argv[1] = "-c";
554 argv[2] = script;
555 argv[3] = NULL;
556 mj_run_ret = minijail_run_pid_pipes_no_preload(
557 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
558 EXPECT_EQ(mj_run_ret, 0);
559
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700560 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400561 EXPECT_GE(read_ret, 0);
562 buf[read_ret] = '\0';
563 EXPECT_STREQ(buf, "yes\n");
564
565 waitpid(pid, &status, 0);
566 ASSERT_TRUE(WIFEXITED(status));
567 EXPECT_EQ(WEXITSTATUS(status), 0);
568
569 minijail_close_open_fds(j);
570 mj_run_ret = minijail_run_pid_pipes_no_preload(
571 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
572 EXPECT_EQ(mj_run_ret, 0);
573
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700574 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400575 EXPECT_GE(read_ret, 0);
576 buf[read_ret] = '\0';
577 EXPECT_STREQ(buf, "no\n");
578
579 waitpid(pid, &status, 0);
580 ASSERT_TRUE(WIFEXITED(status));
581 EXPECT_EQ(WEXITSTATUS(status), 0);
582
583 minijail_destroy(j);
584
585 close(dev_null);
586}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100587
Dylan Reid0412dcc2017-08-24 11:33:15 -0700588TEST(Test, test_minijail_fork) {
589 pid_t mj_fork_ret;
590 int status;
591 int pipe_fds[2];
592 ssize_t pid_size = sizeof(mj_fork_ret);
593
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700594 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700595
596 ASSERT_EQ(pipe(pipe_fds), 0);
597
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700598 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700599 ASSERT_GE(mj_fork_ret, 0);
600 if (mj_fork_ret == 0) {
601 pid_t pid_in_parent;
602 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700603 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
604 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700605 exit(0);
606 }
607
608 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
609 waitpid(mj_fork_ret, &status, 0);
610 ASSERT_TRUE(WIFEXITED(status));
611 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700612}
613
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700614static int early_exit(void* payload) {
615 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
616}
617
618TEST(Test, test_minijail_callback) {
619 pid_t pid;
620 int mj_run_ret;
621 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700622 char *argv[2];
623 int exit_code = 42;
624
625 struct minijail *j = minijail_new();
626
627 status =
628 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500629 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700630 EXPECT_EQ(status, 0);
631
François Degros87f0e832019-10-10 10:22:39 +1100632 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700633 argv[1] = NULL;
634 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500635 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700636 EXPECT_EQ(mj_run_ret, 0);
637
638 status = minijail_wait(j);
639 EXPECT_EQ(status, exit_code);
640
641 minijail_destroy(j);
642}
643
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700644TEST(Test, test_minijail_preserve_fd) {
645 int mj_run_ret;
646 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700647 char *argv[2];
648 char teststr[] = "test\n";
649 size_t teststr_len = strlen(teststr);
650 int read_pipe[2];
651 int write_pipe[2];
652 char buf[1024];
653
654 struct minijail *j = minijail_new();
655
656 status = pipe(read_pipe);
657 ASSERT_EQ(status, 0);
658 status = pipe(write_pipe);
659 ASSERT_EQ(status, 0);
660
661 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
662 ASSERT_EQ(status, 0);
663 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
664 ASSERT_EQ(status, 0);
665 minijail_close_open_fds(j);
666
François Degros87f0e832019-10-10 10:22:39 +1100667 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700668 argv[1] = NULL;
669 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
670 EXPECT_EQ(mj_run_ret, 0);
671
672 close(write_pipe[0]);
673 status = write(write_pipe[1], teststr, teststr_len);
674 EXPECT_EQ(status, (int)teststr_len);
675 close(write_pipe[1]);
676
677 close(read_pipe[1]);
678 status = read(read_pipe[0], buf, 8);
679 EXPECT_EQ(status, (int)teststr_len);
680 buf[teststr_len] = 0;
681 EXPECT_EQ(strcmp(buf, teststr), 0);
682
683 status = minijail_wait(j);
684 EXPECT_EQ(status, 0);
685
686 minijail_destroy(j);
687}
688
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700689TEST(Test, test_minijail_reset_signal_mask) {
690 struct minijail *j = minijail_new();
691
692 sigset_t original_signal_mask;
693 {
694 sigset_t signal_mask;
695 ASSERT_EQ(0, sigemptyset(&signal_mask));
696 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
697 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
698 }
699
700 minijail_reset_signal_mask(j);
701
702 pid_t mj_fork_ret = minijail_fork(j);
703 ASSERT_GE(mj_fork_ret, 0);
704 if (mj_fork_ret == 0) {
705 sigset_t signal_mask;
706 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
707 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400708 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700709 exit(0);
710 }
711
712 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
713
714 int status;
715 waitpid(mj_fork_ret, &status, 0);
716 ASSERT_TRUE(WIFEXITED(status));
717 EXPECT_EQ(WEXITSTATUS(status), 0);
718
719 minijail_destroy(j);
720}
721
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700722TEST(Test, test_minijail_reset_signal_handlers) {
723 struct minijail *j = minijail_new();
724
725 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
726 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
727 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
728
729 minijail_reset_signal_handlers(j);
730
731 pid_t mj_fork_ret = minijail_fork(j);
732 ASSERT_GE(mj_fork_ret, 0);
733 if (mj_fork_ret == 0) {
734 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400735 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700736 exit(0);
737 }
738
739 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
740
741 int status;
742 waitpid(mj_fork_ret, &status, 0);
743 ASSERT_TRUE(WIFEXITED(status));
744 EXPECT_EQ(WEXITSTATUS(status), 0);
745
746 minijail_destroy(j);
747}
748
Mike Frysinger780aef72017-10-03 01:39:52 -0400749namespace {
750
751// Tests that require userns access.
752// Android unit tests don't currently support entering user namespaces as
753// unprivileged users due to having an older kernel. Chrome OS unit tests
754// don't support it either due to being in a chroot environment (see man 2
755// clone for more information about failure modes with the CLONE_NEWUSER flag).
756class NamespaceTest : public ::testing::Test {
757 protected:
758 static void SetUpTestCase() {
759 userns_supported_ = UsernsSupported();
760 }
761
762 // Whether userns is supported.
763 static bool userns_supported_;
764
765 static bool UsernsSupported() {
766 pid_t pid = fork();
767 if (pid == -1)
768 pdie("could not fork");
769
770 if (pid == 0)
771 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
772
773 int status;
774 if (waitpid(pid, &status, 0) < 0)
775 pdie("could not wait");
776
777 if (!WIFEXITED(status))
778 die("child did not exit properly: %#x", status);
779
780 bool ret = WEXITSTATUS(status) == 0;
781 if (!ret)
782 warn("Skipping userns related tests");
783 return ret;
784 }
785};
786
787bool NamespaceTest::userns_supported_;
788
789} // namespace
790
791TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700792 int mj_run_ret;
793 int status;
794 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700795 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700796 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
797 constexpr gid_t kTargetGid = 1000;
798
Mike Frysinger780aef72017-10-03 01:39:52 -0400799 if (!userns_supported_) {
800 SUCCEED();
801 return;
802 }
803
Luis Hector Chavez71323552017-09-05 09:17:22 -0700804 struct minijail *j = minijail_new();
805
806 minijail_namespace_pids(j);
807 minijail_namespace_vfs(j);
808 minijail_mount_tmp(j);
809 minijail_run_as_init(j);
810
811 // Perform userns mapping.
812 minijail_namespace_user(j);
813 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
814 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
815 minijail_change_uid(j, kTargetUid);
816 minijail_change_gid(j, kTargetGid);
817 minijail_uidmap(j, uidmap);
818 minijail_gidmap(j, gidmap);
819 minijail_namespace_user_disable_setgroups(j);
820
François Degros87f0e832019-10-10 10:22:39 +1100821 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -0700822 argv[1] = "-c";
823 argv[2] = "exec touch /tmp/foo";
824 argv[3] = NULL;
825 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
826 EXPECT_EQ(mj_run_ret, 0);
827
828 status = minijail_wait(j);
829 EXPECT_EQ(status, 0);
830
831 minijail_destroy(j);
832}
833
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700834TEST_F(NamespaceTest, test_namespaces) {
835 constexpr char teststr[] = "test\n";
836
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700837 // TODO(crbug.com/895875): The preload library interferes with ASan since they
838 // both need to use LD_PRELOAD.
839 if (!userns_supported_ || running_with_asan()) {
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700840 SUCCEED();
841 return;
842 }
843
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700844 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
845 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700846
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700847 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
848 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700849 // Grab the set of namespaces outside the container.
850 std::map<std::string, std::string> init_namespaces =
851 GetNamespaces(getpid(), namespace_names);
852 std::function<void(struct minijail*)> test_functions[] = {
853 [](struct minijail* j attribute_unused) {},
854 [](struct minijail* j) {
855 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
856 minijail_enter_pivot_root(j, "/tmp");
857 },
858 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
859 };
860
861 // This test is run with and without the preload library.
862 for (const auto& run_function :
863 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
864 for (const auto& test_function : test_functions) {
865 ScopedMinijail j(minijail_new());
866 minijail_set_preload_path(j.get(), kPreloadPath);
867
868 // Enter all the namespaces we can.
869 minijail_namespace_cgroups(j.get());
870 minijail_namespace_net(j.get());
871 minijail_namespace_pids(j.get());
872 minijail_namespace_user(j.get());
873 minijail_namespace_vfs(j.get());
874 minijail_namespace_uts(j.get());
875
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700876 // Set up the user namespace.
877 minijail_uidmap(j.get(), uidmap.c_str());
878 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700879 minijail_namespace_user_disable_setgroups(j.get());
880
881 minijail_close_open_fds(j.get());
882 test_function(j.get());
883
François Degros87f0e832019-10-10 10:22:39 +1100884 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700885 pid_t container_pid;
886 int child_stdin, child_stdout;
887 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +1100888 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700889 &container_pid, &child_stdin, &child_stdout, nullptr);
890 EXPECT_EQ(mj_run_ret, 0);
891
892 // Send some data to stdin and read it back to ensure that the child
893 // process is running.
894 const size_t teststr_len = strlen(teststr);
895 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
896 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
897
898 char buf[kBufferSize];
899 ssize_t read_ret = read(child_stdout, buf, 8);
900 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
901 buf[teststr_len] = 0;
902 EXPECT_EQ(strcmp(buf, teststr), 0);
903
904 // Grab the set of namespaces in every container process. They must not
905 // match the ones in the init namespace, and they must all match each
906 // other.
907 std::map<std::string, std::string> container_namespaces =
908 GetNamespaces(container_pid, namespace_names);
909 EXPECT_NE(container_namespaces, init_namespaces);
910 for (pid_t pid : GetProcessSubtreePids(container_pid))
911 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
912
913 EXPECT_EQ(0, close(child_stdin));
914
915 int status = minijail_wait(j.get());
916 EXPECT_EQ(status, 0);
917 }
918 }
919}
920
Mike Frysinger902a4492018-12-27 05:22:56 -0500921TEST_F(NamespaceTest, test_enter_ns) {
922 char uidmap[kBufferSize], gidmap[kBufferSize];
923
924 if (!userns_supported_) {
925 SUCCEED();
926 return;
927 }
928
929 // We first create a child in a new userns so we have privs to run more tests.
930 // We can't combine the steps as the kernel disallows many resource sharing
931 // from outside the userns.
932 struct minijail *j = minijail_new();
933
934 minijail_namespace_vfs(j);
935 minijail_namespace_pids(j);
936 minijail_run_as_init(j);
937
938 // Perform userns mapping.
939 minijail_namespace_user(j);
940 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
941 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
942 minijail_uidmap(j, uidmap);
943 minijail_gidmap(j, gidmap);
944 minijail_namespace_user_disable_setgroups(j);
945
946 pid_t pid = minijail_fork(j);
947 if (pid == 0) {
948 // Child.
949 minijail_destroy(j);
950
951 // Create new namespaces inside this userns which we may enter.
952 j = minijail_new();
953 minijail_namespace_net(j);
954 minijail_namespace_vfs(j);
955 pid = minijail_fork(j);
956 if (pid == 0) {
957 // Child.
958 minijail_destroy(j);
959
960 // Finally enter those namespaces.
961 j = minijail_new();
962
963 // We need to get the absolute path because entering a new mntns will
964 // implicitly chdir(/) for us.
965 char *path = realpath(kPreloadPath, nullptr);
966 ASSERT_NE(nullptr, path);
967 minijail_set_preload_path(j, path);
968
969 minijail_namespace_net(j);
970 minijail_namespace_vfs(j);
971
972 minijail_namespace_enter_net(j, "/proc/self/ns/net");
973 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
974
975 char *argv[] = {"/bin/true", nullptr};
976 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
977 EXPECT_EQ(0, minijail_wait(j));
978 minijail_destroy(j);
979 exit(0);
980 } else {
981 ASSERT_GT(pid, 0);
982 EXPECT_EQ(0, minijail_wait(j));
983 minijail_destroy(j);
984 exit(0);
985 }
986 } else {
987 ASSERT_GT(pid, 0);
988 EXPECT_EQ(0, minijail_wait(j));
989 minijail_destroy(j);
990 }
991}
992
Martin Pelikánab9eb442017-01-25 11:53:58 +1100993TEST(Test, parse_size) {
994 size_t size;
995
996 ASSERT_EQ(0, parse_size(&size, "42"));
997 ASSERT_EQ(42U, size);
998
999 ASSERT_EQ(0, parse_size(&size, "16K"));
1000 ASSERT_EQ(16384U, size);
1001
1002 ASSERT_EQ(0, parse_size(&size, "1M"));
1003 ASSERT_EQ(1024U * 1024, size);
1004
1005 uint64_t gigabyte = 1024ULL * 1024 * 1024;
1006 ASSERT_EQ(0, parse_size(&size, "3G"));
1007 ASSERT_EQ(3U, size / gigabyte);
1008 ASSERT_EQ(0U, size % gigabyte);
1009
1010 ASSERT_EQ(0, parse_size(&size, "4294967294"));
1011 ASSERT_EQ(3U, size / gigabyte);
1012 ASSERT_EQ(gigabyte - 2, size % gigabyte);
1013
1014#if __WORDSIZE == 64
1015 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
1016 ASSERT_EQ(0, parse_size(&size, "9E"));
1017 ASSERT_EQ(9U, size / exabyte);
1018 ASSERT_EQ(0U, size % exabyte);
1019
1020 ASSERT_EQ(0, parse_size(&size, "15E"));
1021 ASSERT_EQ(15U, size / exabyte);
1022 ASSERT_EQ(0U, size % exabyte);
1023
1024 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
1025 ASSERT_EQ(15U, size / exabyte);
1026 ASSERT_EQ(exabyte - 2, size % exabyte);
1027
1028 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
1029 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -08001030 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001031#elif __WORDSIZE == 32
1032 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
1033 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
1034 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -08001035 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001036#endif
1037
1038 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
1039 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
1040 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001041 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
1042 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
1043}
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001044
1045void TestCreateSession(bool create_session) {
1046 int status;
1047 int pipe_fds[2];
1048 pid_t child_pid;
1049 pid_t parent_sid = getsid(0);
1050 ssize_t pid_size = sizeof(pid_t);
1051
1052 ScopedMinijail j(minijail_new());
1053 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1054 // a new session because of that.
1055 minijail_close_open_fds(j.get());
1056
1057 if (create_session)
1058 minijail_create_session(j.get());
1059
1060 ASSERT_EQ(pipe(pipe_fds), 0);
1061 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1062
1063 child_pid = minijail_fork(j.get());
1064 ASSERT_GE(child_pid, 0);
1065 if (child_pid == 0) {
1066 pid_t sid_in_parent;
1067 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1068 if (create_session)
1069 ASSERT_NE(sid_in_parent, getsid(0));
1070 else
1071 ASSERT_EQ(sid_in_parent, getsid(0));
1072 exit(0);
1073 }
1074
1075 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1076 waitpid(child_pid, &status, 0);
1077 ASSERT_TRUE(WIFEXITED(status));
1078 EXPECT_EQ(WEXITSTATUS(status), 0);
1079}
1080
1081TEST(Test, default_no_new_session) {
1082 TestCreateSession(/*create_session=*/false);
1083}
1084
1085TEST(Test, create_new_session) {
1086 TestCreateSession(/*create_session=*/true);
1087}