• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 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  */
7 
8 #include <errno.h>
9 
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/wait.h>
14 #include <unistd.h>
15 
16 #include <gtest/gtest.h>
17 
18 #include "libminijail.h"
19 #include "libminijail-private.h"
20 #include "util.h"
21 
22 namespace {
23 
24 #if defined(__ANDROID__)
25 # define ROOT_PREFIX "/system"
26 #else
27 # define ROOT_PREFIX ""
28 #endif
29 
30 const char kShellPath[] = ROOT_PREFIX "/bin/sh";
31 const char kCatPath[] = ROOT_PREFIX "/bin/cat";
32 
33 }  // namespace
34 
35 /* Prototypes needed only by test. */
36 size_t minijail_get_tmpfs_size(const struct minijail *);
37 
38 /* Silence unused variable warnings. */
TEST(silence,silence_unused)39 TEST(silence, silence_unused) {
40   EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
41   EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
42   EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
43 }
44 
TEST(consumebytes,zero)45 TEST(consumebytes, zero) {
46   char buf[1024];
47   size_t len = sizeof(buf);
48   char *pos = &buf[0];
49   EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
50   EXPECT_EQ(&buf[0], pos);
51   EXPECT_EQ(sizeof(buf), len);
52 }
53 
TEST(consumebytes,exact)54 TEST(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)];
60   EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
61   EXPECT_EQ((size_t)0, len);
62   EXPECT_EQ(end, pos);
63 }
64 
TEST(consumebytes,half)65 TEST(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];
71   EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
72   EXPECT_EQ(sizeof(buf) / 2, len);
73   EXPECT_EQ(end, pos);
74 }
75 
TEST(consumebytes,toolong)76 TEST(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. */
81   EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
82   EXPECT_EQ(sizeof(buf), len);
83   EXPECT_EQ(&buf[0], pos);
84 }
85 
TEST(consumestr,zero)86 TEST(consumestr, zero) {
87   char buf[1024];
88   size_t len = 0;
89   char *pos = &buf[0];
90   memset(buf, 0xff, sizeof(buf));
91   EXPECT_EQ(nullptr, consumestr(&pos, &len));
92   EXPECT_EQ((size_t)0, len);
93   EXPECT_EQ(&buf[0], pos);
94 }
95 
TEST(consumestr,nonul)96 TEST(consumestr, nonul) {
97   char buf[1024];
98   size_t len = sizeof(buf);
99   char *pos = &buf[0];
100   memset(buf, 0xff, sizeof(buf));
101   EXPECT_EQ(nullptr, consumestr(&pos, &len));
102   EXPECT_EQ(sizeof(buf), len);
103   EXPECT_EQ(&buf[0], pos);
104 }
105 
TEST(consumestr,full)106 TEST(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 
TEST(consumestr,trailing_nul)117 TEST(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';
123   EXPECT_EQ(nullptr, consumestr(&pos, &len));
124   EXPECT_EQ(sizeof(buf) - 1, len);
125   EXPECT_EQ(&buf[0], pos);
126 }
127 
128 class MarshalTest : public ::testing::Test {
129  protected:
SetUp()130   virtual void SetUp() {
131     m_ = minijail_new();
132     j_ = minijail_new();
133     size_ = minijail_size(m_);
134   }
TearDown()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 
TEST_F(MarshalTest,empty)146 TEST_F(MarshalTest, empty) {
147   ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
148   EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
149 }
150 
151 TEST_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 
TEST(Test,minijail_run_pid_pipes_no_preload)157 TEST(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;
165   char teststr[] = "test\n";
166   size_t teststr_len = strlen(teststr);
167   char *argv[4];
168 
169   struct minijail *j = minijail_new();
170 
171   argv[0] = (char*)kCatPath;
172   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 
192   argv[0] = (char*)kShellPath;
193   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 }
210 
TEST(Test,test_minijail_no_fd_leaks)211 TEST(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 }
266 
TEST(Test,test_minijail_fork)267 TEST(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 
early_exit(void * payload)295 static int early_exit(void* payload) {
296   exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
297 }
298 
TEST(Test,test_minijail_callback)299 TEST(Test, test_minijail_callback) {
300   pid_t pid;
301   int mj_run_ret;
302   int status;
303   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 
313   argv[0] = (char*)kCatPath;
314   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 
TEST(Test,test_minijail_preserve_fd)325 TEST(Test, test_minijail_preserve_fd) {
326   int mj_run_ret;
327   int status;
328   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 
348   argv[0] = (char*)kCatPath;
349   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 
370 namespace {
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).
377 class NamespaceTest : public ::testing::Test {
378  protected:
SetUpTestCase()379   static void SetUpTestCase() {
380     userns_supported_ = UsernsSupported();
381   }
382 
383   // Whether userns is supported.
384   static bool userns_supported_;
385 
UsernsSupported()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 
408 bool NamespaceTest::userns_supported_;
409 
410 }  // namespace
411 
TEST_F(NamespaceTest,test_tmpfs_userns)412 TEST_F(NamespaceTest, test_tmpfs_userns) {
413   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 
420   if (!userns_supported_) {
421     SUCCEED();
422     return;
423   }
424 
425   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 
TEST(Test,parse_size)455 TEST(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"));
492   ASSERT_EQ(-EINVAL, parse_size(&size, "7GTPE"));
493 #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"));
497   ASSERT_EQ(-ERANGE, parse_size(&size, "7GTPE"));
498 #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"));
503   ASSERT_EQ(-EINVAL, parse_size(&size, "-1G"));
504   ASSERT_EQ(-EINVAL, parse_size(&size, "; /bin/rm -- "));
505 }
506