Upstream version 10.39.225.0
[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                         uint32_t             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_PRIx32", "
135            "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n"),
136           (uintptr_t) natp, d, 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, 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                     uint32_t              buf,
200                     uint32_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_PRIx32", "
212            "%"NACL_PRIu32"[0x%"NACL_PRIx32"])\n"),
213           (uintptr_t) natp, d, 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, 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, buf, buf + count - 1);
238   read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
239                  Read)(ndp, (void *) sysaddr, count);
240   NaClVmIoHasEnded(nap, buf, buf + count - 1);
241   if (read_result > 0) {
242     NaClLog(4, "read returned %"NACL_PRIdS" bytes\n", read_result);
243     log_bytes = (size_t) read_result;
244     if (log_bytes > INT32_MAX) {
245       log_bytes = INT32_MAX;
246       ellipsis = "...";
247     }
248     if (NaClLogGetVerbosity() < 10) {
249       if (log_bytes > kdefault_io_buffer_bytes_to_log) {
250         log_bytes = kdefault_io_buffer_bytes_to_log;
251         ellipsis = "...";
252       }
253     }
254     NaClLog(8, "read result: %.*s%s\n",
255             (int) log_bytes, (char *) sysaddr, ellipsis);
256   } else {
257     NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
258   }
259   NaClDescUnref(ndp);
260
261   /* This cast is safe because we clamped count above.*/
262   retval = (int32_t) read_result;
263 cleanup:
264   return retval;
265 }
266
267 int32_t NaClSysWrite(struct NaClAppThread *natp,
268                      int                  d,
269                      uint32_t             buf,
270                      uint32_t             count) {
271   struct NaClApp  *nap = natp->nap;
272   int32_t         retval = -NACL_ABI_EINVAL;
273   ssize_t         write_result = -NACL_ABI_EINVAL;
274   uintptr_t       sysaddr;
275   char const      *ellipsis = "";
276   struct NaClDesc *ndp;
277   size_t          log_bytes;
278
279   NaClLog(3,
280           "Entered NaClSysWrite(0x%08"NACL_PRIxPTR", "
281           "%d, 0x%08"NACL_PRIx32", "
282           "%"NACL_PRIu32"[0x%"NACL_PRIx32"])\n",
283           (uintptr_t) natp, d, buf, count, count);
284
285   ndp = NaClAppGetDesc(nap, d);
286   NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
287   if (NULL == ndp) {
288     retval = -NACL_ABI_EBADF;
289     goto cleanup;
290   }
291
292   sysaddr = NaClUserToSysAddrRange(nap, buf, count);
293   if (kNaClBadAddress == sysaddr) {
294     NaClDescUnref(ndp);
295     retval = -NACL_ABI_EFAULT;
296     goto cleanup;
297   }
298
299   log_bytes = count;
300   if (log_bytes > INT32_MAX) {
301     log_bytes = INT32_MAX;
302     ellipsis = "...";
303   }
304   if (NaClLogGetVerbosity() < 10) {
305     if (log_bytes > kdefault_io_buffer_bytes_to_log) {
306       log_bytes = kdefault_io_buffer_bytes_to_log;
307       ellipsis = "...";
308     }
309   }
310   NaClLog(8, "In NaClSysWrite(%d, %.*s%s, %"NACL_PRIu32")\n",
311           d, (int) log_bytes, (char *) sysaddr, ellipsis, count);
312
313   /*
314    * The maximum length for read and write is INT32_MAX--anything larger and
315    * the return value would overflow. Passing larger values isn't an error--
316    * we'll just clamp the request size if it's too large.
317    */
318   if (count > INT32_MAX) {
319     count = INT32_MAX;
320   }
321
322   NaClVmIoWillStart(nap, buf, buf + count - 1);
323   write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
324                   Write)(ndp, (void *) sysaddr, count);
325   NaClVmIoHasEnded(nap, buf, buf + count - 1);
326
327   NaClDescUnref(ndp);
328
329   /* This cast is safe because we clamped count above.*/
330   retval = (int32_t) write_result;
331
332 cleanup:
333   return retval;
334 }
335
336 /*
337  * This implements 64-bit offsets, so we use |offp| as an in/out
338  * address so we can have a 64 bit return value.
339  */
340 int32_t NaClSysLseek(struct NaClAppThread *natp,
341                      int                  d,
342                      uint32_t             offp,
343                      int                  whence) {
344   struct NaClApp  *nap = natp->nap;
345   nacl_abi_off_t  offset;
346   nacl_off64_t    retval64;
347   int32_t         retval = -NACL_ABI_EINVAL;
348   struct NaClDesc *ndp;
349
350   NaClLog(3,
351           ("Entered NaClSysLseek(0x%08"NACL_PRIxPTR", %d,"
352            " 0x%08"NACL_PRIx32", %d)\n"),
353           (uintptr_t) natp, d, offp, whence);
354
355   ndp = NaClAppGetDesc(nap, d);
356   if (NULL == ndp) {
357     retval = -NACL_ABI_EBADF;
358     goto cleanup;
359   }
360
361   if (!NaClCopyInFromUser(nap, &offset, offp, sizeof offset)) {
362     retval = -NACL_ABI_EFAULT;
363     goto cleanup_unref;
364   }
365   NaClLog(4, "offset 0x%08"NACL_PRIx64"\n", (uint64_t) offset);
366
367   retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
368               Seek)(ndp, (nacl_off64_t) offset, whence);
369   if (NaClOff64IsNegErrno(&retval64)) {
370     retval = (int32_t) retval64;
371   } else {
372     if (NaClCopyOutToUser(nap, offp, &retval64, sizeof retval64)) {
373       retval = 0;
374     } else {
375       NaClLog(LOG_FATAL,
376               "NaClSysLseek: in/out ptr became invalid at copyout?\n");
377     }
378   }
379 cleanup_unref:
380   NaClDescUnref(ndp);
381 cleanup:
382   return retval;
383 }
384
385 int32_t NaClSysFstat(struct NaClAppThread *natp,
386                      int                  d,
387                      uint32_t             nasp) {
388   struct NaClApp        *nap = natp->nap;
389   int32_t               retval = -NACL_ABI_EINVAL;
390   struct NaClDesc       *ndp;
391   struct nacl_abi_stat  result;
392
393   NaClLog(3,
394           ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
395            ", %d, 0x%08"NACL_PRIx32")\n"),
396           (uintptr_t) natp, d, nasp);
397
398   ndp = NaClAppGetDesc(nap, d);
399   if (NULL == ndp) {
400     NaClLog(4, "bad desc\n");
401     retval = -NACL_ABI_EBADF;
402     goto cleanup;
403   }
404
405   retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
406             Fstat)(ndp, &result);
407   if (0 == retval) {
408     if (!NaClCopyOutToUser(nap, nasp, &result, sizeof result)) {
409       retval = -NACL_ABI_EFAULT;
410     }
411   }
412
413   NaClDescUnref(ndp);
414 cleanup:
415   return retval;
416 }