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

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

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

Powered by Google App Engine
This is Rietveld 408576698