| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2016 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include "native_client/src/trusted/service_runtime/sel_ldr_filename.h" | 7 #include "native_client/src/trusted/service_runtime/sel_ldr_filename.h" |
| 8 | 8 |
| 9 #include <errno.h> | 9 #include <errno.h> |
| 10 #include <string.h> | 10 #include <string.h> |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 return 0; | 34 return 0; |
| 35 /* If the root is "/foo", then "/foobar" should be marked as invalid. */ | 35 /* If the root is "/foo", then "/foobar" should be marked as invalid. */ |
| 36 if (path_len > NaClRootDirLen && path[NaClRootDirLen] != '/') | 36 if (path_len > NaClRootDirLen && path[NaClRootDirLen] != '/') |
| 37 return 0; | 37 return 0; |
| 38 return 1; | 38 return 1; |
| 39 } | 39 } |
| 40 | 40 |
| 41 #if !NACL_WINDOWS | 41 #if !NACL_WINDOWS |
| 42 /* | 42 /* |
| 43 * Given a |virtual_path| (a path supplied by the user with no knowledge of | 43 * Given a |virtual_path| (a path supplied by the user with no knowledge of |
| 44 * the mounted directory) transform it into an |absolute_path|, which is an | 44 * the mounted directory) transform it into an |real_path|, which is either |
| 45 * absolute path prefixed by the root mount directory. | 45 * an absolute path prefixed by the root mount directory, or a relative path. |
| 46 * | |
| 47 * TODO(smklein): The virtual_path is assumed to be absolute. Change this. | |
| 48 * | 46 * |
| 49 * @param[in] virtual_path Virtual path supplied by user. | 47 * @param[in] virtual_path Virtual path supplied by user. |
| 50 * @param[out] absolute_path The absolute path referenced by the |virtual_path|. | 48 * @param[out] real_path The real path referenced by the |virtual_path|. |
| 51 * @param[in] absolute_path_size The size of the |absolute_path| buffer. | 49 * @param[in] real_path_size The size of the |real_path| buffer. |
| 52 * @return 0 on success, else a negated NaCl errno. | 50 * @return 0 on success, else a negated NaCl errno. |
| 53 */ | 51 */ |
| 54 static uint32_t VirtualToAbsolutePath(const char *virtual_path, | 52 static uint32_t VirtualToRealPath(const char *virtual_path, |
| 55 char *absolute_path, | 53 char *real_path, |
| 56 size_t absolute_path_max_size) { | 54 size_t real_path_max_size) { |
| 57 size_t virtual_path_len = strlen(virtual_path); | 55 size_t virtual_path_len = strlen(virtual_path); |
| 58 /* Check that we have enough room to prepend the prefix (absolute case). */ | 56 if (virtual_path[0] == '/') { |
| 59 if (virtual_path_len + NaClRootDirLen + 1 > absolute_path_max_size) { | 57 /* Absolute Path = Prefix + Absolute Virtual Path + '\0' */ |
| 60 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); | 58 if (virtual_path_len + NaClRootDirLen + 1 > real_path_max_size) { |
| 61 return -NACL_ABI_ENAMETOOLONG; | 59 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); |
| 60 return -NACL_ABI_ENAMETOOLONG; |
| 61 } |
| 62 /* Prefix */ |
| 63 strcpy(real_path, NaClRootDir); |
| 64 /* Prefix + Virtual Path */ |
| 65 strcat(real_path, virtual_path); |
| 66 } else { |
| 67 /* Relative Path = Relative Virtual Path + '\0' */ |
| 68 if (virtual_path_len + 1 > real_path_max_size) { |
| 69 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); |
| 70 return -NACL_ABI_ENAMETOOLONG; |
| 71 } |
| 72 strcpy(real_path, virtual_path); |
| 62 } | 73 } |
| 63 | 74 |
| 64 /* Prefix */ | |
| 65 memcpy(absolute_path, NaClRootDir, NaClRootDirLen); | |
| 66 /* Prefix + Virtual Path */ | |
| 67 memcpy(absolute_path + NaClRootDirLen, virtual_path, virtual_path_len); | |
| 68 /* Prefix + Virtual Path + Terminator */ | |
| 69 absolute_path[virtual_path_len + NaClRootDirLen] = '\0'; | |
| 70 | |
| 71 return 0; | 75 return 0; |
| 72 } | 76 } |
| 73 | 77 |
| 74 /* | 78 /* |
| 75 * Determine if |path| points to a symbolic link. | 79 * Determine if |path| points to a symbolic link. |
| 76 * | 80 * |
| 77 * @param[in] path Path of file to be checked. | 81 * @param[in] path Path of file to be checked. |
| 78 * @return Nonzero if path is symbolic link. | 82 * @return Nonzero if path is symbolic link. |
| 79 */ | 83 */ |
| 80 static int IsSymbolicLink(const char *path) { | 84 static int IsSymbolicLink(const char *path) { |
| 81 struct stat buf; | 85 struct stat buf; |
| 82 int result = lstat(path, &buf); | 86 int result = lstat(path, &buf); |
| 83 return result == 0 && S_ISLNK(buf.st_mode); | 87 return result == 0 && S_ISLNK(buf.st_mode); |
| 84 } | 88 } |
| 85 | 89 |
| 86 /* | 90 /* |
| 87 * Preconditions: | |
| 88 * The path is absolute (aka, it starts with "/"). | |
| 89 * | |
| 90 * @param[in] path The path to be verified. | 91 * @param[in] path The path to be verified. |
| 91 * @return 0 if the path is valid, else a negated NaCl errno. | 92 * @return 0 if the path is valid, else a negated NaCl errno. |
| 92 */ | 93 */ |
| 93 static uint32_t ValidateAbsolutePath(const char *path) { | 94 static uint32_t ValidatePath(const char *path) { |
| 94 if (strstr(path, "..")) { | 95 if (strstr(path, "..")) { |
| 95 NaClLog(LOG_ERROR, "Pathname contains ..: %s\n", path); | 96 NaClLog(LOG_ERROR, "Pathname contains ..: %s\n", path); |
| 96 return -NACL_ABI_EACCES; | 97 return -NACL_ABI_EACCES; |
| 97 } | 98 } |
| 98 | 99 |
| 99 CHECK(PathContainsRootPrefix(path, strlen(path))); | 100 if (path[0] == '/') |
| 101 CHECK(PathContainsRootPrefix(path, strlen(path))); |
| 100 | 102 |
| 101 /* | 103 /* |
| 102 * This is an informal check, and we still require the users of sel_ldr to | 104 * This is an informal check, and we still require the users of sel_ldr to |
| 103 * ensure that no symbolic links exist in the mounted directory. | 105 * ensure that no symbolic links exist in the mounted directory. |
| 104 * | 106 * |
| 105 * A race condition exists that can bypass this check: | 107 * A race condition exists that can bypass this check: |
| 106 * 1) Open (or any file access function) called on a path to a regular | 108 * 1) Open (or any file access function) called on a path to a regular |
| 107 * file (PATH_REG). "IsSymbolicLink" returns zero, but the original file | 109 * file (PATH_REG). "IsSymbolicLink" returns zero, but the original file |
| 108 * access function has not yet been called. | 110 * access function has not yet been called. |
| 109 * 2) Outside of sel_ldr, a symbolic link is moved into PATH_REG. | 111 * 2) Outside of sel_ldr, a symbolic link is moved into PATH_REG. |
| 110 * 3) The original file access function is called on a symbolic link. | 112 * 3) The original file access function is called on a symbolic link. |
| 111 * | 113 * |
| 112 * Thus, we still require the caller of sel_ldr to guarantee that no symbolic | 114 * Thus, we still require the caller of sel_ldr to guarantee that no symbolic |
| 113 * links are inside the mounted directory. | 115 * links are inside the mounted directory. |
| 114 */ | 116 */ |
| 115 if (IsSymbolicLink(path)) { | 117 if (IsSymbolicLink(path)) { |
| 116 return -NACL_ABI_EACCES; | 118 return -NACL_ABI_EACCES; |
| 117 } | 119 } |
| 118 return 0; | 120 return 0; |
| 119 } | 121 } |
| 120 | 122 |
| 121 /* | 123 /* |
| 122 * Transforms a raw file path from the user into an absolute path | 124 * Transforms a raw file path from the user into an absolute path prefixed by |
| 123 * prefixed by the mounted file system root. Also validates the path to | 125 * the mounted file system root (or leave it as a relative path). Also validates |
| 124 * ensure it does not access anything outside the mount point. | 126 * the path to ensure it does not access anything outside the mount point. |
| 125 * | 127 * |
| 126 * @param[in/out] dest The raw file path from the user | 128 * @param[in/out] dest The raw file path from the user |
| 127 * @param[in] dest_max_size The size of the buffer holding dest. | 129 * @param[in] dest_max_size The size of the buffer holding dest. |
| 128 * @return 0 on success, else a NaCl errno. | 130 * @return 0 on success, else a NaCl errno. |
| 129 */ | 131 */ |
| 130 static uint32_t CopyHostPathMounted(char *dest, size_t dest_max_size) { | 132 static uint32_t CopyHostPathMounted(char *dest, size_t dest_max_size) { |
| 131 uint32_t retval; | 133 uint32_t retval; |
| 132 char raw_path[NACL_CONFIG_PATH_MAX]; | 134 char raw_path[NACL_CONFIG_PATH_MAX]; |
| 133 | 135 |
| 134 if (dest_max_size <= 0 || dest[0] == '\0') { | 136 if (dest_max_size <= 0 || dest[0] == '\0') { |
| 135 NaClLog(LOG_ERROR, "Dest cannot be empty path\n"); | 137 NaClLog(LOG_ERROR, "Dest cannot be empty path\n"); |
| 136 return -NACL_ABI_ENOENT; | 138 return -NACL_ABI_ENOENT; |
| 137 } else if (dest[0] != '/') { | |
| 138 /* TODO(smklein): Allow usage of relative paths. */ | |
| 139 NaClLog(LOG_ERROR, "Pathname is not absolute: %s\n", dest); | |
| 140 return -NACL_ABI_EACCES; | |
| 141 } | 139 } |
| 142 | 140 |
| 143 CHECK(dest_max_size == NACL_CONFIG_PATH_MAX); | 141 CHECK(dest_max_size == NACL_CONFIG_PATH_MAX); |
| 144 CHECK(strlen(dest) < NACL_CONFIG_PATH_MAX); | 142 CHECK(strlen(dest) < NACL_CONFIG_PATH_MAX); |
| 145 strcpy(raw_path, dest); | 143 strcpy(raw_path, dest); |
| 146 | 144 |
| 147 /* Transform the user's raw path into an absolute path. */ | 145 /* |
| 148 retval = VirtualToAbsolutePath(raw_path, dest, dest_max_size); | 146 * Transform the user's raw path into the actual path. |
| 147 * The path will reference a file inside the mount directory once |
| 148 * VirtualToRealPath returns successfully. |
| 149 */ |
| 150 retval = VirtualToRealPath(raw_path, dest, dest_max_size); |
| 149 if (retval != 0) | 151 if (retval != 0) |
| 150 return retval; | 152 return retval; |
| 151 | 153 |
| 152 /* Verify that the path cannot escape root. */ | 154 /* Verify that the path cannot escape root. */ |
| 153 return ValidateAbsolutePath(dest); | 155 return ValidatePath(dest); |
| 154 } | 156 } |
| 155 #endif /* !NACL_WINDOWS */ | 157 #endif /* !NACL_WINDOWS */ |
| 156 | 158 |
| 157 uint32_t CopyHostPathInFromUser(struct NaClApp *nap, | 159 uint32_t CopyHostPathInFromUser(struct NaClApp *nap, |
| 158 char *dest, | 160 char *dest, |
| 159 size_t dest_max_size, | 161 size_t dest_max_size, |
| 160 uint32_t src) { | 162 uint32_t src) { |
| 161 /* | 163 /* |
| 162 * NaClCopyInFromUserZStr may (try to) get bytes that is outside the | 164 * NaClCopyInFromUserZStr may (try to) get bytes that is outside the |
| 163 * app's address space and generate a fault. | 165 * app's address space and generate a fault. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 return (uint32_t) -NACL_ABI_EFAULT; | 220 return (uint32_t) -NACL_ABI_EFAULT; |
| 219 return 0; | 221 return 0; |
| 220 } | 222 } |
| 221 | 223 |
| 222 /* Copy out everything after the root dir (including the slash). */ | 224 /* Copy out everything after the root dir (including the slash). */ |
| 223 if (!NaClCopyOutToUser(nap, dst_usr_addr, path + NaClRootDirLen, | 225 if (!NaClCopyOutToUser(nap, dst_usr_addr, path + NaClRootDirLen, |
| 224 path_len - NaClRootDirLen + 1)) | 226 path_len - NaClRootDirLen + 1)) |
| 225 return (uint32_t) -NACL_ABI_EFAULT; | 227 return (uint32_t) -NACL_ABI_EFAULT; |
| 226 return 0; | 228 return 0; |
| 227 } | 229 } |
| OLD | NEW |