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/syscall_broker/broker_process.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <poll.h> 10 #include <stddef.h> 11 #include <sys/resource.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <sys/wait.h> 15 #include <unistd.h> 16 17 #include <algorithm> 18 #include <memory> 19 #include <string> 20 #include <vector> 21 22 #include "base/bind.h" 23 #include "base/files/file_util.h" 24 #include "base/files/scoped_file.h" 25 #include "base/logging.h" 26 #include "base/macros.h" 27 #include "base/posix/eintr_wrapper.h" 28 #include "base/posix/unix_domain_socket_linux.h" 29 #include "sandbox/linux/syscall_broker/broker_client.h" 30 #include "sandbox/linux/tests/scoped_temporary_file.h" 31 #include "sandbox/linux/tests/test_utils.h" 32 #include "sandbox/linux/tests/unit_tests.h" 33 #include "testing/gtest/include/gtest/gtest.h" 34 35 namespace sandbox { 36 37 namespace syscall_broker { 38 39 class BrokerProcessTestHelper { 40 public: 41 static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); } 42 // Get the client's IPC descriptor to send IPC requests directly. 43 // TODO(jln): refator tests to get rid of this. 44 static int GetIPCDescriptor(const BrokerProcess* broker) { 45 return broker->broker_client_->GetIPCDescriptor(); 46 } 47 }; 48 49 namespace { 50 51 bool NoOpCallback() { 52 return true; 53 } 54 55 } // namespace 56 57 TEST(BrokerProcess, CreateAndDestroy) { 58 std::vector<BrokerFilePermission> permissions; 59 permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo")); 60 61 std::unique_ptr<BrokerProcess> open_broker( 62 new BrokerProcess(EPERM, permissions)); 63 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); 64 65 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); 66 // Destroy the broker and check it has exited properly. 67 open_broker.reset(); 68 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); 69 } 70 71 TEST(BrokerProcess, TestOpenAccessNull) { 72 std::vector<BrokerFilePermission> empty; 73 BrokerProcess open_broker(EPERM, empty); 74 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 75 76 int fd = open_broker.Open(NULL, O_RDONLY); 77 ASSERT_EQ(fd, -EFAULT); 78 79 int ret = open_broker.Access(NULL, F_OK); 80 ASSERT_EQ(ret, -EFAULT); 81 } 82 83 void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) { 84 const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1"; 85 // We can't debug the init process, and shouldn't be able to access 86 // its auxv file. 87 const char kR_WhiteListedButDenied[] = "/proc/1/auxv"; 88 const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2"; 89 const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; 90 const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; 91 92 std::vector<BrokerFilePermission> permissions; 93 permissions.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed)); 94 permissions.push_back( 95 BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied)); 96 permissions.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed)); 97 permissions.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed)); 98 99 BrokerProcess open_broker(denied_errno, permissions, fast_check_in_client); 100 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 101 102 int fd = -1; 103 fd = open_broker.Open(kR_WhiteListed, O_RDONLY); 104 ASSERT_EQ(fd, -ENOENT); 105 fd = open_broker.Open(kR_WhiteListed, O_WRONLY); 106 ASSERT_EQ(fd, -denied_errno); 107 fd = open_broker.Open(kR_WhiteListed, O_RDWR); 108 ASSERT_EQ(fd, -denied_errno); 109 int ret = -1; 110 ret = open_broker.Access(kR_WhiteListed, F_OK); 111 ASSERT_EQ(ret, -ENOENT); 112 ret = open_broker.Access(kR_WhiteListed, R_OK); 113 ASSERT_EQ(ret, -ENOENT); 114 ret = open_broker.Access(kR_WhiteListed, W_OK); 115 ASSERT_EQ(ret, -denied_errno); 116 ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK); 117 ASSERT_EQ(ret, -denied_errno); 118 ret = open_broker.Access(kR_WhiteListed, X_OK); 119 ASSERT_EQ(ret, -denied_errno); 120 ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK); 121 ASSERT_EQ(ret, -denied_errno); 122 123 // Android sometimes runs tests as root. 124 // This part of the test requires a process that doesn't have 125 // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that. 126 if (geteuid()) { 127 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY); 128 // The broker process will allow this, but the normal permission system 129 // won't. 130 ASSERT_EQ(fd, -EACCES); 131 fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY); 132 ASSERT_EQ(fd, -denied_errno); 133 fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR); 134 ASSERT_EQ(fd, -denied_errno); 135 ret = open_broker.Access(kR_WhiteListedButDenied, F_OK); 136 // The normal permission system will let us check that the file exists. 137 ASSERT_EQ(ret, 0); 138 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK); 139 ASSERT_EQ(ret, -EACCES); 140 ret = open_broker.Access(kR_WhiteListedButDenied, W_OK); 141 ASSERT_EQ(ret, -denied_errno); 142 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK); 143 ASSERT_EQ(ret, -denied_errno); 144 ret = open_broker.Access(kR_WhiteListedButDenied, X_OK); 145 ASSERT_EQ(ret, -denied_errno); 146 ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK); 147 ASSERT_EQ(ret, -denied_errno); 148 } 149 150 fd = open_broker.Open(kW_WhiteListed, O_RDONLY); 151 ASSERT_EQ(fd, -denied_errno); 152 fd = open_broker.Open(kW_WhiteListed, O_WRONLY); 153 ASSERT_EQ(fd, -ENOENT); 154 fd = open_broker.Open(kW_WhiteListed, O_RDWR); 155 ASSERT_EQ(fd, -denied_errno); 156 ret = open_broker.Access(kW_WhiteListed, F_OK); 157 ASSERT_EQ(ret, -ENOENT); 158 ret = open_broker.Access(kW_WhiteListed, R_OK); 159 ASSERT_EQ(ret, -denied_errno); 160 ret = open_broker.Access(kW_WhiteListed, W_OK); 161 ASSERT_EQ(ret, -ENOENT); 162 ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK); 163 ASSERT_EQ(ret, -denied_errno); 164 ret = open_broker.Access(kW_WhiteListed, X_OK); 165 ASSERT_EQ(ret, -denied_errno); 166 ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK); 167 ASSERT_EQ(ret, -denied_errno); 168 169 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY); 170 ASSERT_EQ(fd, -ENOENT); 171 fd = open_broker.Open(kRW_WhiteListed, O_WRONLY); 172 ASSERT_EQ(fd, -ENOENT); 173 fd = open_broker.Open(kRW_WhiteListed, O_RDWR); 174 ASSERT_EQ(fd, -ENOENT); 175 ret = open_broker.Access(kRW_WhiteListed, F_OK); 176 ASSERT_EQ(ret, -ENOENT); 177 ret = open_broker.Access(kRW_WhiteListed, R_OK); 178 ASSERT_EQ(ret, -ENOENT); 179 ret = open_broker.Access(kRW_WhiteListed, W_OK); 180 ASSERT_EQ(ret, -ENOENT); 181 ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK); 182 ASSERT_EQ(ret, -ENOENT); 183 ret = open_broker.Access(kRW_WhiteListed, X_OK); 184 ASSERT_EQ(ret, -denied_errno); 185 ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK); 186 ASSERT_EQ(ret, -denied_errno); 187 188 fd = open_broker.Open(k_NotWhitelisted, O_RDONLY); 189 ASSERT_EQ(fd, -denied_errno); 190 fd = open_broker.Open(k_NotWhitelisted, O_WRONLY); 191 ASSERT_EQ(fd, -denied_errno); 192 fd = open_broker.Open(k_NotWhitelisted, O_RDWR); 193 ASSERT_EQ(fd, -denied_errno); 194 ret = open_broker.Access(k_NotWhitelisted, F_OK); 195 ASSERT_EQ(ret, -denied_errno); 196 ret = open_broker.Access(k_NotWhitelisted, R_OK); 197 ASSERT_EQ(ret, -denied_errno); 198 ret = open_broker.Access(k_NotWhitelisted, W_OK); 199 ASSERT_EQ(ret, -denied_errno); 200 ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK); 201 ASSERT_EQ(ret, -denied_errno); 202 ret = open_broker.Access(k_NotWhitelisted, X_OK); 203 ASSERT_EQ(ret, -denied_errno); 204 ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK); 205 ASSERT_EQ(ret, -denied_errno); 206 207 // We have some extra sanity check for clearly wrong values. 208 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY | O_WRONLY | O_RDWR); 209 ASSERT_EQ(fd, -denied_errno); 210 211 // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this 212 // is denied. 213 fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT); 214 ASSERT_EQ(fd, -denied_errno); 215 } 216 217 // Run the same thing twice. The second time, we make sure that no security 218 // check is performed on the client. 219 TEST(BrokerProcess, OpenFilePermsWithClientCheck) { 220 TestOpenFilePerms(true /* fast_check_in_client */, EPERM); 221 // Don't do anything here, so that ASSERT works in the subfunction as 222 // expected. 223 } 224 225 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) { 226 TestOpenFilePerms(false /* fast_check_in_client */, EPERM); 227 // Don't do anything here, so that ASSERT works in the subfunction as 228 // expected. 229 } 230 231 // Run the same twice again, but with ENOENT instead of EPERM. 232 TEST(BrokerProcess, OpenFilePermsWithClientCheckNoEnt) { 233 TestOpenFilePerms(true /* fast_check_in_client */, ENOENT); 234 // Don't do anything here, so that ASSERT works in the subfunction as 235 // expected. 236 } 237 238 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) { 239 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT); 240 // Don't do anything here, so that ASSERT works in the subfunction as 241 // expected. 242 } 243 244 void TestBadPaths(bool fast_check_in_client) { 245 const char kFileCpuInfo[] = "/proc/cpuinfo"; 246 const char kNotAbsPath[] = "proc/cpuinfo"; 247 const char kDotDotStart[] = "/../proc/cpuinfo"; 248 const char kDotDotMiddle[] = "/proc/self/../cpuinfo"; 249 const char kDotDotEnd[] = "/proc/.."; 250 const char kTrailingSlash[] = "/proc/"; 251 252 std::vector<BrokerFilePermission> permissions; 253 254 permissions.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/")); 255 std::unique_ptr<BrokerProcess> open_broker( 256 new BrokerProcess(EPERM, permissions, fast_check_in_client)); 257 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); 258 // Open cpuinfo via the broker. 259 int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); 260 base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd); 261 ASSERT_GE(cpuinfo_fd, 0); 262 263 int fd = -1; 264 int can_access; 265 266 can_access = open_broker->Access(kNotAbsPath, R_OK); 267 ASSERT_EQ(can_access, -EPERM); 268 fd = open_broker->Open(kNotAbsPath, O_RDONLY); 269 ASSERT_EQ(fd, -EPERM); 270 271 can_access = open_broker->Access(kDotDotStart, R_OK); 272 ASSERT_EQ(can_access, -EPERM); 273 fd = open_broker->Open(kDotDotStart, O_RDONLY); 274 ASSERT_EQ(fd, -EPERM); 275 276 can_access = open_broker->Access(kDotDotMiddle, R_OK); 277 ASSERT_EQ(can_access, -EPERM); 278 fd = open_broker->Open(kDotDotMiddle, O_RDONLY); 279 ASSERT_EQ(fd, -EPERM); 280 281 can_access = open_broker->Access(kDotDotEnd, R_OK); 282 ASSERT_EQ(can_access, -EPERM); 283 fd = open_broker->Open(kDotDotEnd, O_RDONLY); 284 ASSERT_EQ(fd, -EPERM); 285 286 can_access = open_broker->Access(kTrailingSlash, R_OK); 287 ASSERT_EQ(can_access, -EPERM); 288 fd = open_broker->Open(kTrailingSlash, O_RDONLY); 289 ASSERT_EQ(fd, -EPERM); 290 } 291 292 TEST(BrokerProcess, BadPathsClientCheck) { 293 TestBadPaths(true /* fast_check_in_client */); 294 // Don't do anything here, so that ASSERT works in the subfunction as 295 // expected. 296 } 297 298 TEST(BrokerProcess, BadPathsNoClientCheck) { 299 TestBadPaths(false /* fast_check_in_client */); 300 // Don't do anything here, so that ASSERT works in the subfunction as 301 // expected. 302 } 303 304 void TestOpenCpuinfo(bool fast_check_in_client, bool recursive) { 305 const char kFileCpuInfo[] = "/proc/cpuinfo"; 306 const char kDirProc[] = "/proc/"; 307 308 std::vector<BrokerFilePermission> permissions; 309 if (recursive) 310 permissions.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc)); 311 else 312 permissions.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo)); 313 314 std::unique_ptr<BrokerProcess> open_broker( 315 new BrokerProcess(EPERM, permissions, fast_check_in_client)); 316 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); 317 318 int fd = -1; 319 fd = open_broker->Open(kFileCpuInfo, O_RDWR); 320 base::ScopedFD fd_closer(fd); 321 ASSERT_EQ(fd, -EPERM); 322 323 // Check we can read /proc/cpuinfo. 324 int can_access = open_broker->Access(kFileCpuInfo, R_OK); 325 ASSERT_EQ(can_access, 0); 326 can_access = open_broker->Access(kFileCpuInfo, W_OK); 327 ASSERT_EQ(can_access, -EPERM); 328 // Check we can not write /proc/cpuinfo. 329 330 // Open cpuinfo via the broker. 331 int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); 332 base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd); 333 ASSERT_GE(cpuinfo_fd, 0); 334 char buf[3]; 335 memset(buf, 0, sizeof(buf)); 336 int read_len1 = read(cpuinfo_fd, buf, sizeof(buf)); 337 ASSERT_GT(read_len1, 0); 338 339 // Open cpuinfo directly. 340 int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY); 341 base::ScopedFD cpuinfo_fd2_closer(cpuinfo_fd2); 342 ASSERT_GE(cpuinfo_fd2, 0); 343 char buf2[3]; 344 memset(buf2, 1, sizeof(buf2)); 345 int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2)); 346 ASSERT_GT(read_len1, 0); 347 348 // The following is not guaranteed true, but will be in practice. 349 ASSERT_EQ(read_len1, read_len2); 350 // Compare the cpuinfo as returned by the broker with the one we opened 351 // ourselves. 352 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0); 353 354 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); 355 open_broker.reset(); 356 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); 357 } 358 359 // Run this test 4 times. With and without the check in client 360 // and using a recursive path. 361 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { 362 TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */); 363 // Don't do anything here, so that ASSERT works in the subfunction as 364 // expected. 365 } 366 367 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { 368 TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */); 369 // Don't do anything here, so that ASSERT works in the subfunction as 370 // expected. 371 } 372 373 TEST(BrokerProcess, OpenCpuinfoWithClientCheckRecursive) { 374 TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */); 375 // Don't do anything here, so that ASSERT works in the subfunction as 376 // expected. 377 } 378 379 TEST(BrokerProcess, OpenCpuinfoNoClientCheckRecursive) { 380 TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */); 381 // Don't do anything here, so that ASSERT works in the subfunction as 382 // expected. 383 } 384 385 TEST(BrokerProcess, OpenFileRW) { 386 ScopedTemporaryFile tempfile; 387 const char* tempfile_name = tempfile.full_file_name(); 388 389 std::vector<BrokerFilePermission> permissions; 390 permissions.push_back(BrokerFilePermission::ReadWrite(tempfile_name)); 391 392 BrokerProcess open_broker(EPERM, permissions); 393 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 394 395 // Check we can access that file with read or write. 396 int can_access = open_broker.Access(tempfile_name, R_OK | W_OK); 397 ASSERT_EQ(can_access, 0); 398 399 int tempfile2 = -1; 400 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); 401 ASSERT_GE(tempfile2, 0); 402 403 // Write to the descriptor opened by the broker. 404 char test_text[] = "TESTTESTTEST"; 405 ssize_t len = write(tempfile2, test_text, sizeof(test_text)); 406 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); 407 408 // Read back from the original file descriptor what we wrote through 409 // the descriptor provided by the broker. 410 char buf[1024]; 411 len = read(tempfile.fd(), buf, sizeof(buf)); 412 413 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); 414 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); 415 416 ASSERT_EQ(close(tempfile2), 0); 417 } 418 419 // SANDBOX_TEST because the process could die with a SIGPIPE 420 // and we want this to happen in a subprocess. 421 SANDBOX_TEST(BrokerProcess, BrokerDied) { 422 const char kCpuInfo[] = "/proc/cpuinfo"; 423 std::vector<BrokerFilePermission> permissions; 424 permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); 425 426 BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, 427 true /* quiet_failures_for_tests */); 428 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); 429 const pid_t broker_pid = open_broker.broker_pid(); 430 SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0); 431 432 // Now we check that the broker has been signaled, but do not reap it. 433 siginfo_t process_info; 434 SANDBOX_ASSERT(HANDLE_EINTR(waitid( 435 P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) == 436 0); 437 SANDBOX_ASSERT(broker_pid == process_info.si_pid); 438 SANDBOX_ASSERT(CLD_KILLED == process_info.si_code); 439 SANDBOX_ASSERT(SIGKILL == process_info.si_status); 440 441 // Check that doing Open with a dead broker won't SIGPIPE us. 442 SANDBOX_ASSERT(open_broker.Open(kCpuInfo, O_RDONLY) == -ENOMEM); 443 SANDBOX_ASSERT(open_broker.Access(kCpuInfo, O_RDONLY) == -ENOMEM); 444 } 445 446 void TestOpenComplexFlags(bool fast_check_in_client) { 447 const char kCpuInfo[] = "/proc/cpuinfo"; 448 std::vector<BrokerFilePermission> permissions; 449 permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); 450 451 BrokerProcess open_broker(EPERM, permissions, fast_check_in_client); 452 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 453 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. 454 int fd = -1; 455 int ret = 0; 456 fd = open_broker.Open(kCpuInfo, O_RDONLY); 457 ASSERT_GE(fd, 0); 458 ret = fcntl(fd, F_GETFL); 459 ASSERT_NE(-1, ret); 460 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK. 461 ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK)); 462 ASSERT_EQ(0, close(fd)); 463 464 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC); 465 ASSERT_GE(fd, 0); 466 ret = fcntl(fd, F_GETFD); 467 ASSERT_NE(-1, ret); 468 // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL 469 // is actually not used by the kernel. 470 ASSERT_TRUE(FD_CLOEXEC & ret); 471 ASSERT_EQ(0, close(fd)); 472 473 fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK); 474 ASSERT_GE(fd, 0); 475 ret = fcntl(fd, F_GETFL); 476 ASSERT_NE(-1, ret); 477 ASSERT_TRUE(O_NONBLOCK & ret); 478 ASSERT_EQ(0, close(fd)); 479 } 480 481 TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) { 482 TestOpenComplexFlags(true /* fast_check_in_client */); 483 // Don't do anything here, so that ASSERT works in the subfunction as 484 // expected. 485 } 486 487 TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) { 488 TestOpenComplexFlags(false /* fast_check_in_client */); 489 // Don't do anything here, so that ASSERT works in the subfunction as 490 // expected. 491 } 492 493 #if defined(OS_LINUX) 494 // Flaky on Linux NG bots: https://crbug.com/595199. 495 #define MAYBE_RecvMsgDescriptorLeak DISABLED_RecvMsgDescriptorLeak 496 #else 497 #define MAYBE_RecvMsgDescriptorLeak RecvMsgDescriptorLeak 498 #endif 499 500 // We need to allow noise because the broker will log when it receives our 501 // bogus IPCs. 502 SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, MAYBE_RecvMsgDescriptorLeak) { 503 // Android creates a socket on first use of the LOG call. 504 // We need to ensure this socket is open before we 505 // begin the test. 506 LOG(INFO) << "Ensure Android LOG socket is allocated"; 507 508 // Find the four lowest available file descriptors. 509 int available_fds[4]; 510 SANDBOX_ASSERT(0 == pipe(available_fds)); 511 SANDBOX_ASSERT(0 == pipe(available_fds + 2)); 512 513 // Save one FD to send to the broker later, and close the others. 514 base::ScopedFD message_fd(available_fds[0]); 515 for (size_t i = 1; i < arraysize(available_fds); i++) { 516 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i]))); 517 } 518 519 // Lower our file descriptor limit to just allow three more file descriptors 520 // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file 521 // descriptors a process can have: it only limits the highest value that can 522 // be assigned to newly-created descriptors allocated by the process.) 523 const rlim_t fd_limit = 524 1 + 525 *std::max_element(available_fds, 526 available_fds + arraysize(available_fds)); 527 528 // Valgrind doesn't allow changing the hard descriptor limit, so we only 529 // change the soft descriptor limit here. 530 struct rlimit rlim; 531 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim)); 532 SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur); 533 rlim.rlim_cur = fd_limit; 534 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); 535 536 static const char kCpuInfo[] = "/proc/cpuinfo"; 537 std::vector<BrokerFilePermission> permissions; 538 permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); 539 540 BrokerProcess open_broker(EPERM, permissions); 541 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); 542 543 const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker); 544 SANDBOX_ASSERT(ipc_fd >= 0); 545 546 static const char kBogus[] = "not a pickle"; 547 std::vector<int> fds; 548 fds.push_back(message_fd.get()); 549 550 // The broker process should only have a couple spare file descriptors 551 // available, but for good measure we send it fd_limit bogus IPCs anyway. 552 for (rlim_t i = 0; i < fd_limit; ++i) { 553 SANDBOX_ASSERT( 554 base::UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds)); 555 } 556 557 const int fd = open_broker.Open(kCpuInfo, O_RDONLY); 558 SANDBOX_ASSERT(fd >= 0); 559 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd))); 560 } 561 562 bool CloseFD(int fd) { 563 PCHECK(0 == IGNORE_EINTR(close(fd))); 564 return true; 565 } 566 567 // Return true if the other end of the |reader| pipe was closed, 568 // false if |timeout_in_seconds| was reached or another event 569 // or error occured. 570 bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) { 571 struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0}; 572 const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms)); 573 if (1 == num_events && poll_fd.revents | POLLHUP) 574 return true; 575 return false; 576 } 577 578 // Closing the broker client's IPC channel should terminate the broker 579 // process. 580 TEST(BrokerProcess, BrokerDiesOnClosedChannel) { 581 std::vector<BrokerFilePermission> permissions; 582 permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo")); 583 584 // Get the writing end of a pipe into the broker (child) process so 585 // that we can reliably detect when it dies. 586 int lifeline_fds[2]; 587 PCHECK(0 == pipe(lifeline_fds)); 588 589 BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, 590 false /* quiet_failures_for_tests */); 591 ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0]))); 592 // Make sure the writing end only exists in the broker process. 593 CloseFD(lifeline_fds[1]); 594 base::ScopedFD reader(lifeline_fds[0]); 595 596 const pid_t broker_pid = open_broker.broker_pid(); 597 598 // This should cause the broker process to exit. 599 BrokerProcessTestHelper::CloseChannel(&open_broker); 600 601 const int kTimeoutInMilliseconds = 5000; 602 const bool broker_lifeline_closed = 603 WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds); 604 // If the broker exited, its lifeline fd should be closed. 605 ASSERT_TRUE(broker_lifeline_closed); 606 // Now check that the broker has exited, but do not reap it. 607 siginfo_t process_info; 608 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info, 609 WEXITED | WNOWAIT))); 610 EXPECT_EQ(broker_pid, process_info.si_pid); 611 EXPECT_EQ(CLD_EXITED, process_info.si_code); 612 EXPECT_EQ(1, process_info.si_status); 613 } 614 615 TEST(BrokerProcess, CreateFile) { 616 std::string temp_str; 617 { 618 ScopedTemporaryFile tmp_file; 619 temp_str = tmp_file.full_file_name(); 620 } 621 const char* tempfile_name = temp_str.c_str(); 622 623 std::vector<BrokerFilePermission> permissions; 624 permissions.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name)); 625 626 BrokerProcess open_broker(EPERM, permissions); 627 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); 628 629 int fd = -1; 630 631 // Try without O_EXCL 632 fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT); 633 ASSERT_EQ(fd, -EPERM); 634 635 const char kTestText[] = "TESTTESTTEST"; 636 // Create a file 637 fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); 638 ASSERT_GE(fd, 0); 639 { 640 base::ScopedFD scoped_fd(fd); 641 642 // Confirm fail if file exists 643 int bad_fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); 644 ASSERT_EQ(bad_fd, -EEXIST); 645 646 // Write to the descriptor opened by the broker. 647 648 ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText))); 649 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); 650 } 651 652 int fd_check = open(tempfile_name, O_RDONLY); 653 ASSERT_GE(fd_check, 0); 654 { 655 base::ScopedFD scoped_fd(fd_check); 656 char buf[1024]; 657 ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf))); 658 659 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); 660 ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0); 661 } 662 } 663 664 } // namespace syscall_broker 665 666 } // namespace sandbox 667