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