blob: c58480823084eb044b82feb84640fb4b63de6991 [file] [log] [blame]
Mike Frysinger50e31fa2018-01-19 18:59:49 -05001/* Copyright 2017 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 system.[ch] module code using gtest.
6 */
Mike Frysinger0b5cffa2017-08-15 18:06:18 -04007
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
Mike Frysinger5fdba4e2018-01-17 15:39:48 -050011#include <sys/stat.h>
Mike Frysinger0b5cffa2017-08-15 18:06:18 -040012#include <unistd.h>
13
14#include <gtest/gtest.h>
15
16#include "system.h"
17
18namespace {
19
20// A random path that really really should not exist on the host.
21const char kNoSuchDir[] = "/.x/..x/...x/path/should/not/exist/";
22
Mike Frysingereaab4202017-08-14 14:57:21 -040023// A random file that should exist.
24const char kValidFile[] = "/etc/passwd";
25
26// A random directory that should exist.
27const char kValidDir[] = "/";
28
29// A random character device that should exist.
30const char kValidCharDev[] = "/dev/null";
31
Mike Frysinger0b5cffa2017-08-15 18:06:18 -040032// Return a temp filename in the cwd that this test can manipulate.
33// It will not exist when it returns, and the user has to free the memory.
34char *get_temp_path() {
35 char *path = strdup("minijail.tests.XXXXXX");
36 if (!path)
37 return nullptr;
38
39 // Just create the temp path.
40 int fd = mkstemp(path);
41 if (fd < 0)
42 return nullptr;
43 close(fd);
44 unlink(path);
45
46 return path;
47}
48
49} // namespace
50
51// Sanity check for the cap range.
52TEST(get_last_valid_cap, basic) {
53 unsigned int cap = get_last_valid_cap();
54
55 // We pick 35 as it's been that since at least v3.0.
56 // If this test is run on older kernels, it might fail.
57 EXPECT_GE(cap, 35u);
58
59 // Pick a really large number that we probably won't hit for a long time.
60 // It helps that caps are bitfields.
61 EXPECT_LT(cap, 128u);
62}
63
64// Might be useful to figure out the return value, but for now,
65// just make sure it doesn't crash?
66TEST(cap_ambient_supported, smoke) {
67 cap_ambient_supported();
68}
69
70// Invalid indexes should return errors, not crash.
71TEST(setup_pipe_end, bad_index) {
72 EXPECT_LT(setup_pipe_end(nullptr, 2), 0);
73 EXPECT_LT(setup_pipe_end(nullptr, 3), 0);
74 EXPECT_LT(setup_pipe_end(nullptr, 4), 0);
75}
76
77// Verify getting the first fd works.
78TEST(setup_pipe_end, index0) {
79 int fds[2];
80 EXPECT_EQ(0, pipe(fds));
81 // This should close fds[1] and return fds[0].
82 EXPECT_EQ(fds[0], setup_pipe_end(fds, 0));
83 // Use close() to verify open/close state.
84 EXPECT_EQ(-1, close(fds[1]));
85 EXPECT_EQ(0, close(fds[0]));
86}
87
88// Verify getting the second fd works.
89TEST(setup_pipe_end, index1) {
90 int fds[2];
91 EXPECT_EQ(0, pipe(fds));
92 // This should close fds[0] and return fds[1].
93 EXPECT_EQ(fds[1], setup_pipe_end(fds, 1));
94 // Use close() to verify open/close state.
95 EXPECT_EQ(-1, close(fds[0]));
96 EXPECT_EQ(0, close(fds[1]));
97}
98
99// Invalid indexes should return errors, not crash.
100TEST(setup_and_dupe_pipe_end, bad_index) {
101 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 2, -1), 0);
102 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 3, -1), 0);
103 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 4, -1), 0);
104}
105
106// An invalid path should return an error.
107TEST(write_pid_to_path, bad_path) {
108 EXPECT_NE(0, write_pid_to_path(0, kNoSuchDir));
109}
110
111// Make sure we can write a pid to the file.
112TEST(write_pid_to_path, basic) {
113 char *path = get_temp_path();
114 ASSERT_NE(nullptr, path);
115
116 EXPECT_EQ(0, write_pid_to_path(1234, path));
117 FILE *fp = fopen(path, "re");
118 unlink(path);
119 EXPECT_NE(nullptr, fp);
lhchavez24b64c22017-09-01 03:52:13 +0000120 char data[6] = {};
Mike Frysinger0b5cffa2017-08-15 18:06:18 -0400121 EXPECT_EQ(5u, fread(data, 1, sizeof(data), fp));
122 fclose(fp);
123 EXPECT_EQ(0, strcmp(data, "1234\n"));
Mike Frysingereaab4202017-08-14 14:57:21 -0400124
125 free(path);
126}
127
128// If the destination exists, there's nothing to do.
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500129// Also check trailing slash handling.
130TEST(mkdir_p, dest_exists) {
131 EXPECT_EQ(0, mkdir_p("/", 0, true));
132 EXPECT_EQ(0, mkdir_p("///", 0, true));
133 EXPECT_EQ(0, mkdir_p("/proc", 0, true));
134 EXPECT_EQ(0, mkdir_p("/proc/", 0, true));
135 EXPECT_EQ(0, mkdir_p("/dev", 0, true));
136 EXPECT_EQ(0, mkdir_p("/dev/", 0, true));
137}
138
139// Create a directory tree that doesn't exist.
140TEST(mkdir_p, create_tree) {
141 char *path = get_temp_path();
142 ASSERT_NE(nullptr, path);
143 unlink(path);
144
145 // Run `mkdir -p <path>/a/b/c`.
146 char *path_a, *path_a_b, *path_a_b_c;
147 ASSERT_NE(-1, asprintf(&path_a, "%s/a", path));
148 ASSERT_NE(-1, asprintf(&path_a_b, "%s/b", path_a));
149 ASSERT_NE(-1, asprintf(&path_a_b_c, "%s/c", path_a_b));
150
151 // First try creating it as a file.
152 EXPECT_EQ(0, mkdir_p(path_a_b_c, 0700, false));
153
154 // Make sure the final path doesn't exist yet.
155 struct stat st;
156 EXPECT_EQ(0, stat(path_a_b, &st));
157 EXPECT_EQ(true, S_ISDIR(st.st_mode));
158 EXPECT_EQ(-1, stat(path_a_b_c, &st));
159
160 // Then create it as a complete dir.
161 EXPECT_EQ(0, mkdir_p(path_a_b_c, 0700, true));
162
163 // Make sure the final dir actually exists.
164 EXPECT_EQ(0, stat(path_a_b_c, &st));
165 EXPECT_EQ(true, S_ISDIR(st.st_mode));
166
167 // Clean up.
168 ASSERT_EQ(0, rmdir(path_a_b_c));
169 ASSERT_EQ(0, rmdir(path_a_b));
170 ASSERT_EQ(0, rmdir(path_a));
171 ASSERT_EQ(0, rmdir(path));
172
173 free(path_a_b_c);
174 free(path_a_b);
175 free(path_a);
176 free(path);
177}
178
179// If the destination exists, there's nothing to do.
Mike Frysingereaab4202017-08-14 14:57:21 -0400180TEST(setup_mount_destination, dest_exists) {
181 // Pick some paths that should always exist. We pass in invalid pointers
182 // for other args so we crash if the dest check doesn't short circuit.
183 EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false));
184 EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true));
185 EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false));
186}
187
188// When given a bind mount where the source is relative, reject it.
189TEST(setup_mount_destination, reject_relative_bind) {
190 // Pick a destination we know doesn't exist.
191 EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true));
192}
193
194// A mount of a pseudo filesystem should make the destination dir.
195TEST(setup_mount_destination, create_pseudo_fs) {
196 char *path = get_temp_path();
197 ASSERT_NE(nullptr, path);
198
199 // Passing -1 for uid/gid tells chown to make no changes.
200 EXPECT_EQ(0, setup_mount_destination("none", path, -1, -1, false));
201 // We check it's a directory by deleting it as such.
202 EXPECT_EQ(0, rmdir(path));
203
204 free(path);
205}
206
207// If the source path does not exist, we should error out.
208TEST(setup_mount_destination, missing_source) {
209 // The missing dest path is so we can exercise the source logic.
210 EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false));
211 EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true));
212}
213
214// A bind mount of a directory should create the destination dir.
215TEST(setup_mount_destination, create_bind_dir) {
216 char *path = get_temp_path();
217 ASSERT_NE(nullptr, path);
218
219 // Passing -1 for uid/gid tells chown to make no changes.
220 EXPECT_EQ(0, setup_mount_destination(kValidDir, path, -1, -1, true));
221 // We check it's a directory by deleting it as such.
222 EXPECT_EQ(0, rmdir(path));
223
224 free(path);
225}
226
227// A bind mount of a file should create the destination file.
228TEST(setup_mount_destination, create_bind_file) {
229 char *path = get_temp_path();
230 ASSERT_NE(nullptr, path);
231
232 // Passing -1 for uid/gid tells chown to make no changes.
233 EXPECT_EQ(0, setup_mount_destination(kValidFile, path, -1, -1, true));
234 // We check it's a file by deleting it as such.
235 EXPECT_EQ(0, unlink(path));
236
237 free(path);
238}
239
240// A mount of a character device should create the destination char.
241TEST(setup_mount_destination, create_char_dev) {
242 char *path = get_temp_path();
243 ASSERT_NE(nullptr, path);
244
245 // Passing -1 for uid/gid tells chown to make no changes.
246 EXPECT_EQ(0, setup_mount_destination(kValidCharDev, path, -1, -1, false));
247 // We check it's a directory by deleting it as such.
248 EXPECT_EQ(0, rmdir(path));
249
250 free(path);
Mike Frysinger0b5cffa2017-08-15 18:06:18 -0400251}