2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Service Runtime. Transferrable shared memory objects.
36 #include "native_client/include/portability.h"
37 #include "native_client/include/nacl_platform.h"
42 #include "native_client/service_runtime/nacl_desc_imc_shm.h"
44 #include "native_client/service_runtime/internal_errno.h"
45 #include "native_client/service_runtime/nacl_config.h"
46 #include "native_client/service_runtime/nacl_desc_base.h"
47 #include "native_client/service_runtime/nacl_desc_effector.h"
48 #include "native_client/service_runtime/nacl_desc_io.h"
49 #include "native_client/service_runtime/nacl_log.h"
50 #include "native_client/service_runtime/nacl_sync_checked.h"
52 #include "native_client/service_runtime/include/sys/errno.h"
53 #include "native_client/service_runtime/include/sys/mman.h"
54 #include "native_client/service_runtime/include/sys/stat.h"
56 #include "native_client/intermodule_comm/nacl_imc_c.h"
59 * This file contains the implementation of the NaClDescImcShm
60 * subclass of NaClDesc.
62 * NaClDescImcShm is the subclass that wraps IMC shm descriptors.
65 int NaClDescImcShmCtor(struct NaClDescImcShm
*self
,
69 struct NaClDesc
*basep
= (struct NaClDesc
*) self
;
72 * off_t is signed, but size_t are not; historically size_t is for
73 * sizeof and similar, and off_t is also used for stat structure
74 * st_size member. This runtime test detects large object sizes
75 * that are silently converted to negative values.
77 basep
->vtbl
= (struct NaClDescVtbl
*) NULL
;
82 if (!NaClDescCtor(basep
)) {
87 basep
->vtbl
= &kNaClDescImcShmVtbl
;
91 void NaClDescImcShmDtor(struct NaClDesc
*vself
)
93 struct NaClDescImcShm
*self
= (struct NaClDescImcShm
*) vself
;
96 self
->h
= NACL_INVALID_HANDLE
;
97 vself
->vtbl
= (struct NaClDescVtbl
*) NULL
;
101 int NaClDescImcShmMap(struct NaClDesc
*vself
,
102 struct NaClDescEffector
*effp
,
109 struct NaClDescImcShm
*self
= (struct NaClDescImcShm
*) vself
;
120 * prot must be not be PROT_NONE nor contain other than PROT_{READ|WRITE}
122 if (NACL_ABI_PROT_NONE
== prot
) {
123 NaClLog(LOG_INFO
, "NaClDescImcShmMap: PROT_NONE not supported\n");
124 return -NACL_ABI_EINVAL
;
126 if (0 != (~(NACL_ABI_PROT_READ
| NACL_ABI_PROT_WRITE
) & prot
)) {
128 "NaClDescImcShmMap: prot has other bits than PROT_{READ|WRITE}\n");
129 return -NACL_ABI_EINVAL
;
132 * Map from NACL_ABI_ prot and flags bits to IMC library flags,
133 * which will later map back into posix-style prot/flags on *x
134 * boxen, and to MapViewOfFileEx arguments on Windows.
137 if (NACL_ABI_PROT_READ
& prot
) {
138 nacl_prot
|= NACL_PROT_READ
;
140 if (NACL_ABI_PROT_WRITE
& prot
) {
141 nacl_prot
|= NACL_PROT_WRITE
;
143 nacl_flags
= NACL_MAP_SHARED
| NACL_MAP_FIXED
;
146 * For *x, we just map with MAP_FIXED and the kernel takes care of
147 * atomically unmapping any existing memory. For Windows, we must
148 * unmap existing memory first, which creates a race condition,
149 * where some other innocent thread puts some other memory into the
150 * hole, and that memory becomes vulnerable to attack by the
151 * untrusted NaCl application.
153 * For now, abort the process. We will need to figure out how to
154 * re-architect this code to do the address space move, since it is
155 * deep surgery and we'll need to ensure that all threads have
156 * stopped and any addresses derived from the old address space
157 * would not be on any thread's call stack, i.e., stop the thread in
158 * user space or before entering real service runtime code. This
159 * means that no application thread may be indefinitely blocked
160 * performing a service call in the service runtime, since otherwise
161 * there is no way for us to stop all threads.
163 * TODO: We will probably return an internal error code
164 * -NACL_ABI_E_MOVE_ADDRESS_SPACE to ask the caller to do the address space
167 for (addr
= (uintptr_t) start_addr
, end_addr
= addr
+ len
, tmp_off
= offset
;
169 addr
+= NACL_MAP_PAGESIZE
, tmp_off
+= NACL_MAP_PAGESIZE
) {
172 * Minimize the time between the unmap and the map for the same
173 * page: we interleave the unmap and map for the pages, rather
174 * than do all the unmap first and then do all of the map
178 (rv
= (*effp
->vtbl
->UnmapMemory
)(effp
,
180 NACL_MAP_PAGESIZE
))) {
182 ("NaClDescImcShmMap: error %d --"
183 " could not unmap 0x%08"PRIxPTR
", length 0x%x\n"),
189 result
= NaClMap((void *) addr
, NACL_MAP_PAGESIZE
, nacl_prot
, nacl_flags
,
191 if (NACL_MAP_FAILED
== result
) {
192 return -NACL_ABI_E_MOVE_ADDRESS_SPACE
;
194 if (result
!= (void *) addr
) {
196 ("NaClDescImcShmMap: NACL_MAP_FIXED but"
197 " got 0x%08"PRIxPTR
" instead of 0x%08"PRIxPTR
"\n"),
198 (uintptr_t) result
, addr
);
201 return (int) start_addr
;
204 int NaClDescImcShmUnmapCommon(struct NaClDesc
*vself
,
205 struct NaClDescEffector
*effp
,
214 for (addr
= (uintptr_t) start_addr
, end_addr
= addr
+ len
;
216 addr
+= NACL_MAP_PAGESIZE
) {
218 * Do the unmap "properly" through NaClUnmap, in case that the IMC
219 * library is changed to do some bookkeeping.
221 status
= NaClUnmap((void *) addr
, NACL_MAP_PAGESIZE
);
224 NaClLog(LOG_FATAL
, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
225 return -NACL_ABI_EINVAL
;
227 /* there's still a race condition */
229 if (NaClIsNegErrno((*effp
->vtbl
->MapAnonymousMemory
)(effp
,
233 NaClLog(LOG_ERROR
, "NaClDescImcShmUnmapCommon: could not fill hole\n");
234 return -NACL_ABI_E_MOVE_ADDRESS_SPACE
;
241 int NaClDescImcShmUnmapUnsafe(struct NaClDesc
*vself
,
242 struct NaClDescEffector
*effp
,
246 return NaClDescImcShmUnmapCommon(vself
, effp
, start_addr
, len
, 0);
249 int NaClDescImcShmUnmap(struct NaClDesc
*vself
,
250 struct NaClDescEffector
*effp
,
254 return NaClDescImcShmUnmapCommon(vself
, effp
, start_addr
, len
, 1);
257 int NaClDescImcShmFstat(struct NaClDesc
*vself
,
258 struct NaClDescEffector
*effp
,
259 struct nacl_abi_stat
*stbp
)
261 struct NaClDescImcShm
*self
= (struct NaClDescImcShm
*) vself
;
263 stbp
->nacl_abi_st_dev
= 0;
264 stbp
->nacl_abi_st_ino
= 0x6c43614e;
265 stbp
->nacl_abi_st_mode
= NACL_ABI_S_IFREG
| NACL_ABI_S_IRWXU
;
266 stbp
->nacl_abi_st_nlink
= 1;
267 stbp
->nacl_abi_st_uid
= -1;
268 stbp
->nacl_abi_st_gid
= -1;
269 stbp
->nacl_abi_st_rdev
= 0;
270 stbp
->nacl_abi_st_size
= self
->size
; /* the only real reason for fstat */
271 stbp
->nacl_abi_st_blksize
= 0;
272 stbp
->nacl_abi_st_blocks
= 0;
273 stbp
->nacl_abi_st_atime
= 0;
274 stbp
->nacl_abi_st_mtime
= 0;
275 stbp
->nacl_abi_st_ctime
= 0;
280 int NaClDescImcShmClose(struct NaClDesc
*vself
,
281 struct NaClDescEffector
*effp
)
283 NaClDescUnref(vself
);
287 int NaClDescImcShmExternalizeSize(struct NaClDesc
*vself
,
291 struct NaClDescImcShm
*self
= (struct NaClDescImcShm
*) vself
;
293 *nbytes
= sizeof self
->size
;
299 int NaClDescImcShmExternalize(struct NaClDesc
*vself
,
300 struct NaClDescXferState
*xfer
)
302 struct NaClDescImcShm
*self
= (struct NaClDescImcShm
*) vself
;
304 *xfer
->next_handle
++ = self
->h
;
305 memcpy(xfer
->next_byte
, &self
->size
, sizeof self
->size
);
306 xfer
->next_byte
+= sizeof self
->size
;
310 struct NaClDescVtbl
const kNaClDescImcShmVtbl
= {
313 NaClDescImcShmUnmapUnsafe
,
315 NaClDescReadNotImplemented
,
316 NaClDescWriteNotImplemented
,
317 NaClDescSeekNotImplemented
,
318 NaClDescIoctlNotImplemented
,
321 NaClDescGetdentsNotImplemented
,
323 NaClDescImcShmExternalizeSize
,
324 NaClDescImcShmExternalize
,
325 NaClDescLockNotImplemented
,
326 NaClDescTryLockNotImplemented
,
327 NaClDescUnlockNotImplemented
,
328 NaClDescWaitNotImplemented
,
329 NaClDescTimedWaitAbsNotImplemented
,
330 NaClDescSignalNotImplemented
,
331 NaClDescBroadcastNotImplemented
,
332 NaClDescSendMsgNotImplemented
,
333 NaClDescRecvMsgNotImplemented
,
334 NaClDescConnectAddrNotImplemented
,
335 NaClDescAcceptConnNotImplemented
,
336 NaClDescPostNotImplemented
,
337 NaClDescSemWaitNotImplemented
,
338 NaClDescGetValueNotImplemented
,
341 int NaClDescImcShmInternalize(struct NaClDesc
**baseptr
,
342 struct NaClDescXferState
*xfer
)
345 struct NaClDescImcShm
*ndisp
;
352 if (xfer
->next_handle
== xfer
->handle_buffer_end
) {
356 if (xfer
->next_byte
+ sizeof ndisp
->size
> xfer
->byte_buffer_end
) {
361 ndisp
= malloc(sizeof *ndisp
);
363 rv
= -NACL_ABI_ENOMEM
;
367 h
= *xfer
->next_handle
;
368 *xfer
->next_handle
++ = NACL_INVALID_HANDLE
;
369 memcpy(&hsize
, xfer
->next_byte
, sizeof hsize
);
370 xfer
->next_byte
+= sizeof hsize
;
372 NaClDescImcShmCtor(ndisp
, h
, hsize
);
374 *baseptr
= (struct NaClDesc
*) ndisp
;