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_filename.h"
8 :
9 : #include <string.h>
10 :
11 : #include "native_client/src/shared/platform/nacl_check.h"
12 : #include "native_client/src/shared/platform/nacl_host_desc.h"
13 : #include "native_client/src/shared/platform/nacl_host_dir.h"
14 : #include "native_client/src/trusted/desc/nacl_desc_dir.h"
15 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
16 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
17 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
18 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
19 : #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
21 : #include "native_client/src/trusted/service_runtime/nacl_copy.h"
22 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
23 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
24 :
25 :
26 238 : static uint32_t CopyPathFromUser(struct NaClApp *nap,
27 238 : char *dest,
28 238 : size_t num_bytes,
29 238 : uintptr_t src) {
30 : /*
31 : * NaClCopyInFromUserZStr may (try to) get bytes that is outside the
32 : * app's address space and generate a fault.
33 : */
34 238 : if (!NaClCopyInFromUserZStr(nap, dest, num_bytes, src)) {
35 1 : if (dest[0] == '\0') {
36 1 : NaClLog(LOG_ERROR, "NaClSys: invalid address for pathname\n");
37 1 : return -NACL_ABI_EFAULT;
38 : }
39 :
40 0 : NaClLog(LOG_ERROR, "NaClSys: pathname string too long\n");
41 0 : return -NACL_ABI_ENAMETOOLONG;
42 : }
43 :
44 237 : return 0;
45 238 : }
46 :
47 174 : int32_t NaClSysOpen(struct NaClAppThread *natp,
48 174 : uint32_t pathname,
49 174 : int flags,
50 174 : int mode) {
51 174 : struct NaClApp *nap = natp->nap;
52 174 : uint32_t retval = -NACL_ABI_EINVAL;
53 174 : char path[NACL_CONFIG_PATH_MAX];
54 174 : nacl_host_stat_t stbuf;
55 174 : int allowed_flags;
56 :
57 174 : NaClLog(3, "NaClSysOpen(0x%08"NACL_PRIxPTR", "
58 : "0x%08"NACL_PRIx32", 0x%x, 0x%x)\n",
59 : (uintptr_t) natp, pathname, flags, mode);
60 :
61 174 : if (!NaClAclBypassChecks) {
62 0 : return -NACL_ABI_EACCES;
63 : }
64 :
65 174 : retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname);
66 174 : if (0 != retval)
67 1 : goto cleanup;
68 :
69 173 : allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
70 : | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
71 173 : if (0 != (flags & ~allowed_flags)) {
72 0 : NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
73 : flags);
74 0 : flags &= allowed_flags;
75 0 : }
76 173 : if (0 != (mode & ~0600)) {
77 92 : NaClLog(1, "IGNORING Invalid access mode bits 0%o\n", mode);
78 92 : mode &= 0600;
79 92 : }
80 :
81 : /*
82 : * Perform a stat to determine whether the file is a directory.
83 : *
84 : * NB: it is okay for the stat to fail, since the request may be to
85 : * create a new file.
86 : *
87 : * There is a race conditions here: between the stat and the
88 : * open-as-a-file and open-as-a-dir, the type of the object that the
89 : * path refers to can change.
90 : */
91 173 : retval = NaClHostDescStat(path, &stbuf);
92 :
93 : /* Windows does not have S_ISDIR(m) macro */
94 270 : if (0 == retval && S_IFDIR == (S_IFDIR & stbuf.st_mode)) {
95 3 : struct NaClHostDir *hd;
96 :
97 3 : hd = malloc(sizeof *hd);
98 3 : if (NULL == hd) {
99 0 : retval = -NACL_ABI_ENOMEM;
100 0 : goto cleanup;
101 : }
102 3 : retval = NaClHostDirOpen(hd, path);
103 3 : NaClLog(1, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s) returned %d\n",
104 : (uintptr_t) hd, path, retval);
105 3 : if (0 == retval) {
106 6 : retval = NaClAppSetDescAvail(
107 3 : nap, (struct NaClDesc *) NaClDescDirDescMake(hd));
108 3 : NaClLog(1, "Entered directory into open file table at %d\n",
109 : retval);
110 3 : }
111 3 : } else {
112 170 : struct NaClHostDesc *hd;
113 :
114 170 : hd = malloc(sizeof *hd);
115 170 : if (NULL == hd) {
116 0 : retval = -NACL_ABI_ENOMEM;
117 0 : goto cleanup;
118 : }
119 170 : retval = NaClHostDescOpen(hd, path, flags, mode);
120 170 : NaClLog(1,
121 : "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o) returned %d\n",
122 : (uintptr_t) hd, path, flags, mode, retval);
123 170 : if (0 == retval) {
124 165 : struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(hd);
125 165 : if ((flags & NACL_ABI_O_ACCMODE) == NACL_ABI_O_RDONLY) {
126 : /*
127 : * Let any read-only open be used for PROT_EXEC mmap
128 : * calls. Under -a, the user informally warrants that
129 : * files' code segments won't be changed after open.
130 : */
131 72 : NaClDescSetFlags(desc,
132 36 : NaClDescGetFlags(desc) | NACL_DESC_FLAGS_MMAP_EXEC_OK);
133 36 : }
134 165 : retval = NaClAppSetDescAvail(nap, desc);
135 165 : NaClLog(1, "Entered into open file table at %d\n", retval);
136 165 : }
137 173 : }
138 : cleanup:
139 174 : return retval;
140 174 : }
141 :
142 16 : int32_t NaClSysStat(struct NaClAppThread *natp,
143 16 : uint32_t pathname,
144 16 : uint32_t nasp) {
145 16 : struct NaClApp *nap = natp->nap;
146 16 : int32_t retval = -NACL_ABI_EINVAL;
147 16 : char path[NACL_CONFIG_PATH_MAX];
148 16 : nacl_host_stat_t stbuf;
149 :
150 16 : NaClLog(3,
151 : ("Entered NaClSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIx32","
152 : " 0x%08"NACL_PRIx32")\n"), (uintptr_t) natp, pathname, nasp);
153 :
154 16 : if (!NaClAclBypassChecks) {
155 0 : return -NACL_ABI_EACCES;
156 : }
157 :
158 16 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
159 16 : if (0 != retval)
160 0 : goto cleanup;
161 :
162 : /*
163 : * Perform a host stat.
164 : */
165 16 : retval = NaClHostDescStat(path, &stbuf);
166 16 : if (0 == retval) {
167 14 : struct nacl_abi_stat abi_stbuf;
168 :
169 14 : retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf);
170 14 : if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) {
171 0 : retval = -NACL_ABI_EFAULT;
172 0 : }
173 30 : }
174 : cleanup:
175 16 : return retval;
176 16 : }
177 :
178 2 : int32_t NaClSysMkdir(struct NaClAppThread *natp,
179 2 : uint32_t pathname,
180 2 : int mode) {
181 2 : struct NaClApp *nap = natp->nap;
182 2 : char path[NACL_CONFIG_PATH_MAX];
183 2 : int32_t retval = -NACL_ABI_EINVAL;
184 :
185 2 : if (!NaClAclBypassChecks) {
186 0 : retval = -NACL_ABI_EACCES;
187 0 : goto cleanup;
188 : }
189 :
190 2 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
191 2 : if (0 != retval)
192 0 : goto cleanup;
193 :
194 2 : retval = NaClHostDescMkdir(path, mode);
195 : cleanup:
196 2 : return retval;
197 : }
198 :
199 6 : int32_t NaClSysRmdir(struct NaClAppThread *natp,
200 6 : uint32_t pathname) {
201 6 : struct NaClApp *nap = natp->nap;
202 6 : char path[NACL_CONFIG_PATH_MAX];
203 6 : int32_t retval = -NACL_ABI_EINVAL;
204 :
205 6 : if (!NaClAclBypassChecks) {
206 0 : retval = -NACL_ABI_EACCES;
207 0 : goto cleanup;
208 : }
209 :
210 6 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
211 6 : if (0 != retval)
212 0 : goto cleanup;
213 :
214 6 : retval = NaClHostDescRmdir(path);
215 : cleanup:
216 6 : return retval;
217 : }
218 :
219 3 : int32_t NaClSysChdir(struct NaClAppThread *natp,
220 3 : uint32_t pathname) {
221 3 : struct NaClApp *nap = natp->nap;
222 3 : char path[NACL_CONFIG_PATH_MAX];
223 3 : int32_t retval = -NACL_ABI_EINVAL;
224 :
225 3 : if (!NaClAclBypassChecks) {
226 0 : retval = -NACL_ABI_EACCES;
227 0 : goto cleanup;
228 : }
229 :
230 3 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
231 3 : if (0 != retval)
232 0 : goto cleanup;
233 :
234 3 : retval = NaClHostDescChdir(path);
235 : cleanup:
236 3 : return retval;
237 : }
238 :
239 5 : int32_t NaClSysGetcwd(struct NaClAppThread *natp,
240 5 : uint32_t buffer,
241 5 : int len) {
242 5 : struct NaClApp *nap = natp->nap;
243 5 : int32_t retval = -NACL_ABI_EINVAL;
244 5 : char path[NACL_CONFIG_PATH_MAX];
245 :
246 5 : if (!NaClAclBypassChecks) {
247 0 : retval = -NACL_ABI_EACCES;
248 0 : goto cleanup;
249 : }
250 :
251 5 : if (len >= NACL_CONFIG_PATH_MAX)
252 4 : len = NACL_CONFIG_PATH_MAX - 1;
253 :
254 5 : retval = NaClHostDescGetcwd(path, len);
255 5 : if (retval != 0)
256 1 : goto cleanup;
257 :
258 4 : if (!NaClCopyOutToUser(nap, buffer, &path, strlen(path) + 1))
259 4 : retval = -NACL_ABI_EFAULT;
260 :
261 : cleanup:
262 5 : return retval;
263 : }
264 :
265 12 : int32_t NaClSysUnlink(struct NaClAppThread *natp,
266 12 : uint32_t pathname) {
267 12 : struct NaClApp *nap = natp->nap;
268 12 : char path[NACL_CONFIG_PATH_MAX];
269 12 : int32_t retval = -NACL_ABI_EINVAL;
270 :
271 12 : if (!NaClAclBypassChecks) {
272 0 : retval = -NACL_ABI_EACCES;
273 0 : goto cleanup;
274 : }
275 :
276 12 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
277 12 : if (0 != retval)
278 0 : goto cleanup;
279 :
280 12 : retval = NaClHostDescUnlink(path);
281 12 : NaClLog(3, "NaClHostDescUnlink '%s' -> %d\n", path, retval);
282 : cleanup:
283 12 : return retval;
284 : }
285 :
286 2 : int32_t NaClSysTruncate(struct NaClAppThread *natp,
287 2 : uint32_t pathname,
288 2 : uint32_t length_addr) {
289 2 : struct NaClApp *nap = natp->nap;
290 2 : char path[NACL_CONFIG_PATH_MAX];
291 2 : int32_t retval = -NACL_ABI_EINVAL;
292 2 : nacl_abi_off_t length;
293 :
294 2 : if (!NaClAclBypassChecks)
295 0 : return -NACL_ABI_EACCES;
296 :
297 2 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
298 2 : if (0 != retval)
299 0 : return retval;
300 :
301 2 : if (!NaClCopyInFromUser(nap, &length, length_addr, sizeof length))
302 0 : return -NACL_ABI_EFAULT;
303 :
304 2 : retval = NaClHostDescTruncate(path, length);
305 2 : NaClLog(3, "NaClHostDescTruncate '%s' %"NACL_PRId64" -> %d\n",
306 : path, length, retval);
307 2 : return retval;
308 2 : }
309 :
310 2 : int32_t NaClSysLstat(struct NaClAppThread *natp,
311 2 : uint32_t pathname,
312 2 : uint32_t nasp) {
313 2 : struct NaClApp *nap = natp->nap;
314 2 : int32_t retval = -NACL_ABI_EINVAL;
315 2 : char path[NACL_CONFIG_PATH_MAX];
316 2 : nacl_host_stat_t stbuf;
317 :
318 2 : NaClLog(3,
319 : ("Entered NaClSysLstat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIx32","
320 : " 0x%08"NACL_PRIx32")\n"), (uintptr_t) natp, pathname, nasp);
321 :
322 2 : if (!NaClAclBypassChecks) {
323 0 : return -NACL_ABI_EACCES;
324 : }
325 :
326 2 : retval = CopyPathFromUser(nap, path, sizeof path, pathname);
327 2 : if (0 != retval)
328 0 : return retval;
329 :
330 : /*
331 : * Perform a host stat.
332 : */
333 2 : retval = NaClHostDescLstat(path, &stbuf);
334 2 : if (0 == retval) {
335 2 : struct nacl_abi_stat abi_stbuf;
336 :
337 2 : retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf);
338 2 : if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) {
339 0 : return -NACL_ABI_EFAULT;
340 : }
341 2 : }
342 2 : return retval;
343 2 : }
344 :
345 1 : int32_t NaClSysLink(struct NaClAppThread *natp,
346 1 : uint32_t oldname,
347 1 : uint32_t newname) {
348 1 : struct NaClApp *nap = natp->nap;
349 1 : char oldpath[NACL_CONFIG_PATH_MAX];
350 1 : char newpath[NACL_CONFIG_PATH_MAX];
351 1 : int32_t retval = -NACL_ABI_EINVAL;
352 :
353 1 : if (!NaClAclBypassChecks)
354 0 : return -NACL_ABI_EACCES;
355 :
356 1 : retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
357 1 : if (0 != retval)
358 0 : return retval;
359 :
360 1 : retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
361 1 : if (0 != retval)
362 0 : return retval;
363 :
364 1 : return NaClHostDescLink(oldpath, newpath);
365 1 : }
366 :
367 1 : int32_t NaClSysRename(struct NaClAppThread *natp,
368 1 : uint32_t oldname,
369 1 : uint32_t newname) {
370 1 : struct NaClApp *nap = natp->nap;
371 1 : char oldpath[NACL_CONFIG_PATH_MAX];
372 1 : char newpath[NACL_CONFIG_PATH_MAX];
373 1 : int32_t retval = -NACL_ABI_EINVAL;
374 :
375 1 : if (!NaClAclBypassChecks)
376 0 : return -NACL_ABI_EACCES;
377 :
378 1 : retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
379 1 : if (0 != retval)
380 0 : return retval;
381 :
382 1 : retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
383 1 : if (0 != retval)
384 0 : return retval;
385 :
386 1 : return NaClHostDescRename(oldpath, newpath);
387 1 : }
388 :
389 2 : int32_t NaClSysSymlink(struct NaClAppThread *natp,
390 2 : uint32_t oldname,
391 2 : uint32_t newname) {
392 2 : struct NaClApp *nap = natp->nap;
393 2 : char oldpath[NACL_CONFIG_PATH_MAX];
394 2 : char newpath[NACL_CONFIG_PATH_MAX];
395 2 : int32_t retval = -NACL_ABI_EINVAL;
396 :
397 2 : if (!NaClAclBypassChecks)
398 0 : return -NACL_ABI_EACCES;
399 :
400 2 : retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
401 2 : if (0 != retval)
402 0 : return retval;
403 :
404 2 : retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
405 2 : if (0 != retval)
406 0 : return retval;
407 :
408 2 : return NaClHostDescSymlink(oldpath, newpath);
409 2 : }
410 :
411 1 : int32_t NaClSysChmod(struct NaClAppThread *natp,
412 1 : uint32_t path,
413 1 : nacl_abi_mode_t mode) {
414 1 : struct NaClApp *nap = natp->nap;
415 1 : char pathname[NACL_CONFIG_PATH_MAX];
416 1 : int32_t retval = -NACL_ABI_EINVAL;
417 :
418 1 : if (!NaClAclBypassChecks)
419 0 : return -NACL_ABI_EACCES;
420 :
421 1 : retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
422 1 : if (0 != retval)
423 0 : return retval;
424 :
425 1 : return NaClHostDescChmod(pathname, mode);
426 1 : }
427 :
428 9 : int32_t NaClSysAccess(struct NaClAppThread *natp,
429 9 : uint32_t path,
430 9 : int amode) {
431 9 : struct NaClApp *nap = natp->nap;
432 9 : char pathname[NACL_CONFIG_PATH_MAX];
433 9 : int32_t retval = -NACL_ABI_EINVAL;
434 :
435 9 : if (!NaClAclBypassChecks)
436 0 : return -NACL_ABI_EACCES;
437 :
438 : /*
439 : * amode must either be F_OK or some combination of the three permission bits.
440 : */
441 15 : if (amode != NACL_ABI_F_OK
442 : && (amode & ~(NACL_ABI_R_OK | NACL_ABI_W_OK | NACL_ABI_X_OK)) != 0)
443 0 : return -NACL_ABI_EINVAL;
444 :
445 9 : retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
446 9 : if (0 != retval)
447 0 : return retval;
448 :
449 9 : retval = NaClHostDescAccess(pathname, amode);
450 9 : NaClLog(3, "NaClHostDescAccess '%s' %d -> %d\n", pathname, amode, retval);
451 9 : return retval;
452 9 : }
453 :
454 2 : int32_t NaClSysReadlink(struct NaClAppThread *natp,
455 2 : uint32_t path,
456 2 : uint32_t buffer,
457 2 : uint32_t buffer_size) {
458 2 : struct NaClApp *nap = natp->nap;
459 2 : char pathname[NACL_CONFIG_PATH_MAX];
460 2 : char realpath[NACL_CONFIG_PATH_MAX];
461 2 : int32_t retval = -NACL_ABI_EINVAL;
462 2 : uint32_t result_size;
463 :
464 2 : if (!NaClAclBypassChecks)
465 0 : return -NACL_ABI_EACCES;
466 :
467 2 : retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
468 2 : if (0 != retval)
469 0 : return retval;
470 :
471 2 : retval = NaClHostDescReadlink(pathname, realpath, sizeof(realpath));
472 2 : if (retval < 0)
473 0 : return retval;
474 2 : result_size = retval;
475 6 : CHECK(result_size <= sizeof(realpath)); /* Sanity check */
476 :
477 2 : if (result_size == sizeof(realpath)) {
478 : /*
479 : * The result either got truncated or it fit exactly. Treat it as
480 : * truncation.
481 : *
482 : * We can't distinguish an exact fit from truncation without doing
483 : * another readlink() call. If result_size == buffer_size, we could
484 : * return success here, but there's little point, because untrusted
485 : * code can't distinguish the two either and we don't currently allow
486 : * using a larger buffer.
487 : */
488 0 : return -NACL_ABI_ENAMETOOLONG;
489 : }
490 :
491 2 : if (result_size > buffer_size)
492 1 : result_size = buffer_size;
493 2 : if (!NaClCopyOutToUser(nap, buffer, realpath, result_size))
494 0 : return -NACL_ABI_EFAULT;
495 :
496 2 : return result_size;
497 2 : }
498 :
499 1 : int32_t NaClSysUtimes(struct NaClAppThread *natp,
500 1 : uint32_t path,
501 1 : uint32_t times) {
502 1 : struct NaClApp *nap = natp->nap;
503 1 : char pathname[NACL_CONFIG_PATH_MAX];
504 1 : int32_t retval = -NACL_ABI_EINVAL;
505 :
506 1 : if (!NaClAclBypassChecks)
507 0 : return -NACL_ABI_EACCES;
508 :
509 1 : retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
510 1 : if (0 != retval)
511 0 : return retval;
512 :
513 1 : if (times == 0)
514 0 : return -NACL_ABI_EACCES;
515 :
516 : /* TODO(sbc): implement in terms of NaClHost function. */
517 1 : return -NACL_ABI_ENOSYS;
518 1 : }
|