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 : /*
8 : * NaCl Service Runtime. Transferrable shared memory objects.
9 : */
10 :
11 : #include "native_client/src/include/portability.h"
12 : #include "native_client/src/include/nacl_platform.h"
13 :
14 : #include <stdlib.h>
15 : #include <string.h>
16 :
17 : #include "native_client/src/shared/imc/nacl_imc_c.h"
18 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
19 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
20 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
21 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
22 :
23 : #include "native_client/src/shared/platform/nacl_find_addrsp.h"
24 : #include "native_client/src/shared/platform/nacl_host_desc.h"
25 : #include "native_client/src/shared/platform/nacl_log.h"
26 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 :
28 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
29 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
30 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
31 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
32 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
33 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
34 :
35 : #ifndef SIZE_T_MAX
36 : # define SIZE_T_MAX (~(size_t) 0)
37 : #endif
38 :
39 : /*
40 : * This file contains the implementation of the NaClDescImcShm
41 : * subclass of NaClDesc.
42 : *
43 : * NaClDescImcShm is the subclass that wraps IMC shm descriptors.
44 : */
45 :
46 : static struct NaClDescVtbl const kNaClDescImcShmVtbl; /* fwd */
47 :
48 284 : static int NaClDescImcShmSubclassCtor(struct NaClDescImcShm *self,
49 284 : NaClHandle h,
50 284 : nacl_off64_t size) {
51 284 : struct NaClDesc *basep = (struct NaClDesc *) self;
52 :
53 : /*
54 : * off_t is signed, but size_t are not; historically size_t is for
55 : * sizeof and similar, and off_t is also used for stat structure
56 : * st_size member. This runtime test detects large object sizes
57 : * that are silently converted to negative values.
58 : */
59 568 : if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
60 0 : return 0;
61 : }
62 284 : self->h = h;
63 284 : self->size = size;
64 284 : basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescImcShmVtbl;
65 284 : return 1;
66 284 : }
67 :
68 284 : int NaClDescImcShmCtor(struct NaClDescImcShm *self,
69 284 : NaClHandle h,
70 284 : nacl_off64_t size) {
71 284 : struct NaClDesc *basep = (struct NaClDesc *) self;
72 284 : int rv;
73 :
74 284 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
75 :
76 284 : if (!NaClDescCtor(basep)) {
77 0 : return 0;
78 : }
79 284 : rv = NaClDescImcShmSubclassCtor(self, h, size);
80 284 : if (!rv) {
81 : /* NaClDescImcShm construction failed, still a NaClDesc object */
82 0 : (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
83 0 : }
84 284 : (*NACL_VTBL(NaClDesc, basep)->SetFlags)(basep, NACL_ABI_O_RDWR);
85 284 : return 1;
86 284 : }
87 :
88 284 : int NaClDescImcShmAllocCtor(struct NaClDescImcShm *self,
89 284 : nacl_off64_t size,
90 284 : int executable) {
91 284 : NaClHandle h;
92 284 : int rv;
93 :
94 568 : if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
95 0 : NaClLog(4,
96 : "NaClDescImcShmAllocCtor: requested size 0x%08"NACL_PRIx64
97 : " (0x%08"NACL_PRId64") too large\n",
98 : size, size);
99 0 : return 0;
100 : }
101 284 : h = NaClCreateMemoryObject((size_t) size, executable);
102 284 : if (NACL_INVALID_HANDLE == h) {
103 0 : return 0;
104 : }
105 284 : if (0 == (rv = NaClDescImcShmCtor(self, h, size))) {
106 0 : (void) NaClClose(h);
107 0 : }
108 284 : return rv;
109 284 : }
110 :
111 0 : struct NaClDesc *NaClDescImcShmMake(NaClHandle handle, nacl_off64_t size) {
112 0 : struct NaClDescImcShm *desc = malloc(sizeof(*desc));
113 0 : if (NULL == desc) {
114 0 : return NULL;
115 : }
116 0 : if (!NaClDescImcShmCtor(desc, handle, size)) {
117 0 : free(desc);
118 0 : return NULL;
119 : }
120 0 : return &desc->base;
121 0 : }
122 :
123 7 : static void NaClDescImcShmDtor(struct NaClRefCount *vself) {
124 7 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
125 :
126 7 : (void) NaClClose(self->h);
127 7 : self->h = NACL_INVALID_HANDLE;
128 7 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
129 7 : (*vself->vtbl->Dtor)(vself);
130 7 : }
131 :
132 377 : static uintptr_t NaClDescImcShmMap(struct NaClDesc *vself,
133 377 : struct NaClDescEffector *effp,
134 377 : void *start_addr,
135 377 : size_t len,
136 377 : int prot,
137 377 : int flags,
138 377 : nacl_off64_t offset) {
139 377 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
140 :
141 377 : int nacl_imc_prot;
142 377 : int nacl_imc_flags;
143 377 : uintptr_t addr;
144 377 : void *result;
145 377 : nacl_off64_t tmp_off64;
146 :
147 377 : NaClLog(4,
148 : "NaClDescImcShmMmap(,,0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS","
149 : "0x%x,0x%x,0x%08"NACL_PRIxNACL_OFF64")\n",
150 : (uintptr_t) start_addr, len, prot, flags, offset);
151 : /*
152 : * shm must have NACL_ABI_MAP_SHARED in flags, and all calls through
153 : * this API must supply a start_addr, so NACL_ABI_MAP_FIXED is
154 : * assumed.
155 : */
156 377 : if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
157 0 : NaClLog(LOG_INFO,
158 : ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
159 : " flags 0x%x\n"),
160 : flags);
161 0 : return -NACL_ABI_EINVAL;
162 : }
163 672 : if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
164 0 : NaClLog(LOG_INFO,
165 : ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
166 : " but start_addr is NULL\n"));
167 0 : }
168 : /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */
169 :
170 : /*
171 : * prot must not contain bits other than PROT_{READ|WRITE|EXEC}.
172 : */
173 377 : if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
174 : & prot)) {
175 0 : NaClLog(LOG_INFO,
176 : "NaClDescImcShmMap: prot has other bits than"
177 : " PROT_{READ|WRITE|EXEC}\n");
178 0 : return -NACL_ABI_EINVAL;
179 : }
180 : /*
181 : * Map from NACL_ABI_ prot and flags bits to IMC library flags,
182 : * which will later map back into posix-style prot/flags on *x
183 : * boxen, and to MapViewOfFileEx arguments on Windows.
184 : */
185 377 : nacl_imc_prot = 0;
186 377 : if (NACL_ABI_PROT_READ & prot) {
187 118 : nacl_imc_prot |= NACL_PROT_READ;
188 118 : }
189 377 : if (NACL_ABI_PROT_WRITE & prot) {
190 116 : nacl_imc_prot |= NACL_PROT_WRITE;
191 116 : }
192 377 : if (NACL_ABI_PROT_EXEC & prot) {
193 0 : nacl_imc_prot |= NACL_PROT_EXEC;
194 0 : }
195 377 : nacl_imc_flags = NACL_MAP_SHARED;
196 377 : if (0 == (NACL_ABI_MAP_FIXED & flags)) {
197 : /* start_addr is a hint, and we just ignore the hint... */
198 82 : if (!NaClFindAddressSpace(&addr, len)) {
199 0 : NaClLog(1, "NaClDescImcShmMap: no address space?!?\n");
200 0 : return -NACL_ABI_ENOMEM;
201 : }
202 82 : start_addr = (void *) addr;
203 82 : }
204 377 : nacl_imc_flags |= NACL_MAP_FIXED;
205 :
206 377 : tmp_off64 = offset + len;
207 : /* just NaClRoundAllocPage, but in 64 bits */
208 377 : tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1)
209 : & ~(uint64_t) (NACL_MAP_PAGESIZE - 1));
210 377 : if (tmp_off64 > INT32_MAX) {
211 0 : NaClLog(LOG_INFO,
212 : "NaClDescImcShmMap: total offset exceeds 32-bits\n");
213 0 : return -NACL_ABI_EOVERFLOW;
214 : }
215 :
216 377 : result = NaClMap(effp,
217 : (void *) start_addr,
218 : len,
219 : nacl_imc_prot,
220 : nacl_imc_flags,
221 : self->h,
222 : (off_t) offset);
223 377 : if (NACL_MAP_FAILED == result) {
224 0 : return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
225 : }
226 672 : if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
227 0 : NaClLog(LOG_FATAL,
228 : ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
229 : result, start_addr);
230 0 : }
231 377 : return (uintptr_t) start_addr;
232 377 : }
233 :
234 : #if NACL_WINDOWS
235 : static int NaClDescImcShmUnmapUnsafe(struct NaClDesc *vself,
236 : void *start_addr,
237 : size_t len) {
238 : int retval;
239 : uintptr_t addr;
240 : uintptr_t end_addr;
241 :
242 : UNREFERENCED_PARAMETER(vself);
243 :
244 : retval = -NACL_ABI_EINVAL;
245 :
246 : for (addr = (uintptr_t) start_addr, end_addr = addr + len;
247 : addr < end_addr;
248 : addr += NACL_MAP_PAGESIZE) {
249 : int status;
250 :
251 : /*
252 : * On windows, we must unmap "properly", since overmapping will
253 : * not tear down existing page mappings.
254 : */
255 : status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
256 : if (0 != status) {
257 : NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
258 : goto done;
259 : }
260 : }
261 : retval = 0;
262 : done:
263 : return retval;
264 : }
265 : #endif
266 :
267 44 : static int NaClDescImcShmFstat(struct NaClDesc *vself,
268 44 : struct nacl_abi_stat *stbp) {
269 44 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
270 :
271 44 : if (self->size > INT32_MAX) {
272 0 : return -NACL_ABI_EOVERFLOW;
273 : }
274 :
275 44 : stbp->nacl_abi_st_dev = 0;
276 44 : stbp->nacl_abi_st_ino = 0x6c43614e;
277 44 : stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
278 : NACL_ABI_S_IRUSR |
279 : NACL_ABI_S_IWUSR);
280 44 : stbp->nacl_abi_st_nlink = 1;
281 44 : stbp->nacl_abi_st_uid = -1;
282 44 : stbp->nacl_abi_st_gid = -1;
283 44 : stbp->nacl_abi_st_rdev = 0;
284 44 : stbp->nacl_abi_st_size = (nacl_abi_off_t) self->size;
285 44 : stbp->nacl_abi_st_blksize = 0;
286 44 : stbp->nacl_abi_st_blocks = 0;
287 44 : stbp->nacl_abi_st_atime = 0;
288 44 : stbp->nacl_abi_st_mtime = 0;
289 44 : stbp->nacl_abi_st_ctime = 0;
290 :
291 44 : return 0;
292 44 : }
293 :
294 0 : static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
295 0 : size_t *nbytes,
296 0 : size_t *nhandles) {
297 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
298 0 : int rv;
299 :
300 0 : rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
301 0 : if (0 != rv) {
302 0 : return rv;
303 : }
304 0 : *nbytes += sizeof self->size;
305 0 : *nhandles += 1;
306 :
307 0 : return 0;
308 0 : }
309 :
310 0 : static int NaClDescImcShmExternalize(struct NaClDesc *vself,
311 0 : struct NaClDescXferState *xfer) {
312 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
313 0 : int rv;
314 :
315 0 : rv = NaClDescExternalize(vself, xfer);
316 0 : if (0 != rv) {
317 0 : return rv;
318 : }
319 0 : *xfer->next_handle++ = self->h;
320 0 : memcpy(xfer->next_byte, &self->size, sizeof self->size);
321 0 : xfer->next_byte += sizeof self->size;
322 0 : return 0;
323 0 : }
324 :
325 : static struct NaClDescVtbl const kNaClDescImcShmVtbl = {
326 : {
327 : NaClDescImcShmDtor,
328 : },
329 : NaClDescImcShmMap,
330 : #if NACL_WINDOWS
331 : NaClDescImcShmUnmapUnsafe,
332 : #else
333 : NACL_DESC_UNMAP_NOT_IMPLEMENTED
334 : #endif
335 : NaClDescReadNotImplemented,
336 : NaClDescWriteNotImplemented,
337 : NaClDescSeekNotImplemented,
338 : NaClDescPReadNotImplemented,
339 : NaClDescPWriteNotImplemented,
340 : NaClDescImcShmFstat,
341 : NaClDescGetdentsNotImplemented,
342 : NaClDescImcShmExternalizeSize,
343 : NaClDescImcShmExternalize,
344 : NaClDescLockNotImplemented,
345 : NaClDescTryLockNotImplemented,
346 : NaClDescUnlockNotImplemented,
347 : NaClDescWaitNotImplemented,
348 : NaClDescTimedWaitAbsNotImplemented,
349 : NaClDescSignalNotImplemented,
350 : NaClDescBroadcastNotImplemented,
351 : NaClDescSendMsgNotImplemented,
352 : NaClDescRecvMsgNotImplemented,
353 : NaClDescLowLevelSendMsgNotImplemented,
354 : NaClDescLowLevelRecvMsgNotImplemented,
355 : NaClDescConnectAddrNotImplemented,
356 : NaClDescAcceptConnNotImplemented,
357 : NaClDescPostNotImplemented,
358 : NaClDescSemWaitNotImplemented,
359 : NaClDescGetValueNotImplemented,
360 : NaClDescSetMetadata,
361 : NaClDescGetMetadata,
362 : NaClDescSetFlags,
363 : NaClDescGetFlags,
364 : NaClDescIsattyNotImplemented,
365 : NACL_DESC_SHM,
366 : };
367 :
368 0 : int NaClDescImcShmInternalize(struct NaClDesc **out_desc,
369 0 : struct NaClDescXferState *xfer,
370 0 : struct NaClDescQuotaInterface *quota_interface) {
371 0 : int rv;
372 0 : struct NaClDescImcShm *ndisp;
373 0 : NaClHandle h;
374 0 : nacl_off64_t hsize;
375 :
376 0 : UNREFERENCED_PARAMETER(quota_interface);
377 0 : rv = -NACL_ABI_EIO;
378 :
379 0 : ndisp = malloc(sizeof *ndisp);
380 0 : if (NULL == ndisp) {
381 0 : rv = -NACL_ABI_ENOMEM;
382 0 : goto cleanup;
383 : }
384 0 : if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
385 0 : free(ndisp);
386 0 : ndisp = NULL;
387 0 : rv = -NACL_ABI_ENOMEM;
388 0 : goto cleanup;
389 : }
390 :
391 0 : if (xfer->next_handle == xfer->handle_buffer_end) {
392 0 : rv = -NACL_ABI_EIO;
393 0 : goto cleanup;
394 : }
395 0 : if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
396 0 : rv = -NACL_ABI_EIO;
397 0 : goto cleanup;
398 : }
399 :
400 0 : h = *xfer->next_handle;
401 0 : *xfer->next_handle++ = NACL_INVALID_HANDLE;
402 0 : memcpy(&hsize, xfer->next_byte, sizeof hsize);
403 0 : xfer->next_byte += sizeof hsize;
404 :
405 0 : if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
406 0 : rv = -NACL_ABI_EIO;
407 0 : goto cleanup;
408 : }
409 :
410 0 : *out_desc = (struct NaClDesc *) ndisp;
411 0 : rv = 0;
412 :
413 : cleanup:
414 0 : if (rv < 0) {
415 0 : NaClDescSafeUnref((struct NaClDesc *) ndisp);
416 0 : }
417 0 : return rv;
418 : }
|