Home | History | Annotate | Download | only in services
      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