1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <sys/mman.h>
7
8#include "base/logging.h"
9#include "components/nacl/loader/nonsfi/irt_interfaces.h"
10#include "components/nacl/loader/nonsfi/irt_util.h"
11#include "native_client/src/trusted/service_runtime/include/machine/_types.h"
12#include "native_client/src/trusted/service_runtime/include/sys/mman.h"
13
14namespace nacl {
15namespace nonsfi {
16namespace {
17
18int NaClProtToProt(int nacl_prot) {
19  int prot = 0;
20  if ((nacl_prot & NACL_ABI_PROT_MASK) == NACL_ABI_PROT_NONE)
21    return PROT_NONE;
22
23  if (nacl_prot & NACL_ABI_PROT_READ)
24    prot |= PROT_READ;
25  if (nacl_prot & NACL_ABI_PROT_WRITE)
26    prot |= PROT_WRITE;
27  if (nacl_prot & NACL_ABI_PROT_EXEC)
28    prot |= PROT_EXEC;
29  return prot;
30}
31
32int NaClFlagsToFlags(int nacl_flags) {
33  int flags = 0;
34
35  if (nacl_flags & NACL_ABI_MAP_SHARED)
36    flags |= MAP_SHARED;
37  if (nacl_flags & NACL_ABI_MAP_PRIVATE)
38    flags |= MAP_PRIVATE;
39  if (nacl_flags & NACL_ABI_MAP_FIXED)
40    flags |= MAP_FIXED;
41
42  // Note: NACL_ABI_MAP_ANON is an alias of NACL_ABI_MAP_ANONYMOUS.
43  if (nacl_flags & NACL_ABI_MAP_ANONYMOUS)
44    flags |= MAP_ANONYMOUS;
45  return flags;
46}
47
48int IrtMMap(void** addr, size_t len, int prot, int flags,
49            int fd, nacl_abi_off_t off) {
50  const int host_prot = NaClProtToProt(prot);
51  // On Chrome OS, mmap can fail if PROT_EXEC is set in |host_prot|,
52  // but mprotect will allow changing the permissions later.
53  // This is because Chrome OS mounts writable filesystems with "noexec".
54  void* result = mmap(
55      *addr, len, host_prot & ~PROT_EXEC, NaClFlagsToFlags(flags), fd, off);
56  if (result == MAP_FAILED)
57    return errno;
58  if (host_prot & PROT_EXEC) {
59    if (mprotect(result, len, host_prot) != 0) {
60      // This aborts here because it cannot easily undo the mmap() call.
61      PLOG(FATAL) << "IrtMMap: mprotect to turn on PROT_EXEC failed.";
62    }
63  }
64
65  *addr = result;
66  return 0;
67}
68
69int IrtMUnmap(void* addr, size_t len) {
70  return CheckError(munmap(addr, len));
71}
72
73int IrtMProtect(void* addr, size_t len, int prot) {
74  return CheckError(mprotect(addr, len, NaClProtToProt(prot)));
75}
76
77}  // namespace
78
79// For mmap, the argument types should be nacl_abi_off_t rather than off_t.
80// However, the definition of nacl_irt_memory uses the host type off_t, so here
81// we need to cast it.
82const nacl_irt_memory kIrtMemory = {
83  reinterpret_cast<int(*)(void**, size_t, int, int, int, off_t)>(IrtMMap),
84  IrtMUnmap,
85  IrtMProtect,
86};
87
88}  // namespace nonsfi
89}  // namespace nacl
90