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