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

Side by Side Diff: sandbox/linux/syscall_broker/broker_file_permission.cc

Issue 721553002: sandbox: Extend BrokerPolicy to support file creation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: make constructor private Created 6 years, 1 month 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
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sandbox/linux/syscall_broker/broker_file_permission.h"
6
7 #include <fcntl.h>
8 #include <string.h>
9
10 #include <string>
11
12 #include "base/logging.h"
13 #include "base/pickle.h"
14 #include "sandbox/linux/syscall_broker/broker_common.h"
15
16 namespace sandbox {
17
18 namespace syscall_broker {
19
20 // Async signal safe
21 bool ValidatePath(const char* path) {
22 if (!path)
23 return false;
24
25 size_t len = strlen(path);
26 // No empty paths
27 if (len == 0)
28 return false;
29 // Paths must be absolute and not relative
30 if (path[0] != '/')
31 return false;
32 // No trailing / (but "/" is valid)
33 if (len > 1 && path[len - 1] == '/')
34 return false;
35 // No trailing /..
36 if (len >= 3 && path[len - 3] == '/' && path[len - 2] == '.' &&
37 path[len - 1] == '.')
38 return false;
39 // No /../ anywhere
40 for (size_t i = 0; i < len; i++) {
41 if (path[i] == '/' && (len - i) > 3) {
42 if (path[i + 1] == '.' && path[i + 2] == '.' && path[i + 3] == '/') {
43 return false;
44 }
45 }
46 }
47 return true;
48 }
49
50 Pickle BrokerFilePermission::Serialize() {
51 Pickle pickle;
52 pickle.WriteString(path_);
53 pickle.WriteBool(recursive_);
54 pickle.WriteBool(unlink_);
55 pickle.WriteBool(allow_read_);
56 pickle.WriteBool(allow_write_);
57 pickle.WriteBool(allow_create_);
58 return pickle;
59 }
60
61 bool BrokerFilePermission::CreateFromPickleBuf(const char* buf,
62 size_t len,
63 BrokerFilePermission** perm) {
64 std::string path;
65 bool recursive;
66 bool unlink;
67 bool allow_read;
68 bool allow_write;
69 bool allow_create;
70 Pickle pickle(buf, len);
71 PickleIterator iter(pickle);
72
73 if (perm && pickle.ReadString(&iter, &path) &&
74 pickle.ReadBool(&iter, &recursive) && pickle.ReadBool(&iter, &unlink) &&
75 pickle.ReadBool(&iter, &allow_read) &&
76 pickle.ReadBool(&iter, &allow_write) &&
77 pickle.ReadBool(&iter, &allow_create)) {
78 *perm = new BrokerFilePermission(path, recursive, unlink, allow_read,
79 allow_write, allow_create);
80 return (perm != NULL);
81 }
82 return false;
83 }
84
85 // Async signal safe
86 // Calls std::string::c_str(), strncmp and strlen. All these
87 // methods are async signal safe in common standard libs.
88 // TODO(leecam): remove dependency on std::string
89 bool BrokerFilePermission::IsPathCoveredByThisPermission(
90 const char* requested_filename) const {
91 const char* path = path_.c_str();
92 if ((recursive_ && strncmp(requested_filename, path, strlen(path)) == 0)) {
93 // Note: This prefix match will allow any path under the whitelisted
94 // path, for any number of directory levels. E.g. if the whitelisted
95 // path is /good/ then the following will be permitted by the policy.
96 // /good/file1
97 // /good/folder/file2
98 // /good/folder/folder2/file3
99 // If an attacker could make 'folder' a symlink to ../../ they would have
100 // access to the entire filesystem.
101 // Whitelisting with multiple depths is useful, e.g /proc/ but
102 // the system needs to ensure symlinks can not be created!
103 // That said if an attacker can convert any of the absolute paths
104 // to a symlink they can control any file on the system also.
105 return true;
106 } else if (strcmp(requested_filename, path) == 0) {
107 return true;
108 }
109 return false;
110 }
111
112 // Async signal safe.
113 // External call to std::string::c_str() is
114 // called in IsPathCoveredByThisPermission.
115 // TODO(leecam): remove dependency on std::string
116 bool BrokerFilePermission::CheckAccess(const char* requested_filename,
117 int mode,
118 const char** file_to_access) const {
119 // First, check if |mode| is existence, ability to read or ability
120 // to write. We do not support X_OK.
121 if (mode != F_OK && mode & ~(R_OK | W_OK)) {
122 return false;
123 }
124
125 if (!ValidatePath(requested_filename))
126 return false;
127
128 if (!IsPathCoveredByThisPermission(requested_filename)) {
129 return false;
130 }
131 bool allowed = false;
132 switch (mode) {
133 case F_OK:
134 if (allow_read_ || allow_write_)
135 allowed = true;
136 break;
137 case R_OK:
138 if (allow_read_)
139 allowed = true;
140 break;
141 case W_OK:
142 if (allow_write_)
143 allowed = true;
144 break;
145 case R_OK | W_OK:
146 if (allow_read_ && allow_write_)
147 allowed = true;
148 break;
149 default:
150 return false;
151 }
152
153 if (allowed && file_to_access) {
154 if (!recursive_)
155 *file_to_access = path_.c_str();
156 else
157 *file_to_access = requested_filename;
158 }
159 return allowed;
160 }
161
162 // Async signal safe.
163 // External call to std::string::c_str() is
164 // called in IsPathCoveredByThisPermission.
165 // TODO(leecam): remove dependency on std::string
166 bool BrokerFilePermission::CheckOpen(const char* requested_filename,
167 int flags,
168 const char** file_to_open,
169 bool* unlink_after_open) const {
170 if (!ValidatePath(requested_filename))
171 return false;
172
173 if (!IsPathCoveredByThisPermission(requested_filename)) {
174 return false;
175 }
176
177 // First, check the access mode is valid.
178 const int access_mode = flags & O_ACCMODE;
179 if (access_mode != O_RDONLY && access_mode != O_WRONLY &&
180 access_mode != O_RDWR) {
181 return false;
182 }
183
184 // Check if read is allowed
185 if (!allow_read_ && (access_mode == O_RDONLY || access_mode == O_RDWR)) {
186 return false;
187 }
188
189 // Check if write is allowed
190 if (!allow_write_ && (access_mode == O_WRONLY || access_mode == O_RDWR)) {
191 return false;
192 }
193
194 // Check if file creation is allowed.
195 if (!allow_create_ && (flags & O_CREAT)) {
196 return false;
197 }
198
199 // If O_CREAT is present, ensure O_EXCL
200 if ((flags & O_CREAT) && !(flags & O_EXCL)) {
201 return false;
202 }
203
204 // If this file is to be unlinked, ensure its created.
205 if (unlink_ && !(flags & O_CREAT)) {
206 return false;
207 }
208
209 // Some flags affect the behavior of the current process. We don't support
210 // them and don't allow them for now.
211 if (flags & kCurrentProcessOpenFlagsMask) {
212 return false;
213 }
214
215 // Now check that all the flags are known to us.
216 const int creation_and_status_flags = flags & ~O_ACCMODE;
217
218 const int known_flags = O_APPEND | O_ASYNC | O_CLOEXEC | O_CREAT | O_DIRECT |
219 O_DIRECTORY | O_EXCL | O_LARGEFILE | O_NOATIME |
220 O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_NDELAY |
221 O_SYNC | O_TRUNC;
222
223 const int unknown_flags = ~known_flags;
224 const bool has_unknown_flags = creation_and_status_flags & unknown_flags;
225
226 if (has_unknown_flags)
227 return false;
228
229 if (file_to_open) {
230 if (!recursive_)
231 *file_to_open = path_.c_str();
232 else
233 *file_to_open = requested_filename;
234 }
235 if (unlink_after_open)
236 *unlink_after_open = unlink_;
237
238 return true;
239 }
240
241 BrokerFilePermission::BrokerFilePermission(std::string path,
242 bool recursive,
243 bool unlink,
244 bool allow_read,
245 bool allow_write,
246 bool allow_create)
247 : path_(path),
248 recursive_(recursive),
249 unlink_(unlink),
250 allow_read_(allow_read),
251 allow_write_(allow_write),
252 allow_create_(allow_create) {
253 // Validate this permission and die if invalid!
254
255 // Don't allow unlinking on creation without create permission
256 if (unlink_)
257 CHECK(allow_create);
258 // Recursive paths must have a trailing slash
259 if (recursive_)
260 CHECK(path_.back() == '/');
261 // Whitelisted paths must be absolute.
262 CHECK(path_.front() == '/');
263 }
264
265 } // namespace syscall_broker
266
267 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698