gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/chmod.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <fcntl.h> 16 #include <sys/stat.h> 17 #include <sys/syscall.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 21 #include <string> 22 23 #include "gtest/gtest.h" 24 #include "test/util/capability_util.h" 25 #include "test/util/file_descriptor.h" 26 #include "test/util/fs_util.h" 27 #include "test/util/temp_path.h" 28 #include "test/util/test_util.h" 29 30 namespace gvisor { 31 namespace testing { 32 33 namespace { 34 35 TEST(ChmodTest, ChmodFileSucceeds) { 36 // Drop capabilities that allow us to override file permissions. 37 AutoCapability cap(CAP_DAC_OVERRIDE, false); 38 39 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 40 41 ASSERT_THAT(chmod(file.path().c_str(), 0466), SyscallSucceeds()); 42 EXPECT_THAT(open(file.path().c_str(), O_RDWR), SyscallFailsWithErrno(EACCES)); 43 } 44 45 TEST(ChmodTest, ChmodDirSucceeds) { 46 // Drop capabilities that allow us to override file and directory permissions. 47 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 48 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 49 50 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 51 const std::string fileInDir = NewTempAbsPathInDir(dir.path()); 52 53 ASSERT_THAT(chmod(dir.path().c_str(), 0466), SyscallSucceeds()); 54 EXPECT_THAT(open(fileInDir.c_str(), O_RDONLY), SyscallFailsWithErrno(EACCES)); 55 } 56 57 TEST(ChmodTest, FchmodFileSucceeds) { 58 // Drop capabilities that allow us to file directory permissions. 59 AutoCapability cap(CAP_DAC_OVERRIDE, false); 60 61 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666)); 62 int fd; 63 ASSERT_THAT(fd = open(file.path().c_str(), O_RDWR), SyscallSucceeds()); 64 65 { 66 const DisableSave ds; // File permissions are reduced. 67 ASSERT_THAT(fchmod(fd, 0444), SyscallSucceeds()); 68 EXPECT_THAT(close(fd), SyscallSucceeds()); 69 } 70 71 EXPECT_THAT(open(file.path().c_str(), O_RDWR), SyscallFailsWithErrno(EACCES)); 72 } 73 74 TEST(ChmodTest, FchmodDirSucceeds) { 75 // Drop capabilities that allow us to override file and directory permissions. 76 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 77 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 78 79 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 80 int fd; 81 ASSERT_THAT(fd = open(dir.path().c_str(), O_RDONLY | O_DIRECTORY), 82 SyscallSucceeds()); 83 84 { 85 const DisableSave ds; // File permissions are reduced. 86 ASSERT_THAT(fchmod(fd, 0), SyscallSucceeds()); 87 EXPECT_THAT(close(fd), SyscallSucceeds()); 88 } 89 90 EXPECT_THAT(open(dir.path().c_str(), O_RDONLY), 91 SyscallFailsWithErrno(EACCES)); 92 } 93 94 TEST(ChmodTest, FchmodBadF) { 95 ASSERT_THAT(fchmod(-1, 0444), SyscallFailsWithErrno(EBADF)); 96 } 97 98 TEST(ChmodTest, FchmodatBadF) { 99 ASSERT_THAT(fchmodat(-1, "foo", 0444, 0), SyscallFailsWithErrno(EBADF)); 100 } 101 102 TEST(ChmodTest, FchmodFileWithOpath) { 103 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 104 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_PATH)); 105 106 // Bionic's implementation of fchmod() uses chmod() when O_PATH is set 107 // to circumvent the behavior this is testing for. 108 // Use syscall() here to avoid running through Bionic on Android. 109 ASSERT_THAT(syscall(SYS_fchmod, fd.get(), 0444), 110 SyscallFailsWithErrno(EBADF)); 111 } 112 113 TEST(ChmodTest, FchmodDirWithOpath) { 114 const auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 115 const auto fd = 116 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_DIRECTORY | O_PATH)); 117 118 ASSERT_THAT(syscall(SYS_fchmod, fd.get(), 0444), 119 SyscallFailsWithErrno(EBADF)); 120 } 121 122 TEST(ChmodTest, FchmodatWithOpath) { 123 // Drop capabilities that allow us to override file permissions. 124 AutoCapability cap(CAP_DAC_OVERRIDE, false); 125 126 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 127 128 const auto parent_fd = ASSERT_NO_ERRNO_AND_VALUE( 129 Open(GetAbsoluteTestTmpdir().c_str(), O_PATH | O_DIRECTORY)); 130 131 ASSERT_THAT( 132 fchmodat(parent_fd.get(), std::string(Basename(temp_file.path())).c_str(), 133 0444, 0), 134 SyscallSucceeds()); 135 136 EXPECT_THAT(open(temp_file.path().c_str(), O_RDWR), 137 SyscallFailsWithErrno(EACCES)); 138 } 139 140 TEST(ChmodTest, FchmodatNotDir) { 141 ASSERT_THAT(fchmodat(-1, "", 0444, 0), SyscallFailsWithErrno(ENOENT)); 142 } 143 144 TEST(ChmodTest, FchmodatFileAbsolutePath) { 145 // Drop capabilities that allow us to override file permissions. 146 AutoCapability cap(CAP_DAC_OVERRIDE, false); 147 148 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 149 150 ASSERT_THAT(fchmodat(-1, file.path().c_str(), 0444, 0), SyscallSucceeds()); 151 EXPECT_THAT(open(file.path().c_str(), O_RDWR), SyscallFailsWithErrno(EACCES)); 152 } 153 154 TEST(ChmodTest, FchmodatDirAbsolutePath) { 155 // Drop capabilities that allow us to override file and directory permissions. 156 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 157 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 158 159 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 160 161 int fd; 162 ASSERT_THAT(fd = open(dir.path().c_str(), O_RDONLY | O_DIRECTORY), 163 SyscallSucceeds()); 164 EXPECT_THAT(close(fd), SyscallSucceeds()); 165 166 ASSERT_THAT(fchmodat(-1, dir.path().c_str(), 0, 0), SyscallSucceeds()); 167 EXPECT_THAT(open(dir.path().c_str(), O_RDONLY), 168 SyscallFailsWithErrno(EACCES)); 169 } 170 171 TEST(ChmodTest, FchmodatFile) { 172 // Drop capabilities that allow us to override file permissions. 173 AutoCapability cap(CAP_DAC_OVERRIDE, false); 174 175 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 176 177 int parent_fd; 178 ASSERT_THAT( 179 parent_fd = open(GetAbsoluteTestTmpdir().c_str(), O_RDONLY | O_DIRECTORY), 180 SyscallSucceeds()); 181 182 ASSERT_THAT( 183 fchmodat(parent_fd, std::string(Basename(temp_file.path())).c_str(), 0444, 184 0), 185 SyscallSucceeds()); 186 EXPECT_THAT(close(parent_fd), SyscallSucceeds()); 187 188 EXPECT_THAT(open(temp_file.path().c_str(), O_RDWR), 189 SyscallFailsWithErrno(EACCES)); 190 } 191 192 TEST(ChmodTest, FchmodatDir) { 193 // Drop capabilities that allow us to override file and directory permissions. 194 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 195 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 196 197 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 198 199 int parent_fd; 200 ASSERT_THAT( 201 parent_fd = open(GetAbsoluteTestTmpdir().c_str(), O_RDONLY | O_DIRECTORY), 202 SyscallSucceeds()); 203 204 int fd; 205 ASSERT_THAT(fd = open(dir.path().c_str(), O_RDONLY | O_DIRECTORY), 206 SyscallSucceeds()); 207 EXPECT_THAT(close(fd), SyscallSucceeds()); 208 209 ASSERT_THAT( 210 fchmodat(parent_fd, std::string(Basename(dir.path())).c_str(), 0, 0), 211 SyscallSucceeds()); 212 EXPECT_THAT(close(parent_fd), SyscallSucceeds()); 213 214 EXPECT_THAT(open(dir.path().c_str(), O_RDONLY | O_DIRECTORY), 215 SyscallFailsWithErrno(EACCES)); 216 } 217 218 TEST(ChmodTest, ChmodDowngradeWritability) { 219 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666)); 220 221 int fd; 222 ASSERT_THAT(fd = open(file.path().c_str(), O_RDWR), SyscallSucceeds()); 223 224 const DisableSave ds; // Permissions are dropped. 225 ASSERT_THAT(chmod(file.path().c_str(), 0444), SyscallSucceeds()); 226 EXPECT_THAT(write(fd, "hello", 5), SyscallSucceedsWithValue(5)); 227 228 EXPECT_THAT(close(fd), SyscallSucceeds()); 229 } 230 231 TEST(ChmodTest, ChmodFileToNoPermissionsSucceeds) { 232 // Drop capabilities that allow us to override file permissions. 233 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 234 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 235 236 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666)); 237 238 ASSERT_THAT(chmod(file.path().c_str(), 0), SyscallSucceeds()); 239 240 EXPECT_THAT(open(file.path().c_str(), O_RDONLY), 241 SyscallFailsWithErrno(EACCES)); 242 } 243 244 TEST(ChmodTest, FchmodDowngradeWritability) { 245 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 246 247 int fd; 248 ASSERT_THAT(fd = open(file.path().c_str(), O_RDWR | O_CREAT, 0666), 249 SyscallSucceeds()); 250 251 const DisableSave ds; // Permissions are dropped. 252 ASSERT_THAT(fchmod(fd, 0444), SyscallSucceeds()); 253 EXPECT_THAT(write(fd, "hello", 5), SyscallSucceedsWithValue(5)); 254 255 EXPECT_THAT(close(fd), SyscallSucceeds()); 256 } 257 258 TEST(ChmodTest, FchmodFileToNoPermissionsSucceeds) { 259 // Drop capabilities that allow us to override file permissions. 260 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 261 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 262 263 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666)); 264 265 int fd; 266 ASSERT_THAT(fd = open(file.path().c_str(), O_RDWR), SyscallSucceeds()); 267 268 { 269 const DisableSave ds; // Permissions are dropped. 270 ASSERT_THAT(fchmod(fd, 0), SyscallSucceeds()); 271 EXPECT_THAT(close(fd), SyscallSucceeds()); 272 } 273 274 EXPECT_THAT(open(file.path().c_str(), O_RDONLY), 275 SyscallFailsWithErrno(EACCES)); 276 } 277 278 // Verify that we can get a RW FD after chmod, even if a RO fd is left open. 279 TEST(ChmodTest, ChmodWritableWithOpenFD) { 280 // FIXME(b/72455313): broken on hostfs. 281 if (IsRunningOnGvisor()) { 282 return; 283 } 284 285 TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0444)); 286 287 FileDescriptor fd1 = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY)); 288 289 ASSERT_THAT(fchmod(fd1.get(), 0644), SyscallSucceeds()); 290 291 // This FD is writable, even though fd1 has a read-only reference to the file. 292 FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 293 294 // fd1 is not writable, but fd2 is. 295 char c = 'a'; 296 EXPECT_THAT(WriteFd(fd1.get(), &c, 1), SyscallFailsWithErrno(EBADF)); 297 EXPECT_THAT(WriteFd(fd2.get(), &c, 1), SyscallSucceedsWithValue(1)); 298 } 299 300 } // namespace 301 302 } // namespace testing 303 } // namespace gvisor