blob: 25aa76e537e9f3a7d30bfd947ec5899ea9cc44ab [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
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700220TEST(Test, minijail_run_pid_pipes) {
221 constexpr char teststr[] = "test\n";
222
223 struct minijail* j = minijail_new();
224 minijail_set_preload_path(j, kPreloadPath);
225
226 char* argv[4];
227 argv[0] = const_cast<char*>(kCatPath);
228 argv[1] = nullptr;
229 pid_t pid;
230 int child_stdin, child_stdout;
231 int mj_run_ret = minijail_run_pid_pipes(j, argv[0], argv, &pid, &child_stdin,
232 &child_stdout, nullptr);
233 EXPECT_EQ(mj_run_ret, 0);
234
235 const size_t teststr_len = strlen(teststr);
236 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
237 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
238
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700239 char buf[kBufferSize];
Luis Hector Chavez9acba452018-10-11 10:13:25 -0700240 ssize_t read_ret = read(child_stdout, buf, 8);
241 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
242 buf[teststr_len] = 0;
243 EXPECT_EQ(strcmp(buf, teststr), 0);
244
245 int status;
246 EXPECT_EQ(kill(pid, SIGTERM), 0);
247 waitpid(pid, &status, 0);
248 ASSERT_TRUE(WIFSIGNALED(status));
249 EXPECT_EQ(WTERMSIG(status), SIGTERM);
250
251 argv[0] = const_cast<char*>(kShellPath);
252 argv[1] = "-c";
253 argv[2] = "echo test >&2";
254 argv[3] = nullptr;
255 int child_stderr;
256 mj_run_ret = minijail_run_pid_pipes(j, argv[0], argv, &pid, &child_stdin,
257 &child_stdout, &child_stderr);
258 EXPECT_EQ(mj_run_ret, 0);
259
260 read_ret = read(child_stderr, buf, sizeof(buf));
261 EXPECT_GE(read_ret, static_cast<ssize_t>(teststr_len));
262
263 waitpid(pid, &status, 0);
264 ASSERT_TRUE(WIFEXITED(status));
265 EXPECT_EQ(WEXITSTATUS(status), 0);
266
267 minijail_destroy(j);
268}
269
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400270TEST(Test, minijail_run_pid_pipes_no_preload) {
271 pid_t pid;
272 int child_stdin, child_stdout, child_stderr;
273 int mj_run_ret;
274 ssize_t write_ret, read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700275 char buf[kBufferSize];
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400276 int status;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400277 char teststr[] = "test\n";
278 size_t teststr_len = strlen(teststr);
279 char *argv[4];
280
281 struct minijail *j = minijail_new();
282
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400283 argv[0] = (char*)kCatPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400284 argv[1] = NULL;
285 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
286 &pid,
287 &child_stdin, &child_stdout,
288 NULL);
289 EXPECT_EQ(mj_run_ret, 0);
290
291 write_ret = write(child_stdin, teststr, teststr_len);
292 EXPECT_EQ(write_ret, (int)teststr_len);
293
294 read_ret = read(child_stdout, buf, 8);
295 EXPECT_EQ(read_ret, (int)teststr_len);
296 buf[teststr_len] = 0;
297 EXPECT_EQ(strcmp(buf, teststr), 0);
298
299 EXPECT_EQ(kill(pid, SIGTERM), 0);
300 waitpid(pid, &status, 0);
301 ASSERT_TRUE(WIFSIGNALED(status));
302 EXPECT_EQ(WTERMSIG(status), SIGTERM);
303
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400304 argv[0] = (char*)kShellPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400305 argv[1] = "-c";
306 argv[2] = "echo test >&2";
307 argv[3] = NULL;
308 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
309 &child_stdin, &child_stdout,
310 &child_stderr);
311 EXPECT_EQ(mj_run_ret, 0);
312
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700313 read_ret = read(child_stderr, buf, sizeof(buf));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400314 EXPECT_GE(read_ret, (int)teststr_len);
315
316 waitpid(pid, &status, 0);
317 ASSERT_TRUE(WIFEXITED(status));
318 EXPECT_EQ(WEXITSTATUS(status), 0);
319
320 minijail_destroy(j);
321}
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400322
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500323TEST(Test, minijail_run_env_pid_pipes_no_preload) {
324 pid_t pid;
325 int child_stdin, child_stdout, child_stderr;
326 int mj_run_ret;
327 ssize_t read_ret;
328 char buf[kBufferSize];
329 int status;
330 char test_envvar[] = "TEST_VAR=test";
331 size_t testvar_len = strlen("test");
332 char *argv[4];
333 char *envp[2];
334
335 struct minijail *j = minijail_new();
336
337 argv[0] = (char*)kShellPath;
338 argv[1] = "-c";
339 argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\"";
340 argv[3] = NULL;
341
342 envp[0] = test_envvar;
343 envp[1] = NULL;
344
345 // Set a canary env var in the parent that should not be present in the child.
346 ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
347
348 mj_run_ret = minijail_run_env_pid_pipes_no_preload(
349 j, argv[0], argv, envp, &pid, &child_stdin, &child_stdout, &child_stderr);
350 EXPECT_EQ(mj_run_ret, 0);
351
352 read_ret = read(child_stdout, buf, sizeof(buf));
353 EXPECT_GE(read_ret, (int)testvar_len);
354
355 EXPECT_EQ("|test\n", std::string(buf));
356
357 EXPECT_EQ(waitpid(pid, &status, 0), pid);
358 ASSERT_TRUE(WIFEXITED(status));
359 EXPECT_EQ(WEXITSTATUS(status), 0);
360
361 minijail_destroy(j);
362}
363
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400364TEST(Test, test_minijail_no_fd_leaks) {
365 pid_t pid;
366 int child_stdout;
367 int mj_run_ret;
368 ssize_t read_ret;
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700369 char buf[kBufferSize];
370 char script[kBufferSize];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400371 int status;
372 char *argv[4];
373
374 int dev_null = open("/dev/null", O_RDONLY);
375 ASSERT_NE(dev_null, -1);
376 snprintf(script,
377 sizeof(script),
378 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
379 dev_null);
380
381 struct minijail *j = minijail_new();
382
383 argv[0] = (char*)kShellPath;
384 argv[1] = "-c";
385 argv[2] = script;
386 argv[3] = NULL;
387 mj_run_ret = minijail_run_pid_pipes_no_preload(
388 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
389 EXPECT_EQ(mj_run_ret, 0);
390
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700391 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400392 EXPECT_GE(read_ret, 0);
393 buf[read_ret] = '\0';
394 EXPECT_STREQ(buf, "yes\n");
395
396 waitpid(pid, &status, 0);
397 ASSERT_TRUE(WIFEXITED(status));
398 EXPECT_EQ(WEXITSTATUS(status), 0);
399
400 minijail_close_open_fds(j);
401 mj_run_ret = minijail_run_pid_pipes_no_preload(
402 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
403 EXPECT_EQ(mj_run_ret, 0);
404
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700405 read_ret = read(child_stdout, buf, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400406 EXPECT_GE(read_ret, 0);
407 buf[read_ret] = '\0';
408 EXPECT_STREQ(buf, "no\n");
409
410 waitpid(pid, &status, 0);
411 ASSERT_TRUE(WIFEXITED(status));
412 EXPECT_EQ(WEXITSTATUS(status), 0);
413
414 minijail_destroy(j);
415
416 close(dev_null);
417}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100418
Dylan Reid0412dcc2017-08-24 11:33:15 -0700419TEST(Test, test_minijail_fork) {
420 pid_t mj_fork_ret;
421 int status;
422 int pipe_fds[2];
423 ssize_t pid_size = sizeof(mj_fork_ret);
424
425 struct minijail *j = minijail_new();
426
427 ASSERT_EQ(pipe(pipe_fds), 0);
428
429 mj_fork_ret = minijail_fork(j);
430 ASSERT_GE(mj_fork_ret, 0);
431 if (mj_fork_ret == 0) {
432 pid_t pid_in_parent;
433 // Wait for the parent to tell us the pid in the parent namespace.
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700434 ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
435 ASSERT_EQ(pid_in_parent, getpid());
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400436 minijail_destroy(j);
Dylan Reid0412dcc2017-08-24 11:33:15 -0700437 exit(0);
438 }
439
440 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
441 waitpid(mj_fork_ret, &status, 0);
442 ASSERT_TRUE(WIFEXITED(status));
443 EXPECT_EQ(WEXITSTATUS(status), 0);
444
445 minijail_destroy(j);
446}
447
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700448static int early_exit(void* payload) {
449 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
450}
451
452TEST(Test, test_minijail_callback) {
453 pid_t pid;
454 int mj_run_ret;
455 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700456 char *argv[2];
457 int exit_code = 42;
458
459 struct minijail *j = minijail_new();
460
461 status =
462 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500463 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700464 EXPECT_EQ(status, 0);
465
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400466 argv[0] = (char*)kCatPath;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700467 argv[1] = NULL;
468 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
Jorge Lucangeli Obesd2c951d2019-02-01 15:43:36 -0500469 NULL, NULL);
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700470 EXPECT_EQ(mj_run_ret, 0);
471
472 status = minijail_wait(j);
473 EXPECT_EQ(status, exit_code);
474
475 minijail_destroy(j);
476}
477
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700478TEST(Test, test_minijail_preserve_fd) {
479 int mj_run_ret;
480 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700481 char *argv[2];
482 char teststr[] = "test\n";
483 size_t teststr_len = strlen(teststr);
484 int read_pipe[2];
485 int write_pipe[2];
486 char buf[1024];
487
488 struct minijail *j = minijail_new();
489
490 status = pipe(read_pipe);
491 ASSERT_EQ(status, 0);
492 status = pipe(write_pipe);
493 ASSERT_EQ(status, 0);
494
495 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
496 ASSERT_EQ(status, 0);
497 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
498 ASSERT_EQ(status, 0);
499 minijail_close_open_fds(j);
500
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400501 argv[0] = (char*)kCatPath;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700502 argv[1] = NULL;
503 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
504 EXPECT_EQ(mj_run_ret, 0);
505
506 close(write_pipe[0]);
507 status = write(write_pipe[1], teststr, teststr_len);
508 EXPECT_EQ(status, (int)teststr_len);
509 close(write_pipe[1]);
510
511 close(read_pipe[1]);
512 status = read(read_pipe[0], buf, 8);
513 EXPECT_EQ(status, (int)teststr_len);
514 buf[teststr_len] = 0;
515 EXPECT_EQ(strcmp(buf, teststr), 0);
516
517 status = minijail_wait(j);
518 EXPECT_EQ(status, 0);
519
520 minijail_destroy(j);
521}
522
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700523TEST(Test, test_minijail_reset_signal_mask) {
524 struct minijail *j = minijail_new();
525
526 sigset_t original_signal_mask;
527 {
528 sigset_t signal_mask;
529 ASSERT_EQ(0, sigemptyset(&signal_mask));
530 ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
531 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
532 }
533
534 minijail_reset_signal_mask(j);
535
536 pid_t mj_fork_ret = minijail_fork(j);
537 ASSERT_GE(mj_fork_ret, 0);
538 if (mj_fork_ret == 0) {
539 sigset_t signal_mask;
540 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
541 ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400542 minijail_destroy(j);
Luis Hector Chavez7e333012018-04-05 12:15:27 -0700543 exit(0);
544 }
545
546 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
547
548 int status;
549 waitpid(mj_fork_ret, &status, 0);
550 ASSERT_TRUE(WIFEXITED(status));
551 EXPECT_EQ(WEXITSTATUS(status), 0);
552
553 minijail_destroy(j);
554}
555
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700556TEST(Test, test_minijail_reset_signal_handlers) {
557 struct minijail *j = minijail_new();
558
559 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
560 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
561 ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
562
563 minijail_reset_signal_handlers(j);
564
565 pid_t mj_fork_ret = minijail_fork(j);
566 ASSERT_GE(mj_fork_ret, 0);
567 if (mj_fork_ret == 0) {
568 ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
Jorge Lucangeli Obes16532802018-05-24 13:03:34 -0400569 minijail_destroy(j);
Luis Hector Chaveza27118a2018-04-04 08:18:01 -0700570 exit(0);
571 }
572
573 ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
574
575 int status;
576 waitpid(mj_fork_ret, &status, 0);
577 ASSERT_TRUE(WIFEXITED(status));
578 EXPECT_EQ(WEXITSTATUS(status), 0);
579
580 minijail_destroy(j);
581}
582
Mike Frysinger780aef72017-10-03 01:39:52 -0400583namespace {
584
585// Tests that require userns access.
586// Android unit tests don't currently support entering user namespaces as
587// unprivileged users due to having an older kernel. Chrome OS unit tests
588// don't support it either due to being in a chroot environment (see man 2
589// clone for more information about failure modes with the CLONE_NEWUSER flag).
590class NamespaceTest : public ::testing::Test {
591 protected:
592 static void SetUpTestCase() {
593 userns_supported_ = UsernsSupported();
594 }
595
596 // Whether userns is supported.
597 static bool userns_supported_;
598
599 static bool UsernsSupported() {
600 pid_t pid = fork();
601 if (pid == -1)
602 pdie("could not fork");
603
604 if (pid == 0)
605 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
606
607 int status;
608 if (waitpid(pid, &status, 0) < 0)
609 pdie("could not wait");
610
611 if (!WIFEXITED(status))
612 die("child did not exit properly: %#x", status);
613
614 bool ret = WEXITSTATUS(status) == 0;
615 if (!ret)
616 warn("Skipping userns related tests");
617 return ret;
618 }
619};
620
621bool NamespaceTest::userns_supported_;
622
623} // namespace
624
625TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700626 int mj_run_ret;
627 int status;
628 char *argv[4];
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700629 char uidmap[kBufferSize], gidmap[kBufferSize];
Luis Hector Chavez71323552017-09-05 09:17:22 -0700630 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
631 constexpr gid_t kTargetGid = 1000;
632
Mike Frysinger780aef72017-10-03 01:39:52 -0400633 if (!userns_supported_) {
634 SUCCEED();
635 return;
636 }
637
Luis Hector Chavez71323552017-09-05 09:17:22 -0700638 struct minijail *j = minijail_new();
639
640 minijail_namespace_pids(j);
641 minijail_namespace_vfs(j);
642 minijail_mount_tmp(j);
643 minijail_run_as_init(j);
644
645 // Perform userns mapping.
646 minijail_namespace_user(j);
647 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
648 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
649 minijail_change_uid(j, kTargetUid);
650 minijail_change_gid(j, kTargetGid);
651 minijail_uidmap(j, uidmap);
652 minijail_gidmap(j, gidmap);
653 minijail_namespace_user_disable_setgroups(j);
654
655 argv[0] = (char*)kShellPath;
656 argv[1] = "-c";
657 argv[2] = "exec touch /tmp/foo";
658 argv[3] = NULL;
659 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
660 EXPECT_EQ(mj_run_ret, 0);
661
662 status = minijail_wait(j);
663 EXPECT_EQ(status, 0);
664
665 minijail_destroy(j);
666}
667
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700668TEST_F(NamespaceTest, test_namespaces) {
669 constexpr char teststr[] = "test\n";
670
671 if (!userns_supported_) {
672 SUCCEED();
673 return;
674 }
675
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700676 std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
677 std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700678
Luis Hector Chavez83a44892018-10-12 08:56:20 -0700679 const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
680 "net", "cgroup", "uts"};
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700681 // Grab the set of namespaces outside the container.
682 std::map<std::string, std::string> init_namespaces =
683 GetNamespaces(getpid(), namespace_names);
684 std::function<void(struct minijail*)> test_functions[] = {
685 [](struct minijail* j attribute_unused) {},
686 [](struct minijail* j) {
687 minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
688 minijail_enter_pivot_root(j, "/tmp");
689 },
690 [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
691 };
692
693 // This test is run with and without the preload library.
694 for (const auto& run_function :
695 {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
696 for (const auto& test_function : test_functions) {
697 ScopedMinijail j(minijail_new());
698 minijail_set_preload_path(j.get(), kPreloadPath);
699
700 // Enter all the namespaces we can.
701 minijail_namespace_cgroups(j.get());
702 minijail_namespace_net(j.get());
703 minijail_namespace_pids(j.get());
704 minijail_namespace_user(j.get());
705 minijail_namespace_vfs(j.get());
706 minijail_namespace_uts(j.get());
707
Luis Hector Chavezac0acf32018-10-15 09:45:01 -0700708 // Set up the user namespace.
709 minijail_uidmap(j.get(), uidmap.c_str());
710 minijail_gidmap(j.get(), gidmap.c_str());
Luis Hector Chavez86e10d32018-10-11 20:36:48 -0700711 minijail_namespace_user_disable_setgroups(j.get());
712
713 minijail_close_open_fds(j.get());
714 test_function(j.get());
715
716 const char* argv[] = {kCatPath, nullptr};
717 pid_t container_pid;
718 int child_stdin, child_stdout;
719 int mj_run_ret =
720 run_function(j.get(), argv[0], const_cast<char* const*>(argv),
721 &container_pid, &child_stdin, &child_stdout, nullptr);
722 EXPECT_EQ(mj_run_ret, 0);
723
724 // Send some data to stdin and read it back to ensure that the child
725 // process is running.
726 const size_t teststr_len = strlen(teststr);
727 ssize_t write_ret = write(child_stdin, teststr, teststr_len);
728 EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
729
730 char buf[kBufferSize];
731 ssize_t read_ret = read(child_stdout, buf, 8);
732 EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
733 buf[teststr_len] = 0;
734 EXPECT_EQ(strcmp(buf, teststr), 0);
735
736 // Grab the set of namespaces in every container process. They must not
737 // match the ones in the init namespace, and they must all match each
738 // other.
739 std::map<std::string, std::string> container_namespaces =
740 GetNamespaces(container_pid, namespace_names);
741 EXPECT_NE(container_namespaces, init_namespaces);
742 for (pid_t pid : GetProcessSubtreePids(container_pid))
743 EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
744
745 EXPECT_EQ(0, close(child_stdin));
746
747 int status = minijail_wait(j.get());
748 EXPECT_EQ(status, 0);
749 }
750 }
751}
752
Mike Frysinger902a4492018-12-27 05:22:56 -0500753TEST_F(NamespaceTest, test_enter_ns) {
754 char uidmap[kBufferSize], gidmap[kBufferSize];
755
756 if (!userns_supported_) {
757 SUCCEED();
758 return;
759 }
760
761 // We first create a child in a new userns so we have privs to run more tests.
762 // We can't combine the steps as the kernel disallows many resource sharing
763 // from outside the userns.
764 struct minijail *j = minijail_new();
765
766 minijail_namespace_vfs(j);
767 minijail_namespace_pids(j);
768 minijail_run_as_init(j);
769
770 // Perform userns mapping.
771 minijail_namespace_user(j);
772 snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
773 snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
774 minijail_uidmap(j, uidmap);
775 minijail_gidmap(j, gidmap);
776 minijail_namespace_user_disable_setgroups(j);
777
778 pid_t pid = minijail_fork(j);
779 if (pid == 0) {
780 // Child.
781 minijail_destroy(j);
782
783 // Create new namespaces inside this userns which we may enter.
784 j = minijail_new();
785 minijail_namespace_net(j);
786 minijail_namespace_vfs(j);
787 pid = minijail_fork(j);
788 if (pid == 0) {
789 // Child.
790 minijail_destroy(j);
791
792 // Finally enter those namespaces.
793 j = minijail_new();
794
795 // We need to get the absolute path because entering a new mntns will
796 // implicitly chdir(/) for us.
797 char *path = realpath(kPreloadPath, nullptr);
798 ASSERT_NE(nullptr, path);
799 minijail_set_preload_path(j, path);
800
801 minijail_namespace_net(j);
802 minijail_namespace_vfs(j);
803
804 minijail_namespace_enter_net(j, "/proc/self/ns/net");
805 minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
806
807 char *argv[] = {"/bin/true", nullptr};
808 EXPECT_EQ(0, minijail_run(j, argv[0], argv));
809 EXPECT_EQ(0, minijail_wait(j));
810 minijail_destroy(j);
811 exit(0);
812 } else {
813 ASSERT_GT(pid, 0);
814 EXPECT_EQ(0, minijail_wait(j));
815 minijail_destroy(j);
816 exit(0);
817 }
818 } else {
819 ASSERT_GT(pid, 0);
820 EXPECT_EQ(0, minijail_wait(j));
821 minijail_destroy(j);
822 }
823}
824
Martin Pelikánab9eb442017-01-25 11:53:58 +1100825TEST(Test, parse_size) {
826 size_t size;
827
828 ASSERT_EQ(0, parse_size(&size, "42"));
829 ASSERT_EQ(42U, size);
830
831 ASSERT_EQ(0, parse_size(&size, "16K"));
832 ASSERT_EQ(16384U, size);
833
834 ASSERT_EQ(0, parse_size(&size, "1M"));
835 ASSERT_EQ(1024U * 1024, size);
836
837 uint64_t gigabyte = 1024ULL * 1024 * 1024;
838 ASSERT_EQ(0, parse_size(&size, "3G"));
839 ASSERT_EQ(3U, size / gigabyte);
840 ASSERT_EQ(0U, size % gigabyte);
841
842 ASSERT_EQ(0, parse_size(&size, "4294967294"));
843 ASSERT_EQ(3U, size / gigabyte);
844 ASSERT_EQ(gigabyte - 2, size % gigabyte);
845
846#if __WORDSIZE == 64
847 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
848 ASSERT_EQ(0, parse_size(&size, "9E"));
849 ASSERT_EQ(9U, size / exabyte);
850 ASSERT_EQ(0U, size % exabyte);
851
852 ASSERT_EQ(0, parse_size(&size, "15E"));
853 ASSERT_EQ(15U, size / exabyte);
854 ASSERT_EQ(0U, size % exabyte);
855
856 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
857 ASSERT_EQ(15U, size / exabyte);
858 ASSERT_EQ(exabyte - 2, size % exabyte);
859
860 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
861 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800862 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100863#elif __WORDSIZE == 32
864 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
865 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
866 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800867 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100868#endif
869
870 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
871 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
872 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100873 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
874 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
875}