LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - mmap_unittest.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 141 141 100.0 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <stdio.h>
       8                 : #include <stdlib.h>
       9                 : 
      10                 : #if NACL_LINUX
      11                 : # include <sys/mman.h>
      12                 : #elif NACL_OSX
      13                 : # include <mach/mach.h>
      14                 : #endif
      15                 : 
      16                 : #include "gtest/gtest.h"
      17                 : 
      18                 : #include "native_client/src/include/portability_io.h"
      19                 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
      20                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      21                 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
      22                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      23                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      24                 : #include "native_client/src/trusted/service_runtime/mmap_test_check.h"
      25                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      26                 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
      27                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      28                 : #include "native_client/src/trusted/service_runtime/sys_memory.h"
      29                 : 
      30              16 : class MmapTest : public testing::Test {
      31                 :  protected:
      32                 :   virtual void SetUp();
      33                 :   virtual void TearDown();
      34                 : };
      35                 : 
      36                 : void MmapTest::SetUp() {
      37               8 :   NaClNrdAllModulesInit();
      38               8 : }
      39                 : 
      40                 : void MmapTest::TearDown() {
      41               8 :   NaClNrdAllModulesFini();
      42               8 : }
      43                 : 
      44                 : // These tests are disabled for ARM/MIPS because the ARM/MIPS sandboxes are
      45                 : // zero-based, and sel_addrspace_(arm/mips).c do not work when allocating a
      46                 : // non-zero-based region.
      47                 : // TODO(mseaborn): Change sel_addrspace_arm.c to work with this test.
      48                 : // However, for now, testing the Linux memory mapping code under
      49                 : // x86-32 and x86-64 gives us good coverage of the Linux code in
      50                 : // general.
      51                 : #if NACL_ARCH(NACL_BUILD_ARCH) != NACL_arm && \
      52                 :     NACL_ARCH(NACL_BUILD_ARCH) != NACL_mips
      53                 : 
      54                 : // Check that the untrusted address space really gets freed by trying
      55                 : // to allocate and free a sandbox multiple times.  On a 32-bit system,
      56                 : // this would fail if NaClAddrSpaceFree() were a no-op because it
      57                 : // would run out of host address space.
      58               8 : TEST_F(MmapTest, TestFreeingAddressSpace) {
      59                 :   // We use a small number of iterations because address space
      60                 :   // allocation can be very slow on Windows (on the order of 1 second
      61                 :   // on the 32-bit Windows bots).
      62              10 :   for (int count = 0; count < 4; count++) {
      63               4 :     struct NaClApp app;
      64              20 :     ASSERT_EQ(NaClAppCtor(&app), 1);
      65              21 :     ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
      66               4 :     NaClAddrSpaceFree(&app);
      67               4 :   }
      68               1 : }
      69                 : 
      70               9 : void MapShmFd(struct NaClApp *nap, uintptr_t addr, size_t shm_size) {
      71               9 :   struct NaClDescImcShm *shm_desc =
      72               9 :       (struct NaClDescImcShm *) malloc(sizeof(*shm_desc));
      73              45 :   ASSERT_TRUE(shm_desc);
      74              45 :   ASSERT_EQ(NaClDescImcShmAllocCtor(shm_desc, shm_size,
      75                 :                                     /* executable= */ 0), 1);
      76               9 :   struct NaClDesc *desc = &shm_desc->base;
      77               9 :   int fd = NaClAppSetDescAvail(nap, desc);
      78                 : 
      79               9 :   uintptr_t mapping_addr = (uint32_t) NaClSysMmapIntern(
      80                 :       nap, (void *) addr, shm_size,
      81                 :       NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
      82                 :       NACL_ABI_MAP_FIXED | NACL_ABI_MAP_SHARED, fd, 0);
      83              45 :   ASSERT_EQ(mapping_addr, addr);
      84               9 : }
      85                 : 
      86               2 : void MapFileFd(struct NaClApp *nap, uintptr_t addr, size_t file_size) {
      87               2 :   int host_fd;
      88                 : #if NACL_WINDOWS
      89                 :   // Open temporary file that is deleted automatically.
      90                 :   const char *temp_prefix = "nacl_mmap_test_temp_";
      91                 :   char *temp_filename = _tempnam("C:\\Windows\\Temp", temp_prefix);
      92                 :   ASSERT_EQ(_sopen_s(&host_fd, temp_filename,
      93                 :                      _O_RDWR | _O_CREAT | _O_TEMPORARY,
      94                 :                      _SH_DENYNO, _S_IREAD | _S_IWRITE), 0);
      95                 : #else
      96               2 :   char temp_filename[] = "/tmp/nacl_mmap_test_temp_XXXXXX";
      97               2 :   host_fd = mkstemp(temp_filename);
      98              10 :   ASSERT_GE(host_fd, 0);
      99                 : #endif
     100              10 :   ASSERT_EQ(remove(temp_filename), 0);
     101                 : 
     102               2 :   struct NaClHostDesc *host_desc =
     103               2 :       (struct NaClHostDesc *) malloc(sizeof(*host_desc));
     104              10 :   ASSERT_TRUE(host_desc);
     105              10 :   ASSERT_EQ(NaClHostDescPosixTake(host_desc, host_fd, NACL_ABI_O_RDWR), 0);
     106               2 :   struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(host_desc);
     107                 : 
     108                 :   // Fill the file.  On Windows, this is necessary to ensure that NaCl
     109                 :   // gives us mappings from the file instead of PROT_NONE-fill.
     110               2 :   char *buf = new char[file_size];
     111               2 :   memset(buf, 0, file_size);
     112               2 :   ssize_t written = NACL_VTBL(NaClDesc, desc)->Write(desc, buf, file_size);
     113              10 :   ASSERT_EQ(written, (ssize_t) file_size);
     114               4 :   delete[] buf;
     115                 : 
     116               2 :   int fd = NaClAppSetDescAvail(nap, desc);
     117                 : 
     118               2 :   uintptr_t mapping_addr = (uint32_t) NaClSysMmapIntern(
     119                 :       nap, (void *) addr, file_size,
     120                 :       NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     121                 :       NACL_ABI_MAP_FIXED | NACL_ABI_MAP_SHARED, fd, 0);
     122              10 :   ASSERT_EQ(mapping_addr, addr);
     123               2 : }
     124                 : 
     125               3 : void UnmapMemory(struct NaClApp *nap, uintptr_t addr, size_t size) {
     126                 :   // Create dummy NaClAppThread.
     127                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     128               3 :   struct NaClAppThread thread;
     129               3 :   memset(&thread, 0xff, sizeof(thread));
     130               3 :   thread.nap = nap;
     131                 : 
     132              18 :   ASSERT_EQ(NaClSysMunmap(&thread, (void *) addr, size), 0);
     133                 : 
     134               3 :   uintptr_t sysaddr = NaClUserToSys(nap, addr);
     135                 : #if NACL_WINDOWS
     136                 :   CheckMapping(sysaddr, size, MEM_RESERVE, 0, MEM_PRIVATE);
     137                 : #elif NACL_LINUX
     138                 :   CheckMapping(sysaddr, size, PROT_NONE, MAP_PRIVATE);
     139                 : #elif NACL_OSX
     140               3 :   CheckMapping(sysaddr, size, VM_PROT_NONE, SM_EMPTY);
     141                 : #else
     142                 : # error Unsupported platform
     143                 : #endif
     144               6 : }
     145                 : 
     146                 : // Test that shared memory mappings can be unmapped by
     147                 : // NaClAddrSpaceFree().  These are different from private memory
     148                 : // mappings because, on Windows, they must be freed with
     149                 : // UnmapViewOfFile() rather than VirtualFree().
     150               8 : TEST_F(MmapTest, TestFreeingShmMappings) {
     151               1 :   struct NaClApp app;
     152               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     153               6 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     154                 : 
     155                 :   // Create a shared memory descriptor of arbitrary size and map it at
     156                 :   // an arbitrary address.
     157               1 :   MapShmFd(&app, 0x200000, 0x100000);
     158                 : 
     159                 :   // Check that we can deallocate the address space.
     160               1 :   NaClAddrSpaceFree(&app);
     161               2 : }
     162                 : 
     163                 : // Test that unmapping a shared memory mapping does not leave behind
     164                 : // an address space hole.
     165               8 : TEST_F(MmapTest, TestUnmapShmMapping) {
     166               1 :   struct NaClApp app;
     167               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     168               6 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     169                 : 
     170                 :   // sel_mem.c does not like having an empty memory map, so create a
     171                 :   // dummy entry that we do not later remove.
     172                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     173               1 :   MapShmFd(&app, 0x400000, 0x10000);
     174                 : 
     175               1 :   uintptr_t addr = 0x200000;
     176               1 :   size_t size = 0x100000;
     177               1 :   MapShmFd(&app, addr, size);
     178                 : 
     179               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     180                 : #if NACL_WINDOWS
     181                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_MAPPED);
     182                 : #elif NACL_LINUX
     183                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_SHARED);
     184                 : #elif NACL_OSX
     185               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_SHARED);
     186                 : #else
     187                 : # error Unsupported platform
     188                 : #endif
     189                 : 
     190               1 :   UnmapMemory(&app, addr, size);
     191                 : 
     192               1 :   NaClAddrSpaceFree(&app);
     193               2 : }
     194                 : 
     195                 : // Test that unmapping a file mapping does not leave behind an address
     196                 : // space hole.
     197               8 : TEST_F(MmapTest, TestUnmapFileMapping) {
     198               1 :   struct NaClApp app;
     199               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     200               6 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     201                 : 
     202                 :   // sel_mem.c does not like having an empty memory map, so create a
     203                 :   // dummy entry that we do not later remove.
     204                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     205               1 :   MapShmFd(&app, 0x400000, 0x10000);
     206                 : 
     207               1 :   uintptr_t addr = 0x200000;
     208               1 :   size_t size = 0x100000;
     209               1 :   MapFileFd(&app, addr, size);
     210                 : 
     211               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     212                 : #if NACL_WINDOWS
     213                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_MAPPED);
     214                 : #elif NACL_LINUX
     215                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_SHARED);
     216                 : #elif NACL_OSX
     217               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_PRIVATE);
     218                 : #else
     219                 : # error Unsupported platform
     220                 : #endif
     221                 : 
     222               1 :   UnmapMemory(&app, addr, size);
     223                 : 
     224               1 :   NaClAddrSpaceFree(&app);
     225               2 : }
     226                 : 
     227                 : // Test we can map an anonymous memory mapping and that unmapping it
     228                 : // does not leave behind an address space hole.
     229               8 : TEST_F(MmapTest, TestUnmapAnonymousMemoryMapping) {
     230               1 :   struct NaClApp app;
     231               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     232               5 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     233                 : 
     234                 :   // sel_mem.c does not like having an empty memory map, so create a
     235                 :   // dummy entry that we do not later remove.
     236                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     237               1 :   MapShmFd(&app, 0x400000, 0x10000);
     238                 : 
     239                 :   // Create an anonymous memory mapping.
     240               1 :   uintptr_t addr = 0x200000;
     241               1 :   size_t size = 0x100000;
     242               1 :   uintptr_t mapping_addr = (uint32_t) NaClSysMmapIntern(
     243                 :       &app, (void *) addr, size,
     244                 :       NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     245                 :       NACL_ABI_MAP_FIXED | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS,
     246                 :       -1, 0);
     247               6 :   ASSERT_EQ(mapping_addr, addr);
     248                 : 
     249               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     250                 : #if NACL_WINDOWS
     251                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_PRIVATE);
     252                 : #elif NACL_LINUX
     253                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE);
     254                 : #elif NACL_OSX
     255               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_EMPTY);
     256                 : #else
     257                 : # error Unsupported platform
     258                 : #endif
     259                 : 
     260               1 :   UnmapMemory(&app, addr, size);
     261                 : 
     262               1 :   NaClAddrSpaceFree(&app);
     263               2 : }
     264                 : 
     265                 : // Test that changing a protection of a shared memory mapping is reflected
     266                 : // by the underlying OS memory mapping.
     267               8 : TEST_F(MmapTest, TestProtectShmMapping) {
     268               1 :   struct NaClApp app;
     269               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     270               5 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     271                 : 
     272                 :   // sel_mem.c does not like having an empty memory map, so create a
     273                 :   // dummy entry that we do not later remove.
     274                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     275               1 :   MapShmFd(&app, 0x400000, 0x10000);
     276                 : 
     277               1 :   uintptr_t addr = 0x200000;
     278               1 :   size_t size = 0x100000;
     279               1 :   MapShmFd(&app, addr, size);
     280                 : 
     281               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     282                 : #if NACL_WINDOWS
     283                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_MAPPED);
     284                 : #elif NACL_LINUX
     285                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_SHARED);
     286                 : #elif NACL_OSX
     287               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_SHARED);
     288                 : #else
     289                 : # error Unsupported platform
     290                 : #endif
     291                 : 
     292               6 :   ASSERT_EQ(0, NaClSysMprotectInternal(
     293                 :                    &app, (uint32_t) addr, size, NACL_ABI_PROT_NONE));
     294                 : 
     295                 : #if NACL_WINDOWS
     296                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_NOACCESS, MEM_MAPPED);
     297                 : #elif NACL_LINUX
     298                 :   CheckMapping(sysaddr, size, PROT_NONE, MAP_SHARED);
     299                 : #elif NACL_OSX
     300               1 :   CheckMapping(sysaddr, size, VM_PROT_NONE, SM_SHARED);
     301                 : #else
     302                 : # error Unsupported platform
     303                 : #endif
     304                 : 
     305               1 :   NaClAddrSpaceFree(&app);
     306               2 : }
     307                 : 
     308                 : // Test that changing a protection of a file mapping is reflected
     309                 : // by the underlying OS memory mapping.
     310               8 : TEST_F(MmapTest, TestProtectFileMapping) {
     311               1 :   struct NaClApp app;
     312               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     313               5 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     314                 : 
     315                 :   // sel_mem.c does not like having an empty memory map, so create a
     316                 :   // dummy entry that we do not later remove.
     317                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     318               1 :   MapShmFd(&app, 0x400000, 0x10000);
     319                 : 
     320               1 :   uintptr_t addr = 0x200000;
     321               1 :   size_t size = 0x100000;
     322               1 :   MapFileFd(&app, addr, size);
     323                 : 
     324               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     325                 : #if NACL_WINDOWS
     326                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_MAPPED);
     327                 : #elif NACL_LINUX
     328                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_SHARED);
     329                 : #elif NACL_OSX
     330               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_PRIVATE);
     331                 : #else
     332                 : # error Unsupported platform
     333                 : #endif
     334                 : 
     335               6 :   ASSERT_EQ(0, NaClSysMprotectInternal(
     336                 :                    &app, (uint32_t) addr, size, NACL_ABI_PROT_NONE));
     337                 : 
     338                 : #if NACL_WINDOWS
     339                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_NOACCESS, MEM_MAPPED);
     340                 : #elif NACL_LINUX
     341                 :   CheckMapping(sysaddr, size, PROT_NONE, MAP_SHARED);
     342                 : #elif NACL_OSX
     343               1 :   CheckMapping(sysaddr, size, VM_PROT_NONE, SM_PRIVATE);
     344                 : #else
     345                 : # error Unsupported platform
     346                 : #endif
     347                 : 
     348               1 :   NaClAddrSpaceFree(&app);
     349               2 : }
     350                 : 
     351                 : // Test that changing a protection of a anonymous memory mapping is
     352                 : // reflected by the underlying OS memory mapping.
     353               8 : TEST_F(MmapTest, TestProtectAnonymousMemory) {
     354               1 :   struct NaClApp app;
     355               5 :   ASSERT_EQ(NaClAppCtor(&app), 1);
     356               5 :   ASSERT_EQ(NaClAllocAddrSpace(&app), LOAD_OK);
     357                 : 
     358                 :   // sel_mem.c does not like having an empty memory map, so create a
     359                 :   // dummy entry that we do not later remove.
     360                 :   // TODO(mseaborn): Clean up so that this is not necessary.
     361               1 :   MapShmFd(&app, 0x400000, 0x10000);
     362                 : 
     363                 :   // Create an anonymous memory mapping.
     364               1 :   uintptr_t addr = 0x200000;
     365               1 :   size_t size = 0x100000;
     366               1 :   uintptr_t mapping_addr = (uint32_t) NaClSysMmapIntern(
     367                 :       &app, (void *) addr, size,
     368                 :       NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     369                 :       NACL_ABI_MAP_FIXED | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS,
     370                 :       -1, 0);
     371               5 :   ASSERT_EQ(mapping_addr, addr);
     372                 : 
     373               1 :   uintptr_t sysaddr = NaClUserToSys(&app, addr);
     374                 : #if NACL_WINDOWS
     375                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_READWRITE, MEM_PRIVATE);
     376                 : #elif NACL_LINUX
     377                 :   CheckMapping(sysaddr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE);
     378                 : #elif NACL_OSX
     379               1 :   CheckMapping(sysaddr, size, VM_PROT_READ | VM_PROT_WRITE, SM_EMPTY);
     380                 : #else
     381                 : # error Unsupported platform
     382                 : #endif
     383                 : 
     384               6 :   ASSERT_EQ(0, NaClSysMprotectInternal(
     385                 :                    &app, (uint32_t) addr, size, NACL_ABI_PROT_NONE));
     386                 : 
     387                 : #if NACL_WINDOWS
     388                 :   CheckMapping(sysaddr, size, MEM_COMMIT, PAGE_NOACCESS, MEM_PRIVATE);
     389                 : #elif NACL_LINUX
     390                 :   CheckMapping(sysaddr, size, PROT_NONE, MAP_PRIVATE);
     391                 : #elif NACL_OSX
     392               1 :   CheckMapping(sysaddr, size, VM_PROT_NONE, SM_EMPTY);
     393                 : #else
     394                 : # error Unsupported platform
     395                 : #endif
     396                 : 
     397               1 :   NaClAddrSpaceFree(&app);
     398               2 : }
     399                 : 
     400                 : #endif /* NACL_ARCH(NACL_BUILD_ARCH) != NACL_arm */

Generated by: LCOV version 1.7