gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/mremap.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 <errno.h>
    16  #include <string.h>
    17  #include <sys/mman.h>
    18  #ifdef __linux__
    19  #include <sys/syscall.h>
    20  #endif
    21  #include <unistd.h>
    22  
    23  #include <string>
    24  
    25  #include "gmock/gmock.h"
    26  #include "absl/strings/string_view.h"
    27  #include "test/util/file_descriptor.h"
    28  #include "test/util/logging.h"
    29  #include "test/util/memory_util.h"
    30  #include "test/util/multiprocess_util.h"
    31  #include "test/util/posix_error.h"
    32  #include "test/util/temp_path.h"
    33  #include "test/util/test_util.h"
    34  
    35  using ::testing::_;
    36  
    37  namespace gvisor {
    38  namespace testing {
    39  
    40  namespace {
    41  
    42  // libc mremap isn't guaranteed to be async-signal-safe by signal-safety(7) and
    43  // therefore isn't necessarily safe to call between fork(2) and execve(2);
    44  // provide our own version that is.
    45  void* MremapSafe(void* old_addr, size_t old_size, size_t new_size,
    46                   unsigned long flags, void* new_address = nullptr) {  // NOLINT
    47    return reinterpret_cast<void*>(
    48        syscall(SYS_mremap, old_addr, old_size, new_size, flags, new_address));
    49  }
    50  
    51  // Fixture for mremap tests parameterized by mmap flags.
    52  using MremapParamTest = ::testing::TestWithParam<int>;
    53  
    54  TEST_P(MremapParamTest, Noop) {
    55    Mapping const m =
    56        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
    57  
    58    ASSERT_THAT(Mremap(m.ptr(), kPageSize, kPageSize, 0, nullptr),
    59                IsPosixErrorOkAndHolds(m.ptr()));
    60    EXPECT_TRUE(IsMapped(m.addr()));
    61  }
    62  
    63  TEST_P(MremapParamTest, InPlace_ShrinkingWholeVMA) {
    64    Mapping const m =
    65        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
    66  
    67    const auto rest = [&] {
    68      // N.B. we must be in a single-threaded subprocess to ensure a
    69      // background thread doesn't concurrently map the second page.
    70      void* addr = MremapSafe(m.ptr(), 2 * kPageSize, kPageSize, 0, nullptr);
    71      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
    72      TEST_CHECK(addr == m.ptr());
    73      MaybeSave();
    74  
    75      TEST_CHECK(IsMapped(m.addr()));
    76      TEST_CHECK(!IsMapped(m.addr() + kPageSize));
    77    };
    78  
    79    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
    80  }
    81  
    82  TEST_P(MremapParamTest, InPlace_ShrinkingPartialVMA) {
    83    Mapping const m =
    84        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam()));
    85  
    86    const auto rest = [&] {
    87      void* addr = MremapSafe(m.ptr(), 2 * kPageSize, kPageSize, 0, nullptr);
    88      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
    89      TEST_CHECK(addr == m.ptr());
    90      MaybeSave();
    91  
    92      TEST_CHECK(IsMapped(m.addr()));
    93      TEST_CHECK(!IsMapped(m.addr() + kPageSize));
    94      TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize));
    95    };
    96  
    97    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
    98  }
    99  
   100  TEST_P(MremapParamTest, InPlace_ShrinkingAcrossVMAs) {
   101    Mapping const m =
   102        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_READ, GetParam()));
   103    // Changing permissions on the first page forces it to become a separate vma.
   104    ASSERT_THAT(mprotect(m.ptr(), kPageSize, PROT_NONE), SyscallSucceeds());
   105  
   106    const auto rest = [&] {
   107      // Both old_size and new_size now span two vmas; mremap
   108      // shouldn't care.
   109      void* addr = MremapSafe(m.ptr(), 3 * kPageSize, 2 * kPageSize, 0, nullptr);
   110      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   111      TEST_CHECK(addr == m.ptr());
   112      MaybeSave();
   113  
   114      TEST_CHECK(IsMapped(m.addr()));
   115      TEST_CHECK(IsMapped(m.addr() + kPageSize));
   116      TEST_CHECK(!IsMapped(m.addr() + 2 * kPageSize));
   117    };
   118  
   119    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   120  }
   121  
   122  TEST_P(MremapParamTest, InPlace_ExpansionSuccess) {
   123    Mapping const m =
   124        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   125  
   126    const auto rest = [&] {
   127      // Unmap the second page so that the first can be expanded back into it.
   128      //
   129      // N.B. we must be in a single-threaded subprocess to ensure a
   130      // background thread doesn't concurrently map this page.
   131      TEST_PCHECK(MunmapSafe(reinterpret_cast<void*>(m.addr() + kPageSize),
   132                             kPageSize) == 0);
   133      MaybeSave();
   134  
   135      void* addr = MremapSafe(m.ptr(), kPageSize, 2 * kPageSize, 0, nullptr);
   136      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   137      TEST_CHECK(addr == m.ptr());
   138      MaybeSave();
   139  
   140      TEST_CHECK(IsMapped(m.addr()));
   141      TEST_CHECK(IsMapped(m.addr() + kPageSize));
   142    };
   143  
   144    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   145  }
   146  
   147  TEST_P(MremapParamTest, InPlace_ExpansionFailure) {
   148    Mapping const m =
   149        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam()));
   150  
   151    const auto rest = [&] {
   152      // Unmap the second page, leaving a one-page hole. Trying to expand the
   153      // first page to three pages should fail since the original third page
   154      // is still mapped.
   155      TEST_PCHECK(MunmapSafe(reinterpret_cast<void*>(m.addr() + kPageSize),
   156                             kPageSize) == 0);
   157      MaybeSave();
   158  
   159      void* addr = MremapSafe(m.ptr(), kPageSize, 3 * kPageSize, 0, nullptr);
   160      TEST_CHECK_MSG(addr == MAP_FAILED, "mremap unexpectedly succeeded");
   161      TEST_PCHECK_MSG(errno == ENOMEM, "mremap failed with wrong errno");
   162      MaybeSave();
   163  
   164      TEST_CHECK(IsMapped(m.addr()));
   165      TEST_CHECK(!IsMapped(m.addr() + kPageSize));
   166      TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize));
   167    };
   168  
   169    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   170  }
   171  
   172  TEST_P(MremapParamTest, MayMove_Expansion) {
   173    Mapping const m =
   174        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam()));
   175  
   176    const auto rest = [&] {
   177      // Unmap the second page, leaving a one-page hole. Trying to expand the
   178      // first page to three pages with MREMAP_MAYMOVE should force the
   179      // mapping to be relocated since the original third page is still
   180      // mapped.
   181      TEST_PCHECK(MunmapSafe(reinterpret_cast<void*>(m.addr() + kPageSize),
   182                             kPageSize) == 0);
   183      MaybeSave();
   184  
   185      void* addr2 =
   186          MremapSafe(m.ptr(), kPageSize, 3 * kPageSize, MREMAP_MAYMOVE, nullptr);
   187      TEST_PCHECK_MSG(addr2 != MAP_FAILED, "mremap failed");
   188      MaybeSave();
   189  
   190      const Mapping m2 = Mapping(addr2, 3 * kPageSize);
   191      TEST_CHECK(m.addr() != m2.addr());
   192  
   193      TEST_CHECK(!IsMapped(m.addr()));
   194      TEST_CHECK(!IsMapped(m.addr() + kPageSize));
   195      TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize));
   196      TEST_CHECK(IsMapped(m2.addr()));
   197      TEST_CHECK(IsMapped(m2.addr() + kPageSize));
   198      TEST_CHECK(IsMapped(m2.addr() + 2 * kPageSize));
   199    };
   200  
   201    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   202  }
   203  
   204  TEST_P(MremapParamTest, Fixed_SourceAndDestinationCannotOverlap) {
   205    Mapping const m =
   206        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   207  
   208    ASSERT_THAT(Mremap(m.ptr(), kPageSize, kPageSize,
   209                       MREMAP_MAYMOVE | MREMAP_FIXED, m.ptr()),
   210                PosixErrorIs(EINVAL, _));
   211    EXPECT_TRUE(IsMapped(m.addr()));
   212  }
   213  
   214  TEST_P(MremapParamTest, Fixed_SameSize) {
   215    Mapping const src =
   216        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   217    Mapping const dst =
   218        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   219  
   220    const auto rest = [&] {
   221      // Unmap dst to create a hole.
   222      TEST_PCHECK(MunmapSafe(dst.ptr(), kPageSize) == 0);
   223      MaybeSave();
   224  
   225      void* addr = MremapSafe(src.ptr(), kPageSize, kPageSize,
   226                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   227      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   228      TEST_CHECK(addr == dst.ptr());
   229      MaybeSave();
   230  
   231      TEST_CHECK(!IsMapped(src.addr()));
   232      TEST_CHECK(IsMapped(dst.addr()));
   233    };
   234  
   235    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   236  }
   237  
   238  TEST_P(MremapParamTest, Fixed_SameSize_Unmapping) {
   239    // Like the Fixed_SameSize case, but expect mremap to unmap the destination
   240    // automatically.
   241    Mapping const src =
   242        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   243    Mapping const dst =
   244        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   245  
   246    const auto rest = [&] {
   247      void* addr = MremapSafe(src.ptr(), kPageSize, kPageSize,
   248                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   249      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   250      TEST_CHECK(addr == dst.ptr());
   251      MaybeSave();
   252  
   253      TEST_CHECK(!IsMapped(src.addr()));
   254      TEST_CHECK(IsMapped(dst.addr()));
   255    };
   256  
   257    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   258  }
   259  
   260  TEST_P(MremapParamTest, Fixed_ShrinkingWholeVMA) {
   261    Mapping const src =
   262        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   263    Mapping const dst =
   264        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   265  
   266    const auto rest = [&] {
   267      // Unmap dst so we can check that mremap does not keep the
   268      // second page.
   269      TEST_PCHECK(MunmapSafe(dst.ptr(), 2 * kPageSize) == 0);
   270      MaybeSave();
   271  
   272      void* addr = MremapSafe(src.ptr(), 2 * kPageSize, kPageSize,
   273                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   274      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   275      TEST_CHECK(addr == dst.ptr());
   276      MaybeSave();
   277  
   278      TEST_CHECK(!IsMapped(src.addr()));
   279      TEST_CHECK(!IsMapped(src.addr() + kPageSize));
   280      TEST_CHECK(IsMapped(dst.addr()));
   281      TEST_CHECK(!IsMapped(dst.addr() + kPageSize));
   282    };
   283  
   284    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   285  }
   286  
   287  TEST_P(MremapParamTest, Fixed_ShrinkingPartialVMA) {
   288    Mapping const src =
   289        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam()));
   290    Mapping const dst =
   291        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   292  
   293    const auto rest = [&] {
   294      // Unmap dst so we can check that mremap does not keep the
   295      // second page.
   296      TEST_PCHECK(MunmapSafe(dst.ptr(), 2 * kPageSize) == 0);
   297      MaybeSave();
   298  
   299      void* addr = MremapSafe(src.ptr(), 2 * kPageSize, kPageSize,
   300                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   301      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   302      TEST_CHECK(addr == dst.ptr());
   303      MaybeSave();
   304  
   305      TEST_CHECK(!IsMapped(src.addr()));
   306      TEST_CHECK(!IsMapped(src.addr() + kPageSize));
   307      TEST_CHECK(IsMapped(src.addr() + 2 * kPageSize));
   308      TEST_CHECK(IsMapped(dst.addr()));
   309      TEST_CHECK(!IsMapped(dst.addr() + kPageSize));
   310    };
   311  
   312    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   313  }
   314  
   315  TEST_P(MremapParamTest, Fixed_ShrinkingAcrossVMAs) {
   316    Mapping const src =
   317        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_READ, GetParam()));
   318    // Changing permissions on the first page forces it to become a separate vma.
   319    ASSERT_THAT(mprotect(src.ptr(), kPageSize, PROT_NONE), SyscallSucceeds());
   320    Mapping const dst =
   321        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   322  
   323    const auto rest = [&] {
   324      // Unlike flags=0, MREMAP_FIXED requires that [old_address,
   325      // old_address+new_size) only spans a single vma.
   326      void* addr = MremapSafe(src.ptr(), 3 * kPageSize, 2 * kPageSize,
   327                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   328      TEST_CHECK_MSG(addr == MAP_FAILED, "mremap unexpectedly succeeded");
   329      TEST_PCHECK_MSG(errno == EFAULT, "mremap failed with wrong errno");
   330      MaybeSave();
   331  
   332      TEST_CHECK(IsMapped(src.addr()));
   333      TEST_CHECK(IsMapped(src.addr() + kPageSize));
   334      // Despite failing, mremap should have unmapped [old_address+new_size,
   335      // old_address+old_size) (i.e. the third page).
   336      TEST_CHECK(!IsMapped(src.addr() + 2 * kPageSize));
   337      // Despite failing, mremap should have unmapped the destination pages.
   338      TEST_CHECK(!IsMapped(dst.addr()));
   339      TEST_CHECK(!IsMapped(dst.addr() + kPageSize));
   340    };
   341  
   342    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   343  }
   344  
   345  TEST_P(MremapParamTest, Fixed_Expansion) {
   346    Mapping const src =
   347        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam()));
   348    Mapping const dst =
   349        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam()));
   350  
   351    const auto rest = [&] {
   352      // Unmap dst so we can check that mremap actually maps all pages
   353      // at the destination.
   354      TEST_PCHECK(MunmapSafe(dst.ptr(), 2 * kPageSize) == 0);
   355      MaybeSave();
   356  
   357      void* addr = MremapSafe(src.ptr(), kPageSize, 2 * kPageSize,
   358                              MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   359      TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed");
   360      TEST_CHECK(addr == dst.ptr());
   361      MaybeSave();
   362  
   363      TEST_CHECK(!IsMapped(src.addr()));
   364      TEST_CHECK(IsMapped(dst.addr()));
   365      TEST_CHECK(IsMapped(dst.addr() + kPageSize));
   366    };
   367  
   368    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   369  }
   370  
   371  INSTANTIATE_TEST_SUITE_P(PrivateShared, MremapParamTest,
   372                           ::testing::Values(MAP_PRIVATE, MAP_SHARED));
   373  
   374  // mremap with old_size == 0 only works with MAP_SHARED after Linux 4.14
   375  // (dba58d3b8c50 "mm/mremap: fail map duplication attempts for private
   376  // mappings").
   377  
   378  TEST(MremapTest, InPlace_Copy) {
   379    Mapping const m =
   380        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED));
   381    EXPECT_THAT(Mremap(m.ptr(), 0, kPageSize, 0, nullptr),
   382                PosixErrorIs(ENOMEM, _));
   383  }
   384  
   385  TEST(MremapTest, MayMove_Copy) {
   386    Mapping const m =
   387        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED));
   388  
   389    // Remainder of this test executes in a subprocess to ensure that if mremap
   390    // incorrectly removes m, it is not remapped by another thread.
   391    const auto rest = [&] {
   392      void* ptr = MremapSafe(m.ptr(), 0, kPageSize, MREMAP_MAYMOVE, nullptr);
   393      MaybeSave();
   394      TEST_PCHECK_MSG(ptr != MAP_FAILED, "mremap failed");
   395      TEST_CHECK(ptr != m.ptr());
   396      TEST_CHECK(IsMapped(m.addr()));
   397      TEST_CHECK(IsMapped(reinterpret_cast<uintptr_t>(ptr)));
   398    };
   399    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   400  }
   401  
   402  TEST(MremapTest, MustMove_Copy) {
   403    Mapping const src =
   404        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED));
   405    Mapping const dst =
   406        ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_PRIVATE));
   407  
   408    // Remainder of this test executes in a subprocess to ensure that if mremap
   409    // incorrectly removes src, it is not remapped by another thread.
   410    const auto rest = [&] {
   411      void* ptr = MremapSafe(src.ptr(), 0, kPageSize,
   412                             MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr());
   413      MaybeSave();
   414      TEST_PCHECK_MSG(ptr != MAP_FAILED, "mremap failed");
   415      TEST_CHECK(ptr == dst.ptr());
   416      TEST_CHECK(IsMapped(src.addr()));
   417      TEST_CHECK(IsMapped(dst.addr()));
   418    };
   419    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   420  }
   421  
   422  void ExpectAllBytesAre(absl::string_view v, char c) {
   423    for (size_t i = 0; i < v.size(); i++) {
   424      ASSERT_EQ(v[i], c) << "at offset " << i;
   425    }
   426  }
   427  
   428  TEST(MremapTest, ExpansionPreservesCOWPagesAndExposesNewFilePages) {
   429    // Create a file with 3 pages. The first is filled with 'a', the second is
   430    // filled with 'b', and the third is filled with 'c'.
   431    TempPath const file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   432    const FileDescriptor fd =
   433        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
   434    ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'a').c_str(), kPageSize),
   435                SyscallSucceedsWithValue(kPageSize));
   436    ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'b').c_str(), kPageSize),
   437                SyscallSucceedsWithValue(kPageSize));
   438    ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'c').c_str(), kPageSize),
   439                SyscallSucceedsWithValue(kPageSize));
   440  
   441    // Create a private mapping of the first 2 pages, and fill the second page
   442    // with 'd'.
   443    Mapping const src = ASSERT_NO_ERRNO_AND_VALUE(Mmap(nullptr, 2 * kPageSize,
   444                                                       PROT_READ | PROT_WRITE,
   445                                                       MAP_PRIVATE, fd.get(), 0));
   446    memset(reinterpret_cast<void*>(src.addr() + kPageSize), 'd', kPageSize);
   447    MaybeSave();
   448  
   449    // Move the mapping while expanding it to 3 pages. The resulting mapping
   450    // should contain the original first page of the file (filled with 'a'),
   451    // followed by the private copy of the second page (filled with 'd'), followed
   452    // by the newly-mapped third page of the file (filled with 'c').
   453    Mapping const dst = ASSERT_NO_ERRNO_AND_VALUE(
   454        MmapAnon(3 * kPageSize, PROT_NONE, MAP_PRIVATE));
   455    ASSERT_THAT(Mremap(src.ptr(), 2 * kPageSize, 3 * kPageSize,
   456                       MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()),
   457                IsPosixErrorOkAndHolds(dst.ptr()));
   458    auto const v = dst.view();
   459    ExpectAllBytesAre(v.substr(0, kPageSize), 'a');
   460    ExpectAllBytesAre(v.substr(kPageSize, kPageSize), 'd');
   461    ExpectAllBytesAre(v.substr(2 * kPageSize, kPageSize), 'c');
   462  }
   463  
   464  TEST(MremapDeathTest, SharedAnon) {
   465    SetupGvisorDeathTest();
   466  
   467    // Reserve 4 pages of address space.
   468    Mapping const reserved = ASSERT_NO_ERRNO_AND_VALUE(
   469        MmapAnon(4 * kPageSize, PROT_NONE, MAP_PRIVATE));
   470  
   471    // Create a 2-page shared anonymous mapping at the beginning of the
   472    // reservation. Fill the first page with 'a' and the second with 'b'.
   473    Mapping const m = ASSERT_NO_ERRNO_AND_VALUE(
   474        Mmap(reserved.ptr(), 2 * kPageSize, PROT_READ | PROT_WRITE,
   475             MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0));
   476    memset(m.ptr(), 'a', kPageSize);
   477    memset(reinterpret_cast<void*>(m.addr() + kPageSize), 'b', kPageSize);
   478    MaybeSave();
   479  
   480    // Shrink the mapping to 1 page in-place.
   481    ASSERT_THAT(Mremap(m.ptr(), 2 * kPageSize, kPageSize, 0, m.ptr()),
   482                IsPosixErrorOkAndHolds(m.ptr()));
   483  
   484    // Expand the mapping to 3 pages, moving it forward by 1 page in the process
   485    // since the old and new mappings can't overlap.
   486    void* const new_m = reinterpret_cast<void*>(m.addr() + kPageSize);
   487    ASSERT_THAT(Mremap(m.ptr(), kPageSize, 3 * kPageSize,
   488                       MREMAP_MAYMOVE | MREMAP_FIXED, new_m),
   489                IsPosixErrorOkAndHolds(new_m));
   490  
   491    // The first 2 pages of the mapping should still contain the data we wrote
   492    // (i.e. shrinking should not have discarded the second page's data), while
   493    // touching the third page should raise SIGBUS.
   494    auto const v =
   495        absl::string_view(static_cast<char const*>(new_m), 3 * kPageSize);
   496    ExpectAllBytesAre(v.substr(0, kPageSize), 'a');
   497    ExpectAllBytesAre(v.substr(kPageSize, kPageSize), 'b');
   498    EXPECT_EXIT(ExpectAllBytesAre(v.substr(2 * kPageSize, kPageSize), '\0'),
   499                ::testing::KilledBySignal(SIGBUS), "");
   500  }
   501  
   502  }  // namespace
   503  
   504  }  // namespace testing
   505  }  // namespace gvisor