Example #1
0
static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc          *vself,
                                       nacl_off64_t             offset,
                                       int                      whence) {
  struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;

  return NaClHostDescSeek(self->hd, offset, whence);
}
int SeekPastEndAndWriteTest(struct NaClHostDesc *test_file,
                            struct NaClHostDesc *ro_view,
                            void const *test_params) {
  nacl_host_stat_t stbuf;
  nacl_off64_t new_size;
  ssize_t io_err;
  int err;
  nacl_off64_t seek_result;

  UNREFERENCED_PARAMETER(test_params);
  err = NaClHostDescFstat(test_file, &stbuf);
  if (0 != err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: fstat failed\n");
    return 0;
  }
  new_size = stbuf.st_size + (2 << 16);
  seek_result = NaClHostDescSeek(test_file, new_size, 0);
  if (seek_result != new_size) {
    fprintf(stderr, "SeekPastEndAndWriteTest: seek failed\n");
    return 0;
  }
  io_err = NaClHostDescWrite(test_file, "1", 1);
  if (1 != io_err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: write failed: %"NACL_PRIdS"\n",
            io_err);
  }
  err = NaClHostDescFstat(test_file, &stbuf);
  if (0 != err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: post-write fstat failed\n");
    return 0;
  }
  ASSERT_EQ(stbuf.st_size, new_size + 1);
  err = NaClHostDescFstat(ro_view, &stbuf);
  if (0 != err) {
    fprintf(stderr,
            "SeekPastEndAndWriteTest: post-write ro_view fstat failed\n");
    return 0;
  }
  ASSERT_EQ(stbuf.st_size, new_size + 1);
  return 1;
}
void CreateTestFile(struct NaClHostDesc *d_out,
                    char const *pathname,
                    struct TestParams *param) {
  struct NaClHostDesc hd;
  int err;
  nacl_off64_t off;
  size_t desired_write;
  ssize_t bytes_written;

  printf("pathname = %s, perms 0%o\n", pathname, param->file_perms);
  if (0 != (err = NaClHostDescOpen(&hd,
                                   pathname,
                                   NACL_ABI_O_WRONLY |
                                   NACL_ABI_O_CREAT |
                                   NACL_ABI_O_TRUNC,
                                   param->file_perms))) {
    fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
    exit(1);
  }
  if (0 != (err = CreateTestData(&hd))) {
    fprintf(stderr,
            "Could not write test data into test scratch file: NaCl errno %d\n",
            -err);
    exit(1);
  }
  if (NULL != param->test_data_start) {
    off = NaClHostDescSeek(&hd, 0, 0);
    if (off < 0) {
      fprintf(stderr,
              "Could not seek to create test data: NaCl errno %d\n",
              (int) -off);
      exit(1);
    }
    desired_write = param->test_data_size;
    bytes_written = NaClHostDescWrite(&hd,
                                      param->test_data_start,
                                      desired_write);
    if (bytes_written < 0) {
      fprintf(stderr,
              "Could not write specialized test data: NaCl errno %d\n",
              (int) -bytes_written);
      exit(1);
    }
    if ((size_t) bytes_written != desired_write) {
      fprintf(stderr,
              "Error while writing specialized test data:"
              " tried to write %d, actual %d\n",
              (int) desired_write, (int) bytes_written);
      exit(1);
    }
  }
  if (0 != (err = NaClHostDescClose(&hd))) {
    fprintf(stderr,
            "Error while closing test data file, errno %d\n", -err);
    exit(1);
  }
  if (0 != (err = NaClHostDescOpen(d_out,
                                   pathname,
                                   param->open_flags,
                                   param->file_perms))) {
    fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
    exit(1);
  }
}
/*
 * mmap MAP_PRIVATE test
 *
 * Make sure that a MAP_PRIVATE view initially sees the changes made
 * in a MAP_SHARED view, but after touching the private view further
 * changes become invisible.
 */
