Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/trusted/service_runtime/sel_ldr_filename.c

Issue 1690983004: Extended restricted filesystem to support relative paths. (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Allow relative paths without prepending CWD Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698