LCOV - code coverage report
Current view: directory - src/shared/platform - nacl_host_desc_mmap_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 150 114 76.0 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2013 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 <limits.h>
       8                 : #include <stdio.h>
       9                 : #include <string.h>
      10                 : 
      11                 : #if !NACL_WINDOWS
      12                 : # include <sys/mman.h>
      13                 : #endif
      14                 : 
      15                 : #include "native_client/src/include/portability.h"
      16                 : #include "native_client/src/include/portability_io.h"
      17                 : #include "native_client/src/include/nacl_compiler_annotations.h"
      18                 : #include "native_client/src/include/nacl_macros.h"
      19                 : 
      20                 : #include "native_client/src/shared/platform/nacl_check.h"
      21                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      22                 : #include "native_client/src/shared/platform/nacl_log.h"
      23                 : #include "native_client/src/shared/platform/platform_init.h"
      24                 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
      25                 : #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
      26                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      27                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      28                 : 
      29                 : static const size_t kNumFileBytes = 2 * 0x10000;
      30                 : 
      31                 : #if !NACL_WINDOWS
      32                 : # define NaClHostDescUnmapUnsafe munmap
      33                 : #endif
      34                 : 
      35                 : 
      36                 : /*
      37                 :  * mmap PROT_EXEC test
      38                 :  *
      39                 :  * Use a file containing mmappable code.  We don't want to
      40                 :  * re-implement a dynamic loader here, nor do we want to duplicate a
      41                 :  * lot of ELF parsing.
      42                 :  */
      43                 : 
      44               1 : int prot_exec_test(struct NaClHostDesc *d, void *test_specifics) {
      45               1 :   struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
      46                 :   uintptr_t addr;
      47                 :   int (*func)(int param);
      48                 :   int param;
      49                 :   int value;
      50                 : 
      51                 :   UNREFERENCED_PARAMETER(test_specifics);
      52                 : 
      53                 :   if ((uintptr_t) -4095 <
      54                 :       (addr = NaClHostDescMap(d,
      55                 :                               null_eff,
      56                 :                               NULL,
      57                 :                               kNumFileBytes,
      58                 :                               NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
      59                 :                               NACL_ABI_MAP_SHARED,
      60               1 :                               /* offset */ 0))) {
      61               0 :     fprintf(stderr, "prot_exec_test: map failed, errno %d\n", -(int) addr);
      62               0 :     return 1;
      63                 :   }
      64                 : 
      65               1 :   func = (int (*)(int)) addr;
      66               1 :   for (param = 0; param < 16; ++param) {
      67               1 :     printf("%d -> ", param);
      68               1 :     fflush(stdout);
      69               1 :     value = (*func)(param);
      70               1 :     printf("%d\n", value);
      71               1 :     CHECK(value == param+1);
      72               1 :   }
      73                 : 
      74               1 :   CHECK(0 == NaClHostDescUnmapUnsafe((void *) addr, kNumFileBytes));
      75                 : 
      76               1 :   return 0;
      77               1 : }
      78                 : 
      79                 : /*
      80                 :  * mmap MAP_SHARED test
      81                 :  *
      82                 :  * Make sure two views of the same file see the changes made from one
      83                 :  * view in the other.
      84                 :  */
      85               1 : int map_shared_test(struct NaClHostDesc *d, void *test_specifics) {
      86               1 :   struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
      87                 :   uintptr_t view1;
      88                 :   uintptr_t view2;
      89                 :   char *v1ptr;
      90                 :   char *v2ptr;
      91                 : 
      92                 :   UNREFERENCED_PARAMETER(test_specifics);
      93                 : 
      94                 :   if ((uintptr_t) -4095 <
      95                 :       (view1 = NaClHostDescMap(d,
      96                 :                                null_eff,
      97                 :                                NULL,
      98                 :                                kNumFileBytes,
      99                 :                                NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     100                 :                                NACL_ABI_MAP_SHARED,
     101               1 :                                /* offset */ 0))) {
     102                 :     fprintf(stderr, "map_shared_test: view1 map failed, errno %d\n",
     103               0 :             -(int) view1);
     104               0 :     return 1;
     105                 :   }
     106                 : 
     107                 :   if ((uintptr_t) -4095 <
     108                 :       (view2 = NaClHostDescMap(d,
     109                 :                                null_eff,
     110                 :                                NULL,
     111                 :                                kNumFileBytes,
     112                 :                                NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     113                 :                                NACL_ABI_MAP_SHARED,
     114               1 :                                /* offset */ 0))) {
     115                 :     fprintf(stderr, "map_shared_test: view2 map failed, errno %d\n",
     116               0 :             -(int) view2);
     117               0 :     return 1;
     118                 :   }
     119                 : 
     120               1 :   v1ptr = (char *) view1;
     121               1 :   v2ptr = (char *) view2;
     122                 : 
     123               1 :   CHECK(v1ptr[0] == '\0');
     124               1 :   CHECK(v2ptr[0] == '\0');
     125               1 :   v1ptr[0] = 'x';
     126               1 :   CHECK(v2ptr[0] == 'x');
     127               1 :   v2ptr[0x400] = 'y';
     128               1 :   CHECK(v1ptr[0x400] == 'y');
     129                 : 
     130               1 :   CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
     131               1 :   CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));
     132                 : 
     133               1 :   return 0;
     134               1 : }
     135                 : 
     136                 : struct MapPrivateSpecifics {
     137                 :   int shm_not_write;
     138                 : };
     139                 : 
     140                 : /*
     141                 :  * mmap MAP_PRIVATE test
     142                 :  *
     143                 :  * Make sure that a MAP_PRIVATE view initially sees the changes made
     144                 :  * in a MAP_SHARED view, but after touching the private view further
     145                 :  * changes become invisible.
     146                 :  */
     147               1 : int map_private_test(struct NaClHostDesc *d, void *test_specifics) {
     148                 :   struct MapPrivateSpecifics *params =
     149               1 :       (struct MapPrivateSpecifics *) test_specifics;
     150               1 :   struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
     151                 :   uintptr_t view1;
     152                 :   uintptr_t view2;
     153                 :   nacl_off64_t off;
     154                 :   ssize_t bytes_written;
     155                 :   char *v1ptr;
     156                 :   char *v2ptr;
     157                 : 
     158                 :   if ((uintptr_t) -4095 <
     159                 :       (view1 = NaClHostDescMap(d,
     160                 :                                null_eff,
     161                 :                                NULL,
     162                 :                                kNumFileBytes,
     163                 :                                NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     164                 :                                NACL_ABI_MAP_SHARED,
     165               1 :                                /* offset */ 0))) {
     166                 :     fprintf(stderr, "map_private_test: view1 map failed, errno %d\n",
     167               0 :             -(int) view1);
     168               0 :     return 1;
     169                 :   }
     170                 : 
     171               1 :   NaClLog(2, "map_private_test: view1 = 0x%"NACL_PRIxPTR"\n", view1);
     172                 : 
     173                 :   if ((uintptr_t) -4095 <
     174                 :       (view2 = NaClHostDescMap(d,
     175                 :                                null_eff,
     176                 :                                NULL,
     177                 :                                kNumFileBytes,
     178                 :                                NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     179                 :                                NACL_ABI_MAP_PRIVATE,
     180               1 :                                /* offset */ 0))) {
     181                 :     fprintf(stderr, "map_private_test: view2 map failed, errno %d\n",
     182               0 :             -(int) view2);
     183               0 :     return 1;
     184                 :   }
     185                 : 
     186               1 :   NaClLog(2, "map_private_test: view2 = 0x%"NACL_PRIxPTR"\n", view2);
     187                 : 
     188               1 :   v1ptr = (char *) view1;
     189               1 :   v2ptr = (char *) view2;
     190                 : 
     191               1 :   CHECK(v1ptr[0] == '\0');
     192               1 :   CHECK(v2ptr[0] == '\0');
     193               1 :   if (params->shm_not_write) {
     194               1 :     NaClLog(2, "map_private_test: changing via shm view\n");
     195               1 :     v1ptr[0] = 'x';  /* write through shared view */
     196               1 :   } else {
     197               1 :     NaClLog(2, "map_private_test: changing via write interface\n");
     198               1 :     off = NaClHostDescSeek(d, 0, 0);
     199               1 :     if (off < 0) {
     200               0 :       fprintf(stderr, "Could not seek: NaCl errno %d\n", (int) -off);
     201               0 :       return 1;
     202                 :     }
     203               1 :     bytes_written = NaClHostDescWrite(d, "x", 1);
     204               1 :     if (1 != bytes_written) {
     205               0 :       fprintf(stderr, "Could not write: NaCl errno %d\n", (int) -bytes_written);
     206               0 :       return 1;
     207                 :     }
     208                 :   }
     209                 : #if NACL_LINUX || NACL_WINDOWS
     210                 :   /*
     211                 :    * Most OSes have this behavior: a PRIVATE mapping is copy-on-write,
     212                 :    * but the COW occurs when the fault occurs on that mapping, not
     213                 :    * other mappings; otherwise, the page tables just point the system
     214                 :    * to the buffer cache (or, if evicted, a stub entry that permits
     215                 :    * faulting in the page).  So, a write through a writable file
     216                 :    * descriptor or a SHARED mapping would modify the buffer cache, and
     217                 :    * the PRIVATE mapping would see such changes until a fault occurs.
     218                 :    */
     219               1 :   CHECK(v2ptr[0] == 'x');  /* visible! */
     220                 : #elif NACL_OSX
     221                 :   /*
     222                 :    * On OSX, however, the underlying Mach primitives provide
     223                 :    * bidirectional COW.
     224                 :    */
     225                 :   CHECK(v2ptr[0] == '\0');  /* NOT visible! */
     226                 : #else
     227                 : # error "Unsupported OS"
     228                 : #endif
     229                 : 
     230               1 :   v2ptr[0] = 'z';  /* COW fault */
     231               1 :   v1ptr[0] = 'y';
     232               1 :   CHECK(v2ptr[0] == 'z'); /* private! */
     233                 : 
     234               1 :   CHECK(v1ptr[0x400] == '\0');
     235               1 :   v2ptr[0x400] = 'y';
     236               1 :   CHECK(v1ptr[0x400] == '\0');
     237                 : 
     238               1 :   CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
     239               1 :   CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));
     240                 : 
     241               1 :   return 0;
     242               1 : }
     243                 : 
     244                 : /*
     245                 :  * Write out kNumFileBytes (a multiple of 64K) bytes of data.
     246                 :  */
     247               1 : int CreateTestData(struct NaClHostDesc *d) {
     248                 :   size_t nbytes;
     249               1 :   size_t written = 0;
     250                 :   ssize_t result;
     251                 :   static char buffer[4096];
     252                 : 
     253               1 :   memset(buffer, 0, sizeof buffer);
     254               1 :   while (written < kNumFileBytes) {
     255               1 :     nbytes = kNumFileBytes - written;
     256               1 :     if (nbytes > sizeof buffer) {
     257               1 :       nbytes = sizeof buffer;
     258                 :     }
     259               1 :     result = NaClHostDescWrite(d, buffer, nbytes);
     260               1 :     if (result < 0) {
     261               0 :       return (int) result;
     262                 :     }
     263               1 :     written += result;
     264               1 :   }
     265               1 :   return 0;
     266               1 : }
     267                 : 
     268                 : struct TestParams {
     269                 :   char const *test_name;
     270                 :   int (*test_func)(struct NaClHostDesc *, void *test_specifics);
     271                 :   int open_flags;
     272                 :   int file_perms;
     273                 : 
     274                 :   unsigned char const *test_data_start;
     275                 :   size_t test_data_size;
     276                 : 
     277                 :   void *test_specifics;
     278                 : };
     279                 : 
     280                 : void CreateTestFile(struct NaClHostDesc *d_out,
     281                 :                     char const *pathname,
     282               1 :                     struct TestParams *param) {
     283                 :   struct NaClHostDesc hd;
     284                 :   int err;
     285                 :   nacl_off64_t off;
     286                 :   size_t desired_write;
     287                 :   ssize_t bytes_written;
     288                 : 
     289               1 :   printf("pathname = %s, perms 0%o\n", pathname, param->file_perms);
     290                 :   if (0 != (err = NaClHostDescOpen(&hd,
     291                 :                                    pathname,
     292                 :                                    NACL_ABI_O_WRONLY |
     293                 :                                    NACL_ABI_O_CREAT |
     294                 :                                    NACL_ABI_O_TRUNC,
     295               1 :                                    param->file_perms))) {
     296               0 :     fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
     297               0 :     exit(1);
     298                 :   }
     299               1 :   if (0 != (err = CreateTestData(&hd))) {
     300                 :     fprintf(stderr,
     301                 :             "Could not write test data into test scratch file: NaCl errno %d\n",
     302               0 :             -err);
     303               0 :     exit(1);
     304                 :   }
     305               1 :   if (NULL != param->test_data_start) {
     306               1 :     off = NaClHostDescSeek(&hd, 0, 0);
     307               1 :     if (off < 0) {
     308                 :       fprintf(stderr,
     309                 :               "Could not seek to create test data: NaCl errno %d\n",
     310               0 :               (int) -off);
     311               0 :       exit(1);
     312                 :     }
     313               1 :     desired_write = param->test_data_size;
     314                 :     bytes_written = NaClHostDescWrite(&hd,
     315                 :                                       param->test_data_start,
     316               1 :                                       desired_write);
     317               1 :     if (bytes_written < 0) {
     318                 :       fprintf(stderr,
     319                 :               "Could not write specialized test data: NaCl errno %d\n",
     320               0 :               (int) -bytes_written);
     321               0 :       exit(1);
     322                 :     }
     323               1 :     if ((size_t) bytes_written != desired_write) {
     324                 :       fprintf(stderr,
     325                 :               "Error while writing specialized test data:"
     326                 :               " tried to write %d, actual %d\n",
     327               0 :               (int) desired_write, (int) bytes_written);
     328               0 :       exit(1);
     329                 :     }
     330                 :   }
     331               1 :   if (0 != (err = NaClHostDescClose(&hd))) {
     332                 :     fprintf(stderr,
     333               0 :             "Error while closing test data file, errno %d\n", -err);
     334               0 :     exit(1);
     335                 :   }
     336                 :   if (0 != (err = NaClHostDescOpen(d_out,
     337                 :                                    pathname,
     338                 :                                    param->open_flags,
     339               1 :                                    param->file_perms))) {
     340               0 :     fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
     341               0 :     exit(1);
     342                 :   }
     343               1 : }
     344                 : 
     345               1 : void CloseTestFile(struct NaClHostDesc *d) {
     346               1 :   CHECK(0 == NaClHostDescClose(d));
     347               1 : }
     348                 : 
     349                 : struct MapPrivateSpecifics test0 = { 0 };
     350                 : struct MapPrivateSpecifics test1 = { 1 };
     351                 : 
     352                 : /*
     353                 :  * This is the function the machine instructions for which is below.
     354                 :  * Instead of making assumptions about taking addresses of functions,
     355                 :  * we open-code the machine instructions.  Since porting this test now
     356                 :  * requires a little more effort, here is the procedure: Put in
     357                 :  * "garbage" data in the test_machine_code for your architecture.
     358                 :  * Build the Test.  The test will fail -- don't bother to run it.
     359                 :  * However, you should now be able to use a debugger to disassemble
     360                 :  * the x_plus_1 function, and update the test_machine_code contents.
     361                 :  */
     362               0 : int x_plus_1(int x) {
     363               0 :   return x+1;
     364               0 : }
     365                 : 
     366                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
     367                 : # if NACL_BUILD_SUBARCH == 32
     368                 : unsigned char const test_machine_code[] = {
     369                 :   0x8b, 0x44, 0x24, 0x04, 0x83, 0xc0, 0x01, 0xc3,
     370                 : };
     371                 : # elif NACL_BUILD_SUBARCH == 64
     372                 : #  if NACL_WINDOWS
     373                 : unsigned char const test_machine_code[] = {
     374                 :   0x8d, 0x41, 0x01, 0xc3,  /* lea 0x1(%rcx), %eax; ret */
     375                 : };
     376                 : #  else
     377                 : unsigned char const test_machine_code[] = {
     378                 :   0x8d, 0x47, 0x01, 0xc3,  /* lea 0x1(%rdi), %eax; ret */
     379                 : };
     380                 : #  endif
     381                 : # else
     382                 : #  error "Who leaked the secret x86-128 project?"
     383                 : # endif
     384                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     385                 : unsigned char const test_machine_code[] = {
     386                 :   0x01, 0x00, 0x80, 0xe2, 0x1e, 0xff, 0x2f, 0xe1
     387                 : };
     388                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     389                 : unsigned char const test_machine_code[] = {
     390                 :   0x01, 0x00, 0x82, 0x20,  /* addi v0, a0, 1 */
     391                 :   0x08, 0x00, 0xe0, 0x03,  /* jr ra */
     392                 :   0x00, 0x00, 0x00, 0x00,  /* nop */
     393                 : };
     394                 : #else
     395                 : # error "What architecture?"
     396                 : #endif
     397                 : 
     398                 : struct TestParams tests[] = {
     399                 :   {
     400                 :     "Shared Mapping Test",
     401                 :     map_shared_test,
     402                 :     (NACL_ABI_O_RDWR | NACL_ABI_O_CREAT), 0666,
     403                 :     NULL, 0,
     404                 :     NULL,
     405                 :   }, {
     406                 :     "Private Mapping Test, modify by write",
     407                 :     map_private_test,
     408                 :     (NACL_ABI_O_RDWR | NACL_ABI_O_CREAT), 0666,
     409                 :     NULL, 0,
     410                 :     &test0,
     411                 :   }, {
     412                 :     "Private Mapping Test, modify by shm",
     413                 :     map_private_test,
     414                 :     (NACL_ABI_O_RDWR | NACL_ABI_O_CREAT), 0666,
     415                 :     NULL, 0,
     416                 :     &test1,
     417                 :   }, {
     418                 :     "PROT_EXEC Mapping Test",
     419                 :     prot_exec_test,
     420                 :     (NACL_ABI_O_RDWR | NACL_ABI_O_CREAT), 0777,
     421                 :     test_machine_code,
     422                 :     sizeof test_machine_code,
     423                 :     NULL,
     424                 :   },
     425                 : };
     426                 : 
     427                 : /*
     428                 :  * It is the responsibility of the invoking environment to delete the
     429                 :  * file passed as command-line argument.  See the build.scons file.
     430                 :  */
     431               1 : int main(int ac, char **av) {
     432               1 :   char const *test_dir_name = "/tmp/nacl_host_desc_test";
     433                 :   struct NaClHostDesc hd;
     434                 :   size_t err_count;
     435                 :   size_t ix;
     436                 :   int opt;
     437               1 :   int num_runs = 1;
     438                 :   int test_run;
     439                 : 
     440               1 :   while (EOF != (opt = getopt(ac, av, "c:t:"))) {
     441               1 :     switch (opt) {
     442                 :       case 'c':
     443               0 :         num_runs = atoi(optarg);
     444               0 :         break;
     445                 :       case 't':
     446               1 :         test_dir_name = optarg;
     447               1 :         break;
     448                 :       default:
     449                 :         fprintf(stderr,
     450                 :                 "Usage: nacl_host_desc_mmap_test [-c run_count]\n"
     451               0 :                 "                                [-t test_temp_dir]\n");
     452               0 :         exit(1);
     453                 :     }
     454               1 :   }
     455                 : 
     456               1 :   NaClPlatformInit();
     457                 : 
     458               1 :   err_count = 0;
     459               1 :   for (test_run = 0; test_run < num_runs; ++test_run) {
     460               1 :     printf("Test run %d\n\n", test_run);
     461               1 :     for (ix = 0; ix < NACL_ARRAY_SIZE(tests); ++ix) {
     462                 :       char test_file_name[PATH_MAX];
     463                 :       SNPRINTF(test_file_name, sizeof test_file_name,
     464               1 :                "%s/f%d.%"NACL_PRIuS, test_dir_name, test_run, ix);
     465               1 :       printf("%s\n", tests[ix].test_name);
     466               1 :       CreateTestFile(&hd, test_file_name, &tests[ix]);
     467               1 :       err_count += (*tests[ix].test_func)(&hd, tests[ix].test_specifics);
     468               1 :       CloseTestFile(&hd);
     469               1 :     }
     470               1 :   }
     471                 : 
     472               1 :   NaClPlatformFini();
     473                 : 
     474                 :   /* we ignore the 2^32 or 2^64 total errors case */
     475               1 :   return (err_count > 255) ? 255 : err_count;
     476               1 : }

Generated by: LCOV version 1.7