14202231c48812665515cdb7fb8adb85b9cf23cb
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sys_fdio.c
1 /*
2  * Copyright (c) 2013 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 #include "native_client/src/trusted/service_runtime/sys_fdio.h"
8
9 #include <string.h>
10
11 #include "native_client/src/trusted/desc/nacl_desc_base.h"
12 #include "native_client/src/trusted/desc/nacl_desc_io.h"
13 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
14 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
15 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
16 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
17 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
18 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
19
20
21 static size_t const kdefault_io_buffer_bytes_to_log = 64;
22
23 int32_t NaClSysDup(struct NaClAppThread *natp,
24                    int                  oldfd) {
25   struct NaClApp  *nap = natp->nap;
26   int             retval;
27   struct NaClDesc *old_nd;
28
29   NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d)\n",
30           (uintptr_t) natp, oldfd);
31   old_nd = NaClAppGetDesc(nap, oldfd);
32   if (NULL == old_nd) {
33     retval = -NACL_ABI_EBADF;
34     goto done;
35   }
36   retval = NaClAppSetDescAvail(nap, old_nd);
37 done:
38   return retval;
39 }
40
41 int32_t NaClSysDup2(struct NaClAppThread  *natp,
42                     int                   oldfd,
43                     int                   newfd) {
44   struct NaClApp  *nap = natp->nap;
45   int             retval;
46   struct NaClDesc *old_nd;
47
48   NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d, %d)\n",
49           (uintptr_t) natp, oldfd, newfd);
50   if (newfd < 0) {
51     retval = -NACL_ABI_EINVAL;
52     goto done;
53   }
54   /*
55    * TODO(bsy): is this a reasonable largest sane value?  The
56    * descriptor array shouldn't get too large.
57    */
58   if (newfd >= NACL_MAX_FD) {
59     retval = -NACL_ABI_EINVAL;
60     goto done;
61   }
62   old_nd = NaClAppGetDesc(nap, oldfd);
63   if (NULL == old_nd) {
64     retval = -NACL_ABI_EBADF;
65     goto done;
66   }
67   NaClAppSetDesc(nap, newfd, old_nd);
68   retval = newfd;
69 done:
70   return retval;
71 }
72
73 int32_t NaClSysClose(struct NaClAppThread *natp,
74                      int                  d) {
75   struct NaClApp  *nap = natp->nap;
76   int             retval = -NACL_ABI_EBADF;
77   struct NaClDesc *ndp;
78
79   NaClLog(3, "Entered NaClSysClose(0x%08"NACL_PRIxPTR", %d)\n",
80           (uintptr_t) natp, d);
81
82   NaClFastMutexLock(&nap->desc_mu);
83   ndp = NaClAppGetDescMu(nap, d);
84   if (NULL != ndp) {
85     NaClAppSetDescMu(nap, d, NULL);  /* Unref the desc_tbl */
86   }
87   NaClFastMutexUnlock(&nap->desc_mu);
88   NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
89           (uintptr_t) ndp);
90   if (NULL != ndp) {
91     NaClDescUnref(ndp);
92     retval = 0;
93   }
94
95   return retval;
96 }
97
98 int32_t NaClSysIsatty(struct NaClAppThread *natp,
99                       int                  d) {
100   struct NaClApp  *nap = natp->nap;
101   int             retval = -NACL_ABI_EBADF;
102   struct NaClDesc *ndp;
103
104   NaClLog(3, "Entered NaClSysIsatty(0x%08"NACL_PRIxPTR", %d)\n",
105           (uintptr_t) natp, d);
106
107   if (!NaClAclBypassChecks) {
108     return -NACL_ABI_EACCES;
109   }
110
111   ndp = NaClAppGetDesc(nap, d);
112   if (NULL == ndp) {
113     NaClLog(4, "bad desc\n");
114     return -NACL_ABI_EBADF;
115   }
116
117   retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->Isatty)(ndp);
118   NaClDescUnref(ndp);
119   return retval;
120 }
121
122 int32_t NaClSysGetdents(struct NaClAppThread *natp,
123                         int                  d,
124                         void                 *dirp,
125                         size_t               count) {
126   struct NaClApp  *nap = natp->nap;
127   int32_t         retval = -NACL_ABI_EINVAL;
128   ssize_t         getdents_ret;
129   uintptr_t       sysaddr;
130   struct NaClDesc *ndp;
131
132   NaClLog(3,
133           ("Entered NaClSysGetdents(0x%08"NACL_PRIxPTR", "
134            "%d, 0x%08"NACL_PRIxPTR", "
135            "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n"),
136           (uintptr_t) natp, d, (uintptr_t) dirp, count, count);
137
138   ndp = NaClAppGetDesc(nap, d);
139   if (NULL == ndp) {
140     retval = -NACL_ABI_EBADF;
141     goto cleanup;
142   }
143
144   /*
145    * Generic NaClCopyOutToUser is not sufficient, since buffer size
146    * |count| is arbitrary and we wouldn't want to have to allocate
147    * memory in trusted address space to match.
148    */
149   sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) dirp, count);
150   if (kNaClBadAddress == sysaddr) {
151     NaClLog(4, " illegal address for directory data\n");
152     retval = -NACL_ABI_EFAULT;
153     goto cleanup_unref;
154   }
155
156   /*
157    * Clamp count to INT32_MAX to avoid the possibility of Getdents returning
158    * a value that is outside the range of an int32.
159    */
160   if (count > INT32_MAX) {
161     count = INT32_MAX;
162   }
163   /*
164    * Grab addr space lock; getdents should not normally block, though
165    * if the directory is on a networked filesystem this could, and
166    * cause mmap to be slower on Windows.
167    */
168   NaClXMutexLock(&nap->mu);
169   getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
170                   Getdents)(ndp,
171                             (void *) sysaddr,
172                             count);
173   NaClXMutexUnlock(&nap->mu);
174   /* drop addr space lock */
175   if ((getdents_ret < INT32_MIN && !NaClSSizeIsNegErrno(&getdents_ret))
176       || INT32_MAX < getdents_ret) {
177     /* This should never happen, because we already clamped the input count */
178     NaClLog(LOG_FATAL, "Overflow in Getdents: return value is %"NACL_PRIxS,
179             (size_t) getdents_ret);
180   } else {
181     retval = (int32_t) getdents_ret;
182   }
183   if (retval > 0) {
184     NaClLog(4, "getdents returned %d bytes\n", retval);
185     NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
186   } else {
187     NaClLog(4, "getdents returned %d\n", retval);
188   }
189
190 cleanup_unref:
191   NaClDescUnref(ndp);
192
193 cleanup:
194   return retval;
195 }
196
197 int32_t NaClSysRead(struct NaClAppThread  *natp,
198                     int                   d,
199                     void                  *buf,
200                     size_t                count) {
201   struct NaClApp  *nap = natp->nap;
202   int32_t         retval = -NACL_ABI_EINVAL;
203   ssize_t         read_result = -NACL_ABI_EINVAL;
204   uintptr_t       sysaddr;
205   struct NaClDesc *ndp;
206   size_t          log_bytes;
207   char const      *ellipsis = "";
208
209   NaClLog(3,
210           ("Entered NaClSysRead(0x%08"NACL_PRIxPTR", "
211            "%d, 0x%08"NACL_PRIxPTR", "
212            "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n"),
213           (uintptr_t) natp, d, (uintptr_t) buf, count, count);
214
215   ndp = NaClAppGetDesc(nap, d);
216   if (NULL == ndp) {
217     retval = -NACL_ABI_EBADF;
218     goto cleanup;
219   }
220
221   sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
222   if (kNaClBadAddress == sysaddr) {
223     NaClDescUnref(ndp);
224     retval = -NACL_ABI_EFAULT;
225     goto cleanup;
226   }
227
228   /*
229    * The maximum length for read and write is INT32_MAX--anything larger and
230    * the return value would overflow. Passing larger values isn't an error--
231    * we'll just clamp the request size if it's too large.
232    */
233   if (count > INT32_MAX) {
234     count = INT32_MAX;
235   }
236
237   NaClVmIoWillStart(nap,
238                     (uint32_t) (uintptr_t) buf,
239                     (uint32_t) (((uintptr_t) buf) + count - 1));
240   read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
241                  Read)(ndp, (void *) sysaddr, count);
242   NaClVmIoHasEnded(nap,
243                     (uint32_t) (uintptr_t) buf,
244                     (uint32_t) (((uintptr_t) buf) + count - 1));
245   if (read_result > 0) {
246     NaClLog(4, "read returned %"NACL_PRIdS" bytes\n", read_result);
247     log_bytes = (size_t) read_result;
248     if (log_bytes > INT32_MAX) {
249       log_bytes = INT32_MAX;
250       ellipsis = "...";
251     }
252     if (NaClLogGetVerbosity() < 10) {
253       if (log_bytes > kdefault_io_buffer_bytes_to_log) {
254         log_bytes = kdefault_io_buffer_bytes_to_log;
255         ellipsis = "...";
256       }
257     }
258     NaClLog(8, "read result: %.*s%s\n",
259             (int) log_bytes, (char *) sysaddr, ellipsis);
260   } else {
261     NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
262   }
263   NaClDescUnref(ndp);
264
265   /* This cast is safe because we clamped count above.*/
266   retval = (int32_t) read_result;
267 cleanup:
268   return retval;
269 }
270
271 int32_t NaClSysWrite(struct NaClAppThread *natp,
272                      int                  d,
273                      void                 *buf,
274                      size_t               count) {
275   struct NaClApp  *nap = natp->nap;
276   int32_t         retval = -NACL_ABI_EINVAL;
277   ssize_t         write_result = -NACL_ABI_EINVAL;
278   uintptr_t       sysaddr;
279   char const      *ellipsis = "";
280   struct NaClDesc *ndp;
281   size_t          log_bytes;
282
283   NaClLog(3,
284           "Entered NaClSysWrite(0x%08"NACL_PRIxPTR", "
285           "%d, 0x%08"NACL_PRIxPTR", "
286           "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n",
287           (uintptr_t) natp, d, (uintptr_t) buf, count, count);
288
289   ndp = NaClAppGetDesc(nap, d);
290   NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
291   if (NULL == ndp) {
292     retval = -NACL_ABI_EBADF;
293     goto cleanup;
294   }
295
296   sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
297   if (kNaClBadAddress == sysaddr) {
298     NaClDescUnref(ndp);
299     retval = -NACL_ABI_EFAULT;
300     goto cleanup;
301   }
302
303   log_bytes = count;
304   if (log_bytes > INT32_MAX) {
305     log_bytes = INT32_MAX;
306     ellipsis = "...";
307   }
308   if (NaClLogGetVerbosity() < 10) {
309     if (log_bytes > kdefault_io_buffer_bytes_to_log) {
310       log_bytes = kdefault_io_buffer_bytes_to_log;
311       ellipsis = "...";
312     }
313   }
314   NaClLog(8, "In NaClSysWrite(%d, %.*s%s, %"NACL_PRIuS")\n",
315           d, (int) log_bytes, (char *) sysaddr, ellipsis, count);
316
317   /*
318    * The maximum length for read and write is INT32_MAX--anything larger and
319    * the return value would overflow. Passing larger values isn't an error--
320    * we'll just clamp the request size if it's too large.
321    */
322   if (count > INT32_MAX) {
323     count = INT32_MAX;
324   }
325
326   NaClVmIoWillStart(nap,
327                     (uint32_t) (uintptr_t) buf,
328                     (uint32_t) (((uintptr_t) buf) + count - 1));
329   write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
330                   Write)(ndp, (void *) sysaddr, count);
331   NaClVmIoHasEnded(nap,
332                    (uint32_t) (uintptr_t) buf,
333                    (uint32_t) (((uintptr_t) buf) + count - 1));
334
335   NaClDescUnref(ndp);
336
337   /* This cast is safe because we clamped count above.*/
338   retval = (int32_t) write_result;
339
340 cleanup:
341   return retval;
342 }
343
344 /*
345  * This implements 64-bit offsets, so we use |offp| as an in/out
346  * address so we can have a 64 bit return value.
347  */
348 int32_t NaClSysLseek(struct NaClAppThread *natp,
349                      int                  d,
350                      nacl_abi_off_t       *offp,
351                      int                  whence) {
352   struct NaClApp  *nap = natp->nap;
353   nacl_abi_off_t  offset;
354   nacl_off64_t    retval64;
355   int32_t         retval = -NACL_ABI_EINVAL;
356   struct NaClDesc *ndp;
357
358   NaClLog(3,
359           ("Entered NaClSysLseek(0x%08"NACL_PRIxPTR", %d,"
360            " 0x%08"NACL_PRIxPTR", %d)\n"),
361           (uintptr_t) natp, d, (uintptr_t) offp, whence);
362
363   ndp = NaClAppGetDesc(nap, d);
364   if (NULL == ndp) {
365     retval = -NACL_ABI_EBADF;
366     goto cleanup;
367   }
368
369   if (!NaClCopyInFromUser(nap, &offset, (uintptr_t) offp, sizeof offset)) {
370     retval = -NACL_ABI_EFAULT;
371     goto cleanup_unref;
372   }
373   NaClLog(4, "offset 0x%08"NACL_PRIx64"\n", (uint64_t) offset);
374
375   retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
376               Seek)(ndp, (nacl_off64_t) offset, whence);
377   if (NaClOff64IsNegErrno(&retval64)) {
378     retval = (int32_t) retval64;
379   } else {
380     if (NaClCopyOutToUser(nap, (uintptr_t) offp, &retval64, sizeof retval64)) {
381       retval = 0;
382     } else {
383       NaClLog(LOG_FATAL,
384               "NaClSysLseek: in/out ptr became invalid at copyout?\n");
385     }
386   }
387 cleanup_unref:
388   NaClDescUnref(ndp);
389 cleanup:
390   return retval;
391 }
392
393 int32_t NaClSysFstat(struct NaClAppThread *natp,
394                      int                  d,
395                      struct nacl_abi_stat *nasp) {
396   struct NaClApp        *nap = natp->nap;
397   int32_t               retval = -NACL_ABI_EINVAL;
398   struct NaClDesc       *ndp;
399   struct nacl_abi_stat  result;
400
401   NaClLog(3,
402           ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
403            ", %d, 0x%08"NACL_PRIxPTR")\n"),
404           (uintptr_t) natp,
405           d, (uintptr_t) nasp);
406
407   NaClLog(4,
408           " sizeof(struct nacl_abi_stat) = %"NACL_PRIuS" (0x%"NACL_PRIxS")\n",
409           sizeof *nasp, sizeof *nasp);
410
411   ndp = NaClAppGetDesc(nap, d);
412   if (NULL == ndp) {
413     NaClLog(4, "bad desc\n");
414     retval = -NACL_ABI_EBADF;
415     goto cleanup;
416   }
417
418   retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
419             Fstat)(ndp, &result);
420   if (0 == retval) {
421     if (!NaClCopyOutToUser(nap, (uintptr_t) nasp,
422                            &result, sizeof result)) {
423       retval = -NACL_ABI_EFAULT;
424     }
425   }
426
427   NaClDescUnref(ndp);
428 cleanup:
429   return retval;
430 }