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 * shm must have NACL_ABI_MAP_SHARED in flags, and all calls through
149 * this API must supply a start_addr, so NACL_ABI_MAP_FIXED is
152 if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
154 ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
157 return -NACL_ABI_EINVAL;
159 if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
161 ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
162 " but start_addr is NULL\n"));
164 /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */
167 * prot must not contain bits other than PROT_{READ|WRITE|EXEC}.
169 if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
172 "NaClDescImcShmMap: prot has other bits than"
173 " PROT_{READ|WRITE|EXEC}\n");
174 return -NACL_ABI_EINVAL;
177 * Map from NACL_ABI_ prot and flags bits to IMC library flags,
178 * which will later map back into posix-style prot/flags on *x
179 * boxen, and to MapViewOfFileEx arguments on Windows.
182 if (NACL_ABI_PROT_READ & prot) {
183 nacl_imc_prot |= NACL_PROT_READ;
185 if (NACL_ABI_PROT_WRITE & prot) {
186 nacl_imc_prot |= NACL_PROT_WRITE;
188 if (NACL_ABI_PROT_EXEC & prot) {
189 nacl_imc_prot |= NACL_PROT_EXEC;
191 nacl_imc_flags = NACL_MAP_SHARED;
192 if (0 == (NACL_ABI_MAP_FIXED & flags)) {
193 /* start_addr is a hint, and we just ignore the hint... */
194 if (!NaClFindAddressSpace(&addr, len)) {
195 NaClLog(1, "NaClDescImcShmMap: no address space?!?\n");
196 return -NACL_ABI_ENOMEM;
198 start_addr = (void *) addr;
200 nacl_imc_flags |= NACL_MAP_FIXED;
202 tmp_off64 = offset + len;
203 /* just NaClRoundAllocPage, but in 64 bits */
204 tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1)
205 & ~(uint64_t) (NACL_MAP_PAGESIZE - 1));
206 if (tmp_off64 > INT32_MAX) {
208 "NaClDescImcShmMap: total offset exceeds 32-bits\n");
209 return -NACL_ABI_EOVERFLOW;
212 result = NaClMap(effp,
219 if (NACL_MAP_FAILED == result) {
220 return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
222 if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
224 ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
227 return (uintptr_t) start_addr;
231 static int NaClDescImcShmUnmapUnsafe(struct NaClDesc *vself,
238 UNREFERENCED_PARAMETER(vself);
240 retval = -NACL_ABI_EINVAL;
242 for (addr = (uintptr_t) start_addr, end_addr = addr + len;
244 addr += NACL_MAP_PAGESIZE) {
248 * On windows, we must unmap "properly", since overmapping will
249 * not tear down existing page mappings.
251 status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
253 NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
263 static int NaClDescImcShmFstat(struct NaClDesc *vself,
264 struct nacl_abi_stat *stbp) {
265 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
267 if (self->size > INT32_MAX) {
268 return -NACL_ABI_EOVERFLOW;
271 stbp->nacl_abi_st_dev = 0;
272 stbp->nacl_abi_st_ino = 0x6c43614e;
273 stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
276 stbp->nacl_abi_st_nlink = 1;
277 stbp->nacl_abi_st_uid = -1;
278 stbp->nacl_abi_st_gid = -1;
279 stbp->nacl_abi_st_rdev = 0;
280 stbp->nacl_abi_st_size = (nacl_abi_off_t) self->size;
281 stbp->nacl_abi_st_blksize = 0;
282 stbp->nacl_abi_st_blocks = 0;
283 stbp->nacl_abi_st_atime = 0;
284 stbp->nacl_abi_st_mtime = 0;
285 stbp->nacl_abi_st_ctime = 0;
290 static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
293 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
296 rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
300 *nbytes += sizeof self->size;
306 static int NaClDescImcShmExternalize(struct NaClDesc *vself,
307 struct NaClDescXferState *xfer) {
308 struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
311 rv = NaClDescExternalize(vself, xfer);
315 *xfer->next_handle++ = self->h;
316 memcpy(xfer->next_byte, &self->size, sizeof self->size);
317 xfer->next_byte += sizeof self->size;
321 static struct NaClDescVtbl const kNaClDescImcShmVtbl = {
327 NaClDescImcShmUnmapUnsafe,
329 NACL_DESC_UNMAP_NOT_IMPLEMENTED
331 NaClDescReadNotImplemented,
332 NaClDescWriteNotImplemented,
333 NaClDescSeekNotImplemented,
334 NaClDescPReadNotImplemented,
335 NaClDescPWriteNotImplemented,
337 NaClDescGetdentsNotImplemented,
338 NaClDescImcShmExternalizeSize,
339 NaClDescImcShmExternalize,
340 NaClDescLockNotImplemented,
341 NaClDescTryLockNotImplemented,
342 NaClDescUnlockNotImplemented,
343 NaClDescWaitNotImplemented,
344 NaClDescTimedWaitAbsNotImplemented,
345 NaClDescSignalNotImplemented,
346 NaClDescBroadcastNotImplemented,
347 NaClDescSendMsgNotImplemented,
348 NaClDescRecvMsgNotImplemented,
349 NaClDescLowLevelSendMsgNotImplemented,
350 NaClDescLowLevelRecvMsgNotImplemented,
351 NaClDescConnectAddrNotImplemented,
352 NaClDescAcceptConnNotImplemented,
353 NaClDescPostNotImplemented,
354 NaClDescSemWaitNotImplemented,
355 NaClDescGetValueNotImplemented,
360 NaClDescIsattyNotImplemented,
364 int NaClDescImcShmInternalize(struct NaClDesc **out_desc,
365 struct NaClDescXferState *xfer,
366 struct NaClDescQuotaInterface *quota_interface) {
368 struct NaClDescImcShm *ndisp;
372 UNREFERENCED_PARAMETER(quota_interface);
375 ndisp = malloc(sizeof *ndisp);
377 rv = -NACL_ABI_ENOMEM;
380 if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
383 rv = -NACL_ABI_ENOMEM;
387 if (xfer->next_handle == xfer->handle_buffer_end) {
391 if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
396 h = *xfer->next_handle;
397 *xfer->next_handle++ = NACL_INVALID_HANDLE;
398 memcpy(&hsize, xfer->next_byte, sizeof hsize);
399 xfer->next_byte += sizeof hsize;
401 if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
406 *out_desc = (struct NaClDesc *) ndisp;
411 NaClDescSafeUnref((struct NaClDesc *) ndisp);