OLD | NEW |
(Empty) | |
| 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 COMPILE_ASSERT(O_ACCMODE == ((1 << kNumberOfBitsInOAccMode) - 1), |
| 128 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 |
OLD | NEW |