1 // Copyright (c) 2012 The Chromium 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 #include "sandbox/linux/services/broker_process.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <sys/stat.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 #include <unistd.h> 13 14 #include <string> 15 #include <vector> 16 17 #include "base/basictypes.h" 18 #include "base/file_util.h" 19 #include "base/logging.h" 20 #include "base/memory/scoped_ptr.h" 21 #include "base/posix/eintr_wrapper.h" 22 #include "sandbox/linux/tests/unit_tests.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 using file_util::ScopedFD; 26 27 namespace sandbox { 28 29 namespace { 30 31 // Creates and open a temporary file on creation and closes 32 // and removes it on destruction. 33 // Unlike base/ helpers, this does not require JNI on Android. 34 class ScopedTemporaryFile { 35 public: 36 ScopedTemporaryFile() 37 : fd_(-1) { 38 #if defined(OS_ANDROID) 39 static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX"; 40 #else 41 static const char file_template[] = "/tmp/ScopedTempFileXXXXXX"; 42 #endif // defined(OS_ANDROID) 43 COMPILE_ASSERT(sizeof(full_file_name_) >= sizeof(file_template), 44 full_file_name_is_large_enough); 45 memcpy(full_file_name_, file_template, sizeof(file_template)); 46 fd_ = mkstemp(full_file_name_); 47 CHECK_LE(0, fd_); 48 } 49 ~ScopedTemporaryFile() { 50 CHECK_EQ(0, unlink(full_file_name_)); 51 CHECK_EQ(0, IGNORE_EINTR(close(fd_))); 52 } 53 54 int fd() const { return fd_; } 55 const char* full_file_name() const { return full_file_name_; } 56 57 private: 58 int fd_; 59 char full_file_name_[128]; 60 DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile); 61 }; 62 63 } // namespace 64 65 #if defined(OS_ANDROID) 66 #define DISABLE_ON_ANDROID(function) DISABLED_##function 67 #else 68 #define DISABLE_ON_ANDROID(function) function 69 #endif 70 71 TEST(BrokerProcess, CreateAndDestroy) { 72 std::vector<std::string> read_whitelist; 73 read_whitelist.push_back("/proc/cpuinfo"); 74 75 scoped_ptr<BrokerProcess> open_broker( 76 new BrokerProcess(EPERM, read_whitelist, std::vector<std::string>())); 77 ASSERT_TRUE(open_broker->Init(NULL)); 78 pid_t broker_pid = open_broker->broker_pid(); 79 80 // Destroy the broker and check it has exited properly. 81 open_broker.reset(); 82 int status = 0; 83 ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid); 84 ASSERT_TRUE(WIFEXITED(status)); 85 ASSERT_EQ(WEXITSTATUS(status), 0); 86 } 87 88 TEST(BrokerProcess, TestOpenAccessNull) { 89 const std::vector<std::string> empty; 90 BrokerProcess open_broker(EPERM, empty, empty); 91 ASSERT_TRUE(open_broker.Init(NULL)); 92 93 int fd = open_broker.Open(NULL, O_RDONLY); 94 ASSERT_EQ(fd, -EFAULT); 95 96 int ret = open_broker.Access(NULL, F_OK); 97 ASSERT_EQ(ret, -EFAULT); 98 } 99 100 void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) { 101 const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1"; 102 // We can't debug the init process, and shouldn't be able to access 103 // its auxv file. 104 const char kR_WhiteListedButDenied[] = "/proc/1/auxv"; 105 const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2"; 106 const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; 107 const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; 108 109 std::vector<std::string> read_whitelist; 110 read_whitelist.push_back(kR_WhiteListed); 111 read_whitelist.push_back(kR_WhiteListedButDenied); 112 read_whitelist.push_back(kRW_WhiteListed); 113 114 std::vector<std::string> write_whitelist; 115 write_whitelist.push_back(kW_WhiteListed); 116 write_whitelist.push_back(kRW_WhiteListed); 117 118 BrokerProcess open_broker(denied_errno, 119 read_whitelist, 120 write_whitelist, 121 fast_check_in_client); 122 ASSERT_TRUE(open_broker.Init(NULL)); 123 124 int fd = -1; 125 fd = open_broker.Open(kR_WhiteListed, O_RDONLY); 126 ASSERT_EQ(fd, -ENOENT); 127 fd = open_broker.Open(kR_WhiteListed, O_WRONLY); 128 ASSERT_EQ(fd, -denied_errno); 129 fd = open_broker.Open(kR_WhiteListed, O_RDWR); 130 ASSERT_EQ(fd, -denied_errno); 131 int ret = -1; 132 ret = open_broker.Access(kR_WhiteListed, F_OK); 133 ASSERT_EQ(ret, -ENOENT); 134 ret = open_broker.Access(kR_WhiteListed, R_OK); 135 ASSERT_EQ(ret, -ENOENT); 136 ret = open_broker.Access(kR_WhiteListed, W_OK); 137 ASSERT_EQ(ret, -denied_errno); 138 ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK); 139 ASSERT_EQ(ret, -denied_errno); 140 ret = open_broker.Access(kR_WhiteListed, X_OK); 141 ASSERT_EQ(ret, -denied_errno); 142 ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK); 143 ASSERT_EQ(ret, -denied_errno); 144 145 // Android sometimes runs tests as root. 146 // This part of the test requires a process that doesn't have 147 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that. 148 if (geteuid()) { 149 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY); 150 // The broker process will allow this, but the normal permission system 151 // won't. 152 ASSERT_EQ(fd, -EACCES); 153 fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY); 154 ASSERT_EQ(fd, -denied_errno); 155 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR); 156 ASSERT_EQ(fd, -denied_errno); 157 ret = open_broker.Access(kR_WhiteListedButDenied, F_OK); 158 // The normal permission system will let us check that the file exists. 159 ASSERT_EQ(ret, 0); 160 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK); 161 ASSERT_EQ(ret, -EACCES); 162 ret = open_broker.Access(kR_WhiteListedButDenied, W_OK); 163 ASSERT_EQ(ret, -denied_errno); 164 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK); 165 ASSERT_EQ(ret, -denied_errno); 166 ret = open_broker.Access(kR_WhiteListedButDenied, X_OK); 167 ASSERT_EQ(ret, -denied_errno); 168 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK); 169 ASSERT_EQ(ret, -denied_errno); 170 } 171 172 fd = open_broker.Open(kW_WhiteListed, O_RDONLY); 173 ASSERT_EQ(fd, -denied_errno); 174 fd = open_broker.Open(kW_WhiteListed, O_WRONLY); 175 ASSERT_EQ(fd, -ENOENT); 176 fd = open_broker.Open(kW_WhiteListed, O_RDWR); 177 ASSERT_EQ(fd, -denied_errno); 178 ret = open_broker.Access(kW_WhiteListed, F_OK); 179 ASSERT_EQ(ret, -ENOENT); 180 ret = open_broker.Access(kW_WhiteListed, R_OK); 181 ASSERT_EQ(ret, -denied_errno); 182 ret = open_broker.Access(kW_WhiteListed, W_OK); 183 ASSERT_EQ(ret, -ENOENT); 184 ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK); 185 ASSERT_EQ(ret, -denied_errno); 186 ret = open_broker.Access(kW_WhiteListed, X_OK); 187 ASSERT_EQ(ret, -denied_errno); 188 ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK); 189 ASSERT_EQ(ret, -denied_errno); 190 191 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY); 192 ASSERT_EQ(fd, -ENOENT); 193 fd = open_broker.Open(kRW_WhiteListed, O_WRONLY); 194 ASSERT_EQ(fd, -ENOENT); 195 fd = open_broker.Open(kRW_WhiteListed, O_RDWR); 196 ASSERT_EQ(fd, -ENOENT); 197 ret = open_broker.Access(kRW_WhiteListed, F_OK); 198 ASSERT_EQ(ret, -ENOENT); 199 ret = open_broker.Access(kRW_WhiteListed, R_OK); 200 ASSERT_EQ(ret, -ENOENT); 201 ret = open_broker.Access(kRW_WhiteListed, W_OK); 202 ASSERT_EQ(ret, -ENOENT); 203 ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK); 204 ASSERT_EQ(ret, -ENOENT); 205 ret = open_broker.Access(kRW_WhiteListed, X_OK); 206 ASSERT_EQ(ret, -denied_errno); 207 ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK); 208 ASSERT_EQ(ret, -denied_errno); 209 210 fd = open_broker.Open(k_NotWhitelisted, O_RDONLY); 211 ASSERT_EQ(fd, -denied_errno); 212 fd = open_broker.Open(k_NotWhitelisted, O_WRONLY); 213 ASSERT_EQ(fd, -denied_errno); 214 fd = open_broker.Open(k_NotWhitelisted, O_RDWR); 215 ASSERT_EQ(fd, -denied_errno); 216 ret = open_broker.Access(k_NotWhitelisted, F_OK); 217 ASSERT_EQ(ret, -denied_errno); 218 ret = open_broker.Access(k_NotWhitelisted, R_OK); 219 ASSERT_EQ(ret, -denied_errno); 220 ret = open_broker.Access(k_NotWhitelisted, W_OK); 221 ASSERT_EQ(ret, -denied_errno); 222 ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK); 223 ASSERT_EQ(ret, -denied_errno); 224 ret = open_broker.Access(k_NotWhitelisted, X_OK); 225 ASSERT_EQ(ret, -denied_errno); 226 ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK); 227 ASSERT_EQ(ret, -denied_errno); 228 229 // We have some extra sanity check for clearly wrong values. 230 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY | O_WRONLY | O_RDWR); 231 ASSERT_EQ(fd, -denied_errno); 232 233 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this 234 // is denied. 235 fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT); 236 ASSERT_EQ(fd, -denied_errno); 237 } 238 239 // Run the same thing twice. The second time, we make sure that no security 240 // check is performed on the client. 241 TEST(BrokerProcess, OpenFilePermsWithClientCheck) { 242 TestOpenFilePerms(true /* fast_check_in_client */, EPERM); 243 // Don't do anything here, so that ASSERT works in the subfunction as 244 // expected. 245 } 246 247 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) { 248 TestOpenFilePerms(false /* fast_check_in_client */, EPERM); 249 // Don't do anything here, so that ASSERT works in the subfunction as 250 // expected. 251 } 252 253 // Run the same twice again, but with ENOENT instead of EPERM. 254 TEST(BrokerProcess, OpenFilePermsWithClientCheckNoEnt) { 255 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT); 256 // Don't do anything here, so that ASSERT works in the subfunction as 257 // expected. 258 } 259 260 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) { 261 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT); 262 // Don't do anything here, so that ASSERT works in the subfunction as 263 // expected. 264 } 265 266 void TestOpenCpuinfo(bool fast_check_in_client) { 267 const char kFileCpuInfo[] = "/proc/cpuinfo"; 268 std::vector<std::string> read_whitelist; 269 read_whitelist.push_back(kFileCpuInfo); 270 271 scoped_ptr<BrokerProcess> open_broker(new BrokerProcess( 272 EPERM, read_whitelist, std::vector<std::string>(), fast_check_in_client)); 273 ASSERT_TRUE(open_broker->Init(NULL)); 274 pid_t broker_pid = open_broker->broker_pid(); 275 276 int fd = -1; 277 fd = open_broker->Open(kFileCpuInfo, O_RDWR); 278 ScopedFD fd_closer(&fd); 279 ASSERT_EQ(fd, -EPERM); 280 281 // Check we can read /proc/cpuinfo. 282 int can_access = open_broker->Access(kFileCpuInfo, R_OK); 283 ASSERT_EQ(can_access, 0); 284 can_access = open_broker->Access(kFileCpuInfo, W_OK); 285 ASSERT_EQ(can_access, -EPERM); 286 // Check we can not write /proc/cpuinfo. 287 288 // Open cpuinfo via the broker. 289 int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); 290 ScopedFD cpuinfo_fd_closer(&cpuinfo_fd); 291 ASSERT_GE(cpuinfo_fd, 0); 292 char buf[3]; 293 memset(buf, 0, sizeof(buf)); 294 int read_len1 = read(cpuinfo_fd, buf, sizeof(buf)); 295 ASSERT_GT(read_len1, 0); 296 297 // Open cpuinfo directly. 298 int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY); 299 ScopedFD cpuinfo_fd2_closer(&cpuinfo_fd2); 300 ASSERT_GE(cpuinfo_fd2, 0); 301 char buf2[3]; 302 memset(buf2, 1, sizeof(buf2)); 303 int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2)); 304 ASSERT_GT(read_len1, 0); 305 306 // The following is not guaranteed true, but will be in practice. 307 ASSERT_EQ(read_len1, read_len2); 308 // Compare the cpuinfo as returned by the broker with the one we opened 309 // ourselves. 310 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0); 311 312 open_broker.reset(); 313 314 // Now we check that the broker has exited properly. 315 int status = 0; 316 ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid); 317 ASSERT_TRUE(WIFEXITED(status)); 318 ASSERT_EQ(WEXITSTATUS(status), 0); 319 } 320 321 // Run the same thing twice. The second time, we make sure that no security 322 // check is performed on the client. 323 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { 324 TestOpenCpuinfo(true /* fast_check_in_client */); 325 // Don't do anything here, so that ASSERT works in the subfunction as 326 // expected. 327 } 328 329 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { 330 TestOpenCpuinfo(false /* fast_check_in_client */); 331 // Don't do anything here, so that ASSERT works in the subfunction as 332 // expected. 333 } 334 335 TEST(BrokerProcess, OpenFileRW) { 336 ScopedTemporaryFile tempfile; 337 const char* tempfile_name = tempfile.full_file_name(); 338 339 std::vector<std::string> whitelist; 340 whitelist.push_back(tempfile_name); 341 342 BrokerProcess open_broker(EPERM, whitelist, whitelist); 343 ASSERT_TRUE(open_broker.Init(NULL)); 344 345 // Check we can access that file with read or write. 346 int can_access = open_broker.Access(tempfile_name, R_OK | W_OK); 347 ASSERT_EQ(can_access, 0); 348 349 int tempfile2 = -1; 350 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); 351 ASSERT_GE(tempfile2, 0); 352 353 // Write to the descriptor opened by the broker. 354 char test_text[] = "TESTTESTTEST"; 355 ssize_t len = write(tempfile2, test_text, sizeof(test_text)); 356 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); 357 358 // Read back from the original file descriptor what we wrote through 359 // the descriptor provided by the broker. 360 char buf[1024]; 361 len = read(tempfile.fd(), buf, sizeof(buf)); 362 363 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); 364 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); 365 366 ASSERT_EQ(close(tempfile2), 0); 367 } 368 369 // SANDBOX_TEST because the process could die with a SIGPIPE 370 // and we want this to happen in a subprocess. 371 SANDBOX_TEST(BrokerProcess, BrokerDied) { 372 std::vector<std::string> read_whitelist; 373 read_whitelist.push_back("/proc/cpuinfo"); 374 375 BrokerProcess open_broker(EPERM, 376 read_whitelist, 377 std::vector<std::string>(), 378 true /* fast_check_in_client */, 379 true /* quiet_failures_for_tests */); 380 SANDBOX_ASSERT(open_broker.Init(NULL)); 381 pid_t broker_pid = open_broker.broker_pid(); 382 SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0); 383 384 // Now we check that the broker has exited properly. 385 int status = 0; 386 SANDBOX_ASSERT(waitpid(broker_pid, &status, 0) == broker_pid); 387 SANDBOX_ASSERT(WIFSIGNALED(status)); 388 SANDBOX_ASSERT(WTERMSIG(status) == SIGKILL); 389 // Check that doing Open with a dead broker won't SIGPIPE us. 390 SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM); 391 SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM); 392 } 393 394 void TestOpenComplexFlags(bool fast_check_in_client) { 395 const char kCpuInfo[] = "/proc/cpuinfo"; 396 std::vector<std::string> whitelist; 397 whitelist.push_back(kCpuInfo); 398 399 BrokerProcess open_broker(EPERM, 400 whitelist, 401 whitelist, 402 fast_check_in_client); 403 ASSERT_TRUE(open_broker.Init(NULL)); 404 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. 405 int fd = -1; 406 int ret = 0; 407 fd = open_broker.Open(kCpuInfo, O_RDONLY); 408 ASSERT_GE(fd, 0); 409 ret = fcntl(fd, F_GETFL); 410 ASSERT_NE(-1, ret); 411 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK. 412 ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK)); 413 ASSERT_EQ(0, close(fd)); 414 415 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC); 416 ASSERT_GE(fd, 0); 417 ret = fcntl(fd, F_GETFD); 418 ASSERT_NE(-1, ret); 419 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL 420 // is actually not used by the kernel. 421 ASSERT_TRUE(FD_CLOEXEC & ret); 422 ASSERT_EQ(0, close(fd)); 423 424 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK); 425 ASSERT_GE(fd, 0); 426 ret = fcntl(fd, F_GETFL); 427 ASSERT_NE(-1, ret); 428 ASSERT_TRUE(O_NONBLOCK & ret); 429 ASSERT_EQ(0, close(fd)); 430 } 431 432 TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) { 433 TestOpenComplexFlags(true /* fast_check_in_client */); 434 // Don't do anything here, so that ASSERT works in the subfunction as 435 // expected. 436 } 437 438 TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) { 439 TestOpenComplexFlags(false /* fast_check_in_client */); 440 // Don't do anything here, so that ASSERT works in the subfunction as 441 // expected. 442 } 443 444 } // namespace sandbox 445