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