1/* 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 */ 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/stat.h> 12#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 23// 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 32// 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); 120 char data[6] = {}; 121 EXPECT_EQ(5u, fread(data, 1, sizeof(data), fp)); 122 fclose(fp); 123 EXPECT_EQ(0, strcmp(data, "1234\n")); 124 125 free(path); 126} 127 128// If the destination exists, there's nothing to do. 129// 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. 180TEST(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); 251} 252