Upstream version 9.38.198.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   /*
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   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             flags);
157     return -NACL_ABI_EINVAL;
158   }
159   if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
160     NaClLog(LOG_INFO,
161             ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
162              " 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             & prot)) {
171     NaClLog(LOG_INFO,
172             "NaClDescImcShmMap: prot has other bits than"
173             " PROT_{READ|WRITE|EXEC}\n");
174     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   nacl_imc_prot = 0;
182   if (NACL_ABI_PROT_READ & prot) {
183     nacl_imc_prot |= NACL_PROT_READ;
184   }
185   if (NACL_ABI_PROT_WRITE & prot) {
186     nacl_imc_prot |= NACL_PROT_WRITE;
187   }
188   if (NACL_ABI_PROT_EXEC & prot) {
189     nacl_imc_prot |= NACL_PROT_EXEC;
190   }
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;
197     }
198     start_addr = (void *) addr;
199   }
200   nacl_imc_flags |= NACL_MAP_FIXED;
201
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) {
207     NaClLog(LOG_INFO,
208             "NaClDescImcShmMap: total offset exceeds 32-bits\n");
209     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                    (off_t) offset);
219   if (NACL_MAP_FAILED == result) {
220     return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
221   }
222   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             result, start_addr);
226   }
227   return (uintptr_t) start_addr;
228 }
229
230 #if NACL_WINDOWS
231 static int NaClDescImcShmUnmapUnsafe(struct NaClDesc  *vself,
232                                      void             *start_addr,
233                                      size_t           len) {
234   int       retval;
235   uintptr_t addr;
236   uintptr_t end_addr;
237
238   UNREFERENCED_PARAMETER(vself);
239
240   retval = -NACL_ABI_EINVAL;
241
242   for (addr = (uintptr_t) start_addr, end_addr = addr + len;
243        addr < end_addr;
244        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     status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
252     if (0 != status) {
253       NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
254       goto done;
255     }
256   }
257   retval = 0;
258 done:
259   return retval;
260 }
261 #endif
262
263 static int NaClDescImcShmFstat(struct NaClDesc         *vself,
264                                struct nacl_abi_stat    *stbp) {
265   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
266
267   if (self->size > INT32_MAX) {
268     return -NACL_ABI_EOVERFLOW;
269   }
270
271   stbp->nacl_abi_st_dev = 0;
272   stbp->nacl_abi_st_ino = 0x6c43614e;
273   stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
274                             NACL_ABI_S_IRUSR |
275                             NACL_ABI_S_IWUSR);
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;
286
287   return 0;
288 }
289
290 static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
291                                          size_t          *nbytes,
292                                          size_t          *nhandles) {
293   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
294   int rv;
295
296   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
297   if (0 != rv) {
298     return rv;
299   }
300   *nbytes += sizeof self->size;
301   *nhandles += 1;
302
303   return 0;
304 }
305
306 static int NaClDescImcShmExternalize(struct NaClDesc           *vself,
307                                      struct NaClDescXferState  *xfer) {
308   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
309   int rv;
310
311   rv = NaClDescExternalize(vself, xfer);
312   if (0 != rv) {
313     return rv;
314   }
315   *xfer->next_handle++ = self->h;
316   memcpy(xfer->next_byte, &self->size, sizeof self->size);
317   xfer->next_byte += sizeof self->size;
318   return 0;
319 }
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                               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   rv = -NACL_ABI_EIO;
374
375   ndisp = malloc(sizeof *ndisp);
376   if (NULL == ndisp) {
377     rv = -NACL_ABI_ENOMEM;
378     goto cleanup;
379   }
380   if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
381     free(ndisp);
382     ndisp = NULL;
383     rv = -NACL_ABI_ENOMEM;
384     goto cleanup;
385   }
386
387   if (xfer->next_handle == xfer->handle_buffer_end) {
388     rv = -NACL_ABI_EIO;
389     goto cleanup;
390   }
391   if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
392     rv = -NACL_ABI_EIO;
393     goto cleanup;
394   }
395
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;
400
401   if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
402     rv = -NACL_ABI_EIO;
403     goto cleanup;
404   }
405
406   *out_desc = (struct NaClDesc *) ndisp;
407   rv = 0;
408
409 cleanup:
410   if (rv < 0) {
411     NaClDescSafeUnref((struct NaClDesc *) ndisp);
412   }
413   return rv;
414 }