Added GetState, GetManagedProperties, CreateNetwork methods to WiFiService.
[chromium-blink-merge.git] / sandbox / win / src / filesystem_policy.cc
blob02707b0a8473e669937ab631017d57cc702c8264
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.
5 #include <string>
7 #include "sandbox/win/src/filesystem_policy.h"
9 #include "base/logging.h"
10 #include "base/win/scoped_handle.h"
11 #include "sandbox/win/src/ipc_tags.h"
12 #include "sandbox/win/src/policy_engine_opcodes.h"
13 #include "sandbox/win/src/policy_params.h"
14 #include "sandbox/win/src/sandbox_utils.h"
15 #include "sandbox/win/src/sandbox_types.h"
16 #include "sandbox/win/src/win_utils.h"
18 namespace {
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);
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;
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;
49 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
50 target_process, target_file_handle, 0, FALSE,
51 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
52 return STATUS_ACCESS_DENIED;
54 return STATUS_SUCCESS;
57 } // namespace.
59 namespace sandbox {
61 bool FileSystemPolicy::GenerateRules(const wchar_t* name,
62 TargetPolicy::Semantics semantics,
63 LowLevelPolicy* policy) {
64 std::wstring mod_name(name);
65 if (mod_name.empty()) {
66 return false;
69 // Don't do any pre-processing if the name starts like the the native
70 // object manager style.
71 if (0 != _wcsnicmp(mod_name.c_str(), kNTObjManPrefix, kNTObjManPrefixLen)) {
72 // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
73 // infrastructure to normalize names. In any case we need to escape the
74 // question marks.
75 if (!PreProcessName(mod_name, &mod_name)) {
76 // The path to be added might contain a reparse point.
77 NOTREACHED();
78 return false;
80 if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
81 // TODO(nsylvain): Find a better way to do name resolution. Right now we
82 // take the name and we expand it.
83 mod_name.insert(0, L"\\/?/?\\");
84 name = mod_name.c_str();
88 EvalResult result = ASK_BROKER;
90 // List of supported calls for the filesystem.
91 const unsigned kCallNtCreateFile = 0x1;
92 const unsigned kCallNtOpenFile = 0x2;
93 const unsigned kCallNtQueryAttributesFile = 0x4;
94 const unsigned kCallNtQueryFullAttributesFile = 0x8;
95 const unsigned kCallNtSetInfoRename = 0x10;
97 DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
98 kCallNtQueryAttributesFile |
99 kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
101 PolicyRule create(result);
102 PolicyRule open(result);
103 PolicyRule query(result);
104 PolicyRule query_full(result);
105 PolicyRule rename(result);
107 switch (semantics) {
108 case TargetPolicy::FILES_ALLOW_DIR_ANY: {
109 open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
110 create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
111 break;
113 case TargetPolicy::FILES_ALLOW_READONLY: {
114 // We consider all flags that are not known to be readonly as potentially
115 // used for write.
116 DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
117 FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
118 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
119 DWORD restricted_flags = ~allowed_flags;
120 open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
121 create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
123 // Read only access don't work for rename.
124 rule_to_add &= ~kCallNtSetInfoRename;
125 break;
127 case TargetPolicy::FILES_ALLOW_QUERY: {
128 // Here we don't want to add policy for the open or the create.
129 rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile |
130 kCallNtSetInfoRename);
131 break;
133 case TargetPolicy::FILES_ALLOW_ANY: {
134 break;
136 default: {
137 NOTREACHED();
138 return false;
142 if ((rule_to_add & kCallNtCreateFile) &&
143 (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
144 !policy->AddRule(IPC_NTCREATEFILE_TAG, &create))) {
145 return false;
148 if ((rule_to_add & kCallNtOpenFile) &&
149 (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
150 !policy->AddRule(IPC_NTOPENFILE_TAG, &open))) {
151 return false;
154 if ((rule_to_add & kCallNtQueryAttributesFile) &&
155 (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
156 !policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &query))) {
157 return false;
160 if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
161 (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE)
162 || !policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
163 &query_full))) {
164 return false;
167 if ((rule_to_add & kCallNtSetInfoRename) &&
168 (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
169 !policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &rename))) {
170 return false;
173 return true;
176 // Right now we insert two rules, to be evaluated before any user supplied rule:
177 // - go to the broker if the path doesn't look like the paths that we push on
178 // the policy (namely \??\something).
179 // - go to the broker if it looks like this is a short-name path.
181 // It is possible to add a rule to go to the broker in any case; it would look
182 // something like:
183 // rule = new PolicyRule(ASK_BROKER);
184 // rule->AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
185 // policy->AddRule(service, rule);
186 bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
187 PolicyRule format(ASK_BROKER);
188 PolicyRule short_name(ASK_BROKER);
190 bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
191 rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
192 CASE_SENSITIVE);
194 rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
195 rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
197 if (!rv || !policy->AddRule(IPC_NTCREATEFILE_TAG, &format))
198 return false;
200 if (!policy->AddRule(IPC_NTCREATEFILE_TAG, &short_name))
201 return false;
203 if (!policy->AddRule(IPC_NTOPENFILE_TAG, &format))
204 return false;
206 if (!policy->AddRule(IPC_NTOPENFILE_TAG, &short_name))
207 return false;
209 if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &format))
210 return false;
212 if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &short_name))
213 return false;
215 if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &format))
216 return false;
218 if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &short_name))
219 return false;
221 if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &format))
222 return false;
224 if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &short_name))
225 return false;
227 return true;
230 bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
231 const ClientInfo& client_info,
232 const std::wstring &file,
233 uint32 attributes,
234 uint32 desired_access,
235 uint32 file_attributes,
236 uint32 share_access,
237 uint32 create_disposition,
238 uint32 create_options,
239 HANDLE *handle,
240 NTSTATUS* nt_status,
241 ULONG_PTR *io_information) {
242 // The only action supported is ASK_BROKER which means create the requested
243 // file as specified.
244 if (ASK_BROKER != eval_result) {
245 *nt_status = STATUS_ACCESS_DENIED;
246 return false;
248 IO_STATUS_BLOCK io_block = {0};
249 UNICODE_STRING uni_name = {0};
250 OBJECT_ATTRIBUTES obj_attributes = {0};
251 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
252 *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
253 &io_block, file_attributes, share_access,
254 create_disposition, create_options, NULL,
255 0, client_info.process);
257 *io_information = io_block.Information;
258 return true;
261 bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
262 const ClientInfo& client_info,
263 const std::wstring &file,
264 uint32 attributes,
265 uint32 desired_access,
266 uint32 share_access,
267 uint32 open_options,
268 HANDLE *handle,
269 NTSTATUS* nt_status,
270 ULONG_PTR *io_information) {
271 // The only action supported is ASK_BROKER which means open the requested
272 // file as specified.
273 if (ASK_BROKER != eval_result) {
274 *nt_status = STATUS_ACCESS_DENIED;
275 return true;
277 // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
278 // CreateDisposition = FILE_OPEN.
279 IO_STATUS_BLOCK io_block = {0};
280 UNICODE_STRING uni_name = {0};
281 OBJECT_ATTRIBUTES obj_attributes = {0};
282 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
283 *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
284 &io_block, 0, share_access, FILE_OPEN,
285 open_options, NULL, 0,
286 client_info.process);
288 *io_information = io_block.Information;
289 return true;
292 bool FileSystemPolicy::QueryAttributesFileAction(
293 EvalResult eval_result,
294 const ClientInfo& client_info,
295 const std::wstring &file,
296 uint32 attributes,
297 FILE_BASIC_INFORMATION* file_info,
298 NTSTATUS* nt_status) {
299 // The only action supported is ASK_BROKER which means query the requested
300 // file as specified.
301 if (ASK_BROKER != eval_result) {
302 *nt_status = STATUS_ACCESS_DENIED;
303 return true;
306 NtQueryAttributesFileFunction NtQueryAttributesFile = NULL;
307 ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
309 UNICODE_STRING uni_name = {0};
310 OBJECT_ATTRIBUTES obj_attributes = {0};
311 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
312 *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
314 return true;
317 bool FileSystemPolicy::QueryFullAttributesFileAction(
318 EvalResult eval_result,
319 const ClientInfo& client_info,
320 const std::wstring &file,
321 uint32 attributes,
322 FILE_NETWORK_OPEN_INFORMATION* file_info,
323 NTSTATUS* nt_status) {
324 // The only action supported is ASK_BROKER which means query the requested
325 // file as specified.
326 if (ASK_BROKER != eval_result) {
327 *nt_status = STATUS_ACCESS_DENIED;
328 return true;
331 NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = NULL;
332 ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
334 UNICODE_STRING uni_name = {0};
335 OBJECT_ATTRIBUTES obj_attributes = {0};
336 InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
337 *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
339 return true;
342 bool FileSystemPolicy::SetInformationFileAction(
343 EvalResult eval_result, const ClientInfo& client_info,
344 HANDLE target_file_handle, void* file_info, uint32 length,
345 uint32 info_class, IO_STATUS_BLOCK* io_block,
346 NTSTATUS* nt_status) {
347 // The only action supported is ASK_BROKER which means open the requested
348 // file as specified.
349 if (ASK_BROKER != eval_result) {
350 *nt_status = STATUS_ACCESS_DENIED;
351 return true;
354 NtSetInformationFileFunction NtSetInformationFile = NULL;
355 ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
357 HANDLE local_handle = NULL;
358 if (!::DuplicateHandle(client_info.process, target_file_handle,
359 ::GetCurrentProcess(), &local_handle, 0, FALSE,
360 DUPLICATE_SAME_ACCESS)) {
361 *nt_status = STATUS_ACCESS_DENIED;
362 return true;
365 base::win::ScopedHandle handle(local_handle);
367 FILE_INFORMATION_CLASS file_info_class =
368 static_cast<FILE_INFORMATION_CLASS>(info_class);
369 *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
370 file_info_class);
372 return true;
375 bool PreProcessName(const std::wstring& path, std::wstring* new_path) {
376 ConvertToLongPath(path, new_path);
378 bool reparsed = false;
379 if (ERROR_SUCCESS != IsReparsePoint(*new_path, &reparsed))
380 return false;
382 // We can't process reparsed file.
383 return !reparsed;
386 } // namespace sandbox