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 11 : int32_t NaClSysDup(struct NaClAppThread *natp,
24 : int oldfd) {
25 11 : struct NaClApp *nap = natp->nap;
26 : int retval;
27 : struct NaClDesc *old_nd;
28 :
29 11 : NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d)\n",
30 : (uintptr_t) natp, oldfd);
31 11 : old_nd = NaClAppGetDesc(nap, oldfd);
32 11 : if (NULL == old_nd) {
33 0 : retval = -NACL_ABI_EBADF;
34 0 : goto done;
35 : }
36 11 : retval = NaClAppSetDescAvail(nap, old_nd);
37 : done:
38 11 : return retval;
39 : }
40 :
41 3 : int32_t NaClSysDup2(struct NaClAppThread *natp,
42 : int oldfd,
43 : int newfd) {
44 3 : struct NaClApp *nap = natp->nap;
45 : int retval;
46 : struct NaClDesc *old_nd;
47 :
48 3 : NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d, %d)\n",
49 : (uintptr_t) natp, oldfd, newfd);
50 3 : if (newfd < 0) {
51 0 : retval = -NACL_ABI_EINVAL;
52 0 : 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 3 : if (newfd >= NACL_MAX_FD) {
59 0 : retval = -NACL_ABI_EINVAL;
60 0 : goto done;
61 : }
62 3 : old_nd = NaClAppGetDesc(nap, oldfd);
63 3 : if (NULL == old_nd) {
64 0 : retval = -NACL_ABI_EBADF;
65 0 : goto done;
66 : }
67 3 : NaClAppSetDesc(nap, newfd, old_nd);
68 3 : retval = newfd;
69 : done:
70 3 : return retval;
71 : }
72 :
73 670 : int32_t NaClSysClose(struct NaClAppThread *natp,
74 : int d) {
75 670 : struct NaClApp *nap = natp->nap;
76 670 : int retval = -NACL_ABI_EBADF;
77 : struct NaClDesc *ndp;
78 :
79 670 : NaClLog(3, "Entered NaClSysClose(0x%08"NACL_PRIxPTR", %d)\n",
80 : (uintptr_t) natp, d);
81 :
82 670 : NaClFastMutexLock(&nap->desc_mu);
83 670 : ndp = NaClAppGetDescMu(nap, d);
84 670 : if (NULL != ndp) {
85 663 : NaClAppSetDescMu(nap, d, NULL); /* Unref the desc_tbl */
86 : }
87 670 : NaClFastMutexUnlock(&nap->desc_mu);
88 670 : NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
89 : (uintptr_t) ndp);
90 670 : if (NULL != ndp) {
91 663 : NaClDescUnref(ndp);
92 663 : retval = 0;
93 : }
94 :
95 670 : return retval;
96 : }
97 :
98 3 : int32_t NaClSysIsatty(struct NaClAppThread *natp,
99 : int d) {
100 3 : struct NaClApp *nap = natp->nap;
101 3 : int retval = -NACL_ABI_EBADF;
102 : struct NaClDesc *ndp;
103 :
104 3 : NaClLog(3, "Entered NaClSysIsatty(0x%08"NACL_PRIxPTR", %d)\n",
105 : (uintptr_t) natp, d);
106 :
107 3 : if (!NaClAclBypassChecks) {
108 0 : return -NACL_ABI_EACCES;
109 : }
110 :
111 3 : ndp = NaClAppGetDesc(nap, d);
112 3 : if (NULL == ndp) {
113 1 : NaClLog(4, "bad desc\n");
114 1 : return -NACL_ABI_EBADF;
115 : }
116 :
117 2 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->Isatty)(ndp);
118 2 : NaClDescUnref(ndp);
119 2 : return retval;
120 : }
121 :
122 8 : int32_t NaClSysGetdents(struct NaClAppThread *natp,
123 : int d,
124 : void *dirp,
125 : size_t count) {
126 8 : struct NaClApp *nap = natp->nap;
127 8 : int32_t retval = -NACL_ABI_EINVAL;
128 : ssize_t getdents_ret;
129 : uintptr_t sysaddr;
130 : struct NaClDesc *ndp;
131 :
132 8 : 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 8 : ndp = NaClAppGetDesc(nap, d);
139 8 : if (NULL == ndp) {
140 0 : retval = -NACL_ABI_EBADF;
141 0 : 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 8 : sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) dirp, count);
150 8 : if (kNaClBadAddress == sysaddr) {
151 0 : NaClLog(4, " illegal address for directory data\n");
152 0 : retval = -NACL_ABI_EFAULT;
153 0 : 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 8 : if (count > INT32_MAX) {
161 0 : 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 8 : NaClXMutexLock(&nap->mu);
169 16 : getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
170 8 : Getdents)(ndp,
171 : (void *) sysaddr,
172 : count);
173 8 : 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 8 : retval = (int32_t) getdents_ret;
182 : }
183 8 : if (retval > 0) {
184 6 : NaClLog(4, "getdents returned %d bytes\n", retval);
185 6 : NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
186 : } else {
187 2 : NaClLog(4, "getdents returned %d\n", retval);
188 : }
189 :
190 : cleanup_unref:
191 8 : NaClDescUnref(ndp);
192 :
193 : cleanup:
194 8 : return retval;
195 : }
196 :
197 53 : int32_t NaClSysRead(struct NaClAppThread *natp,
198 : int d,
199 : void *buf,
200 : size_t count) {
201 53 : struct NaClApp *nap = natp->nap;
202 53 : int32_t retval = -NACL_ABI_EINVAL;
203 53 : ssize_t read_result = -NACL_ABI_EINVAL;
204 : uintptr_t sysaddr;
205 : struct NaClDesc *ndp;
206 : size_t log_bytes;
207 53 : char const *ellipsis = "";
208 :
209 53 : 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 53 : ndp = NaClAppGetDesc(nap, d);
216 53 : if (NULL == ndp) {
217 6 : retval = -NACL_ABI_EBADF;
218 6 : goto cleanup;
219 : }
220 :
221 47 : sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
222 47 : if (kNaClBadAddress == sysaddr) {
223 1 : NaClDescUnref(ndp);
224 1 : retval = -NACL_ABI_EFAULT;
225 1 : 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 46 : if (count > INT32_MAX) {
234 0 : count = INT32_MAX;
235 : }
236 :
237 46 : NaClVmIoWillStart(nap,
238 : (uint32_t) (uintptr_t) buf,
239 46 : (uint32_t) (((uintptr_t) buf) + count - 1));
240 92 : read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
241 46 : Read)(ndp, (void *) sysaddr, count);
242 46 : NaClVmIoHasEnded(nap,
243 : (uint32_t) (uintptr_t) buf,
244 46 : (uint32_t) (((uintptr_t) buf) + count - 1));
245 46 : if (read_result > 0) {
246 41 : NaClLog(4, "read returned %"NACL_PRIdS" bytes\n", read_result);
247 41 : log_bytes = (size_t) read_result;
248 41 : if (log_bytes > INT32_MAX) {
249 0 : log_bytes = INT32_MAX;
250 0 : ellipsis = "...";
251 : }
252 41 : if (NaClLogGetVerbosity() < 10) {
253 41 : if (log_bytes > kdefault_io_buffer_bytes_to_log) {
254 16 : log_bytes = kdefault_io_buffer_bytes_to_log;
255 16 : ellipsis = "...";
256 : }
257 : }
258 41 : NaClLog(8, "read result: %.*s%s\n",
259 : (int) log_bytes, (char *) sysaddr, ellipsis);
260 : } else {
261 5 : NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
262 : }
263 46 : NaClDescUnref(ndp);
264 :
265 : /* This cast is safe because we clamped count above.*/
266 46 : retval = (int32_t) read_result;
267 : cleanup:
268 53 : return retval;
269 : }
270 :
271 51912 : int32_t NaClSysWrite(struct NaClAppThread *natp,
272 : int d,
273 : void *buf,
274 : size_t count) {
275 51912 : struct NaClApp *nap = natp->nap;
276 51912 : int32_t retval = -NACL_ABI_EINVAL;
277 51912 : ssize_t write_result = -NACL_ABI_EINVAL;
278 : uintptr_t sysaddr;
279 51912 : char const *ellipsis = "";
280 : struct NaClDesc *ndp;
281 : size_t log_bytes;
282 :
283 51912 : 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 51912 : ndp = NaClAppGetDesc(nap, d);
290 51912 : NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
291 51912 : if (NULL == ndp) {
292 2 : retval = -NACL_ABI_EBADF;
293 2 : goto cleanup;
294 : }
295 :
296 51910 : sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
297 51910 : if (kNaClBadAddress == sysaddr) {
298 1 : NaClDescUnref(ndp);
299 1 : retval = -NACL_ABI_EFAULT;
300 1 : goto cleanup;
301 : }
302 :
303 51909 : log_bytes = count;
304 51909 : if (log_bytes > INT32_MAX) {
305 0 : log_bytes = INT32_MAX;
306 0 : ellipsis = "...";
307 : }
308 51909 : if (NaClLogGetVerbosity() < 10) {
309 51909 : if (log_bytes > kdefault_io_buffer_bytes_to_log) {
310 1473 : log_bytes = kdefault_io_buffer_bytes_to_log;
311 1473 : ellipsis = "...";
312 : }
313 : }
314 51909 : 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 51909 : if (count > INT32_MAX) {
323 0 : count = INT32_MAX;
324 : }
325 :
326 51909 : NaClVmIoWillStart(nap,
327 : (uint32_t) (uintptr_t) buf,
328 51909 : (uint32_t) (((uintptr_t) buf) + count - 1));
329 103818 : write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
330 51909 : Write)(ndp, (void *) sysaddr, count);
331 51909 : NaClVmIoHasEnded(nap,
332 : (uint32_t) (uintptr_t) buf,
333 51909 : (uint32_t) (((uintptr_t) buf) + count - 1));
334 :
335 51909 : NaClDescUnref(ndp);
336 :
337 : /* This cast is safe because we clamped count above.*/
338 51909 : retval = (int32_t) write_result;
339 :
340 : cleanup:
341 51912 : 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 48 : int32_t NaClSysLseek(struct NaClAppThread *natp,
349 : int d,
350 : nacl_abi_off_t *offp,
351 : int whence) {
352 48 : struct NaClApp *nap = natp->nap;
353 : nacl_abi_off_t offset;
354 : nacl_off64_t retval64;
355 48 : int32_t retval = -NACL_ABI_EINVAL;
356 : struct NaClDesc *ndp;
357 :
358 48 : 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 48 : ndp = NaClAppGetDesc(nap, d);
364 48 : if (NULL == ndp) {
365 1 : retval = -NACL_ABI_EBADF;
366 1 : goto cleanup;
367 : }
368 :
369 47 : if (!NaClCopyInFromUser(nap, &offset, (uintptr_t) offp, sizeof offset)) {
370 0 : retval = -NACL_ABI_EFAULT;
371 0 : goto cleanup_unref;
372 : }
373 47 : NaClLog(4, "offset 0x%08"NACL_PRIxNACL_OFF"\n", offset);
374 :
375 94 : retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
376 47 : Seek)(ndp, (nacl_off64_t) offset, whence);
377 47 : if (NaClOff64IsNegErrno(&retval64)) {
378 5 : retval = (int32_t) retval64;
379 : } else {
380 42 : if (NaClCopyOutToUser(nap, (uintptr_t) offp, &retval64, sizeof retval64)) {
381 42 : retval = 0;
382 : } else {
383 0 : NaClLog(LOG_FATAL,
384 : "NaClSysLseek: in/out ptr became invalid at copyout?\n");
385 : }
386 : }
387 : cleanup_unref:
388 47 : NaClDescUnref(ndp);
389 : cleanup:
390 48 : return retval;
391 : }
392 :
393 194 : int32_t NaClSysFstat(struct NaClAppThread *natp,
394 : int d,
395 : struct nacl_abi_stat *nasp) {
396 194 : struct NaClApp *nap = natp->nap;
397 194 : int32_t retval = -NACL_ABI_EINVAL;
398 : struct NaClDesc *ndp;
399 : struct nacl_abi_stat result;
400 :
401 194 : 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 194 : NaClLog(4,
408 : " sizeof(struct nacl_abi_stat) = %"NACL_PRIuS" (0x%"NACL_PRIxS")\n",
409 : sizeof *nasp, sizeof *nasp);
410 :
411 194 : ndp = NaClAppGetDesc(nap, d);
412 194 : if (NULL == ndp) {
413 0 : NaClLog(4, "bad desc\n");
414 0 : retval = -NACL_ABI_EBADF;
415 0 : goto cleanup;
416 : }
417 :
418 388 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
419 194 : Fstat)(ndp, &result);
420 194 : if (0 == retval) {
421 194 : if (!NaClCopyOutToUser(nap, (uintptr_t) nasp,
422 : &result, sizeof result)) {
423 0 : retval = -NACL_ABI_EFAULT;
424 : }
425 : }
426 :
427 194 : NaClDescUnref(ndp);
428 : cleanup:
429 194 : return retval;
430 : }
|