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

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: Remove serialization 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"
Jorge Lucangeli Obes 2014/11/20 00:13:20 not needed anymore.
leecam 2014/11/20 00:56:38 Done.
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) {
jln (very slow on Chromium) 2014/11/24 20:12:16 This absolutely needs unit tests. Maybe move to a
leecam 2014/11/25 02:06:49 Done.
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 // Async signal safe
51 // Calls std::string::c_str(), strncmp and strlen. All these
52 // methods are async signal safe in common standard libs.
53 // TODO(leecam): remove dependency on std::string
54 bool BrokerFilePermission::IsPathCoveredByThisPermission(
55 const char* requested_filename) const {
56 const char* path = path_.c_str();
57 if ((recursive_ && strncmp(requested_filename, path, strlen(path)) == 0)) {
58 // Note: This prefix match will allow any path under the whitelisted
59 // path, for any number of directory levels. E.g. if the whitelisted
60 // path is /good/ then the following will be permitted by the policy.
61 // /good/file1
62 // /good/folder/file2
63 // /good/folder/folder2/file3
64 // If an attacker could make 'folder' a symlink to ../../ they would have
65 // access to the entire filesystem.
66 // Whitelisting with multiple depths is useful, e.g /proc/ but
67 // the system needs to ensure symlinks can not be created!
68 // That said if an attacker can convert any of the absolute paths
69 // to a symlink they can control any file on the system also.
70 return true;
71 } else if (strcmp(requested_filename, path) == 0) {
72 return true;
73 }
74 return false;
75 }
76
77 // Async signal safe.
78 // External call to std::string::c_str() is
79 // called in IsPathCoveredByThisPermission.
80 // TODO(leecam): remove dependency on std::string
81 bool BrokerFilePermission::CheckAccess(const char* requested_filename,
82 int mode,
83 const char** file_to_access) const {
84 // First, check if |mode| is existence, ability to read or ability
85 // to write. We do not support X_OK.
86 if (mode != F_OK && mode & ~(R_OK | W_OK)) {
87 return false;
88 }
89
90 if (!ValidatePath(requested_filename))
91 return false;
92
93 if (!IsPathCoveredByThisPermission(requested_filename)) {
94 return false;
95 }
96 bool allowed = false;
97 switch (mode) {
98 case F_OK:
99 if (allow_read_ || allow_write_)
100 allowed = true;
101 break;
102 case R_OK:
103 if (allow_read_)
104 allowed = true;
105 break;
106 case W_OK:
107 if (allow_write_)
108 allowed = true;
109 break;
110 case R_OK | W_OK:
111 if (allow_read_ && allow_write_)
112 allowed = true;
113 break;
114 default:
115 return false;
116 }
117
118 if (allowed && file_to_access) {
119 if (!recursive_)
120 *file_to_access = path_.c_str();
121 else
122 *file_to_access = requested_filename;
123 }
124 return allowed;
125 }
126
127 // Async signal safe.
128 // External call to std::string::c_str() is
129 // called in IsPathCoveredByThisPermission.
130 // TODO(leecam): remove dependency on std::string
131 bool BrokerFilePermission::CheckOpen(const char* requested_filename,
132 int flags,
133 const char** file_to_open,
134 bool* unlink_after_open) const {
135 if (!ValidatePath(requested_filename))
136 return false;
137
138 if (!IsPathCoveredByThisPermission(requested_filename)) {
139 return false;
140 }
141
142 // First, check the access mode is valid.
143 const int access_mode = flags & O_ACCMODE;
144 if (access_mode != O_RDONLY && access_mode != O_WRONLY &&
145 access_mode != O_RDWR) {
146 return false;
147 }
148
149 // Check if read is allowed
150 if (!allow_read_ && (access_mode == O_RDONLY || access_mode == O_RDWR)) {
151 return false;
152 }
153
154 // Check if write is allowed
155 if (!allow_write_ && (access_mode == O_WRONLY || access_mode == O_RDWR)) {
156 return false;
157 }
158
159 // Check if file creation is allowed.
160 if (!allow_create_ && (flags & O_CREAT)) {
161 return false;
162 }
163
164 // If O_CREAT is present, ensure O_EXCL
165 if ((flags & O_CREAT) && !(flags & O_EXCL)) {
166 return false;
167 }
168
169 // If this file is to be unlinked, ensure its created.
170 if (unlink_ && !(flags & O_CREAT)) {
171 return false;
172 }
173
174 // Some flags affect the behavior of the current process. We don't support
175 // them and don't allow them for now.
176 if (flags & kCurrentProcessOpenFlagsMask) {
177 return false;
178 }
179
180 // Now check that all the flags are known to us.
181 const int creation_and_status_flags = flags & ~O_ACCMODE;
182
183 const int known_flags = O_APPEND | O_ASYNC | O_CLOEXEC | O_CREAT | O_DIRECT |
184 O_DIRECTORY | O_EXCL | O_LARGEFILE | O_NOATIME |
185 O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_NDELAY |
186 O_SYNC | O_TRUNC;
187
188 const int unknown_flags = ~known_flags;
189 const bool has_unknown_flags = creation_and_status_flags & unknown_flags;
190
191 if (has_unknown_flags)
192 return false;
193
194 if (file_to_open) {
195 if (!recursive_)
196 *file_to_open = path_.c_str();
197 else
198 *file_to_open = requested_filename;
199 }
200 if (unlink_after_open)
201 *unlink_after_open = unlink_;
202
203 return true;
204 }
205
206 BrokerFilePermission::BrokerFilePermission(std::string path,
207 bool recursive,
208 bool unlink,
209 bool allow_read,
210 bool allow_write,
211 bool allow_create)
212 : path_(path),
213 recursive_(recursive),
214 unlink_(unlink),
215 allow_read_(allow_read),
216 allow_write_(allow_write),
217 allow_create_(allow_create) {
218 // Validate this permission and die if invalid!
219
220 // Don't allow unlinking on creation without create permission
221 if (unlink_)
222 CHECK(allow_create);
Jorge Lucangeli Obes 2014/11/20 00:13:20 Add comments as strings to CHECK: CHECK(...) << "
leecam 2014/11/20 00:56:38 Done.
223 // Recursive paths must have a trailing slash
224 if (recursive_)
225 CHECK(path_.back() == '/');
Jorge Lucangeli Obes 2014/11/20 00:13:20 Here too.
leecam 2014/11/20 00:56:38 Done.
226 // Whitelisted paths must be absolute.
227 CHECK(path_.front() == '/');
Jorge Lucangeli Obes 2014/11/20 00:13:20 And here.
leecam 2014/11/20 00:56:38 Done.
228 }
229
230 } // namespace syscall_broker
231
232 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698