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 : static int NaClDescImcShmSubclassCtor(struct NaClDescImcShm *self,
49 : NaClHandle h,
50 0 : nacl_off64_t size) {
51 0 : 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 0 : if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
60 0 : return 0;
61 : }
62 0 : self->h = h;
63 0 : self->size = size;
64 0 : basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescImcShmVtbl;
65 0 : return 1;
66 0 : }
67 :
68 : int NaClDescImcShmCtor(struct NaClDescImcShm *self,
69 : NaClHandle h,
70 0 : nacl_off64_t size) {
71 0 : struct NaClDesc *basep = (struct NaClDesc *) self;
72 : int rv;
73 :
74 0 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
75 :
76 0 : if (!NaClDescCtor(basep)) {
77 0 : return 0;
78 : }
79 0 : rv = NaClDescImcShmSubclassCtor(self, h, size);
80 0 : if (!rv) {
81 : /* NaClDescImcShm construction failed, still a NaClDesc object */
82 0 : (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
83 : }
84 0 : (*NACL_VTBL(NaClDesc, basep)->SetFlags)(basep, NACL_ABI_O_RDWR);
85 0 : return 1;
86 0 : }
87 :
88 : int NaClDescImcShmAllocCtor(struct NaClDescImcShm *self,
89 : nacl_off64_t size,
90 0 : int executable) {
91 : NaClHandle h;
92 : int rv;
93 :
94 0 : if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
95 : NaClLog(4,
96 : "NaClDescImcShmAllocCtor: requested size 0x%08"NACL_PRIx64
97 : " (0x%08"NACL_PRId64") too large\n",
98 0 : size, size);
99 0 : return 0;
100 : }
101 0 : h = NaClCreateMemoryObject((size_t) size, executable);
102 0 : if (NACL_INVALID_HANDLE == h) {
103 0 : return 0;
104 : }
105 0 : if (0 == (rv = NaClDescImcShmCtor(self, h, size))) {
106 0 : (void) NaClClose(h);
107 : }
108 0 : return rv;
109 0 : }
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 0 : static void NaClDescImcShmDtor(struct NaClRefCount *vself) {
124 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
125 :
126 0 : (void) NaClClose(self->h);
127 0 : self->h = NACL_INVALID_HANDLE;
128 0 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
129 0 : (*vself->vtbl->Dtor)(vself);
130 0 : }
131 :
132 : static uintptr_t NaClDescImcShmMap(struct NaClDesc *vself,
133 : struct NaClDescEffector *effp,
134 : void *start_addr,
135 : size_t len,
136 : int prot,
137 : int flags,
138 0 : nacl_off64_t offset) {
139 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
140 :
141 : int nacl_imc_prot;
142 : int nacl_imc_flags;
143 : uintptr_t addr;
144 : void *result;
145 : nacl_off64_t tmp_off64;
146 :
147 : /*
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
150 : * assumed.
151 : */
152 0 : if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
153 : NaClLog(LOG_INFO,
154 : ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
155 : " flags 0x%x\n"),
156 0 : flags);
157 0 : return -NACL_ABI_EINVAL;
158 : }
159 0 : if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
160 : NaClLog(LOG_INFO,
161 : ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
162 0 : " but start_addr is NULL\n"));
163 : }
164 : /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */
165 :
166 : /*
167 : * prot must not contain bits other than PROT_{READ|WRITE|EXEC}.
168 : */
169 : if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
170 0 : & prot)) {
171 : NaClLog(LOG_INFO,
172 : "NaClDescImcShmMap: prot has other bits than"
173 0 : " PROT_{READ|WRITE|EXEC}\n");
174 0 : return -NACL_ABI_EINVAL;
175 : }
176 : /*
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.
180 : */
181 0 : nacl_imc_prot = 0;
182 0 : if (NACL_ABI_PROT_READ & prot) {
183 0 : nacl_imc_prot |= NACL_PROT_READ;
184 : }
185 0 : if (NACL_ABI_PROT_WRITE & prot) {
186 0 : nacl_imc_prot |= NACL_PROT_WRITE;
187 : }
188 0 : if (NACL_ABI_PROT_EXEC & prot) {
189 0 : nacl_imc_prot |= NACL_PROT_EXEC;
190 : }
191 0 : nacl_imc_flags = NACL_MAP_SHARED;
192 0 : if (0 == (NACL_ABI_MAP_FIXED & flags)) {
193 : /* start_addr is a hint, and we just ignore the hint... */
194 0 : if (!NaClFindAddressSpace(&addr, len)) {
195 0 : NaClLog(1, "NaClDescImcShmMap: no address space?!?\n");
196 0 : return -NACL_ABI_ENOMEM;
197 : }
198 0 : start_addr = (void *) addr;
199 : }
200 0 : nacl_imc_flags |= NACL_MAP_FIXED;
201 :
202 0 : tmp_off64 = offset + len;
203 : /* just NaClRoundAllocPage, but in 64 bits */
204 : tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1)
205 0 : & ~(uint64_t) (NACL_MAP_PAGESIZE - 1));
206 0 : if (tmp_off64 > INT32_MAX) {
207 : NaClLog(LOG_INFO,
208 0 : "NaClDescImcShmMap: total offset exceeds 32-bits\n");
209 0 : return -NACL_ABI_EOVERFLOW;
210 : }
211 :
212 : result = NaClMap(effp,
213 : (void *) start_addr,
214 : len,
215 : nacl_imc_prot,
216 : nacl_imc_flags,
217 : self->h,
218 0 : (off_t) offset);
219 0 : if (NACL_MAP_FAILED == result) {
220 0 : return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
221 : }
222 0 : if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
223 : NaClLog(LOG_FATAL,
224 : ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
225 0 : result, start_addr);
226 : }
227 0 : return (uintptr_t) start_addr;
228 0 : }
229 :
230 : #if NACL_WINDOWS
231 : static int NaClDescImcShmUnmapUnsafe(struct NaClDesc *vself,
232 : void *start_addr,
233 0 : size_t len) {
234 : int retval;
235 : uintptr_t addr;
236 : uintptr_t end_addr;
237 :
238 : UNREFERENCED_PARAMETER(vself);
239 :
240 0 : retval = -NACL_ABI_EINVAL;
241 :
242 : for (addr = (uintptr_t) start_addr, end_addr = addr + len;
243 : addr < end_addr;
244 0 : addr += NACL_MAP_PAGESIZE) {
245 : int status;
246 :
247 : /*
248 : * On windows, we must unmap "properly", since overmapping will
249 : * not tear down existing page mappings.
250 : */
251 0 : status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
252 0 : if (0 != status) {
253 0 : NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
254 0 : goto done;
255 : }
256 0 : }
257 0 : retval = 0;
258 : done:
259 0 : return retval;
260 0 : }
261 : #endif
262 :
263 : static int NaClDescImcShmFstat(struct NaClDesc *vself,
264 0 : struct nacl_abi_stat *stbp) {
265 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
266 :
267 0 : if (self->size > INT32_MAX) {
268 0 : return -NACL_ABI_EOVERFLOW;
269 : }
270 :
271 0 : stbp->nacl_abi_st_dev = 0;
272 0 : stbp->nacl_abi_st_ino = 0x6c43614e;
273 : stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
274 : NACL_ABI_S_IRUSR |
275 0 : NACL_ABI_S_IWUSR);
276 0 : stbp->nacl_abi_st_nlink = 1;
277 0 : stbp->nacl_abi_st_uid = -1;
278 0 : stbp->nacl_abi_st_gid = -1;
279 0 : stbp->nacl_abi_st_rdev = 0;
280 0 : stbp->nacl_abi_st_size = (nacl_abi_off_t) self->size;
281 0 : stbp->nacl_abi_st_blksize = 0;
282 0 : stbp->nacl_abi_st_blocks = 0;
283 0 : stbp->nacl_abi_st_atime = 0;
284 0 : stbp->nacl_abi_st_mtime = 0;
285 0 : stbp->nacl_abi_st_ctime = 0;
286 :
287 0 : return 0;
288 0 : }
289 :
290 : static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
291 : size_t *nbytes,
292 0 : size_t *nhandles) {
293 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
294 : int rv;
295 :
296 0 : rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
297 0 : if (0 != rv) {
298 0 : return rv;
299 : }
300 0 : *nbytes += sizeof self->size;
301 0 : *nhandles += 1;
302 :
303 0 : return 0;
304 0 : }
305 :
306 : static int NaClDescImcShmExternalize(struct NaClDesc *vself,
307 0 : struct NaClDescXferState *xfer) {
308 0 : struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself;
309 : int rv;
310 :
311 0 : rv = NaClDescExternalize(vself, xfer);
312 0 : if (0 != rv) {
313 0 : return rv;
314 : }
315 0 : *xfer->next_handle++ = self->h;
316 0 : memcpy(xfer->next_byte, &self->size, sizeof self->size);
317 0 : xfer->next_byte += sizeof self->size;
318 0 : return 0;
319 0 : }
320 :
321 : static struct NaClDescVtbl const kNaClDescImcShmVtbl = {
322 : {
323 : NaClDescImcShmDtor,
324 : },
325 : NaClDescImcShmMap,
326 : #if NACL_WINDOWS
327 : NaClDescImcShmUnmapUnsafe,
328 : #else
329 : NACL_DESC_UNMAP_NOT_IMPLEMENTED
330 : #endif
331 : NaClDescReadNotImplemented,
332 : NaClDescWriteNotImplemented,
333 : NaClDescSeekNotImplemented,
334 : NaClDescPReadNotImplemented,
335 : NaClDescPWriteNotImplemented,
336 : NaClDescImcShmFstat,
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,
356 : NaClDescSetMetadata,
357 : NaClDescGetMetadata,
358 : NaClDescSetFlags,
359 : NaClDescGetFlags,
360 : NaClDescIsattyNotImplemented,
361 : NACL_DESC_SHM,
362 : };
363 :
364 : int NaClDescImcShmInternalize(struct NaClDesc **out_desc,
365 : struct NaClDescXferState *xfer,
366 0 : struct NaClDescQuotaInterface *quota_interface) {
367 : int rv;
368 : struct NaClDescImcShm *ndisp;
369 : NaClHandle h;
370 : nacl_off64_t hsize;
371 :
372 : UNREFERENCED_PARAMETER(quota_interface);
373 0 : rv = -NACL_ABI_EIO;
374 :
375 0 : ndisp = malloc(sizeof *ndisp);
376 0 : if (NULL == ndisp) {
377 0 : rv = -NACL_ABI_ENOMEM;
378 0 : goto cleanup;
379 : }
380 0 : if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
381 0 : free(ndisp);
382 0 : ndisp = NULL;
383 0 : rv = -NACL_ABI_ENOMEM;
384 0 : goto cleanup;
385 : }
386 :
387 0 : if (xfer->next_handle == xfer->handle_buffer_end) {
388 0 : rv = -NACL_ABI_EIO;
389 0 : goto cleanup;
390 : }
391 0 : if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
392 0 : rv = -NACL_ABI_EIO;
393 0 : goto cleanup;
394 : }
395 :
396 0 : h = *xfer->next_handle;
397 0 : *xfer->next_handle++ = NACL_INVALID_HANDLE;
398 0 : memcpy(&hsize, xfer->next_byte, sizeof hsize);
399 0 : xfer->next_byte += sizeof hsize;
400 :
401 0 : if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
402 0 : rv = -NACL_ABI_EIO;
403 0 : goto cleanup;
404 : }
405 :
406 0 : *out_desc = (struct NaClDesc *) ndisp;
407 0 : rv = 0;
408 :
409 : cleanup:
410 0 : if (rv < 0) {
411 0 : NaClDescSafeUnref((struct NaClDesc *) ndisp);
412 : }
413 0 : return rv;
414 0 : }
|