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/stat.h>
     10 #include <sys/types.h>
     11 #include <sys/wait.h>
     12 #include <unistd.h>
     13 
     14 #include <string>
     15 #include <vector>
     16 
     17 #include "base/basictypes.h"
     18 #include "base/logging.h"
     19 #include "base/posix/eintr_wrapper.h"
     20 #include "sandbox/linux/tests/unit_tests.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace sandbox {
     24 
     25 namespace {
     26 
     27 // Creates and open a temporary file on creation and closes
     28 // and removes it on destruction.
     29 // Unlike base/ helpers, this does not require JNI on Android.
     30 class ScopedTemporaryFile {
     31  public:
     32   ScopedTemporaryFile()
     33       : fd_(-1) {
     34 #if defined(OS_ANDROID)
     35     static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX";
     36 #else
     37     static const char file_template[] = "/tmp/ScopedTempFileXXXXXX";
     38 #endif  // defined(OS_ANDROID)
     39     COMPILE_ASSERT(sizeof(full_file_name_) >= sizeof(file_template),
     40                    full_file_name_is_large_enough);
     41     memcpy(full_file_name_, file_template, sizeof(file_template));
     42     fd_ = mkstemp(full_file_name_);
     43     CHECK_LE(0, fd_);
     44   }
     45   ~ScopedTemporaryFile() {
     46     CHECK_EQ(0, unlink(full_file_name_));
     47     CHECK_EQ(0, HANDLE_EINTR(close(fd_)));
     48   }
     49 
     50   int fd() const { return fd_; }
     51   const char* full_file_name() const { return full_file_name_; }
     52 
     53  private:
     54   int fd_;
     55   char full_file_name_[128];
     56   DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
     57 };
     58 
     59 }  // namespace
     60 
     61 #if defined(OS_ANDROID)
     62   #define DISABLE_ON_ANDROID(function) DISABLED_##function
     63 #else
     64   #define DISABLE_ON_ANDROID(function) function
     65 #endif
     66 
     67 TEST(BrokerProcess, CreateAndDestroy) {
     68   std::vector<std::string> read_whitelist;
     69   read_whitelist.push_back("/proc/cpuinfo");
     70 
     71   BrokerProcess* open_broker = new BrokerProcess(read_whitelist,
     72                                                  std::vector<std::string>());
     73   ASSERT_TRUE(open_broker->Init(NULL));
     74   pid_t broker_pid = open_broker->broker_pid();
     75   delete(open_broker);
     76 
     77   // Now we check that the broker has exited properly.
     78   int status = 0;
     79   ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid);
     80   ASSERT_TRUE(WIFEXITED(status));
     81   ASSERT_EQ(WEXITSTATUS(status), 0);
     82 }
     83 
     84 TEST(BrokerProcess, TestOpenAccessNull) {
     85   const std::vector<std::string> empty;
     86   BrokerProcess open_broker(empty, empty);
     87   ASSERT_TRUE(open_broker.Init(NULL));
     88 
     89   int fd = open_broker.Open(NULL, O_RDONLY);
     90   ASSERT_EQ(fd, -EFAULT);
     91 
     92   int ret = open_broker.Access(NULL, F_OK);
     93   ASSERT_EQ(ret, -EFAULT);
     94 }
     95 
     96 void TestOpenFilePerms(bool fast_check_in_client) {
     97   const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1";
     98   // We can't debug the init process, and shouldn't be able to access
     99   // its auxv file.
    100   const char kR_WhiteListedButDenied[] = "/proc/1/auxv";
    101   const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2";
    102   const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3";
    103   const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4";
    104 
    105   std::vector<std::string> read_whitelist;
    106   read_whitelist.push_back(kR_WhiteListed);
    107   read_whitelist.push_back(kR_WhiteListedButDenied);
    108   read_whitelist.push_back(kRW_WhiteListed);
    109 
    110   std::vector<std::string> write_whitelist;
    111   write_whitelist.push_back(kW_WhiteListed);
    112   write_whitelist.push_back(kRW_WhiteListed);
    113 
    114   BrokerProcess open_broker(read_whitelist,
    115                             write_whitelist,
    116                             fast_check_in_client);
    117   ASSERT_TRUE(open_broker.Init(NULL));
    118 
    119   int fd = -1;
    120   fd = open_broker.Open(kR_WhiteListed, O_RDONLY);
    121   ASSERT_EQ(fd, -ENOENT);
    122   fd = open_broker.Open(kR_WhiteListed, O_WRONLY);
    123   ASSERT_EQ(fd, -EPERM);
    124   fd = open_broker.Open(kR_WhiteListed, O_RDWR);
    125   ASSERT_EQ(fd, -EPERM);
    126   int ret = -1;
    127   ret = open_broker.Access(kR_WhiteListed, F_OK);
    128   ASSERT_EQ(ret, -ENOENT);
    129   ret = open_broker.Access(kR_WhiteListed, R_OK);
    130   ASSERT_EQ(ret, -ENOENT);
    131   ret = open_broker.Access(kR_WhiteListed, W_OK);
    132   ASSERT_EQ(ret, -EPERM);
    133   ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK);
    134   ASSERT_EQ(ret, -EPERM);
    135   ret = open_broker.Access(kR_WhiteListed, X_OK);
    136   ASSERT_EQ(ret, -EPERM);
    137   ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK);
    138   ASSERT_EQ(ret, -EPERM);
    139 
    140   // Android sometimes runs tests as root.
    141   // This part of the test requires a process that doesn't have
    142   // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
    143   if (geteuid()) {
    144     fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
    145     // The broker process will allow this, but the normal permission system
    146     // won't.
    147     ASSERT_EQ(fd, -EACCES);
    148     fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY);
    149     ASSERT_EQ(fd, -EPERM);
    150     fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR);
    151     ASSERT_EQ(fd, -EPERM);
    152     ret = open_broker.Access(kR_WhiteListedButDenied, F_OK);
    153     // The normal permission system will let us check that the file exists.
    154     ASSERT_EQ(ret, 0);
    155     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK);
    156     ASSERT_EQ(ret, -EACCES);
    157     ret = open_broker.Access(kR_WhiteListedButDenied, W_OK);
    158     ASSERT_EQ(ret, -EPERM);
    159     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK);
    160     ASSERT_EQ(ret, -EPERM);
    161     ret = open_broker.Access(kR_WhiteListedButDenied, X_OK);
    162     ASSERT_EQ(ret, -EPERM);
    163     ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK);
    164     ASSERT_EQ(ret, -EPERM);
    165   }
    166 
    167   fd = open_broker.Open(kW_WhiteListed, O_RDONLY);
    168   ASSERT_EQ(fd, -EPERM);
    169   fd = open_broker.Open(kW_WhiteListed, O_WRONLY);
    170   ASSERT_EQ(fd, -ENOENT);
    171   fd = open_broker.Open(kW_WhiteListed, O_RDWR);
    172   ASSERT_EQ(fd, -EPERM);
    173   ret = open_broker.Access(kW_WhiteListed, F_OK);
    174   ASSERT_EQ(ret, -ENOENT);
    175   ret = open_broker.Access(kW_WhiteListed, R_OK);
    176   ASSERT_EQ(ret, -EPERM);
    177   ret = open_broker.Access(kW_WhiteListed, W_OK);
    178   ASSERT_EQ(ret, -ENOENT);
    179   ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK);
    180   ASSERT_EQ(ret, -EPERM);
    181   ret = open_broker.Access(kW_WhiteListed, X_OK);
    182   ASSERT_EQ(ret, -EPERM);
    183   ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK);
    184   ASSERT_EQ(ret, -EPERM);
    185 
    186   fd = open_broker.Open(kRW_WhiteListed, O_RDONLY);
    187   ASSERT_EQ(fd, -ENOENT);
    188   fd = open_broker.Open(kRW_WhiteListed, O_WRONLY);
    189   ASSERT_EQ(fd, -ENOENT);
    190   fd = open_broker.Open(kRW_WhiteListed, O_RDWR);
    191   ASSERT_EQ(fd, -ENOENT);
    192   ret = open_broker.Access(kRW_WhiteListed, F_OK);
    193   ASSERT_EQ(ret, -ENOENT);
    194   ret = open_broker.Access(kRW_WhiteListed, R_OK);
    195   ASSERT_EQ(ret, -ENOENT);
    196   ret = open_broker.Access(kRW_WhiteListed, W_OK);
    197   ASSERT_EQ(ret, -ENOENT);
    198   ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK);
    199   ASSERT_EQ(ret, -ENOENT);
    200   ret = open_broker.Access(kRW_WhiteListed, X_OK);
    201   ASSERT_EQ(ret, -EPERM);
    202   ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK);
    203   ASSERT_EQ(ret, -EPERM);
    204 
    205   fd = open_broker.Open(k_NotWhitelisted, O_RDONLY);
    206   ASSERT_EQ(fd, -EPERM);
    207   fd = open_broker.Open(k_NotWhitelisted, O_WRONLY);
    208   ASSERT_EQ(fd, -EPERM);
    209   fd = open_broker.Open(k_NotWhitelisted, O_RDWR);
    210   ASSERT_EQ(fd, -EPERM);
    211   ret = open_broker.Access(k_NotWhitelisted, F_OK);
    212   ASSERT_EQ(ret, -EPERM);
    213   ret = open_broker.Access(k_NotWhitelisted, R_OK);
    214   ASSERT_EQ(ret, -EPERM);
    215   ret = open_broker.Access(k_NotWhitelisted, W_OK);
    216   ASSERT_EQ(ret, -EPERM);
    217   ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK);
    218   ASSERT_EQ(ret, -EPERM);
    219   ret = open_broker.Access(k_NotWhitelisted, X_OK);
    220   ASSERT_EQ(ret, -EPERM);
    221   ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK);
    222   ASSERT_EQ(ret, -EPERM);
    223 
    224 
    225   // We have some extra sanity check for clearly wrong values.
    226   fd = open_broker.Open(kRW_WhiteListed, O_RDONLY|O_WRONLY|O_RDWR);
    227   ASSERT_EQ(fd, -EPERM);
    228 
    229   // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
    230   // is denied.
    231   fd = open_broker.Open(kRW_WhiteListed, O_RDWR|O_CREAT);
    232   ASSERT_EQ(fd, -EPERM);
    233 }
    234 
    235 // Run the same thing twice. The second time, we make sure that no security
    236 // check is performed on the client.
    237 TEST(BrokerProcess, OpenFilePermsWithClientCheck) {
    238   TestOpenFilePerms(true /* fast_check_in_client */);
    239   // Don't do anything here, so that ASSERT works in the subfunction as
    240   // expected.
    241 }
    242 
    243 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) {
    244   TestOpenFilePerms(false /* fast_check_in_client */);
    245   // Don't do anything here, so that ASSERT works in the subfunction as
    246   // expected.
    247 }
    248 
    249 
    250 void TestOpenCpuinfo(bool fast_check_in_client) {
    251   const char kFileCpuInfo[] = "/proc/cpuinfo";
    252   std::vector<std::string> read_whitelist;
    253   read_whitelist.push_back(kFileCpuInfo);
    254 
    255   BrokerProcess* open_broker = new BrokerProcess(read_whitelist,
    256                                                  std::vector<std::string>(),
    257                                                  fast_check_in_client);
    258   ASSERT_TRUE(open_broker->Init(NULL));
    259   pid_t broker_pid = open_broker->broker_pid();
    260 
    261   int fd = -1;
    262   fd = open_broker->Open(kFileCpuInfo, O_RDWR);
    263   ASSERT_EQ(fd, -EPERM);
    264 
    265   // Check we can read /proc/cpuinfo.
    266   int can_access = open_broker->Access(kFileCpuInfo, R_OK);
    267   ASSERT_EQ(can_access, 0);
    268   can_access = open_broker->Access(kFileCpuInfo, W_OK);
    269   ASSERT_EQ(can_access, -EPERM);
    270   // Check we can not write /proc/cpuinfo.
    271 
    272   // Open cpuinfo via the broker.
    273   int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
    274   ASSERT_GE(cpuinfo_fd, 0);
    275   char buf[3];
    276   memset(buf, 0, sizeof(buf));
    277   int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
    278   ASSERT_GT(read_len1, 0);
    279 
    280   // Open cpuinfo directly.
    281   int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY);
    282   ASSERT_GE(cpuinfo_fd2, 0);
    283   char buf2[3];
    284   memset(buf2, 1, sizeof(buf2));
    285   int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
    286   ASSERT_GT(read_len1, 0);
    287 
    288   // The following is not guaranteed true, but will be in practice.
    289   ASSERT_EQ(read_len1, read_len2);
    290   // Compare the cpuinfo as returned by the broker with the one we opened
    291   // ourselves.
    292   ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
    293 
    294   if (fd >= 0)
    295     close(fd);
    296   if (cpuinfo_fd >= 0)
    297     close(cpuinfo_fd);
    298   if (cpuinfo_fd2 >= 0)
    299     close(cpuinfo_fd);
    300 
    301   delete(open_broker);
    302 
    303   // Now we check that the broker has exited properly.
    304   int status = 0;
    305   ASSERT_EQ(waitpid(broker_pid, &status, 0), broker_pid);
    306   ASSERT_TRUE(WIFEXITED(status));
    307   ASSERT_EQ(WEXITSTATUS(status), 0);
    308 }
    309 
    310 // Run the same thing twice. The second time, we make sure that no security
    311 // check is performed on the client.
    312 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) {
    313   TestOpenCpuinfo(true /* fast_check_in_client */);
    314   // Don't do anything here, so that ASSERT works in the subfunction as
    315   // expected.
    316 }
    317 
    318 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) {
    319   TestOpenCpuinfo(false /* fast_check_in_client */);
    320   // Don't do anything here, so that ASSERT works in the subfunction as
    321   // expected.
    322 }
    323 
    324 TEST(BrokerProcess, OpenFileRW) {
    325   ScopedTemporaryFile tempfile;
    326   const char* tempfile_name = tempfile.full_file_name();
    327 
    328   std::vector<std::string> whitelist;
    329   whitelist.push_back(tempfile_name);
    330 
    331   BrokerProcess open_broker(whitelist, whitelist);
    332   ASSERT_TRUE(open_broker.Init(NULL));
    333 
    334   // Check we can access that file with read or write.
    335   int can_access = open_broker.Access(tempfile_name, R_OK | W_OK);
    336   ASSERT_EQ(can_access, 0);
    337 
    338   int tempfile2 = -1;
    339   tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
    340   ASSERT_GE(tempfile2, 0);
    341 
    342   // Write to the descriptor opened by the broker.
    343   char test_text[] = "TESTTESTTEST";
    344   ssize_t len = write(tempfile2, test_text, sizeof(test_text));
    345   ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
    346 
    347   // Read back from the original file descriptor what we wrote through
    348   // the descriptor provided by the broker.
    349   char buf[1024];
    350   len = read(tempfile.fd(), buf, sizeof(buf));
    351 
    352   ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
    353   ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
    354 
    355   ASSERT_EQ(close(tempfile2), 0);
    356 }
    357 
    358 // Sandbox test because we could get a SIGPIPE.
    359 SANDBOX_TEST(BrokerProcess, BrokerDied) {
    360   std::vector<std::string> read_whitelist;
    361   read_whitelist.push_back("/proc/cpuinfo");
    362 
    363   BrokerProcess open_broker(read_whitelist,
    364                             std::vector<std::string>(),
    365                             true /* fast_check_in_client */,
    366                             true /* quiet_failures_for_tests */);
    367   SANDBOX_ASSERT(open_broker.Init(NULL));
    368   pid_t broker_pid = open_broker.broker_pid();
    369   SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0);
    370 
    371   // Now we check that the broker has exited properly.
    372   int status = 0;
    373   SANDBOX_ASSERT(waitpid(broker_pid, &status, 0) == broker_pid);
    374   SANDBOX_ASSERT(WIFSIGNALED(status));
    375   SANDBOX_ASSERT(WTERMSIG(status) == SIGKILL);
    376   // Hopefully doing Open with a dead broker won't SIGPIPE us.
    377   SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
    378   SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM);
    379 }
    380 
    381 void TestOpenComplexFlags(bool fast_check_in_client) {
    382   const char kCpuInfo[] = "/proc/cpuinfo";
    383   std::vector<std::string> whitelist;
    384   whitelist.push_back(kCpuInfo);
    385 
    386   BrokerProcess open_broker(whitelist,
    387                             whitelist,
    388                             fast_check_in_client);
    389   ASSERT_TRUE(open_broker.Init(NULL));
    390   // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
    391   int fd = -1;
    392   int ret = 0;
    393   fd = open_broker.Open(kCpuInfo, O_RDONLY);
    394   ASSERT_GE(fd, 0);
    395   ret = fcntl(fd, F_GETFL);
    396   ASSERT_NE(-1, ret);
    397   // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
    398   ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK));
    399   ASSERT_EQ(0, close(fd));
    400 
    401   fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
    402   ASSERT_GE(fd, 0);
    403   ret = fcntl(fd, F_GETFD);
    404   ASSERT_NE(-1, ret);
    405   // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
    406   // is actually not used by the kernel.
    407   ASSERT_TRUE(FD_CLOEXEC & ret);
    408 
    409   // There is buggy userland code that can check for O_CLOEXEC with fcntl(2)
    410   // even though it doesn't mean anything. We need to support this case.
    411   // See crbug.com/237283.
    412   ret = fcntl(fd, F_GETFL);
    413   ASSERT_NE(-1, ret);
    414   ASSERT_TRUE(O_CLOEXEC & ret);
    415 
    416   ASSERT_EQ(0, close(fd));
    417 
    418   fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
    419   ASSERT_GE(fd, 0);
    420   ret = fcntl(fd, F_GETFL);
    421   ASSERT_NE(-1, ret);
    422   ASSERT_TRUE(O_NONBLOCK & ret);
    423   ASSERT_EQ(0, close(fd));
    424 }
    425 
    426 TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) {
    427   TestOpenComplexFlags(true /* fast_check_in_client */);
    428   // Don't do anything here, so that ASSERT works in the subfunction as
    429   // expected.
    430 }
    431 
    432 TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) {
    433   TestOpenComplexFlags(false /* fast_check_in_client */);
    434   // Don't do anything here, so that ASSERT works in the subfunction as
    435   // expected.
    436 }
    437 
    438 }  // namespace sandbox
    439