int map_private_test(struct NaClHostDesc *d, void *test_specifics) {
  struct MapPrivateSpecifics *params =
      (struct MapPrivateSpecifics *) test_specifics;
  struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
  uintptr_t view1;
  uintptr_t view2;
  nacl_off64_t off;
  ssize_t bytes_written;
  char *v1ptr;
  char *v2ptr;

  if ((uintptr_t) -4095 <
      (view1 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_SHARED,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view1 map failed, errno %d\n",
            -(int) view1);
    return 1;
  }

  NaClLog(2, "map_private_test: view1 = 0x%"NACL_PRIxPTR"\n", view1);

  if ((uintptr_t) -4095 <
      (view2 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_PRIVATE,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view2 map failed, errno %d\n",
            -(int) view2);
    return 1;
  }

  NaClLog(2, "map_private_test: view2 = 0x%"NACL_PRIxPTR"\n", view2);

  v1ptr = (char *) view1;
  v2ptr = (char *) view2;

  CHECK(v1ptr[0] == '\0');
  CHECK(v2ptr[0] == '\0');
  if (params->shm_not_write) {
    NaClLog(2, "map_private_test: changing via shm view\n");
    v1ptr[0] = 'x';  /* write through shared view */
  } else {
    NaClLog(2, "map_private_test: changing via write interface\n");
    off = NaClHostDescSeek(d, 0, 0);
    if (off < 0) {
      fprintf(stderr, "Could not seek: NaCl errno %d\n", (int) -off);
      return 1;
    }
    bytes_written = NaClHostDescWrite(d, "x", 1);
    if (1 != bytes_written) {
      fprintf(stderr, "Could not write: NaCl errno %d\n", (int) -bytes_written);
      return 1;
    }
  }
#if NACL_LINUX || NACL_WINDOWS
  /*
   * Most OSes have this behavior: a PRIVATE mapping is copy-on-write,
   * but the COW occurs when the fault occurs on that mapping, not
   * other mappings; otherwise, the page tables just point the system
   * to the buffer cache (or, if evicted, a stub entry that permits
   * faulting in the page).  So, a write through a writable file
   * descriptor or a SHARED mapping would modify the buffer cache, and
   * the PRIVATE mapping would see such changes until a fault occurs.
   */
  CHECK(v2ptr[0] == 'x');  /* visible! */
#elif NACL_OSX
  /*
   * On OSX, however, the underlying Mach primitives provide
   * bidirectional COW.
   */
  CHECK(v2ptr[0] == '\0');  /* NOT visible! */
#else
# error "Unsupported OS"
#endif

  v2ptr[0] = 'z';  /* COW fault */
  v1ptr[0] = 'y';
  CHECK(v2ptr[0] == 'z'); /* private! */

  CHECK(v1ptr[0x400] == '\0');
  v2ptr[0x400] = 'y';
  CHECK(v1ptr[0x400] == '\0');

  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));

  return 0;
}
int PWriteUsesOffsetReadPtrVerification(struct NaClHostDesc *test_file,
                                        struct NaClHostDesc *ro_view,
                                        void const *test_params) {
  nacl_off64_t seek_err;
  char buffer[512];
  ssize_t io_rv;
  const size_t pwrite_position = 4096;

  UNREFERENCED_PARAMETER(test_params);

  seek_err = NaClHostDescSeek(test_file, 0, 0);
  if (seek_err < 0) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: seek failed, errno %d\n",
            -(int) seek_err);
    return 0;
  }
  io_rv = NaClHostDescRead(test_file, buffer, sizeof buffer);
  if (sizeof buffer != io_rv) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: read failed, got %d,"
            " expected %d",
            (int) io_rv, (int) sizeof buffer);
    return 0;
  }
  if (0 != memcmp(buffer, quote, sizeof buffer)) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: initial bytes mangled?!?\n");
    return 0;
  }
  io_rv = NaClHostDescPWrite(test_file, another_quote, sizeof another_quote - 1,
                             pwrite_position);
  if (io_rv != sizeof another_quote - 1) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: pwrite failed\n");
    return 0;
  }
  io_rv = NaClHostDescRead(test_file, buffer, sizeof buffer);
  if (sizeof buffer != io_rv) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification:"
            " 2nd implicit file ptr read failed, got %d,"
            " expected %d\n",
            (int) io_rv, (int) sizeof buffer);
    return 0;
  }
  if (0 != memcmp(buffer, quote + sizeof buffer, sizeof buffer)) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: 2nd read contents mangled\n"
            "Expected:\n"
            "%.*s\n"
            "Got:\n"
            "%.*s\n",
            (int) sizeof buffer, quote + sizeof buffer,
            (int) sizeof buffer, buffer);
    return 0;
  }

  io_rv = NaClHostDescPRead(ro_view, buffer, sizeof buffer,
                            pwrite_position);
  if (io_rv != sizeof buffer) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: verification pread failed,"
            " got %d, expected %d",
            (int) io_rv, (int) sizeof buffer);
    return 0;
  }
  if (0 != memcmp(buffer, another_quote, sizeof buffer)) {
    fprintf(stderr,
            "PWriteUsesOffsetReadPtrVerification: verification content bad\n"
            "Got:\n"
            "%.*s\n"
            "Expected:\n"
            "%.*s\n",
            (int) sizeof buffer, buffer,
            (int) sizeof buffer, another_quote);
    return 0;
  }

  return 1;
}
int PWriteUsesOffsetSeekReadVerification(struct NaClHostDesc *test_file,
                                         struct NaClHostDesc *ro_view,
                                         void const *test_params) {
  size_t len = strlen(another_quote);
  char buffer[4096];
  ssize_t io_rv;
  nacl_off64_t seek_err;

  UNREFERENCED_PARAMETER(ro_view);
  UNREFERENCED_PARAMETER(test_params);

  CHECK(len <= sizeof buffer);

  io_rv = NaClHostDescPWrite(test_file, another_quote, len, GG_LONGLONG(0));
  if (io_rv < 0) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " pwrite (ostensibly to beginning) failed,"
            " errno %d\n", -(int) io_rv);
    return 0;
  }
  if ((size_t) io_rv != len) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " pwrite short write, expected %"NACL_PRIuS
            ", got %"NACL_PRIuS"\n",
            len, (size_t) io_rv);
    return 0;
  }
  seek_err = NaClHostDescSeek(test_file, 0, 0);
  if (seek_err < 0) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " seek failed, errno %d\n", -(int) seek_err);
    return 0;
  }
  ASSERT_EQ(seek_err, (nacl_off64_t) 0);
  CHECK(len <= sizeof buffer);
  io_rv = NaClHostDescRead(test_file, buffer, len);
  if (io_rv < 0) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " NaClHostDescRead failed, errno %d\n",
            -(int) io_rv);
    return 0;
  }
  if ((size_t) io_rv != len) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " short read, expected %"NACL_PRIuS
            ", got %"NACL_PRIuS"\n",
            len, (size_t) io_rv);
    return 0;
  }
  if (0 != memcmp(buffer, another_quote, len)) {
    fprintf(stderr,
            "PWriteUsesOffsetSeekReadVerification:"
            " data at beginning differs\n"
            " Expected: %.*s\n"
            "      Got: %.*s\n",
            (int) len, another_quote,
            (int) len, buffer);
    return 0;
  }
  return 1;
}
int BasicPermChecks(struct NaClHostDesc *test_file,
                    struct NaClHostDesc *ro_view,
                    void const *test_params) {
  struct BasicPermChecksParams const *params =
      (struct BasicPermChecksParams const *) test_params;
  char buffer[1<<16];
  ssize_t result;
  nacl_off64_t seek_result;
  size_t len;

  CHECK(params->seq_read_bytes1 <= sizeof buffer);
  CHECK(params->seq_read_bytes2 <= sizeof buffer);
  seek_result = NaClHostDescSeek(test_file, 0, 0);
  ASSERT_EQ(0, seek_result);
  /*
   * Some tests skip the initial read.
   */
  if (0 != params->seq_read_bytes1) {
    memset(buffer, 0, sizeof buffer);
    CHECK(params->seq_read_bytes1 <= sizeof buffer);
    result = NaClHostDescRead(test_file, buffer, params->seq_read_bytes1);
    if (result != (ssize_t) params->seq_read_bytes1) {
      fprintf(stderr,
              "BasicPermChecks: first sequential read, got %"NACL_PRIdS
              ", expected %"NACL_PRIuS" bytes\n",
              result, params->seq_read_bytes1);
      return 0;
    }
    if (0 != memcmp(quote, buffer, params->seq_read_bytes1)) {
      fprintf(stderr,
              "BasicPermChecks: first sequential read result differs\n");
      fprintf(stderr, "got: %.*s\n", (int) params->seq_read_bytes1, buffer);
      return 0;
    }
  }
  len = strlen(params->expected_pread_data);
  memset(buffer, 0, sizeof buffer);
  CHECK(len <= sizeof buffer);
  result = NaClHostDescPRead(test_file, buffer, len, params->pread_offset);
  if (result != (ssize_t) params->expected_pread_result) {
    fprintf(stderr,
            "BasicPermChecks: pread failed, got %"NACL_PRIdS", expected %"
            NACL_PRIuS" bytes\n",
            result, params->expected_pread_result);
    return 0;
  }
  if (params->expected_pread_result > 0 &&
      0 != memcmp(params->expected_pread_data, buffer, len)) {
    fprintf(stderr,
            "BasicPermChecks: pread result: %.*s\n"
            "              expected output: %.*s\n",
            (int) len, buffer,
            (int) len, quote + params->pread_offset);
    return 0;
  }
  if (0 != params->seq_read_bytes2) {
    /*
     * Make sure that the read pointer did not change.
     */
    memset(buffer, 0, sizeof buffer);
    CHECK(params->seq_read_bytes2 <= sizeof buffer);
    result = NaClHostDescRead(test_file, buffer, params->seq_read_bytes2);
    if (result != (ssize_t) params->seq_read_bytes2) {
      fprintf(stderr,
              "BasicPermChecks: second sequential read, got %"NACL_PRIdS
              ", expected %"NACL_PRIuS" bytes\n",
              result, params->seq_read_bytes2);
      return 0;
    }
    if (0 != memcmp(quote + params->seq_read_bytes1, buffer,
                    params->seq_read_bytes2)) {
      fprintf(stderr,
              "BasicPermChecks: second sequential read result differs\n");
      fprintf(stderr, "got: %.*s\n", (int) params->seq_read_bytes1, buffer);
      return 0;
    }
  }
  /*
   * Now try to write.
   */
  if (NULL != params->pwrite_data) {
    len = strlen(params->pwrite_data);
    result = NaClHostDescPWrite(test_file, params->pwrite_data, len,
                                params->pwrite_offset);
    if (result != params->expected_pwrite_result) {
      fprintf(stderr, "BasicPermChecks: pwrite failed, got %"NACL_PRIdS
              ", expected %"NACL_PRIdS"\n",
              result, params->expected_pwrite_result);
      return 0;
    }
    if (result == (ssize_t) len) {
      /* re-read by seek/sequential read and check data, using ro_view */
      seek_result = NaClHostDescSeek(ro_view, params->pwrite_offset, 0);
      ASSERT_EQ(params->pwrite_offset, seek_result);
      memset(buffer, 0, sizeof buffer);
      CHECK(len <= sizeof buffer);
      result = NaClHostDescRead(ro_view, buffer, len);
      if (result != (ssize_t) len) {
        fprintf(stderr, "BasicPermChecks: pwrite verification read failed\n");
        fprintf(stderr, " got %"NACL_PRIdS", expected %"NACL_PRIuS"\n",
                result, len);
        return 0;
      }
      if (0 != memcmp(buffer, params->pwrite_data, len)) {
        fprintf(stderr, "BasicPermChecks: pwrite verification data mismatch\n");
        fprintf(stderr,
                "     got %.*s\n"
                "expected %.*s\n",
                (int) len, buffer,
                (int) len, params->pwrite_data);
        return 0;
      }
    }
  }
  return 1;
}