blob: 18d016d6dc5e2c17507ee9199537ca385a0be56f [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
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100384TEST(Test, minijail_run_env_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
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700392 ScopedMinijail j(minijail_new());
393 minijail_set_preload_path(j.get(), kPreloadPath);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700394
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100395 char *argv[4];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700396 argv[0] = const_cast<char*>(kCatPath);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100397 argv[1] = NULL;
398
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700399 pid_t pid;
400 int child_stdin, child_stdout;
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100401 int mj_run_ret = minijail_run_pid_pipes(
402 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700403 EXPECT_EQ(mj_run_ret, 0);
404
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100405 char teststr[] = "test\n";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700406 const size_t teststr_len = strlen(teststr);
407 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
408 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
409
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100410 char buf[kBufferSize] = {};
411 ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700412 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100413 EXPECT_STREQ(buf, teststr);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700414
415 int status;
416 EXPECT_EQ(kill(pid, SIGTERM), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100417 EXPECT_EQ(waitpid(pid, &status, 0), pid);
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700418 ASSERT_TRUE(WIFSIGNALED(status));
419 EXPECT_EQ(WTERMSIG(status), SIGTERM);
420
421 argv[0] = const_cast<char*>(kShellPath);
422 argv[1] = "-c";
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100423 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700424 argv[3] = nullptr;
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700425
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500426 char *envp[2];
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100427 envp[0] = "TEST_VAR=test";
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500428 envp[1] = NULL;
429
430 // Set a canary env var in the parent that should not be present in the child.
431 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
432
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100433 int child_stderr;
434 mj_run_ret =
435 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
436 &child_stdin, &child_stdout, &child_stderr);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500437 EXPECT_EQ(mj_run_ret, 0);
438
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100439 memset(buf, 0, sizeof(buf));
440 read_ret = read(child_stderr, buf, sizeof(buf) - 1);
441 EXPECT_GE(read_ret, 0);
442 EXPECT_STREQ(buf, "|test\n");
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500443
444 EXPECT_EQ(waitpid(pid, &status, 0), pid);
445 ASSERT_TRUE(WIFEXITED(status));
446 EXPECT_EQ(WEXITSTATUS(status), 0);
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100447}
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500448
Mattias Nisslerb35f2c12020-02-07 13:37:36 +0100449TEST(Test, minijail_run_env_pid_pipes_no_preload) {
450 ScopedMinijail j(minijail_new());
451
452 char *argv[4];
453 argv[0] = const_cast<char*>(kCatPath);
454 argv[1] = NULL;
455
456 pid_t pid;
457 int child_stdin, child_stdout;
458 int mj_run_ret = minijail_run_pid_pipes(
459 j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
460 EXPECT_EQ(mj_run_ret, 0);
461
462 char teststr[] = "test\n";
463 const size_t teststr_len = strlen(teststr);
464 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
465 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
466
467 char buf[kBufferSize] = {};
468 ssize_t read_ret = read(child_stdout, buf, 8);
469 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
470 EXPECT_STREQ(buf, teststr);
471
472 int status;
473 EXPECT_EQ(kill(pid, SIGTERM), 0);
474 EXPECT_EQ(waitpid(pid, &status, 0), pid);
475 ASSERT_TRUE(WIFSIGNALED(status));
476 EXPECT_EQ(WTERMSIG(status), SIGTERM);
477
478 argv[0] = const_cast<char*>(kShellPath);
479 argv[1] = "-c";
480 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
481 argv[3] = nullptr;
482
483 char *envp[2];
484 envp[0] = "TEST_VAR=test";
485 envp[1] = NULL;
486
487 // Set a canary env var in the parent that should not be present in the child.
488 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
489
490 int child_stderr;
491 mj_run_ret =
492 minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
493 &child_stdin, &child_stdout, &child_stderr);
494 EXPECT_EQ(mj_run_ret, 0);
495
496 memset(buf, 0, sizeof(buf));
497 read_ret = read(child_stderr, buf, sizeof(buf));
498 EXPECT_GE(read_ret, 0);
499 EXPECT_STREQ(buf, "|test\n");
500
501 EXPECT_EQ(waitpid(pid, &status, 0), pid);
502 ASSERT_TRUE(WIFEXITED(status));
503 EXPECT_EQ(WEXITSTATUS(status), 0);
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500504}
505
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400506TEST(Test, test_minijail_no_fd_leaks) {
507 pid_t pid;
508 int child_stdout;
509 int mj_run_ret;
510 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700511 char buf[kBufferSize];
512 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400513 int status;
514 char *argv[4];
515
516 int dev_null = open("/dev/null", O_RDONLY);
517 ASSERT_NE(dev_null, -1);
518 snprintf(script,
519 sizeof(script),
520 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
521 dev_null);
522
523 struct minijail *j = minijail_new();
524
François Degros87f0e832019-10-10 10:22:39 +1100525 argv[0] = const_cast<char*>(kShellPath);
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400526 argv[1] = "-c";
527 argv[2] = script;
528 argv[3] = NULL;
529 mj_run_ret = minijail_run_pid_pipes_no_preload(
530 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
531 EXPECT_EQ(mj_run_ret, 0);
532
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700533 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400534 EXPECT_GE(read_ret, 0);
535 buf[read_ret] = '\0';
536 EXPECT_STREQ(buf, "yes\n");
537
538 waitpid(pid, &status, 0);
539 ASSERT_TRUE(WIFEXITED(status));
540 EXPECT_EQ(WEXITSTATUS(status), 0);
541
542 minijail_close_open_fds(j);
543 mj_run_ret = minijail_run_pid_pipes_no_preload(
544 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
545 EXPECT_EQ(mj_run_ret, 0);
546
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700547 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400548 EXPECT_GE(read_ret, 0);
549 buf[read_ret] = '\0';
550 EXPECT_STREQ(buf, "no\n");
551
552 waitpid(pid, &status, 0);
553 ASSERT_TRUE(WIFEXITED(status));
554 EXPECT_EQ(WEXITSTATUS(status), 0);
555
556 minijail_destroy(j);
557
558 close(dev_null);
559}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100560
Dylan Reid0412dcc2017-08-24 11:33:15 -0700561TEST(Test, test_minijail_fork) {
562 pid_t mj_fork_ret;
563 int status;
564 int pipe_fds[2];
565 ssize_t pid_size = sizeof(mj_fork_ret);
566
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700567 ScopedMinijail j(minijail_new());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700568
569 ASSERT_EQ(pipe(pipe_fds), 0);
570
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700571 mj_fork_ret = minijail_fork(j.get());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700572 ASSERT_GE(mj_fork_ret, 0);
573 if (mj_fork_ret == 0) {
574 pid_t pid_in_parent;
575 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700576 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
577 ASSERT_EQ(pid_in_parent, getpid());
Dylan Reid0412dcc2017-08-24 11:33:15 -0700578 exit(0);
579 }
580
581 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
582 waitpid(mj_fork_ret, &status, 0);
583 ASSERT_TRUE(WIFEXITED(status));
584 EXPECT_EQ(WEXITSTATUS(status), 0);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700585}
586
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700587static int early_exit(void* payload) {
588 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
589}
590
591TEST(Test, test_minijail_callback) {
592 pid_t pid;
593 int mj_run_ret;
594 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700595 char *argv[2];
596 int exit_code = 42;
597
598 struct minijail *j = minijail_new();
599
600 status =
601 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500602 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700603 EXPECT_EQ(status, 0);
604
François Degros87f0e832019-10-10 10:22:39 +1100605 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700606 argv[1] = NULL;
607 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500608 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700609 EXPECT_EQ(mj_run_ret, 0);
610
611 status = minijail_wait(j);
612 EXPECT_EQ(status, exit_code);
613
614 minijail_destroy(j);
615}
616
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700617TEST(Test, test_minijail_preserve_fd) {
618 int mj_run_ret;
619 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700620 char *argv[2];
621 char teststr[] = "test\n";
622 size_t teststr_len = strlen(teststr);
623 int read_pipe[2];
624 int write_pipe[2];
625 char buf[1024];
626
627 struct minijail *j = minijail_new();
628
629 status = pipe(read_pipe);
630 ASSERT_EQ(status, 0);
631 status = pipe(write_pipe);
632 ASSERT_EQ(status, 0);
633
634 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
635 ASSERT_EQ(status, 0);
636 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
637 ASSERT_EQ(status, 0);
638 minijail_close_open_fds(j);
639
François Degros87f0e832019-10-10 10:22:39 +1100640 argv[0] = const_cast<char*>(kCatPath);
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700641 argv[1] = NULL;
642 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
643 EXPECT_EQ(mj_run_ret, 0);
644
645 close(write_pipe[0]);
646 status = write(write_pipe[1], teststr, teststr_len);
647 EXPECT_EQ(status, (int)teststr_len);
648 close(write_pipe[1]);
649
650 close(read_pipe[1]);
651 status = read(read_pipe[0], buf, 8);
652 EXPECT_EQ(status, (int)teststr_len);
653 buf[teststr_len] = 0;
654 EXPECT_EQ(strcmp(buf, teststr), 0);
655
656 status = minijail_wait(j);
657 EXPECT_EQ(status, 0);
658
659 minijail_destroy(j);
660}
661
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700662TEST(Test, test_minijail_reset_signal_mask) {
663 struct minijail *j = minijail_new();
664
665 sigset_t original_signal_mask;
666 {
667 sigset_t signal_mask;
668 ASSERT_EQ(0, sigemptyset(&signal_mask));
669 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
670 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
671 }
672
673 minijail_reset_signal_mask(j);
674
675 pid_t mj_fork_ret = minijail_fork(j);
676 ASSERT_GE(mj_fork_ret, 0);
677 if (mj_fork_ret == 0) {
678 sigset_t signal_mask;
679 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
680 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400681 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700682 exit(0);
683 }
684
685 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
686
687 int status;
688 waitpid(mj_fork_ret, &status, 0);
689 ASSERT_TRUE(WIFEXITED(status));
690 EXPECT_EQ(WEXITSTATUS(status), 0);
691
692 minijail_destroy(j);
693}
694
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700695TEST(Test, test_minijail_reset_signal_handlers) {
696 struct minijail *j = minijail_new();
697
698 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
699 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
700 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
701
702 minijail_reset_signal_handlers(j);
703
704 pid_t mj_fork_ret = minijail_fork(j);
705 ASSERT_GE(mj_fork_ret, 0);
706 if (mj_fork_ret == 0) {
707 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400708 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700709 exit(0);
710 }
711
712 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
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
Mike Frysinger780aef72017-10-03 01:39:52 -0400722namespace {
723
724// Tests that require userns access.
725// Android unit tests don't currently support entering user namespaces as
726// unprivileged users due to having an older kernel. Chrome OS unit tests
727// don't support it either due to being in a chroot environment (see man 2
728// clone for more information about failure modes with the CLONE_NEWUSER flag).
729class NamespaceTest : public ::testing::Test {
730 protected:
731 static void SetUpTestCase() {
732 userns_supported_ = UsernsSupported();
733 }
734
735 // Whether userns is supported.
736 static bool userns_supported_;
737
738 static bool UsernsSupported() {
739 pid_t pid = fork();
740 if (pid == -1)
741 pdie("could not fork");
742
743 if (pid == 0)
744 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
745
746 int status;
747 if (waitpid(pid, &status, 0) < 0)
748 pdie("could not wait");
749
750 if (!WIFEXITED(status))
751 die("child did not exit properly: %#x", status);
752
753 bool ret = WEXITSTATUS(status) == 0;
754 if (!ret)
755 warn("Skipping userns related tests");
756 return ret;
757 }
758};
759
760bool NamespaceTest::userns_supported_;
761
762} // namespace
763
764TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700765 int mj_run_ret;
766 int status;
767 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700768 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700769 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
770 constexpr gid_t kTargetGid = 1000;
771
Mike Frysinger780aef72017-10-03 01:39:52 -0400772 if (!userns_supported_) {
773 SUCCEED();
774 return;
775 }
776
Luis Hector Chavez71323552017-09-05 09:17:22 -0700777 struct minijail *j = minijail_new();
778
779 minijail_namespace_pids(j);
780 minijail_namespace_vfs(j);
781 minijail_mount_tmp(j);
782 minijail_run_as_init(j);
783
784 // Perform userns mapping.
785 minijail_namespace_user(j);
786 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
787 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
788 minijail_change_uid(j, kTargetUid);
789 minijail_change_gid(j, kTargetGid);
790 minijail_uidmap(j, uidmap);
791 minijail_gidmap(j, gidmap);
792 minijail_namespace_user_disable_setgroups(j);
793
François Degros87f0e832019-10-10 10:22:39 +1100794 argv[0] = const_cast<char*>(kShellPath);
Luis Hector Chavez71323552017-09-05 09:17:22 -0700795 argv[1] = "-c";
796 argv[2] = "exec touch /tmp/foo";
797 argv[3] = NULL;
798 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
799 EXPECT_EQ(mj_run_ret, 0);
800
801 status = minijail_wait(j);
802 EXPECT_EQ(status, 0);
803
804 minijail_destroy(j);
805}
806
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700807TEST_F(NamespaceTest, test_namespaces) {
808 constexpr char teststr[] = "test\n";
809
Luis Hector Chavezeb42bb72018-10-15 09:46:29 -0700810 // TODO(crbug.com/895875): The preload library interferes with ASan since they
811 // both need to use LD_PRELOAD.
812 if (!userns_supported_ || running_with_asan()) {
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700813 SUCCEED();
814 return;
815 }
816
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700817 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
818 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700819
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700820 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
821 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700822 // Grab the set of namespaces outside the container.
823 std::map<std::string, std::string> init_namespaces =
824 GetNamespaces(getpid(), namespace_names);
825 std::function<void(struct minijail*)> test_functions[] = {
826 [](struct minijail* j attribute_unused) {},
827 [](struct minijail* j) {
828 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
829 minijail_enter_pivot_root(j, "/tmp");
830 },
831 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
832 };
833
834 // This test is run with and without the preload library.
835 for (const auto& run_function :
836 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
837 for (const auto& test_function : test_functions) {
838 ScopedMinijail j(minijail_new());
839 minijail_set_preload_path(j.get(), kPreloadPath);
840
841 // Enter all the namespaces we can.
842 minijail_namespace_cgroups(j.get());
843 minijail_namespace_net(j.get());
844 minijail_namespace_pids(j.get());
845 minijail_namespace_user(j.get());
846 minijail_namespace_vfs(j.get());
847 minijail_namespace_uts(j.get());
848
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700849 // Set up the user namespace.
850 minijail_uidmap(j.get(), uidmap.c_str());
851 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700852 minijail_namespace_user_disable_setgroups(j.get());
853
854 minijail_close_open_fds(j.get());
855 test_function(j.get());
856
François Degros87f0e832019-10-10 10:22:39 +1100857 char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700858 pid_t container_pid;
859 int child_stdin, child_stdout;
860 int mj_run_ret =
François Degros87f0e832019-10-10 10:22:39 +1100861 run_function(j.get(), argv[0], argv,
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700862 &container_pid, &child_stdin, &child_stdout, nullptr);
863 EXPECT_EQ(mj_run_ret, 0);
864
865 // Send some data to stdin and read it back to ensure that the child
866 // process is running.
867 const size_t teststr_len = strlen(teststr);
868 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
869 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
870
871 char buf[kBufferSize];
872 ssize_t read_ret = read(child_stdout, buf, 8);
873 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
874 buf[teststr_len] = 0;
875 EXPECT_EQ(strcmp(buf, teststr), 0);
876
877 // Grab the set of namespaces in every container process. They must not
878 // match the ones in the init namespace, and they must all match each
879 // other.
880 std::map<std::string, std::string> container_namespaces =
881 GetNamespaces(container_pid, namespace_names);
882 EXPECT_NE(container_namespaces, init_namespaces);
883 for (pid_t pid : GetProcessSubtreePids(container_pid))
884 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
885
886 EXPECT_EQ(0, close(child_stdin));
887
888 int status = minijail_wait(j.get());
889 EXPECT_EQ(status, 0);
890 }
891 }
892}
893
Mike Frysinger902a4492018-12-27 05:22:56 -0500894TEST_F(NamespaceTest, test_enter_ns) {
895 char uidmap[kBufferSize], gidmap[kBufferSize];
896
897 if (!userns_supported_) {
898 SUCCEED();
899 return;
900 }
901
902 // We first create a child in a new userns so we have privs to run more tests.
903 // We can't combine the steps as the kernel disallows many resource sharing
904 // from outside the userns.
905 struct minijail *j = minijail_new();
906
907 minijail_namespace_vfs(j);
908 minijail_namespace_pids(j);
909 minijail_run_as_init(j);
910
911 // Perform userns mapping.
912 minijail_namespace_user(j);
913 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
914 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
915 minijail_uidmap(j, uidmap);
916 minijail_gidmap(j, gidmap);
917 minijail_namespace_user_disable_setgroups(j);
918
919 pid_t pid = minijail_fork(j);
920 if (pid == 0) {
921 // Child.
922 minijail_destroy(j);
923
924 // Create new namespaces inside this userns which we may enter.
925 j = minijail_new();
926 minijail_namespace_net(j);
927 minijail_namespace_vfs(j);
928 pid = minijail_fork(j);
929 if (pid == 0) {
930 // Child.
931 minijail_destroy(j);
932
933 // Finally enter those namespaces.
934 j = minijail_new();
935
936 // We need to get the absolute path because entering a new mntns will
937 // implicitly chdir(/) for us.
938 char *path = realpath(kPreloadPath, nullptr);
939 ASSERT_NE(nullptr, path);
940 minijail_set_preload_path(j, path);
941
942 minijail_namespace_net(j);
943 minijail_namespace_vfs(j);
944
945 minijail_namespace_enter_net(j, "/proc/self/ns/net");
946 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
947
948 char *argv[] = {"/bin/true", nullptr};
949 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
950 EXPECT_EQ(0, minijail_wait(j));
951 minijail_destroy(j);
952 exit(0);
953 } else {
954 ASSERT_GT(pid, 0);
955 EXPECT_EQ(0, minijail_wait(j));
956 minijail_destroy(j);
957 exit(0);
958 }
959 } else {
960 ASSERT_GT(pid, 0);
961 EXPECT_EQ(0, minijail_wait(j));
962 minijail_destroy(j);
963 }
964}
965
Martin Pelikánab9eb442017-01-25 11:53:58 +1100966TEST(Test, parse_size) {
967 size_t size;
968
969 ASSERT_EQ(0, parse_size(&size, "42"));
970 ASSERT_EQ(42U, size);
971
972 ASSERT_EQ(0, parse_size(&size, "16K"));
973 ASSERT_EQ(16384U, size);
974
975 ASSERT_EQ(0, parse_size(&size, "1M"));
976 ASSERT_EQ(1024U * 1024, size);
977
978 uint64_t gigabyte = 1024ULL * 1024 * 1024;
979 ASSERT_EQ(0, parse_size(&size, "3G"));
980 ASSERT_EQ(3U, size / gigabyte);
981 ASSERT_EQ(0U, size % gigabyte);
982
983 ASSERT_EQ(0, parse_size(&size, "4294967294"));
984 ASSERT_EQ(3U, size / gigabyte);
985 ASSERT_EQ(gigabyte - 2, size % gigabyte);
986
987#if __WORDSIZE == 64
988 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
989 ASSERT_EQ(0, parse_size(&size, "9E"));
990 ASSERT_EQ(9U, size / exabyte);
991 ASSERT_EQ(0U, size % exabyte);
992
993 ASSERT_EQ(0, parse_size(&size, "15E"));
994 ASSERT_EQ(15U, size / exabyte);
995 ASSERT_EQ(0U, size % exabyte);
996
997 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
998 ASSERT_EQ(15U, size / exabyte);
999 ASSERT_EQ(exabyte - 2, size % exabyte);
1000
1001 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
1002 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -08001003 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001004#elif __WORDSIZE == 32
1005 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
1006 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
1007 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -08001008 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001009#endif
1010
1011 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
1012 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
1013 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
Martin Pelikánab9eb442017-01-25 11:53:58 +11001014 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
1015 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
1016}
Xiyuan Xia9b41e652019-05-23 11:03:04 -07001017
1018void TestCreateSession(bool create_session) {
1019 int status;
1020 int pipe_fds[2];
1021 pid_t child_pid;
1022 pid_t parent_sid = getsid(0);
1023 ssize_t pid_size = sizeof(pid_t);
1024
1025 ScopedMinijail j(minijail_new());
1026 // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1027 // a new session because of that.
1028 minijail_close_open_fds(j.get());
1029
1030 if (create_session)
1031 minijail_create_session(j.get());
1032
1033 ASSERT_EQ(pipe(pipe_fds), 0);
1034 minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1035
1036 child_pid = minijail_fork(j.get());
1037 ASSERT_GE(child_pid, 0);
1038 if (child_pid == 0) {
1039 pid_t sid_in_parent;
1040 ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1041 if (create_session)
1042 ASSERT_NE(sid_in_parent, getsid(0));
1043 else
1044 ASSERT_EQ(sid_in_parent, getsid(0));
1045 exit(0);
1046 }
1047
1048 EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1049 waitpid(child_pid, &status, 0);
1050 ASSERT_TRUE(WIFEXITED(status));
1051 EXPECT_EQ(WEXITSTATUS(status), 0);
1052}
1053
1054TEST(Test, default_no_new_session) {
1055 TestCreateSession(/*create_session=*/false);
1056}
1057
1058TEST(Test, create_new_session) {
1059 TestCreateSession(/*create_session=*/true);
1060}