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

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: 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
« no previous file with comments | « documentation/filesystem_access.txt ('k') | src/trusted/service_runtime/sel_main.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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 }
OLDNEW
« no previous file with comments | « documentation/filesystem_access.txt ('k') | src/trusted/service_runtime/sel_main.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698