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.
7 #include "native_client/src/trusted/service_runtime/sys_fdio.h"
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"
21 static size_t const kdefault_io_buffer_bytes_to_log = 64;
23 int32_t NaClSysDup(struct NaClAppThread *natp,
25 struct NaClApp *nap = natp->nap;
27 struct NaClDesc *old_nd;
29 NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d)\n",
30 (uintptr_t) natp, oldfd);
31 old_nd = NaClAppGetDesc(nap, oldfd);
33 retval = -NACL_ABI_EBADF;
36 retval = NaClAppSetDescAvail(nap, old_nd);
41 int32_t NaClSysDup2(struct NaClAppThread *natp,
44 struct NaClApp *nap = natp->nap;
46 struct NaClDesc *old_nd;
48 NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d, %d)\n",
49 (uintptr_t) natp, oldfd, newfd);
51 retval = -NACL_ABI_EINVAL;
55 * TODO(bsy): is this a reasonable largest sane value? The
56 * descriptor array shouldn't get too large.
58 if (newfd >= NACL_MAX_FD) {
59 retval = -NACL_ABI_EINVAL;
62 old_nd = NaClAppGetDesc(nap, oldfd);
64 retval = -NACL_ABI_EBADF;
67 NaClAppSetDesc(nap, newfd, old_nd);
73 int32_t NaClSysClose(struct NaClAppThread *natp,
75 struct NaClApp *nap = natp->nap;
76 int retval = -NACL_ABI_EBADF;
79 NaClLog(3, "Entered NaClSysClose(0x%08"NACL_PRIxPTR", %d)\n",
82 NaClFastMutexLock(&nap->desc_mu);
83 ndp = NaClAppGetDescMu(nap, d);
85 NaClAppSetDescMu(nap, d, NULL); /* Unref the desc_tbl */
87 NaClFastMutexUnlock(&nap->desc_mu);
88 NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
98 int32_t NaClSysIsatty(struct NaClAppThread *natp,
100 struct NaClApp *nap = natp->nap;
101 int retval = -NACL_ABI_EBADF;
102 struct NaClDesc *ndp;
104 NaClLog(3, "Entered NaClSysIsatty(0x%08"NACL_PRIxPTR", %d)\n",
105 (uintptr_t) natp, d);
107 if (!NaClAclBypassChecks) {
108 return -NACL_ABI_EACCES;
111 ndp = NaClAppGetDesc(nap, d);
113 NaClLog(4, "bad desc\n");
114 return -NACL_ABI_EBADF;
117 retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->Isatty)(ndp);
122 int32_t NaClSysGetdents(struct NaClAppThread *natp,
126 struct NaClApp *nap = natp->nap;
127 int32_t retval = -NACL_ABI_EINVAL;
128 ssize_t getdents_ret;
130 struct NaClDesc *ndp;
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);
138 ndp = NaClAppGetDesc(nap, d);
140 retval = -NACL_ABI_EBADF;
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.
149 sysaddr = NaClUserToSysAddrRange(nap, dirp, count);
150 if (kNaClBadAddress == sysaddr) {
151 NaClLog(4, " illegal address for directory data\n");
152 retval = -NACL_ABI_EFAULT;
157 * Clamp count to INT32_MAX to avoid the possibility of Getdents returning
158 * a value that is outside the range of an int32.
160 if (count > INT32_MAX) {
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.
168 NaClXMutexLock(&nap->mu);
169 getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
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);
181 retval = (int32_t) getdents_ret;
184 NaClLog(4, "getdents returned %d bytes\n", retval);
185 NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
187 NaClLog(4, "getdents returned %d\n", retval);
197 int32_t NaClSysRead(struct NaClAppThread *natp,
201 struct NaClApp *nap = natp->nap;
202 int32_t retval = -NACL_ABI_EINVAL;
203 ssize_t read_result = -NACL_ABI_EINVAL;
205 struct NaClDesc *ndp;
207 char const *ellipsis = "";
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);
215 ndp = NaClAppGetDesc(nap, d);
217 retval = -NACL_ABI_EBADF;
221 sysaddr = NaClUserToSysAddrRange(nap, buf, count);
222 if (kNaClBadAddress == sysaddr) {
224 retval = -NACL_ABI_EFAULT;
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.
233 if (count > INT32_MAX) {
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;
248 if (NaClLogGetVerbosity() < 10) {
249 if (log_bytes > kdefault_io_buffer_bytes_to_log) {
250 log_bytes = kdefault_io_buffer_bytes_to_log;
254 NaClLog(8, "read result: %.*s%s\n",
255 (int) log_bytes, (char *) sysaddr, ellipsis);
257 NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
261 /* This cast is safe because we clamped count above.*/
262 retval = (int32_t) read_result;
267 int32_t NaClSysWrite(struct NaClAppThread *natp,
271 struct NaClApp *nap = natp->nap;
272 int32_t retval = -NACL_ABI_EINVAL;
273 ssize_t write_result = -NACL_ABI_EINVAL;
275 char const *ellipsis = "";
276 struct NaClDesc *ndp;
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);
285 ndp = NaClAppGetDesc(nap, d);
286 NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
288 retval = -NACL_ABI_EBADF;
292 sysaddr = NaClUserToSysAddrRange(nap, buf, count);
293 if (kNaClBadAddress == sysaddr) {
295 retval = -NACL_ABI_EFAULT;
300 if (log_bytes > INT32_MAX) {
301 log_bytes = INT32_MAX;
304 if (NaClLogGetVerbosity() < 10) {
305 if (log_bytes > kdefault_io_buffer_bytes_to_log) {
306 log_bytes = kdefault_io_buffer_bytes_to_log;
310 NaClLog(8, "In NaClSysWrite(%d, %.*s%s, %"NACL_PRIu32")\n",
311 d, (int) log_bytes, (char *) sysaddr, ellipsis, count);
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.
318 if (count > INT32_MAX) {
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);
329 /* This cast is safe because we clamped count above.*/
330 retval = (int32_t) write_result;
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.
340 int32_t NaClSysLseek(struct NaClAppThread *natp,
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;
351 ("Entered NaClSysLseek(0x%08"NACL_PRIxPTR", %d,"
352 " 0x%08"NACL_PRIx32", %d)\n"),
353 (uintptr_t) natp, d, offp, whence);
355 ndp = NaClAppGetDesc(nap, d);
357 retval = -NACL_ABI_EBADF;
361 if (!NaClCopyInFromUser(nap, &offset, offp, sizeof offset)) {
362 retval = -NACL_ABI_EFAULT;
365 NaClLog(4, "offset 0x%08"NACL_PRIx64"\n", (uint64_t) offset);
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;
372 if (NaClCopyOutToUser(nap, offp, &retval64, sizeof retval64)) {
376 "NaClSysLseek: in/out ptr became invalid at copyout?\n");
385 int32_t NaClSysFstat(struct NaClAppThread *natp,
388 struct NaClApp *nap = natp->nap;
389 int32_t retval = -NACL_ABI_EINVAL;
390 struct NaClDesc *ndp;
391 struct nacl_abi_stat result;
394 ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
395 ", %d, 0x%08"NACL_PRIx32")\n"),
396 (uintptr_t) natp, d, nasp);
398 ndp = NaClAppGetDesc(nap, d);
400 NaClLog(4, "bad desc\n");
401 retval = -NACL_ABI_EBADF;
405 retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
406 Fstat)(ndp, &result);
408 if (!NaClCopyOutToUser(nap, nasp, &result, sizeof result)) {
409 retval = -NACL_ABI_EFAULT;