Home | History | Annotate | Download | only in syscall_broker
      1 // Copyright 2014 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_file_permission.h"
      6 
      7 #include <fcntl.h>
      8 #include <string.h>
      9 #include <sys/stat.h>
     10 #include <sys/types.h>
     11 #include <unistd.h>
     12 
     13 #include "base/logging.h"
     14 #include "base/macros.h"
     15 #include "sandbox/linux/tests/test_utils.h"
     16 #include "sandbox/linux/tests/unit_tests.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace sandbox {
     20 
     21 namespace syscall_broker {
     22 
     23 class BrokerFilePermissionTester {
     24  public:
     25   static bool ValidatePath(const char* path) {
     26     return BrokerFilePermission::ValidatePath(path);
     27   }
     28   static const char* GetErrorMessage() {
     29     return BrokerFilePermission::GetErrorMessageForTests();
     30   }
     31 
     32  private:
     33   DISALLOW_COPY_AND_ASSIGN(BrokerFilePermissionTester);
     34 };
     35 
     36 namespace {
     37 
     38 // Creation tests are DEATH tests as a bad permission causes termination.
     39 SANDBOX_TEST(BrokerFilePermission, CreateGood) {
     40   const char kPath[] = "/tmp/good";
     41   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
     42 }
     43 
     44 SANDBOX_TEST(BrokerFilePermission, CreateGoodRecursive) {
     45   const char kPath[] = "/tmp/good/";
     46   BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
     47 }
     48 
     49 SANDBOX_DEATH_TEST(
     50     BrokerFilePermission,
     51     CreateBad,
     52     DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
     53   const char kPath[] = "/tmp/bad/";
     54   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
     55 }
     56 
     57 SANDBOX_DEATH_TEST(
     58     BrokerFilePermission,
     59     CreateBadRecursive,
     60     DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
     61   const char kPath[] = "/tmp/bad";
     62   BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
     63 }
     64 
     65 SANDBOX_DEATH_TEST(
     66     BrokerFilePermission,
     67     CreateBadNotAbs,
     68     DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
     69   const char kPath[] = "tmp/bad";
     70   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
     71 }
     72 
     73 SANDBOX_DEATH_TEST(
     74     BrokerFilePermission,
     75     CreateBadEmpty,
     76     DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
     77   const char kPath[] = "";
     78   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
     79 }
     80 
     81 // CheckPerm tests |path| against |perm| given |access_flags|.
     82 // If |create| is true then file creation is tested for success.
     83 void CheckPerm(const BrokerFilePermission& perm,
     84                const char* path,
     85                int access_flags,
     86                bool create) {
     87   const char* file_to_open = NULL;
     88 
     89   ASSERT_FALSE(perm.CheckAccess(path, X_OK, NULL));
     90   ASSERT_TRUE(perm.CheckAccess(path, F_OK, NULL));
     91   // check bad perms
     92   switch (access_flags) {
     93     case O_RDONLY:
     94       ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
     95       ASSERT_FALSE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
     96       ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
     97       ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
     98       ASSERT_FALSE(perm.CheckAccess(path, W_OK, NULL));
     99       break;
    100     case O_WRONLY:
    101       ASSERT_FALSE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
    102       ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
    103       ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
    104       ASSERT_FALSE(perm.CheckAccess(path, R_OK, NULL));
    105       ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
    106       break;
    107     case O_RDWR:
    108       ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
    109       ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
    110       ASSERT_TRUE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
    111       ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
    112       ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
    113       break;
    114     default:
    115       // Bad test case
    116       NOTREACHED();
    117   }
    118 
    119 // O_SYNC can be defined as (__O_SYNC|O_DSYNC)
    120 #ifdef O_DSYNC
    121   const int kSyncFlag = O_SYNC & ~O_DSYNC;
    122 #else
    123   const int kSyncFlag = O_SYNC;
    124 #endif
    125 
    126   const int kNumberOfBitsInOAccMode = 2;
    127   static_assert(O_ACCMODE == ((1 << kNumberOfBitsInOAccMode) - 1),
    128                 "incorrect number of bits");
    129   // check every possible flag and act accordingly.
    130   // Skipping AccMode bits as they are present in every case.
    131   for (int i = kNumberOfBitsInOAccMode; i < 32; i++) {
    132     int flag = 1 << i;
    133     switch (flag) {
    134       case O_APPEND:
    135       case O_ASYNC:
    136       case O_DIRECT:
    137       case O_DIRECTORY:
    138 #ifdef O_DSYNC
    139       case O_DSYNC:
    140 #endif
    141       case O_EXCL:
    142       case O_LARGEFILE:
    143       case O_NOATIME:
    144       case O_NOCTTY:
    145       case O_NOFOLLOW:
    146       case O_NONBLOCK:
    147 #if (O_NONBLOCK != O_NDELAY)
    148       case O_NDELAY:
    149 #endif
    150       case kSyncFlag:
    151       case O_TRUNC:
    152         ASSERT_TRUE(
    153             perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
    154         break;
    155       case O_CLOEXEC:
    156       case O_CREAT:
    157       default:
    158         ASSERT_FALSE(
    159             perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
    160     }
    161   }
    162   if (create) {
    163     bool unlink;
    164     ASSERT_TRUE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
    165                                &file_to_open, &unlink));
    166     ASSERT_FALSE(unlink);
    167   } else {
    168     ASSERT_FALSE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
    169                                 &file_to_open, NULL));
    170   }
    171 }
    172 
    173 TEST(BrokerFilePermission, ReadOnly) {
    174   const char kPath[] = "/tmp/good";
    175   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
    176   CheckPerm(perm, kPath, O_RDONLY, false);
    177   // Don't do anything here, so that ASSERT works in the subfunction as
    178   // expected.
    179 }
    180 
    181 TEST(BrokerFilePermission, ReadOnlyRecursive) {
    182   const char kPath[] = "/tmp/good/";
    183   const char kPathFile[] = "/tmp/good/file";
    184   BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
    185   CheckPerm(perm, kPathFile, O_RDONLY, false);
    186   // Don't do anything here, so that ASSERT works in the subfunction as
    187   // expected.
    188 }
    189 
    190 TEST(BrokerFilePermission, WriteOnly) {
    191   const char kPath[] = "/tmp/good";
    192   BrokerFilePermission perm = BrokerFilePermission::WriteOnly(kPath);
    193   CheckPerm(perm, kPath, O_WRONLY, false);
    194   // Don't do anything here, so that ASSERT works in the subfunction as
    195   // expected.
    196 }
    197 
    198 TEST(BrokerFilePermission, ReadWrite) {
    199   const char kPath[] = "/tmp/good";
    200   BrokerFilePermission perm = BrokerFilePermission::ReadWrite(kPath);
    201   CheckPerm(perm, kPath, O_RDWR, false);
    202   // Don't do anything here, so that ASSERT works in the subfunction as
    203   // expected.
    204 }
    205 
    206 TEST(BrokerFilePermission, ReadWriteCreate) {
    207   const char kPath[] = "/tmp/good";
    208   BrokerFilePermission perm = BrokerFilePermission::ReadWriteCreate(kPath);
    209   CheckPerm(perm, kPath, O_RDWR, true);
    210   // Don't do anything here, so that ASSERT works in the subfunction as
    211   // expected.
    212 }
    213 
    214 void CheckUnlink(BrokerFilePermission& perm,
    215                  const char* path,
    216                  int access_flags) {
    217   bool unlink;
    218   ASSERT_FALSE(perm.CheckOpen(path, access_flags, NULL, &unlink));
    219   ASSERT_FALSE(perm.CheckOpen(path, access_flags | O_CREAT, NULL, &unlink));
    220   ASSERT_TRUE(
    221       perm.CheckOpen(path, access_flags | O_CREAT | O_EXCL, NULL, &unlink));
    222   ASSERT_TRUE(unlink);
    223 }
    224 
    225 TEST(BrokerFilePermission, ReadWriteCreateUnlink) {
    226   const char kPath[] = "/tmp/good";
    227   BrokerFilePermission perm =
    228       BrokerFilePermission::ReadWriteCreateUnlink(kPath);
    229   CheckUnlink(perm, kPath, O_RDWR);
    230   // Don't do anything here, so that ASSERT works in the subfunction as
    231   // expected.
    232 }
    233 
    234 TEST(BrokerFilePermission, ReadWriteCreateUnlinkRecursive) {
    235   const char kPath[] = "/tmp/good/";
    236   const char kPathFile[] = "/tmp/good/file";
    237   BrokerFilePermission perm =
    238       BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kPath);
    239   CheckUnlink(perm, kPathFile, O_RDWR);
    240   // Don't do anything here, so that ASSERT works in the subfunction as
    241   // expected.
    242 }
    243 
    244 TEST(BrokerFilePermission, ValidatePath) {
    245   EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path"));
    246   EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/"));
    247   EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/..path"));
    248 
    249   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath(""));
    250   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad"));
    251   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/"));
    252   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad/"));
    253   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/.."));
    254   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/../bad"));
    255   EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/../bad"));
    256 }
    257 
    258 }  // namespace
    259 
    260 }  // namespace syscall_broker
    261 
    262 }  // namespace sandbox
    263