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

Side by Side Diff: sandbox/src/filesystem_policy.cc

Issue 10783004: Move Windows Sandbox, trybots version (don't commit me!) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to top of tree Created 8 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « sandbox/src/filesystem_policy.h ('k') | sandbox/src/handle_closer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 <string>
6
7 #include "sandbox/src/filesystem_policy.h"
8
9 #include "base/logging.h"
10 #include "base/win/scoped_handle.h"
11 #include "sandbox/src/ipc_tags.h"
12 #include "sandbox/src/policy_engine_opcodes.h"
13 #include "sandbox/src/policy_params.h"
14 #include "sandbox/src/sandbox_utils.h"
15 #include "sandbox/src/sandbox_types.h"
16 #include "sandbox/src/win_utils.h"
17
18 namespace {
19
20 NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
21 ACCESS_MASK desired_access,
22 OBJECT_ATTRIBUTES* obj_attributes,
23 IO_STATUS_BLOCK* io_status_block,
24 ULONG file_attributes,
25 ULONG share_access,
26 ULONG create_disposition,
27 ULONG create_options,
28 PVOID ea_buffer,
29 ULONG ea_lenght,
30 HANDLE target_process) {
31 NtCreateFileFunction NtCreateFile = NULL;
32 ResolveNTFunctionPtr("NtCreateFile", &NtCreateFile);
33
34 HANDLE local_handle = INVALID_HANDLE_VALUE;
35 NTSTATUS status = NtCreateFile(&local_handle, desired_access, obj_attributes,
36 io_status_block, NULL, file_attributes,
37 share_access, create_disposition,
38 create_options, ea_buffer, ea_lenght);
39 if (!NT_SUCCESS(status)) {
40 return status;
41 }
42
43 if (!sandbox::SameObject(local_handle, obj_attributes->ObjectName->Buffer)) {
44 // The handle points somewhere else. Fail the operation.
45 ::CloseHandle(local_handle);
46 return STATUS_ACCESS_DENIED;
47 }
48
49 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
50 target_process, target_file_handle, 0, FALSE,
51 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
52 ::CloseHandle(local_handle);
53 return STATUS_ACCESS_DENIED;
54 }
55 return STATUS_SUCCESS;
56 }
57
58 } // namespace.
59
60 namespace sandbox {
61
62 bool FileSystemPolicy::GenerateRules(const wchar_t* name,
63 TargetPolicy::Semantics semantics,
64 LowLevelPolicy* policy) {
65 std::wstring mod_name(name);
66 if (mod_name.empty()) {
67 return false;
68 }
69
70 // Don't do any pre-processing if the name starts like the the native
71 // object manager style.
72 if (0 != _wcsnicmp(mod_name.c_str(), kNTObjManPrefix, kNTObjManPrefixLen)) {
73 // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
74 // infrastructure to normalize names. In any case we need to escape the
75 // question marks.
76 if (!PreProcessName(mod_name, &mod_name)) {
77 // The path to be added might contain a reparse point.
78 NOTREACHED();
79 return false;
80 }
81 if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
82 // TODO(nsylvain): Find a better way to do name resolution. Right now we
83 // take the name and we expand it.
84 mod_name.insert(0, L"\\/?/?\\");
85 name = mod_name.c_str();
86 }
87 }
88
89 EvalResult result = ASK_BROKER;
90
91 // List of supported calls for the filesystem.
92 const unsigned kCallNtCreateFile = 0x1;
93 const unsigned kCallNtOpenFile = 0x2;
94 const unsigned kCallNtQueryAttributesFile = 0x4;
95 const unsigned kCallNtQueryFullAttributesFile = 0x8;
96 const unsigned kCallNtSetInfoRename = 0x10;
97
98 DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
99 kCallNtQueryAttributesFile |
100 kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
101
102 PolicyRule create(result);
103 PolicyRule open(result);
104 PolicyRule query(result);
105 PolicyRule query_full(result);
106 PolicyRule rename(result);
107
108 switch (semantics) {
109 case TargetPolicy::FILES_ALLOW_DIR_ANY: {
110 open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
111 create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
112 break;
113 }
114 case TargetPolicy::FILES_ALLOW_READONLY: {
115 // We consider all flags that are not known to be readonly as potentially
116 // used for write.
117 DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
118 FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
119 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
120 DWORD restricted_flags = ~allowed_flags;
121 open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
122 create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
123
124 // Read only access don't work for rename.
125 rule_to_add &= ~kCallNtSetInfoRename;
126 break;
127 }
128 case TargetPolicy::FILES_ALLOW_QUERY: {
129 // Here we don't want to add policy for the open or the create.
130 rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile |
131 kCallNtSetInfoRename);
132 break;
133 }
134 case TargetPolicy::FILES_ALLOW_ANY: {
135 break;
136 }
137 default: {
138 NOTREACHED();
139 return false;
140 }
141 }
142
143 if ((rule_to_add & kCallNtCreateFile) &&
144 (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
145 !policy->AddRule(IPC_NTCREATEFILE_TAG, &create))) {
146 return false;
147 }
148
149 if ((rule_to_add & kCallNtOpenFile) &&
150 (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
151 !policy->AddRule(IPC_NTOPENFILE_TAG, &open))) {
152 return false;
153 }
154
155 if ((rule_to_add & kCallNtQueryAttributesFile) &&
156 (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
157 !policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &query))) {
158 return false;
159 }
160
161 if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
162 (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE)
163 || !policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
164 &query_full))) {
165 return false;
166 }
167
168 if ((rule_to_add & kCallNtSetInfoRename) &&
169 (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
170 !policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &rename))) {
171 return false;
172 }
173
174 return true;
175 }
176
177 // Right now we insert two rules, to be evaluated before any user supplied rule:
178 // - go to the broker if the path doesn't look like the paths that we push on
179 // the policy (namely \??\something).
180 // - go to the broker if it looks like this is a short-name path.
181 //
182 // It is possible to add a rule to go to the broker in any case; it would look
183 // something like:
184 // rule = new PolicyRule(ASK_BROKER);
185 // rule->AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
186 // policy->AddRule(service, rule);
187 bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
188 PolicyRule format(ASK_BROKER);
189 PolicyRule short_name(ASK_BROKER);
190
191 bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
192 rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
193 CASE_SENSITIVE);
194
195 rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
196 rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
197
198 if (!rv || !policy->AddRule(IPC_NTCREATEFILE_TAG, &format))
199 return false;
200
201 if (!policy->AddRule(IPC_NTCREATEFILE_TAG, &short_name))
202 return false;
203
204 if (!policy->AddRule(IPC_NTOPENFILE_TAG, &format))
205 return false;
206
207 if (!policy->AddRule(IPC_NTOPENFILE_TAG, &short_name))
208 return false;
209
210 if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &format))
211 return false;
212
213 if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &short_name))
214 return false;
215
216 if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &format))
217 return false;
218
219 if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &short_name))
220 return false;
221
222 if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &format))
223 return false;
224
225 if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &short_name))
226 return false;
227
228 return true;
229 }
230
231 bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
232 const ClientInfo& client_info,
233 const std::wstring &file,
234 uint32 attributes,
235 uint32 desired_access,
236 uint32 file_attributes,
237 uint32 share_access,
238 uint32 create_disposition,
239 uint32 create_options,
240 HANDLE *handle,
241 NTSTATUS* nt_status,
242 ULONG_PTR *io_information) {
243 // The only action supported is ASK_BROKER which means create the requested
244 // file as specified.
245 if (ASK_BROKER != eval_result) {
246 *nt_status = STATUS_ACCESS_DENIED;
247 return false;
248 }
249 IO_STATUS_BLOCK io_block = {0};
250 UNICODE_STRING uni_name = {0};
251 OBJECT_ATTRIBUTES obj_attributes = {0};
252 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
253 *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
254 &io_block, file_attributes, share_access,
255 create_disposition, create_options, NULL,
256 0, client_info.process);
257
258 *io_information = io_block.Information;
259 return true;
260 }
261
262 bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
263 const ClientInfo& client_info,
264 const std::wstring &file,
265 uint32 attributes,
266 uint32 desired_access,
267 uint32 share_access,
268 uint32 open_options,
269 HANDLE *handle,
270 NTSTATUS* nt_status,
271 ULONG_PTR *io_information) {
272 // The only action supported is ASK_BROKER which means open the requested
273 // file as specified.
274 if (ASK_BROKER != eval_result) {
275 *nt_status = STATUS_ACCESS_DENIED;
276 return true;
277 }
278 // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
279 // CreateDisposition = FILE_OPEN.
280 IO_STATUS_BLOCK io_block = {0};
281 UNICODE_STRING uni_name = {0};
282 OBJECT_ATTRIBUTES obj_attributes = {0};
283 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
284 *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
285 &io_block, 0, share_access, FILE_OPEN,
286 open_options, NULL, 0,
287 client_info.process);
288
289 *io_information = io_block.Information;
290 return true;
291 }
292
293 bool FileSystemPolicy::QueryAttributesFileAction(
294 EvalResult eval_result,
295 const ClientInfo& client_info,
296 const std::wstring &file,
297 uint32 attributes,
298 FILE_BASIC_INFORMATION* file_info,
299 NTSTATUS* nt_status) {
300 // The only action supported is ASK_BROKER which means query the requested
301 // file as specified.
302 if (ASK_BROKER != eval_result) {
303 *nt_status = STATUS_ACCESS_DENIED;
304 return true;
305 }
306
307 NtQueryAttributesFileFunction NtQueryAttributesFile = NULL;
308 ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
309
310 UNICODE_STRING uni_name = {0};
311 OBJECT_ATTRIBUTES obj_attributes = {0};
312 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
313 *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
314
315 return true;
316 }
317
318 bool FileSystemPolicy::QueryFullAttributesFileAction(
319 EvalResult eval_result,
320 const ClientInfo& client_info,
321 const std::wstring &file,
322 uint32 attributes,
323 FILE_NETWORK_OPEN_INFORMATION* file_info,
324 NTSTATUS* nt_status) {
325 // The only action supported is ASK_BROKER which means query the requested
326 // file as specified.
327 if (ASK_BROKER != eval_result) {
328 *nt_status = STATUS_ACCESS_DENIED;
329 return true;
330 }
331
332 NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = NULL;
333 ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
334
335 UNICODE_STRING uni_name = {0};
336 OBJECT_ATTRIBUTES obj_attributes = {0};
337 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
338 *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
339
340 return true;
341 }
342
343 bool FileSystemPolicy::SetInformationFileAction(
344 EvalResult eval_result, const ClientInfo& client_info,
345 HANDLE target_file_handle, void* file_info, uint32 length,
346 uint32 info_class, IO_STATUS_BLOCK* io_block,
347 NTSTATUS* nt_status) {
348 // The only action supported is ASK_BROKER which means open the requested
349 // file as specified.
350 if (ASK_BROKER != eval_result) {
351 *nt_status = STATUS_ACCESS_DENIED;
352 return true;
353 }
354
355 NtSetInformationFileFunction NtSetInformationFile = NULL;
356 ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
357
358 HANDLE local_handle = NULL;
359 if (!::DuplicateHandle(client_info.process, target_file_handle,
360 ::GetCurrentProcess(), &local_handle, 0, FALSE,
361 DUPLICATE_SAME_ACCESS)) {
362 *nt_status = STATUS_ACCESS_DENIED;
363 return true;
364 }
365
366 base::win::ScopedHandle handle(local_handle);
367
368 FILE_INFORMATION_CLASS file_info_class =
369 static_cast<FILE_INFORMATION_CLASS>(info_class);
370 *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
371 file_info_class);
372
373 return true;
374 }
375
376 bool PreProcessName(const std::wstring& path, std::wstring* new_path) {
377 ConvertToLongPath(path, new_path);
378
379 bool reparsed = false;
380 if (ERROR_SUCCESS != IsReparsePoint(*new_path, &reparsed))
381 return false;
382
383 // We can't process reparsed file.
384 return !reparsed;
385 }
386
387 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/src/filesystem_policy.h ('k') | sandbox/src/handle_closer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698