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.
8 * NaCl Service Runtime. Transferrable shared memory objects.
11 #include "native_client/src/include/portability.h"
12 #include "native_client/src/include/nacl_platform.h"
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"
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"
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"
36 # define SIZE_T_MAX (~(size_t) 0)
40 * This file contains the implementation of the NaClDescImcShm
41 * subclass of NaClDesc.
43 * NaClDescImcShm is the subclass that wraps IMC shm descriptors.
46 static struct NaClDescVtbl const kNaClDescImcShmVtbl; /* fwd */
48 static int NaClDescImcShmSubclassCtor(struct NaClDescImcShm *self,
51 struct NaClDesc *basep = (struct NaClDesc *) self;
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.
59 if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
64 basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescImcShmVtbl;
68 int NaClDescImcShmCtor(struct NaClDescImcShm *self,
71 struct NaClDesc *basep = (struct NaClDesc *) self;
74 basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
76 if (!NaClDescCtor(basep)) {
79 rv = NaClDescImcShmSubclassCtor(self, h, size);
81 /* NaClDescImcShm construction failed, still a NaClDesc object */
82 (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
84 (*NACL_VTBL(NaClDesc, basep)->SetFlags)(basep, NACL_ABI_O_RDWR);
88 int NaClDescImcShmAllocCtor(struct NaClDescImcShm *self,
94 if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
96 "NaClDescImcShmAllocCtor: requested size 0x%08"NACL_PRIx64
97 " (0x%08"NACL_PRId64") too large\n",
101 h = NaClCreateMemoryObject((size_t) size, executable);
102 if (NACL_INVALID_HANDLE == h) {
105 if (0 == (rv = NaClDescImcShmCtor(self, h, size))) {
111 struct NaClDesc *NaClDescImcShmMake(NaClHandle handle, nacl_off64_t size) {
112 struct NaClDescImcShm *desc = malloc(sizeof(*desc));
116 if (!NaClDescImcShmCtor(desc, handle, size)) {
123 static void NaClDescImcShmDtor(struct NaClRefCount *vself) {
124 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
126 (void) NaClClose(self->h);
127 self->h = NACL_INVALID_HANDLE;
128 vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
129 (*vself->vtbl->Dtor)(vself);
132 static uintptr_t NaClDescImcShmMap(struct NaClDesc *vself,
133 struct NaClDescEffector *effp,
138 nacl_off64_t offset) {
139 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
145 nacl_off64_t tmp_off64;
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);
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
156 if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
158 ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
161 return -NACL_ABI_EINVAL;
163 if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
165 ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
166 " but start_addr is NULL\n"));
168 /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */
171 * prot must not contain bits other than PROT_{READ|WRITE|EXEC}.
173 if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
176 "NaClDescImcShmMap: prot has other bits than"
177 " PROT_{READ|WRITE|EXEC}\n");
178 return -NACL_ABI_EINVAL;
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.
186 if (NACL_ABI_PROT_READ & prot) {
187 nacl_imc_prot |= NACL_PROT_READ;
189 if (NACL_ABI_PROT_WRITE & prot) {
190 nacl_imc_prot |= NACL_PROT_WRITE;
192 if (NACL_ABI_PROT_EXEC & prot) {
193 nacl_imc_prot |= NACL_PROT_EXEC;
195 nacl_imc_flags = NACL_MAP_SHARED;
196 if (0 == (NACL_ABI_MAP_FIXED & flags)) {
197 /* start_addr is a hint, and we just ignore the hint... */
198 if (!NaClFindAddressSpace(&addr, len)) {
199 NaClLog(1, "NaClDescImcShmMap: no address space?!?\n");
200 return -NACL_ABI_ENOMEM;
202 start_addr = (void *) addr;
204 nacl_imc_flags |= NACL_MAP_FIXED;
206 tmp_off64 = offset + len;
207 /* just NaClRoundAllocPage, but in 64 bits */
208 tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1)
209 & ~(uint64_t) (NACL_MAP_PAGESIZE - 1));
210 if (tmp_off64 > INT32_MAX) {
212 "NaClDescImcShmMap: total offset exceeds 32-bits\n");
213 return -NACL_ABI_EOVERFLOW;
216 result = NaClMap(effp,
223 if (NACL_MAP_FAILED == result) {
224 return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
226 if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
228 ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
231 return (uintptr_t) start_addr;
235 static int NaClDescImcShmUnmapUnsafe(struct NaClDesc *vself,
242 UNREFERENCED_PARAMETER(vself);
244 retval = -NACL_ABI_EINVAL;
246 for (addr = (uintptr_t) start_addr, end_addr = addr + len;
248 addr += NACL_MAP_PAGESIZE) {
252 * On windows, we must unmap "properly", since overmapping will
253 * not tear down existing page mappings.
255 status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
257 NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
267 static int NaClDescImcShmFstat(struct NaClDesc *vself,
268 struct nacl_abi_stat *stbp) {
269 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
271 if (self->size > INT32_MAX) {
272 return -NACL_ABI_EOVERFLOW;
275 stbp->nacl_abi_st_dev = 0;
276 stbp->nacl_abi_st_ino = 0x6c43614e;
277 stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
280 stbp->nacl_abi_st_nlink = 1;
281 stbp->nacl_abi_st_uid = -1;
282 stbp->nacl_abi_st_gid = -1;
283 stbp->nacl_abi_st_rdev = 0;
284 stbp->nacl_abi_st_size = (nacl_abi_off_t) self->size;
285 stbp->nacl_abi_st_blksize = 0;
286 stbp->nacl_abi_st_blocks = 0;
287 stbp->nacl_abi_st_atime = 0;
288 stbp->nacl_abi_st_mtime = 0;
289 stbp->nacl_abi_st_ctime = 0;
294 static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
297 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
300 rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
304 *nbytes += sizeof self->size;
310 static int NaClDescImcShmExternalize(struct NaClDesc *vself,
311 struct NaClDescXferState *xfer) {
312 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
315 rv = NaClDescExternalize(vself, xfer);
319 *xfer->next_handle++ = self->h;
320 memcpy(xfer->next_byte, &self->size, sizeof self->size);
321 xfer->next_byte += sizeof self->size;
325 static struct NaClDescVtbl const kNaClDescImcShmVtbl = {
331 NaClDescImcShmUnmapUnsafe,
333 NACL_DESC_UNMAP_NOT_IMPLEMENTED
335 NaClDescReadNotImplemented,
336 NaClDescWriteNotImplemented,
337 NaClDescSeekNotImplemented,
338 NaClDescPReadNotImplemented,
339 NaClDescPWriteNotImplemented,
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,
364 NaClDescIsattyNotImplemented,
368 int NaClDescImcShmInternalize(struct NaClDesc **out_desc,
369 struct NaClDescXferState *xfer,
370 struct NaClDescQuotaInterface *quota_interface) {
372 struct NaClDescImcShm *ndisp;
376 UNREFERENCED_PARAMETER(quota_interface);
379 ndisp = malloc(sizeof *ndisp);
381 rv = -NACL_ABI_ENOMEM;
384 if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
387 rv = -NACL_ABI_ENOMEM;
391 if (xfer->next_handle == xfer->handle_buffer_end) {
395 if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
400 h = *xfer->next_handle;
401 *xfer->next_handle++ = NACL_INVALID_HANDLE;
402 memcpy(&hsize, xfer->next_byte, sizeof hsize);
403 xfer->next_byte += sizeof hsize;
405 if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
410 *out_desc = (struct NaClDesc *) ndisp;
415 NaClDescSafeUnref((struct NaClDesc *) ndisp);