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 : /*
8 : * NaCl service run-time, list_mappings system call.
9 : */
10 :
11 : #include <stdlib.h>
12 :
13 : #include "native_client/src/trusted/service_runtime/sys_list_mappings.h"
14 :
15 : #include "native_client/src/include/nacl_platform.h"
16 : #include "native_client/src/include/portability_string.h"
17 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
18 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
19 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
20 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
21 : #include "native_client/src/trusted/service_runtime/include/sys/nacl_list_mappings.h"
22 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
23 : #include "native_client/src/trusted/service_runtime/nacl_copy.h"
24 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
25 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
26 :
27 : struct NaClSysListMappingsState {
28 : struct NaClApp *nap;
29 : struct NaClMemMappingInfo *regions;
30 : uint32_t count;
31 : uint32_t capacity;
32 : int out_of_memory;
33 : };
34 :
35 : static const int kStartCapacity = 8;
36 :
37 21 : static void NaClSysListMappingsAdd(struct NaClSysListMappingsState *state,
38 21 : uint32_t start,
39 21 : uint32_t size,
40 21 : uint32_t prot,
41 21 : uint32_t max_prot,
42 21 : uint32_t vmmap_type) {
43 21 : struct NaClMemMappingInfo *info;
44 21 : uint32_t new_capacity;
45 :
46 21 : if (state->out_of_memory) {
47 0 : return;
48 : }
49 21 : if (state->count == state->capacity) {
50 3 : if (state->capacity == 0) {
51 3 : new_capacity = kStartCapacity;
52 3 : } else {
53 0 : new_capacity = state->capacity * 2;
54 0 : if (UINT32_MAX / sizeof(*state->regions) < new_capacity) {
55 : /* state->capacity * sizeof(*state->regions) would overflow. */
56 0 : state->out_of_memory = 1;
57 0 : return;
58 : }
59 : }
60 3 : info = (struct NaClMemMappingInfo *) realloc(
61 : state->regions, new_capacity * sizeof(*state->regions));
62 3 : if (info == NULL) {
63 0 : state->out_of_memory = 1;
64 0 : return;
65 : }
66 3 : state->capacity = new_capacity;
67 3 : state->regions = info;
68 3 : }
69 21 : info = &state->regions[state->count];
70 21 : ++state->count;
71 :
72 63 : memset(info, 0, sizeof(*info));
73 21 : info->start = start;
74 21 : info->size = size;
75 21 : info->prot = prot;
76 21 : info->max_prot = max_prot;
77 21 : info->vmmap_type = vmmap_type;
78 42 : }
79 :
80 39 : static int NaClSysListMappingsOrder(const void *a, const void *b) {
81 39 : const struct NaClMemMappingInfo *am = (const struct NaClMemMappingInfo *) a;
82 39 : const struct NaClMemMappingInfo *bm = (const struct NaClMemMappingInfo *) b;
83 :
84 66 : if (am->start < bm->start) return -1;
85 24 : if (am->start > bm->start) return 1;
86 0 : return 0;
87 39 : }
88 :
89 24 : static void NaClSysListMappingsVisit(void *statev,
90 24 : struct NaClVmmapEntry *vmep) {
91 24 : struct NaClSysListMappingsState *state =
92 : (struct NaClSysListMappingsState *) statev;
93 :
94 24 : uint32_t start = (uint32_t) (vmep->page_num << NACL_PAGESHIFT);
95 24 : uint32_t size = (uint32_t) (vmep->npages << NACL_PAGESHIFT);
96 24 : uint32_t max_prot = NaClVmmapEntryMaxProt(vmep);
97 : /* Skip dynamic code region as its parts will be visited separately. */
98 27 : if (state->nap->dynamic_text_start == start &&
99 : state->nap->dynamic_text_end == start + size) {
100 3 : return;
101 : }
102 21 : NaClSysListMappingsAdd(
103 : state,
104 : /* start= */ start,
105 : /* size= */ size,
106 : /* prot= */ vmep->prot,
107 : /* max_prot= */ max_prot,
108 : /* vmmap_type= */ vmep->desc != NULL);
109 45 : }
110 :
111 0 : static void NaClSysListMappingsDyncodeVisit(void *statev,
112 0 : struct NaClDynamicRegion *rg) {
113 0 : struct NaClSysListMappingsState *state =
114 : (struct NaClSysListMappingsState *) statev;
115 :
116 0 : NaClSysListMappingsAdd(
117 : state,
118 0 : /* start= */ (uint32_t) NaClSysToUser(state->nap, rg->start),
119 : /* size= */ (uint32_t) rg->size,
120 : /* prot= */ NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
121 : /* max_prot= */ NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
122 : /* vmmap_type= */ 0);
123 0 : }
124 :
125 3 : int32_t NaClSysListMappings(struct NaClAppThread *natp,
126 3 : uint32_t regions,
127 3 : uint32_t count) {
128 3 : struct NaClApp *nap = natp->nap;
129 3 : struct NaClSysListMappingsState state;
130 :
131 3 : if (!nap->enable_list_mappings) {
132 0 : return -NACL_ABI_ENOSYS;
133 : }
134 :
135 3 : state.nap = nap;
136 3 : state.count = 0;
137 3 : state.capacity = 0;
138 3 : state.out_of_memory = 0;
139 3 : state.regions = NULL;
140 :
141 3 : NaClXMutexLock(&nap->mu);
142 3 : NaClVmmapVisit(&nap->mem_map, NaClSysListMappingsVisit, &state);
143 3 : NaClDyncodeVisit(nap, NaClSysListMappingsDyncodeVisit, &state);
144 3 : NaClXMutexUnlock(&nap->mu);
145 :
146 3 : if (state.out_of_memory) {
147 0 : NaClLog(3, "Out of memory while gathering memory map\n");
148 0 : return -NACL_ABI_ENOMEM;
149 : }
150 :
151 3 : qsort(state.regions, state.count, sizeof(*state.regions),
152 : NaClSysListMappingsOrder);
153 :
154 3 : if (state.count < count) {
155 3 : count = state.count;
156 3 : }
157 3 : if (!NaClCopyOutToUser(nap, regions, state.regions,
158 : sizeof(*state.regions) * count)) {
159 1 : NaClLog(3, "Illegal address for ListMappings at 0x%08"NACL_PRIxPTR"\n",
160 : (uintptr_t) regions);
161 1 : return -NACL_ABI_EFAULT;
162 : }
163 2 : free(state.regions);
164 :
165 2 : return state.count;
166 3 : }
|