Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / desc / nacl_desc_imc_shm.c
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                                       nacl_off64_t           size) {
51   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   if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
60     return 0;
61   }
62   self->h = h;
63   self->size = size;
64   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescImcShmVtbl;
65   return 1;
66 }
67
68 int NaClDescImcShmCtor(struct NaClDescImcShm  *self,
69                        NaClHandle             h,
70                        nacl_off64_t           size) {
71   struct NaClDesc *basep = (struct NaClDesc *) self;
72   int rv;
73
74   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
75
76   if (!NaClDescCtor(basep)) {
77     return 0;
78   }
79   rv = NaClDescImcShmSubclassCtor(self, h, size);
80   if (!rv) {
81     /* NaClDescImcShm construction failed, still a NaClDesc object */
82     (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
83   }
84   (*NACL_VTBL(NaClDesc, basep)->SetFlags)(basep, NACL_ABI_O_RDWR);
85   return 1;
86 }
87
88 int NaClDescImcShmAllocCtor(struct NaClDescImcShm  *self,
89                             nacl_off64_t           size,
90                             int                    executable) {
91   NaClHandle h;
92   int        rv;
93
94   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             size, size);
99     return 0;
100   }
101   h = NaClCreateMemoryObject((size_t) size, executable);
102   if (NACL_INVALID_HANDLE == h) {
103     return 0;
104   }
105   if (0 == (rv = NaClDescImcShmCtor(self, h, size))) {
106     (void) NaClClose(h);
107   }
108   return rv;
109 }
110
111 struct NaClDesc *NaClDescImcShmMake(NaClHandle handle, nacl_off64_t size) {
112   struct NaClDescImcShm *desc = malloc(sizeof(*desc));
113   if (NULL == desc) {
114     return NULL;
115   }
116   if (!NaClDescImcShmCtor(desc, handle, size)) {
117     free(desc);
118     return NULL;
119   }
120   return &desc->base;
121 }
122
123 static void NaClDescImcShmDtor(struct NaClRefCount *vself) {
124   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
125
126   (void) NaClClose(self->h);
127   self->h = NACL_INVALID_HANDLE;
128   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
129   (*vself->vtbl->Dtor)(vself);
130 }
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                                    nacl_off64_t            offset) {
139   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   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   if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
157     NaClLog(LOG_INFO,
158             ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
159              " flags 0x%x\n"),
160             flags);
161     return -NACL_ABI_EINVAL;
162   }
163   if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
164     NaClLog(LOG_INFO,
165             ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
166              " but start_addr is NULL\n"));
167   }
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   if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
174             & prot)) {
175     NaClLog(LOG_INFO,
176             "NaClDescImcShmMap: prot has other bits than"
177             " PROT_{READ|WRITE|EXEC}\n");
178     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   nacl_imc_prot = 0;
186   if (NACL_ABI_PROT_READ & prot) {
187     nacl_imc_prot |= NACL_PROT_READ;
188   }
189   if (NACL_ABI_PROT_WRITE & prot) {
190     nacl_imc_prot |= NACL_PROT_WRITE;
191   }
192   if (NACL_ABI_PROT_EXEC & prot) {
193     nacl_imc_prot |= NACL_PROT_EXEC;
194   }
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;
201     }
202     start_addr = (void *) addr;
203   }
204   nacl_imc_flags |= NACL_MAP_FIXED;
205
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) {
211     NaClLog(LOG_INFO,
212             "NaClDescImcShmMap: total offset exceeds 32-bits\n");
213     return -NACL_ABI_EOVERFLOW;
214   }
215
216   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   if (NACL_MAP_FAILED == result) {
224     return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
225   }
226   if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
227     NaClLog(LOG_FATAL,
228             ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
229             result, start_addr);
230   }
231   return (uintptr_t) start_addr;
232 }
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 static int NaClDescImcShmFstat(struct NaClDesc         *vself,
268                                struct nacl_abi_stat    *stbp) {
269   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
270
271   if (self->size > INT32_MAX) {
272     return -NACL_ABI_EOVERFLOW;
273   }
274
275   stbp->nacl_abi_st_dev = 0;
276   stbp->nacl_abi_st_ino = 0x6c43614e;
277   stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
278                             NACL_ABI_S_IRUSR |
279                             NACL_ABI_S_IWUSR);
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;
290
291   return 0;
292 }
293
294 static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
295                                          size_t          *nbytes,
296                                          size_t          *nhandles) {
297   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
298   int rv;
299
300   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
301   if (0 != rv) {
302     return rv;
303   }
304   *nbytes += sizeof self->size;
305   *nhandles += 1;
306
307   return 0;
308 }
309
310 static int NaClDescImcShmExternalize(struct NaClDesc           *vself,
311                                      struct NaClDescXferState  *xfer) {
312   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
313   int rv;
314
315   rv = NaClDescExternalize(vself, xfer);
316   if (0 != rv) {
317     return rv;
318   }
319   *xfer->next_handle++ = self->h;
320   memcpy(xfer->next_byte, &self->size, sizeof self->size);
321   xfer->next_byte += sizeof self->size;
322   return 0;
323 }
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 int NaClDescImcShmInternalize(struct NaClDesc               **out_desc,
369                               struct NaClDescXferState      *xfer,
370                               struct NaClDescQuotaInterface *quota_interface) {
371   int                   rv;
372   struct NaClDescImcShm *ndisp;
373   NaClHandle            h;
374   nacl_off64_t          hsize;
375
376   UNREFERENCED_PARAMETER(quota_interface);
377   rv = -NACL_ABI_EIO;
378
379   ndisp = malloc(sizeof *ndisp);
380   if (NULL == ndisp) {
381     rv = -NACL_ABI_ENOMEM;
382     goto cleanup;
383   }
384   if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
385     free(ndisp);
386     ndisp = NULL;
387     rv = -NACL_ABI_ENOMEM;
388     goto cleanup;
389   }
390
391   if (xfer->next_handle == xfer->handle_buffer_end) {
392     rv = -NACL_ABI_EIO;
393     goto cleanup;
394   }
395   if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
396     rv = -NACL_ABI_EIO;
397     goto cleanup;
398   }
399
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;
404
405   if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
406     rv = -NACL_ABI_EIO;
407     goto cleanup;
408   }
409
410   *out_desc = (struct NaClDesc *) ndisp;
411   rv = 0;
412
413 cleanup:
414   if (rv < 0) {
415     NaClDescSafeUnref((struct NaClDesc *) ndisp);
416   }
417   return rv;
418 }