blob: 71aa6cd6de8b3fe2155291b6e01db700116a17f2 [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
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040010#include <fcntl.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040011#include <sys/types.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040012#include <sys/stat.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040013#include <sys/wait.h>
Dylan Reid0412dcc2017-08-24 11:33:15 -070014#include <unistd.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040015
16#include <gtest/gtest.h>
17
18#include "libminijail.h"
19#include "libminijail-private.h"
20#include "util.h"
21
Mike Frysingerb2c12d12017-09-29 21:18:59 -040022namespace {
23
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040024#if defined(__ANDROID__)
Mike Frysingerb2c12d12017-09-29 21:18:59 -040025# define ROOT_PREFIX "/system"
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040026#else
Mike Frysingerb2c12d12017-09-29 21:18:59 -040027# define ROOT_PREFIX ""
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040028#endif
29
Mike Frysingerb2c12d12017-09-29 21:18:59 -040030const char kShellPath[] = ROOT_PREFIX "/bin/sh";
31const char kCatPath[] = ROOT_PREFIX "/bin/cat";
32
33} // namespace
34
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040035/* Prototypes needed only by test. */
Martin Pelikánab9eb442017-01-25 11:53:58 +110036size_t minijail_get_tmpfs_size(const struct minijail *);
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040037
38/* Silence unused variable warnings. */
39TEST(silence, silence_unused) {
40 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
41 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
42 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
43}
44
45TEST(consumebytes, zero) {
46 char buf[1024];
47 size_t len = sizeof(buf);
48 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040049 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040050 EXPECT_EQ(&buf[0], pos);
51 EXPECT_EQ(sizeof(buf), len);
52}
53
54TEST(consumebytes, exact) {
55 char buf[1024];
56 size_t len = sizeof(buf);
57 char *pos = &buf[0];
58 /* One past the end since it consumes the whole buffer. */
59 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040060 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040061 EXPECT_EQ((size_t)0, len);
62 EXPECT_EQ(end, pos);
63}
64
65TEST(consumebytes, half) {
66 char buf[1024];
67 size_t len = sizeof(buf);
68 char *pos = &buf[0];
69 /* One past the end since it consumes the whole buffer. */
70 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040071 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040072 EXPECT_EQ(sizeof(buf) / 2, len);
73 EXPECT_EQ(end, pos);
74}
75
76TEST(consumebytes, toolong) {
77 char buf[1024];
78 size_t len = sizeof(buf);
79 char *pos = &buf[0];
80 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040081 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040082 EXPECT_EQ(sizeof(buf), len);
83 EXPECT_EQ(&buf[0], pos);
84}
85
86TEST(consumestr, zero) {
87 char buf[1024];
88 size_t len = 0;
89 char *pos = &buf[0];
90 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040091 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040092 EXPECT_EQ((size_t)0, len);
93 EXPECT_EQ(&buf[0], pos);
94}
95
96TEST(consumestr, nonul) {
97 char buf[1024];
98 size_t len = sizeof(buf);
99 char *pos = &buf[0];
100 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400101 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400102 EXPECT_EQ(sizeof(buf), len);
103 EXPECT_EQ(&buf[0], pos);
104}
105
106TEST(consumestr, full) {
107 char buf[1024];
108 size_t len = sizeof(buf);
109 char *pos = &buf[0];
110 memset(buf, 0xff, sizeof(buf));
111 buf[sizeof(buf)-1] = '\0';
112 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
113 EXPECT_EQ((size_t)0, len);
114 EXPECT_EQ(&buf[sizeof(buf)], pos);
115}
116
117TEST(consumestr, trailing_nul) {
118 char buf[1024];
119 size_t len = sizeof(buf) - 1;
120 char *pos = &buf[0];
121 memset(buf, 0xff, sizeof(buf));
122 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400123 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400124 EXPECT_EQ(sizeof(buf) - 1, len);
125 EXPECT_EQ(&buf[0], pos);
126}
127
128class MarshalTest : public ::testing::Test {
129 protected:
130 virtual void SetUp() {
131 m_ = minijail_new();
132 j_ = minijail_new();
133 size_ = minijail_size(m_);
134 }
135 virtual void TearDown() {
136 minijail_destroy(m_);
137 minijail_destroy(j_);
138 }
139
140 char buf_[4096];
141 struct minijail *m_;
142 struct minijail *j_;
143 size_t size_;
144};
145
146TEST_F(MarshalTest, empty) {
147 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
148 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
149}
150
151TEST_F(MarshalTest, 0xff) {
152 memset(buf_, 0xff, sizeof(buf_));
153 /* Should fail on the first consumestr since a NUL will never be found. */
154 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
155}
156
157TEST(Test, minijail_run_pid_pipes_no_preload) {
158 pid_t pid;
159 int child_stdin, child_stdout, child_stderr;
160 int mj_run_ret;
161 ssize_t write_ret, read_ret;
162 const size_t buf_len = 128;
163 char buf[buf_len];
164 int status;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400165 char teststr[] = "test\n";
166 size_t teststr_len = strlen(teststr);
167 char *argv[4];
168
169 struct minijail *j = minijail_new();
170
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400171 argv[0] = (char*)kCatPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400172 argv[1] = NULL;
173 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
174 &pid,
175 &child_stdin, &child_stdout,
176 NULL);
177 EXPECT_EQ(mj_run_ret, 0);
178
179 write_ret = write(child_stdin, teststr, teststr_len);
180 EXPECT_EQ(write_ret, (int)teststr_len);
181
182 read_ret = read(child_stdout, buf, 8);
183 EXPECT_EQ(read_ret, (int)teststr_len);
184 buf[teststr_len] = 0;
185 EXPECT_EQ(strcmp(buf, teststr), 0);
186
187 EXPECT_EQ(kill(pid, SIGTERM), 0);
188 waitpid(pid, &status, 0);
189 ASSERT_TRUE(WIFSIGNALED(status));
190 EXPECT_EQ(WTERMSIG(status), SIGTERM);
191
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400192 argv[0] = (char*)kShellPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400193 argv[1] = "-c";
194 argv[2] = "echo test >&2";
195 argv[3] = NULL;
196 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
197 &child_stdin, &child_stdout,
198 &child_stderr);
199 EXPECT_EQ(mj_run_ret, 0);
200
201 read_ret = read(child_stderr, buf, buf_len);
202 EXPECT_GE(read_ret, (int)teststr_len);
203
204 waitpid(pid, &status, 0);
205 ASSERT_TRUE(WIFEXITED(status));
206 EXPECT_EQ(WEXITSTATUS(status), 0);
207
208 minijail_destroy(j);
209}
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400210
211TEST(Test, test_minijail_no_fd_leaks) {
212 pid_t pid;
213 int child_stdout;
214 int mj_run_ret;
215 ssize_t read_ret;
216 const size_t buf_len = 128;
217 char buf[buf_len];
218 char script[buf_len];
219 int status;
220 char *argv[4];
221
222 int dev_null = open("/dev/null", O_RDONLY);
223 ASSERT_NE(dev_null, -1);
224 snprintf(script,
225 sizeof(script),
226 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
227 dev_null);
228
229 struct minijail *j = minijail_new();
230
231 argv[0] = (char*)kShellPath;
232 argv[1] = "-c";
233 argv[2] = script;
234 argv[3] = NULL;
235 mj_run_ret = minijail_run_pid_pipes_no_preload(
236 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
237 EXPECT_EQ(mj_run_ret, 0);
238
239 read_ret = read(child_stdout, buf, buf_len);
240 EXPECT_GE(read_ret, 0);
241 buf[read_ret] = '\0';
242 EXPECT_STREQ(buf, "yes\n");
243
244 waitpid(pid, &status, 0);
245 ASSERT_TRUE(WIFEXITED(status));
246 EXPECT_EQ(WEXITSTATUS(status), 0);
247
248 minijail_close_open_fds(j);
249 mj_run_ret = minijail_run_pid_pipes_no_preload(
250 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
251 EXPECT_EQ(mj_run_ret, 0);
252
253 read_ret = read(child_stdout, buf, buf_len);
254 EXPECT_GE(read_ret, 0);
255 buf[read_ret] = '\0';
256 EXPECT_STREQ(buf, "no\n");
257
258 waitpid(pid, &status, 0);
259 ASSERT_TRUE(WIFEXITED(status));
260 EXPECT_EQ(WEXITSTATUS(status), 0);
261
262 minijail_destroy(j);
263
264 close(dev_null);
265}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100266
Dylan Reid0412dcc2017-08-24 11:33:15 -0700267TEST(Test, test_minijail_fork) {
268 pid_t mj_fork_ret;
269 int status;
270 int pipe_fds[2];
271 ssize_t pid_size = sizeof(mj_fork_ret);
272
273 struct minijail *j = minijail_new();
274
275 ASSERT_EQ(pipe(pipe_fds), 0);
276
277 mj_fork_ret = minijail_fork(j);
278 ASSERT_GE(mj_fork_ret, 0);
279 if (mj_fork_ret == 0) {
280 pid_t pid_in_parent;
281 // Wait for the parent to tell us the pid in the parent namespace.
282 EXPECT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
283 EXPECT_EQ(pid_in_parent, getpid());
284 exit(0);
285 }
286
287 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
288 waitpid(mj_fork_ret, &status, 0);
289 ASSERT_TRUE(WIFEXITED(status));
290 EXPECT_EQ(WEXITSTATUS(status), 0);
291
292 minijail_destroy(j);
293}
294
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700295static int early_exit(void* payload) {
296 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
297}
298
299TEST(Test, test_minijail_callback) {
300 pid_t pid;
301 int mj_run_ret;
302 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700303 char *argv[2];
304 int exit_code = 42;
305
306 struct minijail *j = minijail_new();
307
308 status =
309 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
310 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
311 EXPECT_EQ(status, 0);
312
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400313 argv[0] = (char*)kCatPath;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700314 argv[1] = NULL;
315 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
316 NULL, NULL);
317 EXPECT_EQ(mj_run_ret, 0);
318
319 status = minijail_wait(j);
320 EXPECT_EQ(status, exit_code);
321
322 minijail_destroy(j);
323}
324
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700325TEST(Test, test_minijail_preserve_fd) {
326 int mj_run_ret;
327 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700328 char *argv[2];
329 char teststr[] = "test\n";
330 size_t teststr_len = strlen(teststr);
331 int read_pipe[2];
332 int write_pipe[2];
333 char buf[1024];
334
335 struct minijail *j = minijail_new();
336
337 status = pipe(read_pipe);
338 ASSERT_EQ(status, 0);
339 status = pipe(write_pipe);
340 ASSERT_EQ(status, 0);
341
342 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
343 ASSERT_EQ(status, 0);
344 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
345 ASSERT_EQ(status, 0);
346 minijail_close_open_fds(j);
347
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400348 argv[0] = (char*)kCatPath;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700349 argv[1] = NULL;
350 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
351 EXPECT_EQ(mj_run_ret, 0);
352
353 close(write_pipe[0]);
354 status = write(write_pipe[1], teststr, teststr_len);
355 EXPECT_EQ(status, (int)teststr_len);
356 close(write_pipe[1]);
357
358 close(read_pipe[1]);
359 status = read(read_pipe[0], buf, 8);
360 EXPECT_EQ(status, (int)teststr_len);
361 buf[teststr_len] = 0;
362 EXPECT_EQ(strcmp(buf, teststr), 0);
363
364 status = minijail_wait(j);
365 EXPECT_EQ(status, 0);
366
367 minijail_destroy(j);
368}
369
Mike Frysinger780aef72017-10-03 01:39:52 -0400370namespace {
371
372// Tests that require userns access.
373// Android unit tests don't currently support entering user namespaces as
374// unprivileged users due to having an older kernel. Chrome OS unit tests
375// don't support it either due to being in a chroot environment (see man 2
376// clone for more information about failure modes with the CLONE_NEWUSER flag).
377class NamespaceTest : public ::testing::Test {
378 protected:
379 static void SetUpTestCase() {
380 userns_supported_ = UsernsSupported();
381 }
382
383 // Whether userns is supported.
384 static bool userns_supported_;
385
386 static bool UsernsSupported() {
387 pid_t pid = fork();
388 if (pid == -1)
389 pdie("could not fork");
390
391 if (pid == 0)
392 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
393
394 int status;
395 if (waitpid(pid, &status, 0) < 0)
396 pdie("could not wait");
397
398 if (!WIFEXITED(status))
399 die("child did not exit properly: %#x", status);
400
401 bool ret = WEXITSTATUS(status) == 0;
402 if (!ret)
403 warn("Skipping userns related tests");
404 return ret;
405 }
406};
407
408bool NamespaceTest::userns_supported_;
409
410} // namespace
411
412TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700413 int mj_run_ret;
414 int status;
415 char *argv[4];
416 char uidmap[128], gidmap[128];
417 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
418 constexpr gid_t kTargetGid = 1000;
419
Mike Frysinger780aef72017-10-03 01:39:52 -0400420 if (!userns_supported_) {
421 SUCCEED();
422 return;
423 }
424
Luis Hector Chavez71323552017-09-05 09:17:22 -0700425 struct minijail *j = minijail_new();
426
427 minijail_namespace_pids(j);
428 minijail_namespace_vfs(j);
429 minijail_mount_tmp(j);
430 minijail_run_as_init(j);
431
432 // Perform userns mapping.
433 minijail_namespace_user(j);
434 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
435 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
436 minijail_change_uid(j, kTargetUid);
437 minijail_change_gid(j, kTargetGid);
438 minijail_uidmap(j, uidmap);
439 minijail_gidmap(j, gidmap);
440 minijail_namespace_user_disable_setgroups(j);
441
442 argv[0] = (char*)kShellPath;
443 argv[1] = "-c";
444 argv[2] = "exec touch /tmp/foo";
445 argv[3] = NULL;
446 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
447 EXPECT_EQ(mj_run_ret, 0);
448
449 status = minijail_wait(j);
450 EXPECT_EQ(status, 0);
451
452 minijail_destroy(j);
453}
454
Martin Pelikánab9eb442017-01-25 11:53:58 +1100455TEST(Test, parse_size) {
456 size_t size;
457
458 ASSERT_EQ(0, parse_size(&size, "42"));
459 ASSERT_EQ(42U, size);
460
461 ASSERT_EQ(0, parse_size(&size, "16K"));
462 ASSERT_EQ(16384U, size);
463
464 ASSERT_EQ(0, parse_size(&size, "1M"));
465 ASSERT_EQ(1024U * 1024, size);
466
467 uint64_t gigabyte = 1024ULL * 1024 * 1024;
468 ASSERT_EQ(0, parse_size(&size, "3G"));
469 ASSERT_EQ(3U, size / gigabyte);
470 ASSERT_EQ(0U, size % gigabyte);
471
472 ASSERT_EQ(0, parse_size(&size, "4294967294"));
473 ASSERT_EQ(3U, size / gigabyte);
474 ASSERT_EQ(gigabyte - 2, size % gigabyte);
475
476#if __WORDSIZE == 64
477 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
478 ASSERT_EQ(0, parse_size(&size, "9E"));
479 ASSERT_EQ(9U, size / exabyte);
480 ASSERT_EQ(0U, size % exabyte);
481
482 ASSERT_EQ(0, parse_size(&size, "15E"));
483 ASSERT_EQ(15U, size / exabyte);
484 ASSERT_EQ(0U, size % exabyte);
485
486 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
487 ASSERT_EQ(15U, size / exabyte);
488 ASSERT_EQ(exabyte - 2, size % exabyte);
489
490 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
491 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800492 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100493#elif __WORDSIZE == 32
494 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
495 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
496 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800497 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100498#endif
499
500 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
501 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
502 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100503 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
504 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
505}