blob: db5fe9840782ec010f9a7141097ad30e9ac9ad62 [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>
11#include <unistd.h>
12
13#include <gtest/gtest.h>
14
15#include "system.h"
16
17namespace {
18
19// A random path that really really should not exist on the host.
20const char kNoSuchDir[] = "/.x/..x/...x/path/should/not/exist/";
21
Mike Frysingereaab4202017-08-14 14:57:21 -040022// A random file that should exist.
23const char kValidFile[] = "/etc/passwd";
24
25// A random directory that should exist.
26const char kValidDir[] = "/";
27
28// A random character device that should exist.
29const char kValidCharDev[] = "/dev/null";
30
Mike Frysinger0b5cffa2017-08-15 18:06:18 -040031// Return a temp filename in the cwd that this test can manipulate.
32// It will not exist when it returns, and the user has to free the memory.
33char *get_temp_path() {
34 char *path = strdup("minijail.tests.XXXXXX");
35 if (!path)
36 return nullptr;
37
38 // Just create the temp path.
39 int fd = mkstemp(path);
40 if (fd < 0)
41 return nullptr;
42 close(fd);
43 unlink(path);
44
45 return path;
46}
47
48} // namespace
49
50// Sanity check for the cap range.
51TEST(get_last_valid_cap, basic) {
52 unsigned int cap = get_last_valid_cap();
53
54 // We pick 35 as it's been that since at least v3.0.
55 // If this test is run on older kernels, it might fail.
56 EXPECT_GE(cap, 35u);
57
58 // Pick a really large number that we probably won't hit for a long time.
59 // It helps that caps are bitfields.
60 EXPECT_LT(cap, 128u);
61}
62
63// Might be useful to figure out the return value, but for now,
64// just make sure it doesn't crash?
65TEST(cap_ambient_supported, smoke) {
66 cap_ambient_supported();
67}
68
69// Invalid indexes should return errors, not crash.
70TEST(setup_pipe_end, bad_index) {
71 EXPECT_LT(setup_pipe_end(nullptr, 2), 0);
72 EXPECT_LT(setup_pipe_end(nullptr, 3), 0);
73 EXPECT_LT(setup_pipe_end(nullptr, 4), 0);
74}
75
76// Verify getting the first fd works.
77TEST(setup_pipe_end, index0) {
78 int fds[2];
79 EXPECT_EQ(0, pipe(fds));
80 // This should close fds[1] and return fds[0].
81 EXPECT_EQ(fds[0], setup_pipe_end(fds, 0));
82 // Use close() to verify open/close state.
83 EXPECT_EQ(-1, close(fds[1]));
84 EXPECT_EQ(0, close(fds[0]));
85}
86
87// Verify getting the second fd works.
88TEST(setup_pipe_end, index1) {
89 int fds[2];
90 EXPECT_EQ(0, pipe(fds));
91 // This should close fds[0] and return fds[1].
92 EXPECT_EQ(fds[1], setup_pipe_end(fds, 1));
93 // Use close() to verify open/close state.
94 EXPECT_EQ(-1, close(fds[0]));
95 EXPECT_EQ(0, close(fds[1]));
96}
97
98// Invalid indexes should return errors, not crash.
99TEST(setup_and_dupe_pipe_end, bad_index) {
100 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 2, -1), 0);
101 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 3, -1), 0);
102 EXPECT_LT(setup_and_dupe_pipe_end(nullptr, 4, -1), 0);
103}
104
105// An invalid path should return an error.
106TEST(write_pid_to_path, bad_path) {
107 EXPECT_NE(0, write_pid_to_path(0, kNoSuchDir));
108}
109
110// Make sure we can write a pid to the file.
111TEST(write_pid_to_path, basic) {
112 char *path = get_temp_path();
113 ASSERT_NE(nullptr, path);
114
115 EXPECT_EQ(0, write_pid_to_path(1234, path));
116 FILE *fp = fopen(path, "re");
117 unlink(path);
118 EXPECT_NE(nullptr, fp);
lhchavez24b64c22017-09-01 03:52:13 +0000119 char data[6] = {};
Mike Frysinger0b5cffa2017-08-15 18:06:18 -0400120 EXPECT_EQ(5u, fread(data, 1, sizeof(data), fp));
121 fclose(fp);
122 EXPECT_EQ(0, strcmp(data, "1234\n"));
Mike Frysingereaab4202017-08-14 14:57:21 -0400123
124 free(path);
125}
126
127// If the destination exists, there's nothing to do.
128TEST(setup_mount_destination, dest_exists) {
129 // Pick some paths that should always exist. We pass in invalid pointers
130 // for other args so we crash if the dest check doesn't short circuit.
131 EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false));
132 EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true));
133 EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false));
134}
135
136// When given a bind mount where the source is relative, reject it.
137TEST(setup_mount_destination, reject_relative_bind) {
138 // Pick a destination we know doesn't exist.
139 EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true));
140}
141
142// A mount of a pseudo filesystem should make the destination dir.
143TEST(setup_mount_destination, create_pseudo_fs) {
144 char *path = get_temp_path();
145 ASSERT_NE(nullptr, path);
146
147 // Passing -1 for uid/gid tells chown to make no changes.
148 EXPECT_EQ(0, setup_mount_destination("none", path, -1, -1, false));
149 // We check it's a directory by deleting it as such.
150 EXPECT_EQ(0, rmdir(path));
151
152 free(path);
153}
154
155// If the source path does not exist, we should error out.
156TEST(setup_mount_destination, missing_source) {
157 // The missing dest path is so we can exercise the source logic.
158 EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false));
159 EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true));
160}
161
162// A bind mount of a directory should create the destination dir.
163TEST(setup_mount_destination, create_bind_dir) {
164 char *path = get_temp_path();
165 ASSERT_NE(nullptr, path);
166
167 // Passing -1 for uid/gid tells chown to make no changes.
168 EXPECT_EQ(0, setup_mount_destination(kValidDir, path, -1, -1, true));
169 // We check it's a directory by deleting it as such.
170 EXPECT_EQ(0, rmdir(path));
171
172 free(path);
173}
174
175// A bind mount of a file should create the destination file.
176TEST(setup_mount_destination, create_bind_file) {
177 char *path = get_temp_path();
178 ASSERT_NE(nullptr, path);
179
180 // Passing -1 for uid/gid tells chown to make no changes.
181 EXPECT_EQ(0, setup_mount_destination(kValidFile, path, -1, -1, true));
182 // We check it's a file by deleting it as such.
183 EXPECT_EQ(0, unlink(path));
184
185 free(path);
186}
187
188// A mount of a character device should create the destination char.
189TEST(setup_mount_destination, create_char_dev) {
190 char *path = get_temp_path();
191 ASSERT_NE(nullptr, path);
192
193 // Passing -1 for uid/gid tells chown to make no changes.
194 EXPECT_EQ(0, setup_mount_destination(kValidCharDev, path, -1, -1, false));
195 // We check it's a directory by deleting it as such.
196 EXPECT_EQ(0, rmdir(path));
197
198 free(path);
Mike Frysinger0b5cffa2017-08-15 18:06:18 -0400199}