| OLD | NEW |
| (Empty) | |
| 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 = NaClSetAvail(nap, |
| 162 ((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 = NaClSetAvail(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 } |
| OLD | NEW |