Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sys_filename.c
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 static uint32_t CopyPathFromUser(struct NaClApp *nap,
27                                  char           *dest,
28                                  size_t         num_bytes,
29                                  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   if (!NaClCopyInFromUserZStr(nap, dest, num_bytes, src)) {
35     if (dest[0] == '\0') {
36       NaClLog(LOG_ERROR, "NaClSys: invalid address for pathname\n");
37       return -NACL_ABI_EFAULT;
38     }
39
40     NaClLog(LOG_ERROR, "NaClSys: pathname string too long\n");
41     return -NACL_ABI_ENAMETOOLONG;
42   }
43
44   return 0;
45 }
46
47 int32_t NaClSysOpen(struct NaClAppThread  *natp,
48                     uint32_t              pathname,
49                     int                   flags,
50                     int                   mode) {
51   struct NaClApp       *nap = natp->nap;
52   uint32_t             retval = -NACL_ABI_EINVAL;
53   char                 path[NACL_CONFIG_PATH_MAX];
54   nacl_host_stat_t     stbuf;
55   int                  allowed_flags;
56
57   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   if (!NaClAclBypassChecks) {
62     return -NACL_ABI_EACCES;
63   }
64
65   retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname);
66   if (0 != retval)
67     goto cleanup;
68
69   allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
70                    | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
71   if (0 != (flags & ~allowed_flags)) {
72     NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
73             flags);
74     flags &= allowed_flags;
75   }
76   if (0 != (mode & ~0600)) {
77     NaClLog(1, "IGNORING Invalid access mode bits 0%o\n", mode);
78     mode &= 0600;
79   }
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   retval = NaClHostDescStat(path, &stbuf);
92
93   /* Windows does not have S_ISDIR(m) macro */
94   if (0 == retval && S_IFDIR == (S_IFDIR & stbuf.st_mode)) {
95     struct NaClHostDir  *hd;
96
97     hd = malloc(sizeof *hd);
98     if (NULL == hd) {
99       retval = -NACL_ABI_ENOMEM;
100       goto cleanup;
101     }
102     retval = NaClHostDirOpen(hd, path);
103     NaClLog(1, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s) returned %d\n",
104             (uintptr_t) hd, path, retval);
105     if (0 == retval) {
106       retval = NaClAppSetDescAvail(
107           nap, (struct NaClDesc *) NaClDescDirDescMake(hd));
108       NaClLog(1, "Entered directory into open file table at %d\n",
109               retval);
110     }
111   } else {
112     struct NaClHostDesc  *hd;
113
114     hd = malloc(sizeof *hd);
115     if (NULL == hd) {
116       retval = -NACL_ABI_ENOMEM;
117       goto cleanup;
118     }
119     retval = NaClHostDescOpen(hd, path, flags, mode);
120     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     if (0 == retval) {
124       struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(hd);
125       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         NaClDescSetFlags(desc,
132                          NaClDescGetFlags(desc) | NACL_DESC_FLAGS_MMAP_EXEC_OK);
133       }
134       retval = NaClAppSetDescAvail(nap, desc);
135       NaClLog(1, "Entered into open file table at %d\n", retval);
136     }
137   }
138 cleanup:
139   return retval;
140 }
141
142 int32_t NaClSysStat(struct NaClAppThread  *natp,
143                     uint32_t              pathname,
144                     uint32_t              nasp) {
145   struct NaClApp      *nap = natp->nap;
146   int32_t             retval = -NACL_ABI_EINVAL;
147   char                path[NACL_CONFIG_PATH_MAX];
148   nacl_host_stat_t    stbuf;
149
150   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   if (!NaClAclBypassChecks) {
155     return -NACL_ABI_EACCES;
156   }
157
158   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
159   if (0 != retval)
160     goto cleanup;
161
162   /*
163    * Perform a host stat.
164    */
165   retval = NaClHostDescStat(path, &stbuf);
166   if (0 == retval) {
167     struct nacl_abi_stat abi_stbuf;
168
169     retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf);
170     if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) {
171       retval = -NACL_ABI_EFAULT;
172     }
173   }
174 cleanup:
175   return retval;
176 }
177
178 int32_t NaClSysMkdir(struct NaClAppThread *natp,
179                      uint32_t             pathname,
180                      int                  mode) {
181   struct NaClApp *nap = natp->nap;
182   char           path[NACL_CONFIG_PATH_MAX];
183   int32_t        retval = -NACL_ABI_EINVAL;
184
185   if (!NaClAclBypassChecks) {
186     retval = -NACL_ABI_EACCES;
187     goto cleanup;
188   }
189
190   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
191   if (0 != retval)
192     goto cleanup;
193
194   retval = NaClHostDescMkdir(path, mode);
195 cleanup:
196   return retval;
197 }
198
199 int32_t NaClSysRmdir(struct NaClAppThread *natp,
200                      uint32_t             pathname) {
201   struct NaClApp *nap = natp->nap;
202   char           path[NACL_CONFIG_PATH_MAX];
203   int32_t        retval = -NACL_ABI_EINVAL;
204
205   if (!NaClAclBypassChecks) {
206     retval = -NACL_ABI_EACCES;
207     goto cleanup;
208   }
209
210   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
211   if (0 != retval)
212     goto cleanup;
213
214   retval = NaClHostDescRmdir(path);
215 cleanup:
216   return retval;
217 }
218
219 int32_t NaClSysChdir(struct NaClAppThread *natp,
220                      uint32_t             pathname) {
221   struct NaClApp *nap = natp->nap;
222   char           path[NACL_CONFIG_PATH_MAX];
223   int32_t        retval = -NACL_ABI_EINVAL;
224
225   if (!NaClAclBypassChecks) {
226     retval = -NACL_ABI_EACCES;
227     goto cleanup;
228   }
229
230   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
231   if (0 != retval)
232     goto cleanup;
233
234   retval = NaClHostDescChdir(path);
235 cleanup:
236   return retval;
237 }
238
239 int32_t NaClSysGetcwd(struct NaClAppThread *natp,
240                       uint32_t             buffer,
241                       int                  len) {
242   struct NaClApp *nap = natp->nap;
243   int32_t        retval = -NACL_ABI_EINVAL;
244   char           path[NACL_CONFIG_PATH_MAX];
245
246   if (!NaClAclBypassChecks) {
247     retval = -NACL_ABI_EACCES;
248     goto cleanup;
249   }
250
251   if (len >= NACL_CONFIG_PATH_MAX)
252     len = NACL_CONFIG_PATH_MAX - 1;
253
254   retval = NaClHostDescGetcwd(path, len);
255   if (retval != 0)
256     goto cleanup;
257
258   if (!NaClCopyOutToUser(nap, buffer, &path, strlen(path) + 1))
259     retval = -NACL_ABI_EFAULT;
260
261 cleanup:
262   return retval;
263 }
264
265 int32_t NaClSysUnlink(struct NaClAppThread *natp,
266                       uint32_t             pathname) {
267   struct NaClApp *nap = natp->nap;
268   char           path[NACL_CONFIG_PATH_MAX];
269   int32_t        retval = -NACL_ABI_EINVAL;
270
271   if (!NaClAclBypassChecks) {
272     retval = -NACL_ABI_EACCES;
273     goto cleanup;
274   }
275
276   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
277   if (0 != retval)
278     goto cleanup;
279
280   retval = NaClHostDescUnlink(path);
281   NaClLog(3, "NaClHostDescUnlink '%s' -> %d\n", path, retval);
282 cleanup:
283   return retval;
284 }
285
286 int32_t NaClSysTruncate(struct NaClAppThread *natp,
287                         uint32_t             pathname,
288                         uint32_t             length_addr) {
289   struct NaClApp *nap = natp->nap;
290   char           path[NACL_CONFIG_PATH_MAX];
291   int32_t        retval = -NACL_ABI_EINVAL;
292   nacl_abi_off_t length;
293
294   if (!NaClAclBypassChecks)
295     return -NACL_ABI_EACCES;
296
297   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
298   if (0 != retval)
299     return retval;
300
301   if (!NaClCopyInFromUser(nap, &length, length_addr, sizeof length))
302     return -NACL_ABI_EFAULT;
303
304   retval = NaClHostDescTruncate(path, length);
305   NaClLog(3, "NaClHostDescTruncate '%s' %"NACL_PRId64" -> %d\n",
306           path, length, retval);
307   return retval;
308 }
309
310 int32_t NaClSysLstat(struct NaClAppThread  *natp,
311                      uint32_t              pathname,
312                      uint32_t              nasp) {
313   struct NaClApp      *nap = natp->nap;
314   int32_t             retval = -NACL_ABI_EINVAL;
315   char                path[NACL_CONFIG_PATH_MAX];
316   nacl_host_stat_t    stbuf;
317
318   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   if (!NaClAclBypassChecks) {
323     return -NACL_ABI_EACCES;
324   }
325
326   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
327   if (0 != retval)
328     return retval;
329
330   /*
331    * Perform a host stat.
332    */
333   retval = NaClHostDescLstat(path, &stbuf);
334   if (0 == retval) {
335     struct nacl_abi_stat abi_stbuf;
336
337     retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf);
338     if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) {
339       return -NACL_ABI_EFAULT;
340     }
341   }
342   return retval;
343 }
344
345 int32_t NaClSysLink(struct NaClAppThread *natp,
346                     uint32_t              oldname,
347                     uint32_t              newname) {
348   struct NaClApp *nap = natp->nap;
349   char           oldpath[NACL_CONFIG_PATH_MAX];
350   char           newpath[NACL_CONFIG_PATH_MAX];
351   int32_t        retval = -NACL_ABI_EINVAL;
352
353   if (!NaClAclBypassChecks)
354     return -NACL_ABI_EACCES;
355
356   retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
357   if (0 != retval)
358     return retval;
359
360   retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
361   if (0 != retval)
362     return retval;
363
364   return NaClHostDescLink(oldpath, newpath);
365 }
366
367 int32_t NaClSysRename(struct NaClAppThread *natp,
368                       uint32_t             oldname,
369                       uint32_t             newname) {
370   struct NaClApp *nap = natp->nap;
371   char           oldpath[NACL_CONFIG_PATH_MAX];
372   char           newpath[NACL_CONFIG_PATH_MAX];
373   int32_t        retval = -NACL_ABI_EINVAL;
374
375   if (!NaClAclBypassChecks)
376     return -NACL_ABI_EACCES;
377
378   retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
379   if (0 != retval)
380     return retval;
381
382   retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
383   if (0 != retval)
384     return retval;
385
386   return NaClHostDescRename(oldpath, newpath);
387 }
388
389 int32_t NaClSysSymlink(struct NaClAppThread *natp,
390                        uint32_t             oldname,
391                        uint32_t             newname) {
392   struct NaClApp *nap = natp->nap;
393   char           oldpath[NACL_CONFIG_PATH_MAX];
394   char           newpath[NACL_CONFIG_PATH_MAX];
395   int32_t        retval = -NACL_ABI_EINVAL;
396
397   if (!NaClAclBypassChecks)
398     return -NACL_ABI_EACCES;
399
400   retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname);
401   if (0 != retval)
402     return retval;
403
404   retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname);
405   if (0 != retval)
406     return retval;
407
408   return NaClHostDescSymlink(oldpath, newpath);
409 }
410
411 int32_t NaClSysChmod(struct NaClAppThread *natp,
412                      uint32_t             path,
413                      nacl_abi_mode_t      mode) {
414   struct NaClApp *nap = natp->nap;
415   char           pathname[NACL_CONFIG_PATH_MAX];
416   int32_t        retval = -NACL_ABI_EINVAL;
417
418   if (!NaClAclBypassChecks)
419     return -NACL_ABI_EACCES;
420
421   retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
422   if (0 != retval)
423     return retval;
424
425   return NaClHostDescChmod(pathname, mode);
426 }
427
428 int32_t NaClSysAccess(struct NaClAppThread *natp,
429                       uint32_t             path,
430                       int                  amode) {
431   struct NaClApp *nap = natp->nap;
432   char           pathname[NACL_CONFIG_PATH_MAX];
433   int32_t        retval = -NACL_ABI_EINVAL;
434
435   if (!NaClAclBypassChecks)
436     return -NACL_ABI_EACCES;
437
438   /*
439    * amode must either be F_OK or some combination of the three permission bits.
440    */
441   if (amode != NACL_ABI_F_OK
442       && (amode & ~(NACL_ABI_R_OK | NACL_ABI_W_OK | NACL_ABI_X_OK)) != 0)
443     return -NACL_ABI_EINVAL;
444
445   retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
446   if (0 != retval)
447     return retval;
448
449   retval = NaClHostDescAccess(pathname, amode);
450   NaClLog(3, "NaClHostDescAccess '%s' %d -> %d\n", pathname, amode, retval);
451   return retval;
452 }
453
454 int32_t NaClSysReadlink(struct NaClAppThread *natp,
455                         uint32_t             path,
456                         uint32_t             buffer,
457                         size_t               count) {
458   struct NaClApp *nap = natp->nap;
459   char           pathname[NACL_CONFIG_PATH_MAX];
460   char           realpath[NACL_CONFIG_PATH_MAX];
461   int32_t        retval = -NACL_ABI_EINVAL;
462
463   if (!NaClAclBypassChecks)
464     return -NACL_ABI_EACCES;
465
466   if (count >= NACL_CONFIG_PATH_MAX)
467     return -NACL_ABI_EINVAL;
468
469   retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
470   if (0 != retval)
471     return retval;
472
473   retval = NaClHostDescReadlink(pathname, realpath, count);
474   if (retval < 0)
475     return retval;
476
477   CHECK(retval <= (int32_t)count);
478   if (!NaClCopyOutToUser(nap, buffer, realpath, retval))
479     return -NACL_ABI_EFAULT;
480
481   return retval;
482 }
483
484 int32_t NaClSysUtimes(struct NaClAppThread *natp,
485                       uint32_t             path,
486                       uint32_t             times) {
487   struct NaClApp *nap = natp->nap;
488   char           pathname[NACL_CONFIG_PATH_MAX];
489   int32_t        retval = -NACL_ABI_EINVAL;
490
491   if (!NaClAclBypassChecks)
492     return -NACL_ABI_EACCES;
493
494   retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
495   if (0 != retval)
496     return retval;
497
498   if (times == 0)
499     return -NACL_ABI_EACCES;
500
501   /* TODO(sbc): implement in terms of NaClHost function. */
502   return -NACL_ABI_ENOSYS;
503 }