gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/memfd.cc (about) 1 // Copyright 2019 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 <errno.h> 16 #include <fcntl.h> 17 #include <linux/memfd.h> 18 #include <linux/unistd.h> 19 #include <string.h> 20 #include <sys/mman.h> 21 #include <sys/syscall.h> 22 23 #include <vector> 24 25 #include "gtest/gtest.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/fs_util.h" 28 #include "test/util/memory_util.h" 29 #include "test/util/multiprocess_util.h" 30 #include "test/util/temp_path.h" 31 #include "test/util/test_util.h" 32 33 namespace gvisor { 34 namespace testing { 35 namespace { 36 37 // The header sys/memfd.h isn't available on all systems, so redefining some of 38 // the constants here. 39 #define F_LINUX_SPECIFIC_BASE 1024 40 41 #ifndef F_ADD_SEALS 42 #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) 43 #endif /* F_ADD_SEALS */ 44 45 #ifndef F_GET_SEALS 46 #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) 47 #endif /* F_GET_SEALS */ 48 49 #define F_SEAL_SEAL 0x0001 50 #define F_SEAL_SHRINK 0x0002 51 #define F_SEAL_GROW 0x0004 52 #define F_SEAL_WRITE 0x0008 53 54 using ::gvisor::testing::IsTmpfs; 55 using ::testing::StartsWith; 56 57 const std::string kMemfdName = "some-memfd"; 58 59 int memfd_create(const std::string& name, unsigned int flags) { 60 return syscall(__NR_memfd_create, name.c_str(), flags); 61 } 62 63 PosixErrorOr<FileDescriptor> MemfdCreate(const std::string& name, 64 uint32_t flags) { 65 int fd = memfd_create(name, flags); 66 if (fd < 0) { 67 return PosixError( 68 errno, absl::StrFormat("memfd_create(\"%s\", %#x)", name, flags)); 69 } 70 MaybeSave(); 71 return FileDescriptor(fd); 72 } 73 74 // Procfs entries for memfds display the appropriate name. 75 TEST(MemfdTest, Name) { 76 const FileDescriptor memfd = 77 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 78 const std::string proc_name = ASSERT_NO_ERRNO_AND_VALUE( 79 ReadLink(absl::StrFormat("/proc/self/fd/%d", memfd.get()))); 80 EXPECT_THAT(proc_name, StartsWith("/memfd:" + kMemfdName)); 81 } 82 83 // Memfds support read/write syscalls. 84 TEST(MemfdTest, WriteRead) { 85 const FileDescriptor memfd = 86 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 87 88 // Write a random page of data to the memfd via write(2). 89 std::vector<char> buf(kPageSize); 90 RandomizeBuffer(buf.data(), buf.size()); 91 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 92 SyscallSucceedsWithValue(kPageSize)); 93 94 // Read back the same data and verify. 95 std::vector<char> buf2(kPageSize); 96 ASSERT_THAT(lseek(memfd.get(), 0, SEEK_SET), SyscallSucceeds()); 97 EXPECT_THAT(read(memfd.get(), buf2.data(), buf2.size()), 98 SyscallSucceedsWithValue(kPageSize)); 99 EXPECT_EQ(buf, buf2); 100 } 101 102 // Memfds can be mapped and used as usual. 103 TEST(MemfdTest, Mmap) { 104 const FileDescriptor memfd = 105 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 106 const Mapping m1 = ASSERT_NO_ERRNO_AND_VALUE(Mmap( 107 nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 108 109 // Write a random page of data to the memfd via mmap m1. 110 std::vector<char> buf(kPageSize); 111 RandomizeBuffer(buf.data(), buf.size()); 112 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 113 memcpy(m1.ptr(), buf.data(), buf.size()); 114 115 // Read the data back via a read syscall on the memfd. 116 std::vector<char> buf2(kPageSize); 117 EXPECT_THAT(read(memfd.get(), buf2.data(), buf2.size()), 118 SyscallSucceedsWithValue(kPageSize)); 119 EXPECT_EQ(buf, buf2); 120 121 // The same data should be accessible via a new mapping m2. 122 const Mapping m2 = ASSERT_NO_ERRNO_AND_VALUE(Mmap( 123 nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 124 EXPECT_EQ(0, memcmp(m1.ptr(), m2.ptr(), kPageSize)); 125 } 126 127 TEST(MemfdTest, DuplicateFDsShareContent) { 128 const FileDescriptor memfd = 129 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 130 const Mapping m1 = ASSERT_NO_ERRNO_AND_VALUE(Mmap( 131 nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 132 const FileDescriptor memfd2 = ASSERT_NO_ERRNO_AND_VALUE(memfd.Dup()); 133 134 // Write a random page of data to the memfd via mmap m1. 135 std::vector<char> buf(kPageSize); 136 RandomizeBuffer(buf.data(), buf.size()); 137 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 138 memcpy(m1.ptr(), buf.data(), buf.size()); 139 140 // Read the data back via a read syscall on a duplicate fd. 141 std::vector<char> buf2(kPageSize); 142 EXPECT_THAT(read(memfd2.get(), buf2.data(), buf2.size()), 143 SyscallSucceedsWithValue(kPageSize)); 144 EXPECT_EQ(buf, buf2); 145 } 146 147 // File seals are disabled by default on memfds. 148 TEST(MemfdTest, SealingDisabledByDefault) { 149 const FileDescriptor memfd = 150 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 151 EXPECT_THAT(fcntl(memfd.get(), F_GET_SEALS), 152 SyscallSucceedsWithValue(F_SEAL_SEAL)); 153 // Attempting to set any seal should fail. 154 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), 155 SyscallFailsWithErrno(EPERM)); 156 } 157 158 // Seals can be retrieved and updated for memfds. 159 TEST(MemfdTest, SealsGetSet) { 160 const FileDescriptor memfd = 161 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 162 int seals; 163 ASSERT_THAT(seals = fcntl(memfd.get(), F_GET_SEALS), SyscallSucceeds()); 164 // No seals are set yet. 165 EXPECT_EQ(0, seals); 166 167 // Set a seal and check that we can get it back. 168 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 169 EXPECT_THAT(fcntl(memfd.get(), F_GET_SEALS), 170 SyscallSucceedsWithValue(F_SEAL_WRITE)); 171 172 // Set some more seals and verify. 173 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK), 174 SyscallSucceeds()); 175 EXPECT_THAT( 176 fcntl(memfd.get(), F_GET_SEALS), 177 SyscallSucceedsWithValue(F_SEAL_WRITE | F_SEAL_GROW | F_SEAL_SHRINK)); 178 179 // Attempting to set a seal that is already set is a no-op. 180 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 181 EXPECT_THAT( 182 fcntl(memfd.get(), F_GET_SEALS), 183 SyscallSucceedsWithValue(F_SEAL_WRITE | F_SEAL_GROW | F_SEAL_SHRINK)); 184 185 // Add remaining seals and verify. 186 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SEAL), SyscallSucceeds()); 187 EXPECT_THAT(fcntl(memfd.get(), F_GET_SEALS), 188 SyscallSucceedsWithValue(F_SEAL_WRITE | F_SEAL_GROW | 189 F_SEAL_SHRINK | F_SEAL_SEAL)); 190 } 191 192 // F_SEAL_GROW prevents a memfd from being grown using ftruncate. 193 TEST(MemfdTest, SealGrowWithTruncate) { 194 const FileDescriptor memfd = 195 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 196 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 197 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_GROW), SyscallSucceeds()); 198 199 // Try grow the memfd by 1 page. 200 ASSERT_THAT(ftruncate(memfd.get(), kPageSize * 2), 201 SyscallFailsWithErrno(EPERM)); 202 203 // Ftruncate calls that don't actually grow the memfd are allowed. 204 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 205 ASSERT_THAT(ftruncate(memfd.get(), kPageSize / 2), SyscallSucceeds()); 206 207 // After shrinking, growing back is not allowed. 208 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallFailsWithErrno(EPERM)); 209 } 210 211 // F_SEAL_GROW prevents a memfd from being grown using the write syscall. 212 TEST(MemfdTest, SealGrowWithWrite) { 213 const FileDescriptor memfd = 214 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 215 216 // Initially, writing to the memfd succeeds. 217 const std::vector<char> buf(kPageSize); 218 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 219 SyscallSucceedsWithValue(kPageSize)); 220 221 // Apply F_SEAL_GROW, subsequent writes which extend the memfd should fail. 222 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_GROW), SyscallSucceeds()); 223 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 224 SyscallFailsWithErrno(EPERM)); 225 226 // However, zero-length writes are ok since they don't grow the memfd. 227 EXPECT_THAT(write(memfd.get(), buf.data(), 0), SyscallSucceeds()); 228 229 // Writing to existing parts of the memfd is also ok. 230 ASSERT_THAT(lseek(memfd.get(), 0, SEEK_SET), SyscallSucceeds()); 231 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 232 SyscallSucceedsWithValue(kPageSize)); 233 234 // Returning the end of the file and writing still not allowed. 235 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 236 SyscallFailsWithErrno(EPERM)); 237 } 238 239 // F_SEAL_GROW causes writes which partially extend off the current EOF to 240 // partially succeed, up to the page containing the EOF. 241 TEST(MemfdTest, SealGrowPartialWriteTruncated) { 242 const FileDescriptor memfd = 243 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 244 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 245 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_GROW), SyscallSucceeds()); 246 247 // FD offset: 1 page, EOF: 1 page. 248 249 ASSERT_THAT(lseek(memfd.get(), kPageSize * 3 / 4, SEEK_SET), 250 SyscallSucceeds()); 251 252 // FD offset: 3/4 page. Writing a full page now should only write 1/4 page 253 // worth of data. This partially succeeds because the first page is entirely 254 // within the file and requires no growth, but attempting to write the final 255 // 3/4 page would require growing the file. 256 const std::vector<char> buf(kPageSize); 257 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 258 SyscallSucceedsWithValue(kPageSize / 4)); 259 } 260 261 // F_SEAL_GROW causes writes which partially extend off the current EOF to fail 262 // in its entirety if the only data written would be to the page containing the 263 // EOF. 264 TEST(MemfdTest, SealGrowPartialWriteTruncatedSamePage) { 265 const FileDescriptor memfd = 266 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 267 ASSERT_THAT(ftruncate(memfd.get(), kPageSize * 3 / 4), SyscallSucceeds()); 268 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_GROW), SyscallSucceeds()); 269 270 // EOF: 3/4 page, writing 1/2 page starting at 1/2 page would cause the file 271 // to grow. Since this would require only the page containing the EOF to be 272 // modified, the write is rejected entirely. 273 const std::vector<char> buf(kPageSize / 2); 274 EXPECT_THAT(pwrite(memfd.get(), buf.data(), buf.size(), kPageSize / 2), 275 SyscallFailsWithErrno(EPERM)); 276 277 // However, writing up to EOF is fine. 278 EXPECT_THAT(pwrite(memfd.get(), buf.data(), buf.size() / 2, kPageSize / 2), 279 SyscallSucceedsWithValue(kPageSize / 4)); 280 } 281 282 // F_SEAL_SHRINK prevents a memfd from being shrunk using ftruncate. 283 TEST(MemfdTest, SealShrink) { 284 const FileDescriptor memfd = 285 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 286 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 287 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SHRINK), 288 SyscallSucceeds()); 289 290 // Shrink by half a page. 291 ASSERT_THAT(ftruncate(memfd.get(), kPageSize / 2), 292 SyscallFailsWithErrno(EPERM)); 293 294 // Ftruncate calls that don't actually shrink the file are allowed. 295 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallSucceeds()); 296 ASSERT_THAT(ftruncate(memfd.get(), kPageSize * 2), SyscallSucceeds()); 297 298 // After growing, shrinking is still not allowed. 299 ASSERT_THAT(ftruncate(memfd.get(), kPageSize), SyscallFailsWithErrno(EPERM)); 300 } 301 302 // F_SEAL_WRITE prevents a memfd from being written to through a write 303 // syscall. 304 TEST(MemfdTest, SealWriteWithWrite) { 305 const FileDescriptor memfd = 306 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 307 const std::vector<char> buf(kPageSize); 308 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 309 SyscallSucceedsWithValue(kPageSize)); 310 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 311 312 // Attemping to write at the end of the file fails. 313 EXPECT_THAT(write(memfd.get(), buf.data(), 1), SyscallFailsWithErrno(EPERM)); 314 315 // Attemping to overwrite an existing part of the memfd fails. 316 EXPECT_THAT(pwrite(memfd.get(), buf.data(), 1, 0), 317 SyscallFailsWithErrno(EPERM)); 318 EXPECT_THAT(pwrite(memfd.get(), buf.data(), buf.size() / 2, kPageSize / 2), 319 SyscallFailsWithErrno(EPERM)); 320 EXPECT_THAT(pwrite(memfd.get(), buf.data(), buf.size(), kPageSize / 2), 321 SyscallFailsWithErrno(EPERM)); 322 323 // Zero-length writes however do not fail. 324 EXPECT_THAT(write(memfd.get(), buf.data(), 0), SyscallSucceeds()); 325 } 326 327 // F_SEAL_WRITE prevents a memfd from being written to through an mmap. 328 TEST(MemfdTest, SealWriteWithMmap) { 329 const FileDescriptor memfd = 330 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 331 const std::vector<char> buf(kPageSize); 332 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 333 SyscallSucceedsWithValue(kPageSize)); 334 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 335 336 // Can't create a shared mapping with writes sealed. 337 void* ret = mmap(nullptr, kPageSize, PROT_WRITE, MAP_SHARED, memfd.get(), 0); 338 EXPECT_EQ(ret, MAP_FAILED); 339 EXPECT_EQ(errno, EPERM); 340 ret = mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, memfd.get(), 0); 341 EXPECT_EQ(ret, MAP_FAILED); 342 EXPECT_EQ(errno, EPERM); 343 344 // However, private mappings are ok. 345 EXPECT_NO_ERRNO(Mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, 346 memfd.get(), 0)); 347 } 348 349 // Adding F_SEAL_WRITE fails when there are outstanding writable mappings to a 350 // memfd. 351 TEST(MemfdTest, SealWriteWithOutstandingWritbleMapping) { 352 const FileDescriptor memfd = 353 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 354 const std::vector<char> buf(kPageSize); 355 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 356 SyscallSucceedsWithValue(kPageSize)); 357 358 // Attempting to add F_SEAL_WRITE with active shared mapping with any set of 359 // permissions fails. 360 361 // Read-only shared mapping. 362 { 363 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE( 364 Mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, memfd.get(), 0)); 365 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), 366 SyscallFailsWithErrno(EBUSY)); 367 } 368 369 // Write-only shared mapping. 370 { 371 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE( 372 Mmap(nullptr, kPageSize, PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 373 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), 374 SyscallFailsWithErrno(EBUSY)); 375 } 376 377 // Read-write shared mapping. 378 { 379 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE( 380 Mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, 381 memfd.get(), 0)); 382 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), 383 SyscallFailsWithErrno(EBUSY)); 384 } 385 386 // F_SEAL_WRITE can be set with private mappings with any permissions. 387 { 388 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE( 389 Mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, 390 memfd.get(), 0)); 391 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), 392 SyscallSucceeds()); 393 } 394 } 395 396 // When applying F_SEAL_WRITE fails due to outstanding writable mappings, any 397 // additional seals passed to the same add seal call are also rejected. 398 TEST(MemfdTest, NoPartialSealApplicationWhenWriteSealRejected) { 399 const FileDescriptor memfd = 400 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 401 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE(Mmap( 402 nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 403 404 // Try add some seals along with F_SEAL_WRITE. The seal application should 405 // fail since there exists an active shared mapping. 406 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW), 407 SyscallFailsWithErrno(EBUSY)); 408 409 // None of the seals should be applied. 410 EXPECT_THAT(fcntl(memfd.get(), F_GET_SEALS), SyscallSucceedsWithValue(0)); 411 } 412 413 // Seals are inode level properties, and apply to all file descriptors referring 414 // to a memfd. 415 TEST(MemfdTest, SealsAreInodeLevelProperties) { 416 const FileDescriptor memfd = 417 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 418 const FileDescriptor memfd2 = ASSERT_NO_ERRNO_AND_VALUE(memfd.Dup()); 419 420 // Add seal through the original memfd, and verify that it appears on the 421 // dupped fd. 422 ASSERT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 423 EXPECT_THAT(fcntl(memfd2.get(), F_GET_SEALS), 424 SyscallSucceedsWithValue(F_SEAL_WRITE)); 425 426 // Verify the seal actually applies to both fds. 427 std::vector<char> buf(kPageSize); 428 EXPECT_THAT(write(memfd.get(), buf.data(), buf.size()), 429 SyscallFailsWithErrno(EPERM)); 430 EXPECT_THAT(write(memfd2.get(), buf.data(), buf.size()), 431 SyscallFailsWithErrno(EPERM)); 432 433 // Seals are enforced on new FDs that are dupped after the seal is already 434 // applied. 435 const FileDescriptor memfd3 = ASSERT_NO_ERRNO_AND_VALUE(memfd2.Dup()); 436 EXPECT_THAT(write(memfd3.get(), buf.data(), buf.size()), 437 SyscallFailsWithErrno(EPERM)); 438 439 // Try a new seal applied to one of the dupped fds. 440 ASSERT_THAT(fcntl(memfd3.get(), F_ADD_SEALS, F_SEAL_GROW), SyscallSucceeds()); 441 EXPECT_THAT(ftruncate(memfd.get(), kPageSize), SyscallFailsWithErrno(EPERM)); 442 EXPECT_THAT(ftruncate(memfd2.get(), kPageSize), SyscallFailsWithErrno(EPERM)); 443 EXPECT_THAT(ftruncate(memfd3.get(), kPageSize), SyscallFailsWithErrno(EPERM)); 444 } 445 446 // Tmpfs files also support seals, but are created with F_SEAL_SEAL. 447 TEST(MemfdTest, TmpfsFilesHaveSealSeal) { 448 std::string tmpdir = GetAbsoluteTestTmpdir(); 449 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(tmpdir.c_str()))); 450 const TempPath tmpfs_file = 451 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(tmpdir.c_str())); 452 const FileDescriptor fd = 453 ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfs_file.path(), O_RDWR, 0644)); 454 EXPECT_THAT(fcntl(fd.get(), F_GET_SEALS), 455 SyscallSucceedsWithValue(F_SEAL_SEAL)); 456 } 457 458 // Can open a memfd from procfs and use as normal. 459 TEST(MemfdTest, CanOpenFromProcfs) { 460 const FileDescriptor memfd = 461 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 462 463 // Write a random page of data to the memfd via write(2). 464 std::vector<char> buf(kPageSize); 465 RandomizeBuffer(buf.data(), buf.size()); 466 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 467 SyscallSucceedsWithValue(kPageSize)); 468 469 // Read back the same data from the fd obtained from procfs and verify. 470 const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE( 471 Open(absl::StrFormat("/proc/self/fd/%d", memfd.get()), O_RDWR)); 472 std::vector<char> buf2(kPageSize); 473 EXPECT_THAT(pread(fd.get(), buf2.data(), buf2.size(), 0), 474 SyscallSucceedsWithValue(kPageSize)); 475 EXPECT_EQ(buf, buf2); 476 } 477 478 // Test that memfd permissions are set up correctly to allow another process to 479 // open it from procfs. 480 TEST(MemfdTest, OtherProcessCanOpenFromProcfs) { 481 const FileDescriptor memfd = 482 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 483 const auto memfd_path = 484 absl::StrFormat("/proc/%d/fd/%d", getpid(), memfd.get()); 485 const auto rest = [&] { 486 int fd = open(memfd_path.c_str(), O_RDWR); 487 TEST_PCHECK(fd >= 0); 488 TEST_PCHECK(close(fd) >= 0); 489 }; 490 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 491 } 492 493 // Test that only files opened as writable can have seals applied to them. 494 // Normally there's no way to specify file permissions on memfds, but we can 495 // obtain a read-only memfd by opening the corresponding procfs fd entry as 496 // read-only. 497 TEST(MemfdTest, MemfdMustBeWritableToModifySeals) { 498 const FileDescriptor memfd = 499 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, MFD_ALLOW_SEALING)); 500 501 // Initially adding a seal works. 502 EXPECT_THAT(fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_WRITE), SyscallSucceeds()); 503 504 // Re-open the memfd as read-only from procfs. 505 const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE( 506 Open(absl::StrFormat("/proc/self/fd/%d", memfd.get()), O_RDONLY)); 507 508 // Can't add seals through an unwritable fd. 509 EXPECT_THAT(fcntl(fd.get(), F_ADD_SEALS, F_SEAL_GROW), 510 SyscallFailsWithErrno(EPERM)); 511 } 512 513 // Test that the memfd implementation internally tracks potentially writable 514 // maps correctly. 515 TEST(MemfdTest, MultipleWritableAndNonWritableRefsToSameFileRegion) { 516 const FileDescriptor memfd = 517 ASSERT_NO_ERRNO_AND_VALUE(MemfdCreate(kMemfdName, 0)); 518 519 // Populate with a random page of data. 520 std::vector<char> buf(kPageSize); 521 RandomizeBuffer(buf.data(), buf.size()); 522 ASSERT_THAT(write(memfd.get(), buf.data(), buf.size()), 523 SyscallSucceedsWithValue(kPageSize)); 524 525 // Read-only map to the page. This should cause an initial mapping to be 526 // created. 527 Mapping m1 = ASSERT_NO_ERRNO_AND_VALUE( 528 Mmap(nullptr, kPageSize, PROT_READ, MAP_PRIVATE, memfd.get(), 0)); 529 530 // Create a shared writable map to the page. This should cause the internal 531 // mapping to become potentially writable. 532 Mapping m2 = ASSERT_NO_ERRNO_AND_VALUE(Mmap( 533 nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, memfd.get(), 0)); 534 535 // Drop the read-only mapping first. If writable-ness isn't tracked correctly, 536 // this can cause some misaccounting, which can trigger asserts internally. 537 m1.reset(); 538 m2.reset(); 539 } 540 541 } // namespace 542 } // namespace testing 543 } // namespace gvisor