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