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 10 : int32_t NaClSysDup(struct NaClAppThread *natp,
24 10 : int oldfd) {
25 10 : struct NaClApp *nap = natp->nap;
26 10 : int retval;
27 10 : struct NaClDesc *old_nd;
28 :
29 10 : NaClLog(3, "NaClSysDup(0x%08"NACL_PRIxPTR", %d)\n",
30 : (uintptr_t) natp, oldfd);
31 10 : old_nd = NaClAppGetDesc(nap, oldfd);
32 10 : if (NULL == old_nd) {
33 0 : retval = -NACL_ABI_EBADF;
34 0 : goto done;
35 : }
36 10 : retval = NaClAppSetDescAvail(nap, old_nd);
37 : done:
38 10 : return retval;
39 : }
40 :
41 3 : int32_t NaClSysDup2(struct NaClAppThread *natp,
42 3 : int oldfd,
43 3 : int newfd) {
44 3 : struct NaClApp *nap = natp->nap;
45 3 : int retval;
46 3 : 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 676 : int32_t NaClSysClose(struct NaClAppThread *natp,
74 676 : int d) {
75 676 : struct NaClApp *nap = natp->nap;
76 676 : int retval = -NACL_ABI_EBADF;
77 676 : struct NaClDesc *ndp;
78 :
79 676 : NaClLog(3, "Entered NaClSysClose(0x%08"NACL_PRIxPTR", %d)\n",
80 : (uintptr_t) natp, d);
81 :
82 676 : NaClFastMutexLock(&nap->desc_mu);
83 676 : ndp = NaClAppGetDescMu(nap, d);
84 676 : if (NULL != ndp) {
85 669 : NaClAppSetDescMu(nap, d, NULL); /* Unref the desc_tbl */
86 669 : }
87 676 : NaClFastMutexUnlock(&nap->desc_mu);
88 676 : NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
89 : (uintptr_t) ndp);
90 676 : if (NULL != ndp) {
91 669 : NaClDescUnref(ndp);
92 669 : retval = 0;
93 669 : }
94 :
95 676 : return retval;
96 : }
97 :
98 3 : int32_t NaClSysIsatty(struct NaClAppThread *natp,
99 3 : int d) {
100 3 : struct NaClApp *nap = natp->nap;
101 3 : int retval = -NACL_ABI_EBADF;
102 3 : 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 3 : }
121 :
122 8 : int32_t NaClSysGetdents(struct NaClAppThread *natp,
123 8 : int d,
124 8 : void *dirp,
125 8 : size_t count) {
126 8 : struct NaClApp *nap = natp->nap;
127 8 : int32_t retval = -NACL_ABI_EINVAL;
128 8 : ssize_t getdents_ret;
129 8 : uintptr_t sysaddr;
130 8 : 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 0 : }
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 8 : getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
170 : Getdents)(ndp,
171 : (void *) sysaddr,
172 : count);
173 8 : NaClXMutexUnlock(&nap->mu);
174 : /* drop addr space lock */
175 16 : 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 0 : NaClLog(LOG_FATAL, "Overflow in Getdents: return value is %"NACL_PRIxS,
179 : (size_t) getdents_ret);
180 0 : } 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 6 : } else {
187 2 : NaClLog(4, "getdents returned %d\n", retval);
188 8 : }
189 :
190 : cleanup_unref:
191 8 : NaClDescUnref(ndp);
192 :
193 : cleanup:
194 8 : return retval;
195 : }
196 :
197 50 : int32_t NaClSysRead(struct NaClAppThread *natp,
198 50 : int d,
199 50 : void *buf,
200 50 : size_t count) {
201 50 : struct NaClApp *nap = natp->nap;
202 50 : int32_t retval = -NACL_ABI_EINVAL;
203 50 : ssize_t read_result = -NACL_ABI_EINVAL;
204 50 : uintptr_t sysaddr;
205 50 : struct NaClDesc *ndp;
206 50 : size_t log_bytes;
207 50 : char const *ellipsis = "";
208 :
209 50 : 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 50 : ndp = NaClAppGetDesc(nap, d);
216 50 : if (NULL == ndp) {
217 3 : retval = -NACL_ABI_EBADF;
218 3 : 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 0 : }
236 :
237 46 : NaClVmIoWillStart(nap,
238 : (uint32_t) (uintptr_t) buf,
239 : (uint32_t) (((uintptr_t) buf) + count - 1));
240 46 : read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
241 : Read)(ndp, (void *) sysaddr, count);
242 46 : NaClVmIoHasEnded(nap,
243 : (uint32_t) (uintptr_t) buf,
244 : (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 0 : }
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 16 : }
257 41 : }
258 41 : NaClLog(8, "read result: %.*s%s\n",
259 : (int) log_bytes, (char *) sysaddr, ellipsis);
260 41 : } 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 50 : return retval;
269 : }
270 :
271 51907 : int32_t NaClSysWrite(struct NaClAppThread *natp,
272 51907 : int d,
273 51907 : void *buf,
274 51907 : size_t count) {
275 51907 : struct NaClApp *nap = natp->nap;
276 51907 : int32_t retval = -NACL_ABI_EINVAL;
277 51907 : ssize_t write_result = -NACL_ABI_EINVAL;
278 51907 : uintptr_t sysaddr;
279 51907 : char const *ellipsis = "";
280 51907 : struct NaClDesc *ndp;
281 51907 : size_t log_bytes;
282 :
283 51907 : 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 51907 : ndp = NaClAppGetDesc(nap, d);
290 51907 : NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
291 51907 : if (NULL == ndp) {
292 5 : retval = -NACL_ABI_EBADF;
293 5 : goto cleanup;
294 : }
295 :
296 51902 : sysaddr = NaClUserToSysAddrRange(nap, (uintptr_t) buf, count);
297 51902 : if (kNaClBadAddress == sysaddr) {
298 1 : NaClDescUnref(ndp);
299 1 : retval = -NACL_ABI_EFAULT;
300 1 : goto cleanup;
301 : }
302 :
303 51901 : log_bytes = count;
304 51901 : if (log_bytes > INT32_MAX) {
305 0 : log_bytes = INT32_MAX;
306 0 : ellipsis = "...";
307 0 : }
308 51901 : if (NaClLogGetVerbosity() < 10) {
309 51901 : if (log_bytes > kdefault_io_buffer_bytes_to_log) {
310 1397 : log_bytes = kdefault_io_buffer_bytes_to_log;
311 1397 : ellipsis = "...";
312 1397 : }
313 51901 : }
314 51901 : 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 51901 : if (count > INT32_MAX) {
323 0 : count = INT32_MAX;
324 0 : }
325 :
326 51901 : NaClVmIoWillStart(nap,
327 : (uint32_t) (uintptr_t) buf,
328 : (uint32_t) (((uintptr_t) buf) + count - 1));
329 51901 : write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
330 : Write)(ndp, (void *) sysaddr, count);
331 51901 : NaClVmIoHasEnded(nap,
332 : (uint32_t) (uintptr_t) buf,
333 : (uint32_t) (((uintptr_t) buf) + count - 1));
334 :
335 51901 : NaClDescUnref(ndp);
336 :
337 : /* This cast is safe because we clamped count above.*/
338 51901 : retval = (int32_t) write_result;
339 :
340 : cleanup:
341 51907 : 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 46 : int32_t NaClSysLseek(struct NaClAppThread *natp,
349 46 : int d,
350 46 : nacl_abi_off_t *offp,
351 46 : int whence) {
352 46 : struct NaClApp *nap = natp->nap;
353 46 : nacl_abi_off_t offset;
354 46 : nacl_off64_t retval64;
355 46 : int32_t retval = -NACL_ABI_EINVAL;
356 46 : struct NaClDesc *ndp;
357 :
358 46 : 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 46 : ndp = NaClAppGetDesc(nap, d);
364 46 : if (NULL == ndp) {
365 1 : retval = -NACL_ABI_EBADF;
366 1 : goto cleanup;
367 : }
368 :
369 45 : if (!NaClCopyInFromUser(nap, &offset, (uintptr_t) offp, sizeof offset)) {
370 0 : retval = -NACL_ABI_EFAULT;
371 0 : goto cleanup_unref;
372 : }
373 45 : NaClLog(4, "offset 0x%08"NACL_PRIxNACL_OFF"\n", offset);
374 :
375 45 : retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
376 : Seek)(ndp, (nacl_off64_t) offset, whence);
377 45 : if (NaClOff64IsNegErrno(&retval64)) {
378 3 : retval = (int32_t) retval64;
379 3 : } else {
380 42 : if (NaClCopyOutToUser(nap, (uintptr_t) offp, &retval64, sizeof retval64)) {
381 42 : retval = 0;
382 42 : } else {
383 0 : NaClLog(LOG_FATAL,
384 : "NaClSysLseek: in/out ptr became invalid at copyout?\n");
385 : }
386 45 : }
387 : cleanup_unref:
388 45 : NaClDescUnref(ndp);
389 : cleanup:
390 46 : return retval;
391 : }
392 :
393 191 : int32_t NaClSysFstat(struct NaClAppThread *natp,
394 191 : int d,
395 191 : struct nacl_abi_stat *nasp) {
396 191 : struct NaClApp *nap = natp->nap;
397 191 : int32_t retval = -NACL_ABI_EINVAL;
398 191 : struct NaClDesc *ndp;
399 191 : struct nacl_abi_stat result;
400 :
401 191 : 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 191 : NaClLog(4,
408 : " sizeof(struct nacl_abi_stat) = %"NACL_PRIuS" (0x%"NACL_PRIxS")\n",
409 : sizeof *nasp, sizeof *nasp);
410 :
411 191 : ndp = NaClAppGetDesc(nap, d);
412 191 : if (NULL == ndp) {
413 0 : NaClLog(4, "bad desc\n");
414 0 : retval = -NACL_ABI_EBADF;
415 0 : goto cleanup;
416 : }
417 :
418 191 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
419 : Fstat)(ndp, &result);
420 191 : if (0 == retval) {
421 191 : if (!NaClCopyOutToUser(nap, (uintptr_t) nasp,
422 : &result, sizeof result)) {
423 0 : retval = -NACL_ABI_EFAULT;
424 0 : }
425 191 : }
426 :
427 191 : NaClDescUnref(ndp);
428 : cleanup:
429 191 : return retval;
430 : }
|