| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sandbox/linux/syscall_broker/broker_process.h" | 5 #include "sandbox/linux/syscall_broker/broker_process.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <poll.h> | 9 #include <poll.h> |
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 bool NoOpCallback() { | 50 bool NoOpCallback() { |
| 51 return true; | 51 return true; |
| 52 } | 52 } |
| 53 | 53 |
| 54 } // namespace | 54 } // namespace |
| 55 | 55 |
| 56 TEST(BrokerProcess, CreateAndDestroy) { | 56 TEST(BrokerProcess, CreateAndDestroy) { |
| 57 std::vector<std::string> read_whitelist; | 57 std::vector<BrokerFilePermission> permissions; |
| 58 read_whitelist.push_back("/proc/cpuinfo"); | 58 permissions.push_back(BrokerFilePermissionReadOnly("/proc/cpuinfo")); |
| 59 | 59 |
| 60 scoped_ptr<BrokerProcess> open_broker( | 60 scoped_ptr<BrokerProcess> open_broker(new BrokerProcess(EPERM, permissions)); |
| 61 new BrokerProcess(EPERM, read_whitelist, std::vector<std::string>())); | |
| 62 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); | 61 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
| 63 | 62 |
| 64 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); | 63 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); |
| 65 // Destroy the broker and check it has exited properly. | 64 // Destroy the broker and check it has exited properly. |
| 66 open_broker.reset(); | 65 open_broker.reset(); |
| 67 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); | 66 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); |
| 68 } | 67 } |
| 69 | 68 |
| 70 TEST(BrokerProcess, TestOpenAccessNull) { | 69 TEST(BrokerProcess, TestOpenAccessNull) { |
| 71 const std::vector<std::string> empty; | 70 std::vector<BrokerFilePermission> empty; |
| 72 BrokerProcess open_broker(EPERM, empty, empty); | 71 BrokerProcess open_broker(EPERM, empty); |
| 73 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); | 72 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
| 74 | 73 |
| 75 int fd = open_broker.Open(NULL, O_RDONLY); | 74 int fd = open_broker.Open(NULL, O_RDONLY); |
| 76 ASSERT_EQ(fd, -EFAULT); | 75 ASSERT_EQ(fd, -EFAULT); |
| 77 | 76 |
| 78 int ret = open_broker.Access(NULL, F_OK); | 77 int ret = open_broker.Access(NULL, F_OK); |
| 79 ASSERT_EQ(ret, -EFAULT); | 78 ASSERT_EQ(ret, -EFAULT); |
| 80 } | 79 } |
| 81 | 80 |
| 82 void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) { | 81 void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) { |
| 83 const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1"; | 82 const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1"; |
| 84 // We can't debug the init process, and shouldn't be able to access | 83 // We can't debug the init process, and shouldn't be able to access |
| 85 // its auxv file. | 84 // its auxv file. |
| 86 const char kR_WhiteListedButDenied[] = "/proc/1/auxv"; | 85 const char kR_WhiteListedButDenied[] = "/proc/1/auxv"; |
| 87 const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2"; | 86 const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2"; |
| 88 const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; | 87 const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; |
| 89 const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; | 88 const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; |
| 90 | 89 |
| 91 std::vector<std::string> read_whitelist; | 90 std::vector<BrokerFilePermission> permissions; |
| 92 read_whitelist.push_back(kR_WhiteListed); | 91 permissions.push_back(BrokerFilePermissionReadOnly(kR_WhiteListed)); |
| 93 read_whitelist.push_back(kR_WhiteListedButDenied); | 92 permissions.push_back(BrokerFilePermissionReadOnly(kR_WhiteListedButDenied)); |
| 94 read_whitelist.push_back(kRW_WhiteListed); | 93 permissions.push_back(BrokerFilePermissionWriteOnly(kW_WhiteListed)); |
| 94 permissions.push_back(BrokerFilePermissionReadWrite(kRW_WhiteListed)); |
| 95 | 95 |
| 96 std::vector<std::string> write_whitelist; | 96 BrokerProcess open_broker(denied_errno, permissions, fast_check_in_client); |
| 97 write_whitelist.push_back(kW_WhiteListed); | |
| 98 write_whitelist.push_back(kRW_WhiteListed); | |
| 99 | |
| 100 BrokerProcess open_broker( | |
| 101 denied_errno, read_whitelist, write_whitelist, fast_check_in_client); | |
| 102 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); | 97 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
| 103 | 98 |
| 104 int fd = -1; | 99 int fd = -1; |
| 105 fd = open_broker.Open(kR_WhiteListed, O_RDONLY); | 100 fd = open_broker.Open(kR_WhiteListed, O_RDONLY); |
| 106 ASSERT_EQ(fd, -ENOENT); | 101 ASSERT_EQ(fd, -ENOENT); |
| 107 fd = open_broker.Open(kR_WhiteListed, O_WRONLY); | 102 fd = open_broker.Open(kR_WhiteListed, O_WRONLY); |
| 108 ASSERT_EQ(fd, -denied_errno); | 103 ASSERT_EQ(fd, -denied_errno); |
| 109 fd = open_broker.Open(kR_WhiteListed, O_RDWR); | 104 fd = open_broker.Open(kR_WhiteListed, O_RDWR); |
| 110 ASSERT_EQ(fd, -denied_errno); | 105 ASSERT_EQ(fd, -denied_errno); |
| 111 int ret = -1; | 106 int ret = -1; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 // Don't do anything here, so that ASSERT works in the subfunction as | 231 // Don't do anything here, so that ASSERT works in the subfunction as |
| 237 // expected. | 232 // expected. |
| 238 } | 233 } |
| 239 | 234 |
| 240 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) { | 235 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) { |
| 241 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT); | 236 TestOpenFilePerms(false /* fast_check_in_client */, ENOENT); |
| 242 // Don't do anything here, so that ASSERT works in the subfunction as | 237 // Don't do anything here, so that ASSERT works in the subfunction as |
| 243 // expected. | 238 // expected. |
| 244 } | 239 } |
| 245 | 240 |
| 246 void TestOpenCpuinfo(bool fast_check_in_client) { | 241 void TestBadPaths(bool fast_check_in_client) { |
| 247 const char kFileCpuInfo[] = "/proc/cpuinfo"; | 242 const char kFileCpuInfo[] = "/proc/cpuinfo"; |
| 248 std::vector<std::string> read_whitelist; | 243 const char kNotAbsPath[] = "proc/cpuinfo"; |
| 249 read_whitelist.push_back(kFileCpuInfo); | 244 const char kDotDotStart[] = "/../proc/cpuinfo"; |
| 245 const char kDotDotMiddle[] = "/proc/self/../cpuinfo"; |
| 246 const char kDotDotEnd[] = "/proc/.."; |
| 247 const char kTrailingSlash[] = "/proc/"; |
| 250 | 248 |
| 251 scoped_ptr<BrokerProcess> open_broker(new BrokerProcess( | 249 std::vector<BrokerFilePermission> permissions; |
| 252 EPERM, read_whitelist, std::vector<std::string>(), fast_check_in_client)); | 250 |
| 251 permissions.push_back(BrokerFilePermissionReadOnlyRecursive("/proc/")); |
| 252 scoped_ptr<BrokerProcess> open_broker( |
| 253 new BrokerProcess(EPERM, permissions, fast_check_in_client)); |
| 254 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
| 255 // Open cpuinfo via the broker. |
| 256 int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); |
| 257 base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd); |
| 258 ASSERT_GE(cpuinfo_fd, 0); |
| 259 |
| 260 int fd = -1; |
| 261 int can_access; |
| 262 |
| 263 can_access = open_broker->Access(kNotAbsPath, R_OK); |
| 264 ASSERT_EQ(can_access, -EPERM); |
| 265 fd = open_broker->Open(kNotAbsPath, O_RDONLY); |
| 266 ASSERT_EQ(fd, -EPERM); |
| 267 |
| 268 can_access = open_broker->Access(kDotDotStart, R_OK); |
| 269 ASSERT_EQ(can_access, -EPERM); |
| 270 fd = open_broker->Open(kDotDotStart, O_RDONLY); |
| 271 ASSERT_EQ(fd, -EPERM); |
| 272 |
| 273 can_access = open_broker->Access(kDotDotMiddle, R_OK); |
| 274 ASSERT_EQ(can_access, -EPERM); |
| 275 fd = open_broker->Open(kDotDotMiddle, O_RDONLY); |
| 276 ASSERT_EQ(fd, -EPERM); |
| 277 |
| 278 can_access = open_broker->Access(kDotDotEnd, R_OK); |
| 279 ASSERT_EQ(can_access, -EPERM); |
| 280 fd = open_broker->Open(kDotDotEnd, O_RDONLY); |
| 281 ASSERT_EQ(fd, -EPERM); |
| 282 |
| 283 can_access = open_broker->Access(kTrailingSlash, R_OK); |
| 284 ASSERT_EQ(can_access, -EPERM); |
| 285 fd = open_broker->Open(kTrailingSlash, O_RDONLY); |
| 286 ASSERT_EQ(fd, -EPERM); |
| 287 } |
| 288 |
| 289 TEST(BrokerProcess, BadPathsClientCheck) { |
| 290 TestBadPaths(true /* fast_check_in_client */); |
| 291 // Don't do anything here, so that ASSERT works in the subfunction as |
| 292 // expected. |
| 293 } |
| 294 |
| 295 TEST(BrokerProcess, BadPathsNoClientCheck) { |
| 296 TestBadPaths(false /* fast_check_in_client */); |
| 297 // Don't do anything here, so that ASSERT works in the subfunction as |
| 298 // expected. |
| 299 } |
| 300 |
| 301 void TestOpenCpuinfo(bool fast_check_in_client, bool recursive) { |
| 302 const char kFileCpuInfo[] = "/proc/cpuinfo"; |
| 303 const char kDirProc[] = "/proc/"; |
| 304 |
| 305 std::vector<BrokerFilePermission> permissions; |
| 306 if (recursive) |
| 307 permissions.push_back(BrokerFilePermissionReadOnlyRecursive(kDirProc)); |
| 308 else |
| 309 permissions.push_back(BrokerFilePermissionReadOnly(kFileCpuInfo)); |
| 310 |
| 311 scoped_ptr<BrokerProcess> open_broker( |
| 312 new BrokerProcess(EPERM, permissions, fast_check_in_client)); |
| 253 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); | 313 ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
| 254 | 314 |
| 255 int fd = -1; | 315 int fd = -1; |
| 256 fd = open_broker->Open(kFileCpuInfo, O_RDWR); | 316 fd = open_broker->Open(kFileCpuInfo, O_RDWR); |
| 257 base::ScopedFD fd_closer(fd); | 317 base::ScopedFD fd_closer(fd); |
| 258 ASSERT_EQ(fd, -EPERM); | 318 ASSERT_EQ(fd, -EPERM); |
| 259 | 319 |
| 260 // Check we can read /proc/cpuinfo. | 320 // Check we can read /proc/cpuinfo. |
| 261 int can_access = open_broker->Access(kFileCpuInfo, R_OK); | 321 int can_access = open_broker->Access(kFileCpuInfo, R_OK); |
| 262 ASSERT_EQ(can_access, 0); | 322 ASSERT_EQ(can_access, 0); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 286 ASSERT_EQ(read_len1, read_len2); | 346 ASSERT_EQ(read_len1, read_len2); |
| 287 // Compare the cpuinfo as returned by the broker with the one we opened | 347 // Compare the cpuinfo as returned by the broker with the one we opened |
| 288 // ourselves. | 348 // ourselves. |
| 289 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0); | 349 ASSERT_EQ(memcmp(buf, buf2, read_len1), 0); |
| 290 | 350 |
| 291 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); | 351 ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); |
| 292 open_broker.reset(); | 352 open_broker.reset(); |
| 293 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); | 353 ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); |
| 294 } | 354 } |
| 295 | 355 |
| 296 // Run the same thing twice. The second time, we make sure that no security | 356 // Run this test 4 times. With and without the check in client |
| 297 // check is performed on the client. | 357 // and using a recursive path. |
| 298 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { | 358 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { |
| 299 TestOpenCpuinfo(true /* fast_check_in_client */); | 359 TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */); |
| 300 // Don't do anything here, so that ASSERT works in the subfunction as | 360 // Don't do anything here, so that ASSERT works in the subfunction as |
| 301 // expected. | 361 // expected. |
| 302 } | 362 } |
| 303 | 363 |
| 304 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { | 364 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { |
| 305 TestOpenCpuinfo(false /* fast_check_in_client */); | 365 TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */); |
| 306 // Don't do anything here, so that ASSERT works in the subfunction as | 366 // Don't do anything here, so that ASSERT works in the subfunction as |
| 307 // expected. | 367 // expected. |
| 308 } | 368 } |
| 369 |
| 370 TEST(BrokerProcess, OpenCpuinfoWithClientCheckRecursive) { |
| 371 TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */); |
| 372 // Don't do anything here, so that ASSERT works in the subfunction as |
| 373 // expected. |
| 374 } |
| 375 |
| 376 TEST(BrokerProcess, OpenCpuinfoNoClientCheckRecursive) { |
| 377 TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */); |
| 378 // Don't do anything here, so that ASSERT works in the subfunction as |
| 379 // expected. |
| 380 } |
| 309 | 381 |
| 310 TEST(BrokerProcess, OpenFileRW) { | 382 TEST(BrokerProcess, OpenFileRW) { |
| 311 ScopedTemporaryFile tempfile; | 383 ScopedTemporaryFile tempfile; |
| 312 const char* tempfile_name = tempfile.full_file_name(); | 384 const char* tempfile_name = tempfile.full_file_name(); |
| 313 | 385 |
| 314 std::vector<std::string> whitelist; | 386 std::vector<BrokerFilePermission> permissions; |
| 315 whitelist.push_back(tempfile_name); | 387 permissions.push_back(BrokerFilePermissionReadWrite(tempfile_name)); |
| 316 | 388 |
| 317 BrokerProcess open_broker(EPERM, whitelist, whitelist); | 389 BrokerProcess open_broker(EPERM, permissions); |
| 318 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); | 390 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
| 319 | 391 |
| 320 // Check we can access that file with read or write. | 392 // Check we can access that file with read or write. |
| 321 int can_access = open_broker.Access(tempfile_name, R_OK | W_OK); | 393 int can_access = open_broker.Access(tempfile_name, R_OK | W_OK); |
| 322 ASSERT_EQ(can_access, 0); | 394 ASSERT_EQ(can_access, 0); |
| 323 | 395 |
| 324 int tempfile2 = -1; | 396 int tempfile2 = -1; |
| 325 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); | 397 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); |
| 326 ASSERT_GE(tempfile2, 0); | 398 ASSERT_GE(tempfile2, 0); |
| 327 | 399 |
| 328 // Write to the descriptor opened by the broker. | 400 // Write to the descriptor opened by the broker. |
| 329 char test_text[] = "TESTTESTTEST"; | 401 char test_text[] = "TESTTESTTEST"; |
| 330 ssize_t len = write(tempfile2, test_text, sizeof(test_text)); | 402 ssize_t len = write(tempfile2, test_text, sizeof(test_text)); |
| 331 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); | 403 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); |
| 332 | 404 |
| 333 // Read back from the original file descriptor what we wrote through | 405 // Read back from the original file descriptor what we wrote through |
| 334 // the descriptor provided by the broker. | 406 // the descriptor provided by the broker. |
| 335 char buf[1024]; | 407 char buf[1024]; |
| 336 len = read(tempfile.fd(), buf, sizeof(buf)); | 408 len = read(tempfile.fd(), buf, sizeof(buf)); |
| 337 | 409 |
| 338 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); | 410 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); |
| 339 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); | 411 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); |
| 340 | 412 |
| 341 ASSERT_EQ(close(tempfile2), 0); | 413 ASSERT_EQ(close(tempfile2), 0); |
| 342 } | 414 } |
| 343 | 415 |
| 344 // SANDBOX_TEST because the process could die with a SIGPIPE | 416 // SANDBOX_TEST because the process could die with a SIGPIPE |
| 345 // and we want this to happen in a subprocess. | 417 // and we want this to happen in a subprocess. |
| 346 SANDBOX_TEST(BrokerProcess, BrokerDied) { | 418 SANDBOX_TEST(BrokerProcess, BrokerDied) { |
| 347 std::vector<std::string> read_whitelist; | 419 const char kCpuInfo[] = "/proc/cpuinfo"; |
| 348 read_whitelist.push_back("/proc/cpuinfo"); | 420 std::vector<BrokerFilePermission> permissions; |
| 421 permissions.push_back(BrokerFilePermissionReadOnly(kCpuInfo)); |
| 349 | 422 |
| 350 BrokerProcess open_broker(EPERM, | 423 BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, |
| 351 read_whitelist, | |
| 352 std::vector<std::string>(), | |
| 353 true /* fast_check_in_client */, | |
| 354 true /* quiet_failures_for_tests */); | 424 true /* quiet_failures_for_tests */); |
| 355 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); | 425 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); |
| 356 const pid_t broker_pid = open_broker.broker_pid(); | 426 const pid_t broker_pid = open_broker.broker_pid(); |
| 357 SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0); | 427 SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0); |
| 358 | 428 |
| 359 // Now we check that the broker has been signaled, but do not reap it. | 429 // Now we check that the broker has been signaled, but do not reap it. |
| 360 siginfo_t process_info; | 430 siginfo_t process_info; |
| 361 SANDBOX_ASSERT(HANDLE_EINTR(waitid( | 431 SANDBOX_ASSERT(HANDLE_EINTR(waitid( |
| 362 P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) == | 432 P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) == |
| 363 0); | 433 0); |
| 364 SANDBOX_ASSERT(broker_pid == process_info.si_pid); | 434 SANDBOX_ASSERT(broker_pid == process_info.si_pid); |
| 365 SANDBOX_ASSERT(CLD_KILLED == process_info.si_code); | 435 SANDBOX_ASSERT(CLD_KILLED == process_info.si_code); |
| 366 SANDBOX_ASSERT(SIGKILL == process_info.si_status); | 436 SANDBOX_ASSERT(SIGKILL == process_info.si_status); |
| 367 | 437 |
| 368 // Check that doing Open with a dead broker won't SIGPIPE us. | 438 // Check that doing Open with a dead broker won't SIGPIPE us. |
| 369 SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM); | 439 SANDBOX_ASSERT(open_broker.Open(kCpuInfo, O_RDONLY) == -ENOMEM); |
| 370 SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM); | 440 SANDBOX_ASSERT(open_broker.Access(kCpuInfo, O_RDONLY) == -ENOMEM); |
| 371 } | 441 } |
| 372 | 442 |
| 373 void TestOpenComplexFlags(bool fast_check_in_client) { | 443 void TestOpenComplexFlags(bool fast_check_in_client) { |
| 374 const char kCpuInfo[] = "/proc/cpuinfo"; | 444 const char kCpuInfo[] = "/proc/cpuinfo"; |
| 375 std::vector<std::string> whitelist; | 445 std::vector<BrokerFilePermission> permissions; |
| 376 whitelist.push_back(kCpuInfo); | 446 permissions.push_back(BrokerFilePermissionReadOnly(kCpuInfo)); |
| 377 | 447 |
| 378 BrokerProcess open_broker(EPERM, whitelist, whitelist, fast_check_in_client); | 448 BrokerProcess open_broker(EPERM, permissions, fast_check_in_client); |
| 379 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); | 449 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
| 380 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. | 450 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. |
| 381 int fd = -1; | 451 int fd = -1; |
| 382 int ret = 0; | 452 int ret = 0; |
| 383 fd = open_broker.Open(kCpuInfo, O_RDONLY); | 453 fd = open_broker.Open(kCpuInfo, O_RDONLY); |
| 384 ASSERT_GE(fd, 0); | 454 ASSERT_GE(fd, 0); |
| 385 ret = fcntl(fd, F_GETFL); | 455 ret = fcntl(fd, F_GETFL); |
| 386 ASSERT_NE(-1, ret); | 456 ASSERT_NE(-1, ret); |
| 387 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK. | 457 // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK. |
| 388 ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK)); | 458 ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK)); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 | 517 |
| 448 // Valgrind doesn't allow changing the hard descriptor limit, so we only | 518 // Valgrind doesn't allow changing the hard descriptor limit, so we only |
| 449 // change the soft descriptor limit here. | 519 // change the soft descriptor limit here. |
| 450 struct rlimit rlim; | 520 struct rlimit rlim; |
| 451 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim)); | 521 SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim)); |
| 452 SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur); | 522 SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur); |
| 453 rlim.rlim_cur = fd_limit; | 523 rlim.rlim_cur = fd_limit; |
| 454 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); | 524 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); |
| 455 | 525 |
| 456 static const char kCpuInfo[] = "/proc/cpuinfo"; | 526 static const char kCpuInfo[] = "/proc/cpuinfo"; |
| 457 std::vector<std::string> read_whitelist; | 527 std::vector<BrokerFilePermission> permissions; |
| 458 read_whitelist.push_back(kCpuInfo); | 528 permissions.push_back(BrokerFilePermissionReadOnly(kCpuInfo)); |
| 459 | 529 |
| 460 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); | 530 BrokerProcess open_broker(EPERM, permissions); |
| 461 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); | 531 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); |
| 462 | 532 |
| 463 const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker); | 533 const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker); |
| 464 SANDBOX_ASSERT(ipc_fd >= 0); | 534 SANDBOX_ASSERT(ipc_fd >= 0); |
| 465 | 535 |
| 466 static const char kBogus[] = "not a pickle"; | 536 static const char kBogus[] = "not a pickle"; |
| 467 std::vector<int> fds; | 537 std::vector<int> fds; |
| 468 fds.push_back(message_fd.get()); | 538 fds.push_back(message_fd.get()); |
| 469 | 539 |
| 470 // The broker process should only have a couple spare file descriptors | 540 // The broker process should only have a couple spare file descriptors |
| (...skipping 20 matching lines...) Expand all Loading... |
| 491 struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0}; | 561 struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0}; |
| 492 const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms)); | 562 const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms)); |
| 493 if (1 == num_events && poll_fd.revents | POLLHUP) | 563 if (1 == num_events && poll_fd.revents | POLLHUP) |
| 494 return true; | 564 return true; |
| 495 return false; | 565 return false; |
| 496 } | 566 } |
| 497 | 567 |
| 498 // Closing the broker client's IPC channel should terminate the broker | 568 // Closing the broker client's IPC channel should terminate the broker |
| 499 // process. | 569 // process. |
| 500 TEST(BrokerProcess, BrokerDiesOnClosedChannel) { | 570 TEST(BrokerProcess, BrokerDiesOnClosedChannel) { |
| 501 std::vector<std::string> read_whitelist; | 571 std::vector<BrokerFilePermission> permissions; |
| 502 read_whitelist.push_back("/proc/cpuinfo"); | 572 permissions.push_back(BrokerFilePermissionReadOnly("/proc/cpuinfo")); |
| 503 | 573 |
| 504 // Get the writing end of a pipe into the broker (child) process so | 574 // Get the writing end of a pipe into the broker (child) process so |
| 505 // that we can reliably detect when it dies. | 575 // that we can reliably detect when it dies. |
| 506 int lifeline_fds[2]; | 576 int lifeline_fds[2]; |
| 507 PCHECK(0 == pipe(lifeline_fds)); | 577 PCHECK(0 == pipe(lifeline_fds)); |
| 508 | 578 |
| 509 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>(), | 579 BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, |
| 510 true /* fast_check_in_client */, | |
| 511 false /* quiet_failures_for_tests */); | 580 false /* quiet_failures_for_tests */); |
| 512 ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0]))); | 581 ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0]))); |
| 513 // Make sure the writing end only exists in the broker process. | 582 // Make sure the writing end only exists in the broker process. |
| 514 CloseFD(lifeline_fds[1]); | 583 CloseFD(lifeline_fds[1]); |
| 515 base::ScopedFD reader(lifeline_fds[0]); | 584 base::ScopedFD reader(lifeline_fds[0]); |
| 516 | 585 |
| 517 const pid_t broker_pid = open_broker.broker_pid(); | 586 const pid_t broker_pid = open_broker.broker_pid(); |
| 518 | 587 |
| 519 // This should cause the broker process to exit. | 588 // This should cause the broker process to exit. |
| 520 BrokerProcessTestHelper::CloseChannel(&open_broker); | 589 BrokerProcessTestHelper::CloseChannel(&open_broker); |
| 521 | 590 |
| 522 const int kTimeoutInMilliseconds = 5000; | 591 const int kTimeoutInMilliseconds = 5000; |
| 523 const bool broker_lifeline_closed = | 592 const bool broker_lifeline_closed = |
| 524 WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds); | 593 WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds); |
| 525 // If the broker exited, its lifeline fd should be closed. | 594 // If the broker exited, its lifeline fd should be closed. |
| 526 ASSERT_TRUE(broker_lifeline_closed); | 595 ASSERT_TRUE(broker_lifeline_closed); |
| 527 // Now check that the broker has exited, but do not reap it. | 596 // Now check that the broker has exited, but do not reap it. |
| 528 siginfo_t process_info; | 597 siginfo_t process_info; |
| 529 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info, | 598 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info, |
| 530 WEXITED | WNOWAIT))); | 599 WEXITED | WNOWAIT))); |
| 531 EXPECT_EQ(broker_pid, process_info.si_pid); | 600 EXPECT_EQ(broker_pid, process_info.si_pid); |
| 532 EXPECT_EQ(CLD_EXITED, process_info.si_code); | 601 EXPECT_EQ(CLD_EXITED, process_info.si_code); |
| 533 EXPECT_EQ(1, process_info.si_status); | 602 EXPECT_EQ(1, process_info.si_status); |
| 534 } | 603 } |
| 535 | 604 |
| 605 void GetTempFileName(char* name, size_t len) { |
| 606 #if defined(OS_ANDROID) |
| 607 static const char file_template[] = "/data/local/tmp/BrokerTempFileXXXXXX"; |
| 608 #else |
| 609 static const char file_template[] = "/tmp/BrokerTempFileXXXXXX"; |
| 610 #endif // defined(OS_ANDROID) |
| 611 |
| 612 ASSERT_GT(len, sizeof(file_template)); |
| 613 |
| 614 strncpy(name, file_template, len); |
| 615 int fd = mkstemp(name); |
| 616 ASSERT_GT(fd, 0); |
| 617 ASSERT_EQ(0, unlink(name)); |
| 618 ASSERT_EQ(0, IGNORE_EINTR(close(fd))); |
| 619 } |
| 620 |
| 621 TEST(BrokerProcess, CreateFile) { |
| 622 char tempfile_name[256] = ""; |
| 623 |
| 624 GetTempFileName(tempfile_name, sizeof(tempfile_name)); |
| 625 |
| 626 std::vector<BrokerFilePermission> permissions; |
| 627 permissions.push_back(BrokerFilePermissionReadWriteCreate(tempfile_name)); |
| 628 |
| 629 BrokerProcess open_broker(EPERM, permissions); |
| 630 ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
| 631 |
| 632 int fd = -1; |
| 633 |
| 634 // Try without O_EXCL |
| 635 fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT); |
| 636 ASSERT_EQ(fd, -1); |
| 637 |
| 638 // Create a file |
| 639 fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); |
| 640 ASSERT_GE(fd, 0); |
| 641 |
| 642 // Write to the descriptor opened by the broker. |
| 643 char test_text[] = "TESTTESTTEST"; |
| 644 ssize_t len = write(fd, test_text, sizeof(test_text)); |
| 645 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); |
| 646 |
| 647 ASSERT_EQ(close(fd), 0); |
| 648 |
| 649 int fd_check = open(tempfile_name, O_RDONLY); |
| 650 ASSERT_GE(fd_check, 0); |
| 651 char buf[1024]; |
| 652 len = read(fd_check, buf, sizeof(buf)); |
| 653 |
| 654 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); |
| 655 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); |
| 656 |
| 657 ASSERT_EQ(close(fd_check), 0); |
| 658 } |
| 659 |
| 536 } // namespace syscall_broker | 660 } // namespace syscall_broker |
| 537 | 661 |
| 538 } // namespace sandbox | 662 } // namespace sandbox |
| OLD | NEW |