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_PRIxPTR", "
135 "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n"),
136 (uintptr_t) natp, d, (uintptr_t) 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, (uintptr_t) 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_PRIxPTR", "
212 "%"NACL_PRIuS"[0x%"NACL_PRIxS"])\n"),
213 (uintptr_t) natp, d, (uintptr_t) buf, count, count);
215 ndp = NaClAppGetDesc(nap, d);
217 retval = -NACL_ABI_EBADF;
221 sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) 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,
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;
252 if (NaClLogGetVerbosity() < 10) {
253 if (log_bytes > kdefault_io_buffer_bytes_to_log) {
254 log_bytes = kdefault_io_buffer_bytes_to_log;
258 NaClLog(8, "read result: %.*s%s\n",
259 (int) log_bytes, (char *) sysaddr, ellipsis);
261 NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
265 /* This cast is safe because we clamped count above.*/
266 retval = (int32_t) read_result;
271 int32_t NaClSysWrite(struct NaClAppThread *natp,
275 struct NaClApp *nap = natp->nap;
276 int32_t retval = -NACL_ABI_EINVAL;
277 ssize_t write_result = -NACL_ABI_EINVAL;
279 char const *ellipsis = "";
280 struct NaClDesc *ndp;
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);
289 ndp = NaClAppGetDesc(nap, d);
290 NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
292 retval = -NACL_ABI_EBADF;
296 sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
297 if (kNaClBadAddress == sysaddr) {
299 retval = -NACL_ABI_EFAULT;
304 if (log_bytes > INT32_MAX) {
305 log_bytes = INT32_MAX;
308 if (NaClLogGetVerbosity() < 10) {
309 if (log_bytes > kdefault_io_buffer_bytes_to_log) {
310 log_bytes = kdefault_io_buffer_bytes_to_log;
314 NaClLog(8, "In NaClSysWrite(%d, %.*s%s, %"NACL_PRIuS")\n",
315 d, (int) log_bytes, (char *) sysaddr, ellipsis, count);
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.
322 if (count > INT32_MAX) {
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));
337 /* This cast is safe because we clamped count above.*/
338 retval = (int32_t) write_result;
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.
348 int32_t NaClSysLseek(struct NaClAppThread *natp,
350 nacl_abi_off_t *offp,
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;
359 ("Entered NaClSysLseek(0x%08"NACL_PRIxPTR", %d,"
360 " 0x%08"NACL_PRIxPTR", %d)\n"),
361 (uintptr_t) natp, d, (uintptr_t) offp, whence);
363 ndp = NaClAppGetDesc(nap, d);
365 retval = -NACL_ABI_EBADF;
369 if (!NaClCopyInFromUser(nap, &offset, (uintptr_t) offp, sizeof offset)) {
370 retval = -NACL_ABI_EFAULT;
373 NaClLog(4, "offset 0x%08"NACL_PRIx64"\n", (uint64_t) offset);
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;
380 if (NaClCopyOutToUser(nap, (uintptr_t) offp, &retval64, sizeof retval64)) {
384 "NaClSysLseek: in/out ptr became invalid at copyout?\n");
393 int32_t NaClSysFstat(struct NaClAppThread *natp,
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;
402 ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
403 ", %d, 0x%08"NACL_PRIxPTR")\n"),
405 d, (uintptr_t) nasp);
408 " sizeof(struct nacl_abi_stat) = %"NACL_PRIuS" (0x%"NACL_PRIxS")\n",
409 sizeof *nasp, sizeof *nasp);
411 ndp = NaClAppGetDesc(nap, d);
413 NaClLog(4, "bad desc\n");
414 retval = -NACL_ABI_EBADF;
418 retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
419 Fstat)(ndp, &result);
421 if (!NaClCopyOutToUser(nap, (uintptr_t) nasp,
422 &result, sizeof result)) {
423 retval = -NACL_ABI_EFAULT;