blob: 86a7dbf4f84731c242e97eb345860156f1d4a800 [file] [log] [blame]
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -04001// libminijail_unittest.cpp
2// Copyright (C) 2016 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// Test platform independent logic of Minijail using gtest.
17
18#include <errno.h>
19
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040020#include <fcntl.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040021#include <sys/types.h>
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040022#include <sys/stat.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040023#include <sys/wait.h>
Dylan Reid0412dcc2017-08-24 11:33:15 -070024#include <unistd.h>
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040025
26#include <gtest/gtest.h>
27
28#include "libminijail.h"
29#include "libminijail-private.h"
30#include "util.h"
31
Mike Frysingerb2c12d12017-09-29 21:18:59 -040032namespace {
33
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040034#if defined(__ANDROID__)
Mike Frysingerb2c12d12017-09-29 21:18:59 -040035# define ROOT_PREFIX "/system"
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040036#else
Mike Frysingerb2c12d12017-09-29 21:18:59 -040037# define ROOT_PREFIX ""
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040038#endif
39
Mike Frysingerb2c12d12017-09-29 21:18:59 -040040const char kShellPath[] = ROOT_PREFIX "/bin/sh";
41const char kCatPath[] = ROOT_PREFIX "/bin/cat";
42
43} // namespace
44
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040045/* Prototypes needed only by test. */
Martin Pelikánab9eb442017-01-25 11:53:58 +110046size_t minijail_get_tmpfs_size(const struct minijail *);
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040047
48/* Silence unused variable warnings. */
49TEST(silence, silence_unused) {
50 EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
51 EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
52 EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
53}
54
55TEST(consumebytes, zero) {
56 char buf[1024];
57 size_t len = sizeof(buf);
58 char *pos = &buf[0];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040059 EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040060 EXPECT_EQ(&buf[0], pos);
61 EXPECT_EQ(sizeof(buf), len);
62}
63
64TEST(consumebytes, exact) {
65 char buf[1024];
66 size_t len = sizeof(buf);
67 char *pos = &buf[0];
68 /* One past the end since it consumes the whole buffer. */
69 char *end = &buf[sizeof(buf)];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040070 EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040071 EXPECT_EQ((size_t)0, len);
72 EXPECT_EQ(end, pos);
73}
74
75TEST(consumebytes, half) {
76 char buf[1024];
77 size_t len = sizeof(buf);
78 char *pos = &buf[0];
79 /* One past the end since it consumes the whole buffer. */
80 char *end = &buf[sizeof(buf) / 2];
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040081 EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040082 EXPECT_EQ(sizeof(buf) / 2, len);
83 EXPECT_EQ(end, pos);
84}
85
86TEST(consumebytes, toolong) {
87 char buf[1024];
88 size_t len = sizeof(buf);
89 char *pos = &buf[0];
90 /* One past the end since it consumes the whole buffer. */
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -040091 EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -040092 EXPECT_EQ(sizeof(buf), len);
93 EXPECT_EQ(&buf[0], pos);
94}
95
96TEST(consumestr, zero) {
97 char buf[1024];
98 size_t len = 0;
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((size_t)0, len);
103 EXPECT_EQ(&buf[0], pos);
104}
105
106TEST(consumestr, nonul) {
107 char buf[1024];
108 size_t len = sizeof(buf);
109 char *pos = &buf[0];
110 memset(buf, 0xff, sizeof(buf));
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400111 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400112 EXPECT_EQ(sizeof(buf), len);
113 EXPECT_EQ(&buf[0], pos);
114}
115
116TEST(consumestr, full) {
117 char buf[1024];
118 size_t len = sizeof(buf);
119 char *pos = &buf[0];
120 memset(buf, 0xff, sizeof(buf));
121 buf[sizeof(buf)-1] = '\0';
122 EXPECT_EQ((void *)buf, consumestr(&pos, &len));
123 EXPECT_EQ((size_t)0, len);
124 EXPECT_EQ(&buf[sizeof(buf)], pos);
125}
126
127TEST(consumestr, trailing_nul) {
128 char buf[1024];
129 size_t len = sizeof(buf) - 1;
130 char *pos = &buf[0];
131 memset(buf, 0xff, sizeof(buf));
132 buf[sizeof(buf)-1] = '\0';
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400133 EXPECT_EQ(nullptr, consumestr(&pos, &len));
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400134 EXPECT_EQ(sizeof(buf) - 1, len);
135 EXPECT_EQ(&buf[0], pos);
136}
137
138class MarshalTest : public ::testing::Test {
139 protected:
140 virtual void SetUp() {
141 m_ = minijail_new();
142 j_ = minijail_new();
143 size_ = minijail_size(m_);
144 }
145 virtual void TearDown() {
146 minijail_destroy(m_);
147 minijail_destroy(j_);
148 }
149
150 char buf_[4096];
151 struct minijail *m_;
152 struct minijail *j_;
153 size_t size_;
154};
155
156TEST_F(MarshalTest, empty) {
157 ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
158 EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
159}
160
161TEST_F(MarshalTest, 0xff) {
162 memset(buf_, 0xff, sizeof(buf_));
163 /* Should fail on the first consumestr since a NUL will never be found. */
164 EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
165}
166
167TEST(Test, minijail_run_pid_pipes_no_preload) {
168 pid_t pid;
169 int child_stdin, child_stdout, child_stderr;
170 int mj_run_ret;
171 ssize_t write_ret, read_ret;
172 const size_t buf_len = 128;
173 char buf[buf_len];
174 int status;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400175 char teststr[] = "test\n";
176 size_t teststr_len = strlen(teststr);
177 char *argv[4];
178
179 struct minijail *j = minijail_new();
180
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400181 argv[0] = (char*)kCatPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400182 argv[1] = NULL;
183 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
184 &pid,
185 &child_stdin, &child_stdout,
186 NULL);
187 EXPECT_EQ(mj_run_ret, 0);
188
189 write_ret = write(child_stdin, teststr, teststr_len);
190 EXPECT_EQ(write_ret, (int)teststr_len);
191
192 read_ret = read(child_stdout, buf, 8);
193 EXPECT_EQ(read_ret, (int)teststr_len);
194 buf[teststr_len] = 0;
195 EXPECT_EQ(strcmp(buf, teststr), 0);
196
197 EXPECT_EQ(kill(pid, SIGTERM), 0);
198 waitpid(pid, &status, 0);
199 ASSERT_TRUE(WIFSIGNALED(status));
200 EXPECT_EQ(WTERMSIG(status), SIGTERM);
201
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400202 argv[0] = (char*)kShellPath;
Jorge Lucangeli Obesa67bd6a2016-08-19 15:33:48 -0400203 argv[1] = "-c";
204 argv[2] = "echo test >&2";
205 argv[3] = NULL;
206 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
207 &child_stdin, &child_stdout,
208 &child_stderr);
209 EXPECT_EQ(mj_run_ret, 0);
210
211 read_ret = read(child_stderr, buf, buf_len);
212 EXPECT_GE(read_ret, (int)teststr_len);
213
214 waitpid(pid, &status, 0);
215 ASSERT_TRUE(WIFEXITED(status));
216 EXPECT_EQ(WEXITSTATUS(status), 0);
217
218 minijail_destroy(j);
219}
Jorge Lucangeli Obese9740af2016-11-02 13:39:24 -0400220
221TEST(Test, test_minijail_no_fd_leaks) {
222 pid_t pid;
223 int child_stdout;
224 int mj_run_ret;
225 ssize_t read_ret;
226 const size_t buf_len = 128;
227 char buf[buf_len];
228 char script[buf_len];
229 int status;
230 char *argv[4];
231
232 int dev_null = open("/dev/null", O_RDONLY);
233 ASSERT_NE(dev_null, -1);
234 snprintf(script,
235 sizeof(script),
236 "[ -e /proc/self/fd/%d ] && echo yes || echo no",
237 dev_null);
238
239 struct minijail *j = minijail_new();
240
241 argv[0] = (char*)kShellPath;
242 argv[1] = "-c";
243 argv[2] = script;
244 argv[3] = NULL;
245 mj_run_ret = minijail_run_pid_pipes_no_preload(
246 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
247 EXPECT_EQ(mj_run_ret, 0);
248
249 read_ret = read(child_stdout, buf, buf_len);
250 EXPECT_GE(read_ret, 0);
251 buf[read_ret] = '\0';
252 EXPECT_STREQ(buf, "yes\n");
253
254 waitpid(pid, &status, 0);
255 ASSERT_TRUE(WIFEXITED(status));
256 EXPECT_EQ(WEXITSTATUS(status), 0);
257
258 minijail_close_open_fds(j);
259 mj_run_ret = minijail_run_pid_pipes_no_preload(
260 j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
261 EXPECT_EQ(mj_run_ret, 0);
262
263 read_ret = read(child_stdout, buf, buf_len);
264 EXPECT_GE(read_ret, 0);
265 buf[read_ret] = '\0';
266 EXPECT_STREQ(buf, "no\n");
267
268 waitpid(pid, &status, 0);
269 ASSERT_TRUE(WIFEXITED(status));
270 EXPECT_EQ(WEXITSTATUS(status), 0);
271
272 minijail_destroy(j);
273
274 close(dev_null);
275}
Martin Pelikánab9eb442017-01-25 11:53:58 +1100276
Dylan Reid0412dcc2017-08-24 11:33:15 -0700277TEST(Test, test_minijail_fork) {
278 pid_t mj_fork_ret;
279 int status;
280 int pipe_fds[2];
281 ssize_t pid_size = sizeof(mj_fork_ret);
282
283 struct minijail *j = minijail_new();
284
285 ASSERT_EQ(pipe(pipe_fds), 0);
286
287 mj_fork_ret = minijail_fork(j);
288 ASSERT_GE(mj_fork_ret, 0);
289 if (mj_fork_ret == 0) {
290 pid_t pid_in_parent;
291 // Wait for the parent to tell us the pid in the parent namespace.
292 EXPECT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
293 EXPECT_EQ(pid_in_parent, getpid());
294 exit(0);
295 }
296
297 EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
298 waitpid(mj_fork_ret, &status, 0);
299 ASSERT_TRUE(WIFEXITED(status));
300 EXPECT_EQ(WEXITSTATUS(status), 0);
301
302 minijail_destroy(j);
303}
304
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700305static int early_exit(void* payload) {
306 exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
307}
308
309TEST(Test, test_minijail_callback) {
310 pid_t pid;
311 int mj_run_ret;
312 int status;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700313 char *argv[2];
314 int exit_code = 42;
315
316 struct minijail *j = minijail_new();
317
318 status =
319 minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
320 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
321 EXPECT_EQ(status, 0);
322
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400323 argv[0] = (char*)kCatPath;
Luis Hector Chaveze0ba4ce2017-07-20 15:12:22 -0700324 argv[1] = NULL;
325 mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
326 NULL, NULL);
327 EXPECT_EQ(mj_run_ret, 0);
328
329 status = minijail_wait(j);
330 EXPECT_EQ(status, exit_code);
331
332 minijail_destroy(j);
333}
334
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700335TEST(Test, test_minijail_preserve_fd) {
336 int mj_run_ret;
337 int status;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700338 char *argv[2];
339 char teststr[] = "test\n";
340 size_t teststr_len = strlen(teststr);
341 int read_pipe[2];
342 int write_pipe[2];
343 char buf[1024];
344
345 struct minijail *j = minijail_new();
346
347 status = pipe(read_pipe);
348 ASSERT_EQ(status, 0);
349 status = pipe(write_pipe);
350 ASSERT_EQ(status, 0);
351
352 status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
353 ASSERT_EQ(status, 0);
354 status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
355 ASSERT_EQ(status, 0);
356 minijail_close_open_fds(j);
357
Mike Frysingerb2c12d12017-09-29 21:18:59 -0400358 argv[0] = (char*)kCatPath;
Luis Hector Chavez1617f632017-08-01 18:32:30 -0700359 argv[1] = NULL;
360 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
361 EXPECT_EQ(mj_run_ret, 0);
362
363 close(write_pipe[0]);
364 status = write(write_pipe[1], teststr, teststr_len);
365 EXPECT_EQ(status, (int)teststr_len);
366 close(write_pipe[1]);
367
368 close(read_pipe[1]);
369 status = read(read_pipe[0], buf, 8);
370 EXPECT_EQ(status, (int)teststr_len);
371 buf[teststr_len] = 0;
372 EXPECT_EQ(strcmp(buf, teststr), 0);
373
374 status = minijail_wait(j);
375 EXPECT_EQ(status, 0);
376
377 minijail_destroy(j);
378}
379
Mike Frysinger780aef72017-10-03 01:39:52 -0400380namespace {
381
382// Tests that require userns access.
383// Android unit tests don't currently support entering user namespaces as
384// unprivileged users due to having an older kernel. Chrome OS unit tests
385// don't support it either due to being in a chroot environment (see man 2
386// clone for more information about failure modes with the CLONE_NEWUSER flag).
387class NamespaceTest : public ::testing::Test {
388 protected:
389 static void SetUpTestCase() {
390 userns_supported_ = UsernsSupported();
391 }
392
393 // Whether userns is supported.
394 static bool userns_supported_;
395
396 static bool UsernsSupported() {
397 pid_t pid = fork();
398 if (pid == -1)
399 pdie("could not fork");
400
401 if (pid == 0)
402 _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
403
404 int status;
405 if (waitpid(pid, &status, 0) < 0)
406 pdie("could not wait");
407
408 if (!WIFEXITED(status))
409 die("child did not exit properly: %#x", status);
410
411 bool ret = WEXITSTATUS(status) == 0;
412 if (!ret)
413 warn("Skipping userns related tests");
414 return ret;
415 }
416};
417
418bool NamespaceTest::userns_supported_;
419
420} // namespace
421
422TEST_F(NamespaceTest, test_tmpfs_userns) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700423 int mj_run_ret;
424 int status;
425 char *argv[4];
426 char uidmap[128], gidmap[128];
427 constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
428 constexpr gid_t kTargetGid = 1000;
429
Mike Frysinger780aef72017-10-03 01:39:52 -0400430 if (!userns_supported_) {
431 SUCCEED();
432 return;
433 }
434
Luis Hector Chavez71323552017-09-05 09:17:22 -0700435 struct minijail *j = minijail_new();
436
437 minijail_namespace_pids(j);
438 minijail_namespace_vfs(j);
439 minijail_mount_tmp(j);
440 minijail_run_as_init(j);
441
442 // Perform userns mapping.
443 minijail_namespace_user(j);
444 snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
445 snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
446 minijail_change_uid(j, kTargetUid);
447 minijail_change_gid(j, kTargetGid);
448 minijail_uidmap(j, uidmap);
449 minijail_gidmap(j, gidmap);
450 minijail_namespace_user_disable_setgroups(j);
451
452 argv[0] = (char*)kShellPath;
453 argv[1] = "-c";
454 argv[2] = "exec touch /tmp/foo";
455 argv[3] = NULL;
456 mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
457 EXPECT_EQ(mj_run_ret, 0);
458
459 status = minijail_wait(j);
460 EXPECT_EQ(status, 0);
461
462 minijail_destroy(j);
463}
464
Martin Pelikánab9eb442017-01-25 11:53:58 +1100465TEST(Test, parse_size) {
466 size_t size;
467
468 ASSERT_EQ(0, parse_size(&size, "42"));
469 ASSERT_EQ(42U, size);
470
471 ASSERT_EQ(0, parse_size(&size, "16K"));
472 ASSERT_EQ(16384U, size);
473
474 ASSERT_EQ(0, parse_size(&size, "1M"));
475 ASSERT_EQ(1024U * 1024, size);
476
477 uint64_t gigabyte = 1024ULL * 1024 * 1024;
478 ASSERT_EQ(0, parse_size(&size, "3G"));
479 ASSERT_EQ(3U, size / gigabyte);
480 ASSERT_EQ(0U, size % gigabyte);
481
482 ASSERT_EQ(0, parse_size(&size, "4294967294"));
483 ASSERT_EQ(3U, size / gigabyte);
484 ASSERT_EQ(gigabyte - 2, size % gigabyte);
485
486#if __WORDSIZE == 64
487 uint64_t exabyte = gigabyte * 1024 * 1024 * 1024;
488 ASSERT_EQ(0, parse_size(&size, "9E"));
489 ASSERT_EQ(9U, size / exabyte);
490 ASSERT_EQ(0U, size % exabyte);
491
492 ASSERT_EQ(0, parse_size(&size, "15E"));
493 ASSERT_EQ(15U, size / exabyte);
494 ASSERT_EQ(0U, size % exabyte);
495
496 ASSERT_EQ(0, parse_size(&size, "18446744073709551614"));
497 ASSERT_EQ(15U, size / exabyte);
498 ASSERT_EQ(exabyte - 2, size % exabyte);
499
500 ASSERT_EQ(-ERANGE, parse_size(&size, "16E"));
501 ASSERT_EQ(-ERANGE, parse_size(&size, "19E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800502 ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100503#elif __WORDSIZE == 32
504 ASSERT_EQ(-ERANGE, parse_size(&size, "5G"));
505 ASSERT_EQ(-ERANGE, parse_size(&size, "9G"));
506 ASSERT_EQ(-ERANGE, parse_size(&size, "9E"));
Chirantan Ekbote8c13d102017-02-09 12:33:19 -0800507 ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100508#endif
509
510 ASSERT_EQ(-EINVAL, parse_size(&size, ""));
511 ASSERT_EQ(-EINVAL, parse_size(&size, "14u"));
512 ASSERT_EQ(-EINVAL, parse_size(&size, "14.2G"));
Martin Pelikánab9eb442017-01-25 11:53:58 +1100513 ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
514 ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
515}