e9410674dba542ded2c94bb069787ba43627bf70
[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_host_desc.h"
12 #include "native_client/src/shared/platform/nacl_host_dir.h"
13 #include "native_client/src/trusted/desc/nacl_desc_dir.h"
14 #include "native_client/src/trusted/desc/nacl_desc_io.h"
15 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
16 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
17 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
18 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
19 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
20 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
21 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
22
23
24 /*
25  * NaClOpenAclCheck: Is the NaCl app authorized to open this file?  The
26  * return value is syscall return convention, so 0 is success and
27  * small negative numbers are negated errno values.
28  */
29 int32_t NaClOpenAclCheck(struct NaClApp *nap,
30                          char const     *path,
31                          int            flags,
32                          int            mode) {
33   /*
34    * TODO(bsy): provide some minimal authorization check, based on
35    * whether a debug flag is set; eventually provide a data-driven
36    * authorization configuration mechanism, perhaps persisted via
37    * gears.  need GUI for user configuration, as well as designing an
38    * appropriate language (with sufficient expressiveness), however.
39    */
40   NaClLog(1, "NaClOpenAclCheck(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o)\n",
41           (uintptr_t) nap, path, flags, mode);
42   if (3 < NaClLogGetVerbosity()) {
43     NaClLog(0, "O_ACCMODE: 0%o\n", flags & NACL_ABI_O_ACCMODE);
44     NaClLog(0, "O_RDONLY = %d\n", NACL_ABI_O_RDONLY);
45     NaClLog(0, "O_WRONLY = %d\n", NACL_ABI_O_WRONLY);
46     NaClLog(0, "O_RDWR   = %d\n", NACL_ABI_O_RDWR);
47 #define FLOG(VAR, BIT) do {\
48       NaClLog(1, "%s: %s\n", #BIT, (VAR & BIT) ? "yes" : "no");\
49     } while (0)
50     FLOG(flags, NACL_ABI_O_CREAT);
51     FLOG(flags, NACL_ABI_O_TRUNC);
52     FLOG(flags, NACL_ABI_O_APPEND);
53 #undef FLOG
54   }
55   if (NaClAclBypassChecks) {
56     return 0;
57   }
58   return -NACL_ABI_EACCES;
59 }
60
61 /*
62  * NaClStatAclCheck: Is the NaCl app authorized to stat this pathname?  The
63  * return value is syscall return convention, so 0 is success and
64  * small negative numbers are negated errno values.
65  *
66  * This is primarily for debug use.  File access should be through
67  * SRPC-based file servers.
68  */
69 int32_t NaClStatAclCheck(struct NaClApp *nap,
70                          char const     *path) {
71   NaClLog(2,
72           "NaClStatAclCheck(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) nap, path);
73   if (NaClAclBypassChecks) {
74     return 0;
75   }
76   return -NACL_ABI_EACCES;
77 }
78
79 static uint32_t CopyPathFromUser(struct NaClApp *nap,
80                                  char           *dest,
81                                  size_t         num_bytes,
82                                  uintptr_t      src) {
83   /*
84    * NaClCopyInFromUserZStr may (try to) get bytes that is outside the
85    * app's address space and generate a fault.
86    */
87   if (!NaClCopyInFromUserZStr(nap, dest, num_bytes, src)) {
88     if (dest[0] == '\0') {
89       NaClLog(LOG_ERROR, "NaClSys: invalid address for pathname\n");
90       return -NACL_ABI_EFAULT;
91     }
92
93     NaClLog(LOG_ERROR, "NaClSys: pathname string too long\n");
94     return -NACL_ABI_ENAMETOOLONG;
95   }
96
97   return 0;
98 }
99
100 int32_t NaClSysOpen(struct NaClAppThread  *natp,
101                     char                  *pathname,
102                     int                   flags,
103                     int                   mode) {
104   struct NaClApp       *nap = natp->nap;
105   uint32_t             retval = -NACL_ABI_EINVAL;
106   char                 path[NACL_CONFIG_PATH_MAX];
107   nacl_host_stat_t     stbuf;
108   int                  allowed_flags;
109
110   NaClLog(3, "NaClSysOpen(0x%08"NACL_PRIxPTR", "
111           "0x%08"NACL_PRIxPTR", 0x%x, 0x%x)\n",
112           (uintptr_t) natp, (uintptr_t) pathname, flags, mode);
113
114   retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname);
115   if (0 != retval)
116     goto cleanup;
117
118   allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
119                    | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
120   if (0 != (flags & ~allowed_flags)) {
121     NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
122             flags);
123     flags &= allowed_flags;
124   }
125   if (0 != (mode & ~0600)) {
126     NaClLog(1, "IGNORING Invalid access mode bits 0%o\n", mode);
127     mode &= 0600;
128   }
129
130   retval = NaClOpenAclCheck(nap, path, flags, mode);
131   if (0 != retval) {
132     NaClLog(3, "Open ACL check rejected \"%s\".\n", path);
133     goto cleanup;
134   }
135
136   /*
137    * Perform a stat to determine whether the file is a directory.
138    *
139    * NB: it is okay for the stat to fail, since the request may be to
140    * create a new file.
141    *
142    * There is a race conditions here: between the stat and the
143    * open-as-a-file and open-as-a-dir, the type of the object that the
144    * path refers to can change.
145    */
146   retval = NaClHostDescStat(path, &stbuf);
147
148   /* Windows does not have S_ISDIR(m) macro */
149   if (0 == retval && S_IFDIR == (S_IFDIR & stbuf.st_mode)) {
150     struct NaClHostDir  *hd;
151
152     hd = malloc(sizeof *hd);
153     if (NULL == hd) {
154       retval = -NACL_ABI_ENOMEM;
155       goto cleanup;
156     }
157     retval = NaClHostDirOpen(hd, path);
158     NaClLog(1, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s) returned %d\n",
159             (uintptr_t) hd, path, retval);
160     if (0 == retval) {
161       retval = NaClAppSetDescAvail(
162           nap, (struct NaClDesc *) NaClDescDirDescMake(hd));
163       NaClLog(1, "Entered directory into open file table at %d\n",
164               retval);
165     }
166   } else {
167     struct NaClHostDesc  *hd;
168
169     hd = malloc(sizeof *hd);
170     if (NULL == hd) {
171       retval = -NACL_ABI_ENOMEM;
172       goto cleanup;
173     }
174     retval = NaClHostDescOpen(hd, path, flags, mode);
175     NaClLog(1,
176             "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o) returned %d\n",
177             (uintptr_t) hd, path, flags, mode, retval);
178     if (0 == retval) {
179       struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(hd);
180       if ((flags & NACL_ABI_O_ACCMODE) == NACL_ABI_O_RDONLY) {
181         /*
182          * Let any read-only open be used for PROT_EXEC mmap
183          * calls.  Under -a, the user informally warrants that
184          * files' code segments won't be changed after open.
185          */
186         NaClDescSetFlags(desc,
187                          NaClDescGetFlags(desc) | NACL_DESC_FLAGS_MMAP_EXEC_OK);
188       }
189       retval = NaClAppSetDescAvail(nap, desc);
190       NaClLog(1, "Entered into open file table at %d\n", retval);
191     }
192   }
193 cleanup:
194   return retval;
195 }
196
197 int32_t NaClSysStat(struct NaClAppThread  *natp,
198                     const char            *pathname,
199                     struct nacl_abi_stat  *buf) {
200   struct NaClApp      *nap = natp->nap;
201   int32_t             retval = -NACL_ABI_EINVAL;
202   char                path[NACL_CONFIG_PATH_MAX];
203   nacl_host_stat_t    stbuf;
204
205   NaClLog(3,
206           ("Entered NaClSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
207            " 0x%08"NACL_PRIxPTR")\n"),
208           (uintptr_t) natp, (uintptr_t) pathname, (uintptr_t) buf);
209
210   retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname);
211   if (0 != retval)
212     goto cleanup;
213
214   retval = NaClStatAclCheck(nap, path);
215   if (0 != retval)
216     goto cleanup;
217
218   /*
219    * Perform a host stat.
220    */
221   retval = NaClHostDescStat(path, &stbuf);
222   if (0 == retval) {
223     struct nacl_abi_stat abi_stbuf;
224
225     retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf,
226                                               &stbuf);
227     if (!NaClCopyOutToUser(nap, (uintptr_t) buf,
228                            &abi_stbuf, sizeof abi_stbuf)) {
229       retval = -NACL_ABI_EFAULT;
230     }
231   }
232 cleanup:
233   return retval;
234 }
235
236 int32_t NaClSysMkdir(struct NaClAppThread *natp,
237                      uint32_t             pathname,
238                      int                  mode) {
239   struct NaClApp *nap = natp->nap;
240   char           path[NACL_CONFIG_PATH_MAX];
241   int32_t        retval = -NACL_ABI_EINVAL;
242
243   if (!NaClAclBypassChecks) {
244     retval = -NACL_ABI_EACCES;
245     goto cleanup;
246   }
247
248   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
249   if (0 != retval)
250     goto cleanup;
251
252   retval = NaClHostDescMkdir(path, mode);
253 cleanup:
254   return retval;
255 }
256
257 int32_t NaClSysRmdir(struct NaClAppThread *natp,
258                      uint32_t             pathname) {
259   struct NaClApp *nap = natp->nap;
260   char           path[NACL_CONFIG_PATH_MAX];
261   int32_t        retval = -NACL_ABI_EINVAL;
262
263   if (!NaClAclBypassChecks) {
264     retval = -NACL_ABI_EACCES;
265     goto cleanup;
266   }
267
268   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
269   if (0 != retval)
270     goto cleanup;
271
272   retval = NaClHostDescRmdir(path);
273 cleanup:
274   return retval;
275 }
276
277 int32_t NaClSysChdir(struct NaClAppThread *natp,
278                      uint32_t             pathname) {
279   struct NaClApp *nap = natp->nap;
280   char           path[NACL_CONFIG_PATH_MAX];
281   int32_t        retval = -NACL_ABI_EINVAL;
282
283   if (!NaClAclBypassChecks) {
284     retval = -NACL_ABI_EACCES;
285     goto cleanup;
286   }
287
288   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
289   if (0 != retval)
290     goto cleanup;
291
292   retval = NaClHostDescChdir(path);
293 cleanup:
294   return retval;
295 }
296
297 int32_t NaClSysGetcwd(struct NaClAppThread *natp,
298                       uint32_t             buffer,
299                       int                  len) {
300   struct NaClApp *nap = natp->nap;
301   int32_t        retval = -NACL_ABI_EINVAL;
302   char           path[NACL_CONFIG_PATH_MAX];
303
304   if (!NaClAclBypassChecks) {
305     retval = -NACL_ABI_EACCES;
306     goto cleanup;
307   }
308
309   if (len >= NACL_CONFIG_PATH_MAX)
310     len = NACL_CONFIG_PATH_MAX - 1;
311
312   retval = NaClHostDescGetcwd(path, len);
313   if (retval != 0)
314     goto cleanup;
315
316   if (!NaClCopyOutToUser(nap, buffer, &path, strlen(path) + 1))
317     retval = -NACL_ABI_EFAULT;
318
319 cleanup:
320   return retval;
321 }
322
323 int32_t NaClSysUnlink(struct NaClAppThread *natp,
324                       uint32_t             pathname) {
325   struct NaClApp *nap = natp->nap;
326   char           path[NACL_CONFIG_PATH_MAX];
327   int32_t        retval = -NACL_ABI_EINVAL;
328
329   if (!NaClAclBypassChecks) {
330     retval = -NACL_ABI_EACCES;
331     goto cleanup;
332   }
333
334   retval = CopyPathFromUser(nap, path, sizeof path, pathname);
335   if (0 != retval)
336     goto cleanup;
337
338   retval = NaClHostDescUnlink(path);
339 cleanup:
340   return retval;
341 }