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.  I/O Descriptor / Handle abstraction.  Memory
9  * mapping using descriptors.
10  */
11 
12 #include "native_client/src/include/build_config.h"
13 #include "native_client/src/include/portability.h"
14 
15 #if NACL_WINDOWS
16 # include "io.h"
17 # include "fcntl.h"
18 #endif
19 
20 #include <string.h>
21 
22 #include "native_client/src/include/nacl_macros.h"
23 #include "native_client/src/shared/imc/nacl_imc_c.h"
24 #include "native_client/src/trusted/desc/nacl_desc_base.h"
25 #include "native_client/src/trusted/desc/nacl_desc_effector.h"
26 #include "native_client/src/trusted/desc/nacl_desc_io.h"
27 
28 #include "native_client/src/shared/platform/nacl_find_addrsp.h"
29 #include "native_client/src/shared/platform/nacl_host_desc.h"
30 #include "native_client/src/shared/platform/nacl_log.h"
31 
32 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
34 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
35 #include "native_client/src/trusted/service_runtime/internal_errno.h"
36 #include "native_client/src/trusted/service_runtime/nacl_config.h"
37 
38 
39 /*
40  * This file contains the implementation for the NaClIoDesc subclass
41  * of NaClDesc.
42  *
43  * NaClDescIoDesc is the subclass that wraps host-OS descriptors
44  * provided by NaClHostDesc (which gives an OS-independent abstraction
45  * for host-OS descriptors).
46  */
47 
48 static struct NaClDescVtbl const kNaClDescIoDescVtbl;  /* fwd */
49 
NaClDescIoDescSubclassCtor(struct NaClDescIoDesc * self,struct NaClHostDesc * hd)50 static int NaClDescIoDescSubclassCtor(struct NaClDescIoDesc  *self,
51                                       struct NaClHostDesc    *hd) {
52   struct NaClDesc *basep = (struct NaClDesc *) self;
53 
54   self->hd = hd;
55   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescIoDescVtbl;
56   return 1;
57 }
58 
59 /*
60  * Takes ownership of hd, will close in Dtor.
61  */
NaClDescIoDescCtor(struct NaClDescIoDesc * self,struct NaClHostDesc * hd)62 int NaClDescIoDescCtor(struct NaClDescIoDesc  *self,
63                        struct NaClHostDesc    *hd) {
64   struct NaClDesc *basep = (struct NaClDesc *) self;
65   int rv;
66 
67   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
68   if (!NaClDescCtor(basep)) {
69     return 0;
70   }
71   rv = NaClDescIoDescSubclassCtor(self, hd);
72   if (!rv) {
73     (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
74   }
75   (*NACL_VTBL(NaClDesc, basep)->
76    SetFlags)(basep, hd->flags & NACL_ABI_O_ACCMODE);
77   return rv;
78 }
79 
NaClDescIoDescDtor(struct NaClRefCount * vself)80 static void NaClDescIoDescDtor(struct NaClRefCount *vself) {
81   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
82 
83   NaClLog(4, "NaClDescIoDescDtor(0x%08"NACL_PRIxPTR").\n",
84           (uintptr_t) vself);
85   if (0 != NaClHostDescClose(self->hd)) {
86     NaClLog(LOG_FATAL, "NaClDescIoDescDtor: NaClHostDescClose failed\n");
87   }
88   free(self->hd);
89   self->hd = NULL;
90   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
91   (*vself->vtbl->Dtor)(vself);
92 }
93 
NaClDescIoDescMake(struct NaClHostDesc * nhdp)94 struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp) {
95   struct NaClDescIoDesc *ndp;
96 
97   ndp = malloc(sizeof *ndp);
98   if (NULL == ndp) {
99     NaClLog(LOG_FATAL,
100             "NaClDescIoDescMake: no memory for 0x%08"NACL_PRIxPTR"\n",
101             (uintptr_t) nhdp);
102   }
103   if (!NaClDescIoDescCtor(ndp, nhdp)) {
104     NaClLog(LOG_FATAL,
105             ("NaClDescIoDescMake:"
106              " NaClDescIoDescCtor(0x%08"NACL_PRIxPTR",0x%08"NACL_PRIxPTR
107              ") failed\n"),
108             (uintptr_t) ndp,
109             (uintptr_t) nhdp);
110   }
111   return ndp;
112 }
113 
NaClDescIoMakeFromHandle(NaClHandle handle,int flags)114 struct NaClDesc *NaClDescIoMakeFromHandle(NaClHandle handle, int flags) {
115   int posix_d;
116 
117 #if NACL_WINDOWS
118   int win_flags = 0;
119 
120   switch (flags & NACL_ABI_O_ACCMODE) {
121     case NACL_ABI_O_RDONLY:
122       win_flags = _O_RDONLY | _O_BINARY;
123       break;
124     case NACL_ABI_O_WRONLY:
125       win_flags = _O_WRONLY | _O_BINARY;
126       break;
127     case NACL_ABI_O_RDWR:
128       win_flags = _O_RDWR | _O_BINARY;
129       break;
130   }
131   if (0 == win_flags) {
132     return NULL;
133   }
134   posix_d = _open_osfhandle((intptr_t) handle, win_flags);
135   if (-1 == posix_d) {
136     return NULL;
137   }
138 #else
139   posix_d = handle;
140 #endif
141   return NaClDescIoDescFromDescAllocCtor(posix_d, flags);
142 }
143 
NaClDescIoDescFromDescAllocCtor(int desc,int flags)144 struct NaClDesc *NaClDescIoDescFromDescAllocCtor(int desc,
145                                                  int flags) {
146   struct NaClHostDesc *nhdp;
147 
148   nhdp = NaClHostDescPosixMake(desc, flags);
149   if (NULL == nhdp) {
150     /*
151      * BUG: In Windows, we leak posix_d representation in the POSIX
152      * layer, since caller will continue to own |handle| on a failure
153      * return, but we cannot close |posix_d| without implicitly
154      * invoking CloseHandle on |handle|.
155      */
156     return NULL;
157   }
158   return (struct NaClDesc *) NaClDescIoDescMake(nhdp);
159 }
160 
NaClDescIoDescOpen(char const * path,int mode,int perms)161 struct NaClDescIoDesc *NaClDescIoDescOpen(char const *path,
162                                           int mode,
163                                           int perms) {
164   struct NaClHostDesc *nhdp;
165 
166   nhdp = malloc(sizeof *nhdp);
167   if (NULL == nhdp) {
168     NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
169   }
170   if (0 != NaClHostDescOpen(nhdp, path, mode, perms)) {
171     NaClLog(4,
172             "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
173             path);
174     return NULL;
175   }
176   return NaClDescIoDescMake(nhdp);
177 }
178 
NaClDescIoDescMap(struct NaClDesc * vself,struct NaClDescEffector * effp,void * start_addr,size_t len,int prot,int flags,nacl_off64_t offset)179 static uintptr_t NaClDescIoDescMap(struct NaClDesc         *vself,
180                                    struct NaClDescEffector *effp,
181                                    void                    *start_addr,
182                                    size_t                  len,
183                                    int                     prot,
184                                    int                     flags,
185                                    nacl_off64_t            offset) {
186   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
187   uintptr_t             status;
188   uintptr_t             addr;
189 
190   /*
191    * prot must only contain NACL_ABI_PROT_* flags.
192    */
193   if (0 != (~(NACL_ABI_PROT_MASK) & prot)) {
194     NaClLog(LOG_INFO,
195             ("NaClDescIoDescMap: prot has other bits"
196              " than NACL_ABI_PROT_{READ|WRITE|EXEC}\n"));
197     return (uintptr_t) -NACL_ABI_EINVAL;
198   }
199 
200   if (0 == (NACL_ABI_MAP_FIXED & flags)) {
201     if (!NaClFindAddressSpace(&addr, len)) {
202       NaClLog(1, "NaClDescIoDescMap: no address space?\n");
203       return (uintptr_t) -NACL_ABI_ENOMEM;
204     }
205     NaClLog(4,
206             "NaClDescIoDescMap: NaClFindAddressSpace"
207             " returned 0x%"NACL_PRIxPTR"\n",
208             addr);
209     start_addr = (void *) addr;
210   }
211   flags |= NACL_ABI_MAP_FIXED;
212 
213   status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
214                            effp,
215                            (void *) start_addr,
216                            len,
217                            prot,
218                            flags,
219                            offset);
220   NaClLog(4, "NaClDescIoDescMap returning %"NACL_PRIxPTR"\n", status);
221   return status;
222 }
223 
NaClDescIoDescMapAnon(struct NaClDescEffector * effp,void * start_addr,size_t len,int prot,int flags,nacl_off64_t offset)224 uintptr_t NaClDescIoDescMapAnon(struct NaClDescEffector *effp,
225                                 void                    *start_addr,
226                                 size_t                  len,
227                                 int                     prot,
228                                 int                     flags,
229                                 nacl_off64_t            offset) {
230   return NaClDescIoDescMap((struct NaClDesc *) NULL, effp, start_addr, len,
231                            prot, flags, offset);
232 }
233 
NaClDescIoDescRead(struct NaClDesc * vself,void * buf,size_t len)234 static ssize_t NaClDescIoDescRead(struct NaClDesc          *vself,
235                                   void                     *buf,
236                                   size_t                   len) {
237   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
238 
239   return NaClHostDescRead(self->hd, buf, len);
240 }
241 
NaClDescIoDescWrite(struct NaClDesc * vself,void const * buf,size_t len)242 static ssize_t NaClDescIoDescWrite(struct NaClDesc         *vself,
243                                    void const              *buf,
244                                    size_t                  len) {
245   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
246 
247   return NaClHostDescWrite(self->hd, buf, len);
248 }
249 
NaClDescIoDescSeek(struct NaClDesc * vself,nacl_off64_t offset,int whence)250 static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc          *vself,
251                                        nacl_off64_t             offset,
252                                        int                      whence) {
253   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
254 
255   return NaClHostDescSeek(self->hd, offset, whence);
256 }
257 
NaClDescIoDescPRead(struct NaClDesc * vself,void * buf,size_t len,nacl_off64_t offset)258 static ssize_t NaClDescIoDescPRead(struct NaClDesc *vself,
259                                    void *buf,
260                                    size_t len,
261                                    nacl_off64_t offset) {
262   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
263 
264   return NaClHostDescPRead(self->hd, buf, len, offset);
265 }
266 
NaClDescIoDescPWrite(struct NaClDesc * vself,void const * buf,size_t len,nacl_off64_t offset)267 static ssize_t NaClDescIoDescPWrite(struct NaClDesc *vself,
268                                     void const *buf,
269                                     size_t len,
270                                     nacl_off64_t offset) {
271   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
272 
273   return NaClHostDescPWrite(self->hd, buf, len, offset);
274 }
275 
NaClDescIoDescFstat(struct NaClDesc * vself,struct nacl_abi_stat * statbuf)276 static int NaClDescIoDescFstat(struct NaClDesc         *vself,
277                                struct nacl_abi_stat    *statbuf) {
278   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
279   int                   rv;
280   nacl_host_stat_t      hstatbuf;
281 
282   rv = NaClHostDescFstat(self->hd, &hstatbuf);
283   if (0 != rv) {
284     return rv;
285   }
286   return NaClAbiStatHostDescStatXlateCtor(statbuf, &hstatbuf);
287 }
288 
NaClDescIoDescFchmod(struct NaClDesc * vself,int mode)289 static int NaClDescIoDescFchmod(struct NaClDesc *vself,
290                                 int             mode) {
291   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
292 
293   return NaClHostDescFchmod(self->hd, mode);
294 }
295 
NaClDescIoDescFsync(struct NaClDesc * vself)296 static int NaClDescIoDescFsync(struct NaClDesc *vself) {
297   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
298 
299   return NaClHostDescFsync(self->hd);
300 }
301 
NaClDescIoDescFdatasync(struct NaClDesc * vself)302 static int NaClDescIoDescFdatasync(struct NaClDesc *vself) {
303   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
304 
305   return NaClHostDescFdatasync(self->hd);
306 }
307 
NaClDescIoDescFtruncate(struct NaClDesc * vself,nacl_abi_off_t length)308 static int NaClDescIoDescFtruncate(struct NaClDesc  *vself,
309                                    nacl_abi_off_t   length) {
310   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
311 
312   return NaClHostDescFtruncate(self->hd, length);
313 }
314 
NaClDescIoIsatty(struct NaClDesc * vself)315 static int32_t NaClDescIoIsatty(struct NaClDesc *vself) {
316   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
317 
318   return NaClHostDescIsatty(self->hd);
319 }
320 
NaClDescIoDescExternalizeSize(struct NaClDesc * vself,size_t * nbytes,size_t * nhandles)321 static int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
322                                          size_t          *nbytes,
323                                          size_t          *nhandles) {
324   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
325   int rv;
326 
327   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
328   if (0 != rv) {
329     return rv;
330   }
331   *nhandles += 1;
332   *nbytes += sizeof self->hd->flags;
333   /* For Windows, we do not need to send flProtect since it is a cache */
334   return 0;
335 }
336 
NaClDescIoDescExternalize(struct NaClDesc * vself,struct NaClDescXferState * xfer)337 static int NaClDescIoDescExternalize(struct NaClDesc           *vself,
338                                      struct NaClDescXferState  *xfer) {
339   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
340   int rv;
341 #if NACL_WINDOWS
342   HANDLE  h;
343 #endif
344 
345   rv = NaClDescExternalize(vself, xfer);
346   if (0 != rv) {
347     return rv;
348   }
349 
350   memcpy(xfer->next_byte, &self->hd->flags, sizeof self->hd->flags);
351   xfer->next_byte += sizeof self->hd->flags;
352 #if NACL_WINDOWS
353   h = (HANDLE) _get_osfhandle(self->hd->d);
354   *xfer->next_handle++ = (NaClHandle) h;
355 #else
356   *xfer->next_handle++ = self->hd->d;
357 #endif
358   return 0;
359 }
360 
361 static struct NaClDescVtbl const kNaClDescIoDescVtbl = {
362   {
363     NaClDescIoDescDtor,
364   },
365   NaClDescIoDescMap,
366   NaClDescIoDescRead,
367   NaClDescIoDescWrite,
368   NaClDescIoDescSeek,
369   NaClDescIoDescPRead,
370   NaClDescIoDescPWrite,
371   NaClDescIoDescFstat,
372   NaClDescFchdirNotImplemented,
373   NaClDescIoDescFchmod,
374   NaClDescIoDescFsync,
375   NaClDescIoDescFdatasync,
376   NaClDescIoDescFtruncate,
377   NaClDescGetdentsNotImplemented,
378   NaClDescIoDescExternalizeSize,
379   NaClDescIoDescExternalize,
380   NaClDescLockNotImplemented,
381   NaClDescTryLockNotImplemented,
382   NaClDescUnlockNotImplemented,
383   NaClDescWaitNotImplemented,
384   NaClDescTimedWaitAbsNotImplemented,
385   NaClDescSignalNotImplemented,
386   NaClDescBroadcastNotImplemented,
387   NaClDescSendMsgNotImplemented,
388   NaClDescRecvMsgNotImplemented,
389   NaClDescLowLevelSendMsgNotImplemented,
390   NaClDescLowLevelRecvMsgNotImplemented,
391   NaClDescConnectAddrNotImplemented,
392   NaClDescAcceptConnNotImplemented,
393   NaClDescPostNotImplemented,
394   NaClDescSemWaitNotImplemented,
395   NaClDescGetValueNotImplemented,
396   NaClDescSetMetadata,
397   NaClDescGetMetadata,
398   NaClDescSetFlags,
399   NaClDescGetFlags,
400   NaClDescIoIsatty,
401   NACL_DESC_HOST_IO,
402 };
403 
404 /* set *out_desc to struct NaClDescIo * output */
NaClDescIoInternalize(struct NaClDesc ** out_desc,struct NaClDescXferState * xfer)405 int NaClDescIoInternalize(struct NaClDesc               **out_desc,
406                           struct NaClDescXferState      *xfer) {
407   int                   rv;
408   NaClHandle            h;
409   int                   d;
410   int                   flags;
411   struct NaClHostDesc   *nhdp;
412   struct NaClDescIoDesc *ndidp;
413 
414   rv = -NACL_ABI_EIO;  /* catch-all */
415   h = NACL_INVALID_HANDLE;
416   nhdp = NULL;
417   ndidp = NULL;
418 
419   nhdp = malloc(sizeof *nhdp);
420   if (NULL == nhdp) {
421     rv = -NACL_ABI_ENOMEM;
422     goto cleanup;
423   }
424   ndidp = malloc(sizeof *ndidp);
425   if (!ndidp) {
426     rv = -NACL_ABI_ENOMEM;
427     goto cleanup;
428   }
429   if (!NaClDescInternalizeCtor((struct NaClDesc *) ndidp, xfer)) {
430     rv = -NACL_ABI_ENOMEM;
431     goto cleanup;
432   }
433   if (xfer->next_handle == xfer->handle_buffer_end ||
434       xfer->next_byte + sizeof ndidp->hd->flags > xfer->byte_buffer_end) {
435     rv = -NACL_ABI_EIO;
436     goto cleanup_ndidp_dtor;
437   }
438 
439   NACL_COMPILE_TIME_ASSERT(sizeof flags == sizeof(ndidp->hd->flags));
440   memcpy(&flags, xfer->next_byte, sizeof flags);
441   xfer->next_byte += sizeof flags;
442 
443   h = *xfer->next_handle;
444   *xfer->next_handle++ = NACL_INVALID_HANDLE;
445 #if NACL_WINDOWS
446   if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
447     rv = -NACL_ABI_EIO;
448     goto cleanup_ndidp_dtor;
449   }
450 #else
451   d = h;
452 #endif
453   /*
454    * We mark it as read/write, but don't really know for sure until we
455    * try to make those syscalls (in which case we'd get EBADF).
456    */
457   if ((rv = NaClHostDescPosixTake(nhdp, d, flags)) < 0) {
458     goto cleanup_ndidp_dtor;
459   }
460   h = NACL_INVALID_HANDLE;  /* nhdp took ownership of h */
461 
462   if (!NaClDescIoDescSubclassCtor(ndidp, nhdp)) {
463     rv = -NACL_ABI_ENOMEM;
464     goto cleanup_nhdp_dtor;
465   }
466   /*
467    * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
468    */
469   *out_desc = (struct NaClDesc *) ndidp;
470   rv = 0;
471  cleanup_nhdp_dtor:
472   if (rv < 0) {
473     if (0 != NaClHostDescClose(nhdp)) {
474       NaClLog(LOG_FATAL, "NaClDescIoInternalize: NaClHostDescClose failed\n");
475     }
476   }
477  cleanup_ndidp_dtor:
478   if (rv < 0) {
479     NaClDescSafeUnref((struct NaClDesc *) ndidp);
480     ndidp = NULL;
481   }
482  cleanup:
483   if (rv < 0) {
484     free(nhdp);
485     free(ndidp);
486     if (NACL_INVALID_HANDLE != h) {
487       (void) NaClClose(h);
488     }
489   }
490   return rv;
491 }
492