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 real_path[0] = '\0'; /* Required to strcat from start of path. */ |
Mark Seaborn
2016/02/24 21:19:19
Why not just use strcpy() instead of the first cal
Sean Klein
2016/02/24 23:40:43
Done.
| |
59 if (virtual_path_len + NaClRootDirLen + 1 > absolute_path_max_size) { | 57 if (virtual_path[0] == '/') { |
60 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); | 58 /* Absolute Path = Prefix + Absolute Virtual Path + '\0' */ |
61 return -NACL_ABI_ENAMETOOLONG; | 59 if (virtual_path_len + NaClRootDirLen + 1 > real_path_max_size) { |
60 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); | |
61 return -NACL_ABI_ENAMETOOLONG; | |
62 } | |
63 /* Prefix */ | |
64 strcat(real_path, NaClRootDir); | |
65 /* Prefix + Virtual Path */ | |
66 strcat(real_path, virtual_path); | |
67 } else { | |
68 /* Relative Path = Relative Virtual Path + '\0' */ | |
69 if (virtual_path_len + 1 > real_path_max_size) { | |
70 NaClLog(LOG_ERROR, "Pathname too long: %s\n", virtual_path); | |
71 return -NACL_ABI_ENAMETOOLONG; | |
72 } | |
73 strcat(real_path, virtual_path); | |
62 } | 74 } |
63 | 75 |
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; | 76 return 0; |
72 } | 77 } |
73 | 78 |
74 /* | 79 /* |
75 * Determine if |path| points to a symbolic link. | 80 * Determine if |path| points to a symbolic link. |
76 * | 81 * |
77 * @param[in] path Path of file to be checked. | 82 * @param[in] path Path of file to be checked. |
78 * @return Nonzero if path is symbolic link. | 83 * @return Nonzero if path is symbolic link. |
79 */ | 84 */ |
80 static int IsSymbolicLink(const char *path) { | 85 static int IsSymbolicLink(const char *path) { |
81 struct stat buf; | 86 struct stat buf; |
82 int result = lstat(path, &buf); | 87 int result = lstat(path, &buf); |
83 return result == 0 && S_ISLNK(buf.st_mode); | 88 return result == 0 && S_ISLNK(buf.st_mode); |
84 } | 89 } |
85 | 90 |
86 /* | 91 /* |
87 * Preconditions: | |
88 * The path is absolute (aka, it starts with "/"). | |
89 * | |
90 * @param[in] path The path to be verified. | 92 * @param[in] path The path to be verified. |
91 * @return 0 if the path is valid, else a negated NaCl errno. | 93 * @return 0 if the path is valid, else a negated NaCl errno. |
92 */ | 94 */ |
93 static uint32_t ValidateAbsolutePath(const char *path) { | 95 static uint32_t ValidatePath(const char *path) { |
94 if (strstr(path, "..")) { | 96 if (strstr(path, "..")) { |
95 NaClLog(LOG_ERROR, "Pathname contains ..: %s\n", path); | 97 NaClLog(LOG_ERROR, "Pathname contains ..: %s\n", path); |
96 return -NACL_ABI_EACCES; | 98 return -NACL_ABI_EACCES; |
97 } | 99 } |
98 | 100 |
99 CHECK(PathContainsRootPrefix(path, strlen(path))); | 101 if (path[0] == '/') |
102 CHECK(PathContainsRootPrefix(path, strlen(path))); | |
100 | 103 |
101 /* | 104 /* |
102 * This is an informal check, and we still require the users of sel_ldr to | 105 * 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. | 106 * ensure that no symbolic links exist in the mounted directory. |
104 * | 107 * |
105 * A race condition exists that can bypass this check: | 108 * A race condition exists that can bypass this check: |
106 * 1) Open (or any file access function) called on a path to a regular | 109 * 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 | 110 * file (PATH_REG). "IsSymbolicLink" returns zero, but the original file |
108 * access function has not yet been called. | 111 * access function has not yet been called. |
109 * 2) Outside of sel_ldr, a symbolic link is moved into PATH_REG. | 112 * 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. | 113 * 3) The original file access function is called on a symbolic link. |
111 * | 114 * |
112 * Thus, we still require the caller of sel_ldr to guarantee that no symbolic | 115 * Thus, we still require the caller of sel_ldr to guarantee that no symbolic |
113 * links are inside the mounted directory. | 116 * links are inside the mounted directory. |
114 */ | 117 */ |
115 if (IsSymbolicLink(path)) { | 118 if (IsSymbolicLink(path)) { |
116 return -NACL_ABI_EACCES; | 119 return -NACL_ABI_EACCES; |
117 } | 120 } |
118 return 0; | 121 return 0; |
119 } | 122 } |
120 | 123 |
121 /* | 124 /* |
122 * Transforms a raw file path from the user into an absolute path | 125 * 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 | 126 * 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. | 127 * the path to ensure it does not access anything outside the mount point. |
125 * | 128 * |
126 * @param[in/out] dest The raw file path from the user | 129 * @param[in/out] dest The raw file path from the user |
127 * @param[in] dest_max_size The size of the buffer holding dest. | 130 * @param[in] dest_max_size The size of the buffer holding dest. |
128 * @return 0 on success, else a NaCl errno. | 131 * @return 0 on success, else a NaCl errno. |
129 */ | 132 */ |
130 static uint32_t CopyHostPathMounted(char *dest, size_t dest_max_size) { | 133 static uint32_t CopyHostPathMounted(char *dest, size_t dest_max_size) { |
131 uint32_t retval; | 134 uint32_t retval; |
132 char raw_path[NACL_CONFIG_PATH_MAX]; | 135 char raw_path[NACL_CONFIG_PATH_MAX]; |
133 | 136 |
134 if (dest_max_size <= 0 || dest[0] == '\0') { | 137 if (dest_max_size <= 0 || dest[0] == '\0') { |
135 NaClLog(LOG_ERROR, "Dest cannot be empty path\n"); | 138 NaClLog(LOG_ERROR, "Dest cannot be empty path\n"); |
136 return -NACL_ABI_ENOENT; | 139 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 } | 140 } |
142 | 141 |
143 CHECK(dest_max_size == NACL_CONFIG_PATH_MAX); | 142 CHECK(dest_max_size == NACL_CONFIG_PATH_MAX); |
144 CHECK(strlen(dest) < NACL_CONFIG_PATH_MAX); | 143 CHECK(strlen(dest) < NACL_CONFIG_PATH_MAX); |
145 strcpy(raw_path, dest); | 144 strcpy(raw_path, dest); |
146 | 145 |
147 /* Transform the user's raw path into an absolute path. */ | 146 /* |
148 retval = VirtualToAbsolutePath(raw_path, dest, dest_max_size); | 147 * Transform the user's raw path into the actual path. |
148 * The path will reference a file inside the mount directory once | |
149 * VirtualToRealPath returns successfully. | |
150 */ | |
151 retval = VirtualToRealPath(raw_path, dest, dest_max_size); | |
149 if (retval != 0) | 152 if (retval != 0) |
150 return retval; | 153 return retval; |
151 | 154 |
152 /* Verify that the path cannot escape root. */ | 155 /* Verify that the path cannot escape root. */ |
153 return ValidateAbsolutePath(dest); | 156 return ValidatePath(dest); |
154 } | 157 } |
155 #endif /* !NACL_WINDOWS */ | 158 #endif /* !NACL_WINDOWS */ |
156 | 159 |
157 uint32_t CopyHostPathInFromUser(struct NaClApp *nap, | 160 uint32_t CopyHostPathInFromUser(struct NaClApp *nap, |
158 char *dest, | 161 char *dest, |
159 size_t dest_max_size, | 162 size_t dest_max_size, |
160 uint32_t src) { | 163 uint32_t src) { |
161 /* | 164 /* |
162 * NaClCopyInFromUserZStr may (try to) get bytes that is outside the | 165 * NaClCopyInFromUserZStr may (try to) get bytes that is outside the |
163 * app's address space and generate a fault. | 166 * 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; | 221 return (uint32_t) -NACL_ABI_EFAULT; |
219 return 0; | 222 return 0; |
220 } | 223 } |
221 | 224 |
222 /* Copy out everything after the root dir (including the slash). */ | 225 /* Copy out everything after the root dir (including the slash). */ |
223 if (!NaClCopyOutToUser(nap, dst_usr_addr, path + NaClRootDirLen, | 226 if (!NaClCopyOutToUser(nap, dst_usr_addr, path + NaClRootDirLen, |
224 path_len - NaClRootDirLen + 1)) | 227 path_len - NaClRootDirLen + 1)) |
225 return (uint32_t) -NACL_ABI_EFAULT; | 228 return (uint32_t) -NACL_ABI_EFAULT; |
226 return 0; | 229 return 0; |
227 } | 230 } |
OLD | NEW |