| Index: sandbox/win/src/filesystem_policy.cc
|
| diff --git a/sandbox/win/src/filesystem_policy.cc b/sandbox/win/src/filesystem_policy.cc
|
| deleted file mode 100644
|
| index fe7f62fc245e776913657cd02e9f087b045feb20..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/filesystem_policy.cc
|
| +++ /dev/null
|
| @@ -1,435 +0,0 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include <stdint.h>
|
| -
|
| -#include <string>
|
| -
|
| -#include "sandbox/win/src/filesystem_policy.h"
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/win/scoped_handle.h"
|
| -#include "base/win/windows_version.h"
|
| -#include "sandbox/win/src/ipc_tags.h"
|
| -#include "sandbox/win/src/policy_engine_opcodes.h"
|
| -#include "sandbox/win/src/policy_params.h"
|
| -#include "sandbox/win/src/sandbox_types.h"
|
| -#include "sandbox/win/src/sandbox_utils.h"
|
| -#include "sandbox/win/src/win_utils.h"
|
| -
|
| -namespace {
|
| -
|
| -NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
|
| - ACCESS_MASK desired_access,
|
| - OBJECT_ATTRIBUTES* obj_attributes,
|
| - IO_STATUS_BLOCK* io_status_block,
|
| - ULONG file_attributes,
|
| - ULONG share_access,
|
| - ULONG create_disposition,
|
| - ULONG create_options,
|
| - PVOID ea_buffer,
|
| - ULONG ea_lenght,
|
| - HANDLE target_process) {
|
| - NtCreateFileFunction NtCreateFile = NULL;
|
| - ResolveNTFunctionPtr("NtCreateFile", &NtCreateFile);
|
| -
|
| - HANDLE local_handle = INVALID_HANDLE_VALUE;
|
| - NTSTATUS status = NtCreateFile(&local_handle, desired_access, obj_attributes,
|
| - io_status_block, NULL, file_attributes,
|
| - share_access, create_disposition,
|
| - create_options, ea_buffer, ea_lenght);
|
| - if (!NT_SUCCESS(status)) {
|
| - return status;
|
| - }
|
| -
|
| - if (!sandbox::SameObject(local_handle, obj_attributes->ObjectName->Buffer)) {
|
| - // The handle points somewhere else. Fail the operation.
|
| - ::CloseHandle(local_handle);
|
| - return STATUS_ACCESS_DENIED;
|
| - }
|
| -
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
|
| - target_process, target_file_handle, 0, FALSE,
|
| - DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
| - return STATUS_ACCESS_DENIED;
|
| - }
|
| - return STATUS_SUCCESS;
|
| -}
|
| -
|
| -// Get an initialized anonymous level Security QOS.
|
| -SECURITY_QUALITY_OF_SERVICE GetAnonymousQOS() {
|
| - SECURITY_QUALITY_OF_SERVICE security_qos = {0};
|
| - security_qos.Length = sizeof(security_qos);
|
| - security_qos.ImpersonationLevel = SecurityAnonymous;
|
| - // Set dynamic tracking so that a pipe doesn't capture the broker's token
|
| - security_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
| - security_qos.EffectiveOnly = TRUE;
|
| -
|
| - return security_qos;
|
| -}
|
| -
|
| -} // namespace.
|
| -
|
| -namespace sandbox {
|
| -
|
| -bool FileSystemPolicy::GenerateRules(const wchar_t* name,
|
| - TargetPolicy::Semantics semantics,
|
| - LowLevelPolicy* policy) {
|
| - base::string16 mod_name(name);
|
| - if (mod_name.empty()) {
|
| - return false;
|
| - }
|
| -
|
| - if (!PreProcessName(&mod_name)) {
|
| - // The path to be added might contain a reparse point.
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
|
| - // infrastructure to normalize names. In any case we need to escape the
|
| - // question marks.
|
| - if (_wcsnicmp(mod_name.c_str(), kNTDevicePrefix, kNTDevicePrefixLen)) {
|
| - mod_name = FixNTPrefixForMatch(mod_name);
|
| - name = mod_name.c_str();
|
| - }
|
| -
|
| - EvalResult result = ASK_BROKER;
|
| -
|
| - // List of supported calls for the filesystem.
|
| - const unsigned kCallNtCreateFile = 0x1;
|
| - const unsigned kCallNtOpenFile = 0x2;
|
| - const unsigned kCallNtQueryAttributesFile = 0x4;
|
| - const unsigned kCallNtQueryFullAttributesFile = 0x8;
|
| - const unsigned kCallNtSetInfoRename = 0x10;
|
| -
|
| - DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
|
| - kCallNtQueryAttributesFile |
|
| - kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
|
| -
|
| - PolicyRule create(result);
|
| - PolicyRule open(result);
|
| - PolicyRule query(result);
|
| - PolicyRule query_full(result);
|
| - PolicyRule rename(result);
|
| -
|
| - switch (semantics) {
|
| - case TargetPolicy::FILES_ALLOW_DIR_ANY: {
|
| - open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
|
| - create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
|
| - break;
|
| - }
|
| - case TargetPolicy::FILES_ALLOW_READONLY: {
|
| - // We consider all flags that are not known to be readonly as potentially
|
| - // used for write.
|
| - DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
|
| - FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
|
| - GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
|
| - DWORD restricted_flags = ~allowed_flags;
|
| - open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
|
| - open.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
|
| - create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
|
| - create.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
|
| -
|
| - // Read only access don't work for rename.
|
| - rule_to_add &= ~kCallNtSetInfoRename;
|
| - break;
|
| - }
|
| - case TargetPolicy::FILES_ALLOW_QUERY: {
|
| - // Here we don't want to add policy for the open or the create.
|
| - rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile |
|
| - kCallNtSetInfoRename);
|
| - break;
|
| - }
|
| - case TargetPolicy::FILES_ALLOW_ANY: {
|
| - break;
|
| - }
|
| - default: {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - if ((rule_to_add & kCallNtCreateFile) &&
|
| - (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
|
| - !policy->AddRule(IPC_NTCREATEFILE_TAG, &create))) {
|
| - return false;
|
| - }
|
| -
|
| - if ((rule_to_add & kCallNtOpenFile) &&
|
| - (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
|
| - !policy->AddRule(IPC_NTOPENFILE_TAG, &open))) {
|
| - return false;
|
| - }
|
| -
|
| - if ((rule_to_add & kCallNtQueryAttributesFile) &&
|
| - (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
|
| - !policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &query))) {
|
| - return false;
|
| - }
|
| -
|
| - if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
|
| - (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE)
|
| - || !policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
|
| - &query_full))) {
|
| - return false;
|
| - }
|
| -
|
| - if ((rule_to_add & kCallNtSetInfoRename) &&
|
| - (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
|
| - !policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &rename))) {
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Right now we insert two rules, to be evaluated before any user supplied rule:
|
| -// - go to the broker if the path doesn't look like the paths that we push on
|
| -// the policy (namely \??\something).
|
| -// - go to the broker if it looks like this is a short-name path.
|
| -//
|
| -// It is possible to add a rule to go to the broker in any case; it would look
|
| -// something like:
|
| -// rule = new PolicyRule(ASK_BROKER);
|
| -// rule->AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
|
| -// policy->AddRule(service, rule);
|
| -bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
|
| - PolicyRule format(ASK_BROKER);
|
| - PolicyRule short_name(ASK_BROKER);
|
| -
|
| - bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
|
| - rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
|
| - CASE_SENSITIVE);
|
| -
|
| - rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
|
| - rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
|
| -
|
| - if (!rv || !policy->AddRule(IPC_NTCREATEFILE_TAG, &format))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTCREATEFILE_TAG, &short_name))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTOPENFILE_TAG, &format))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTOPENFILE_TAG, &short_name))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &format))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &short_name))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &format))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &short_name))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &format))
|
| - return false;
|
| -
|
| - if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &short_name))
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
|
| - const ClientInfo& client_info,
|
| - const base::string16& file,
|
| - uint32_t attributes,
|
| - uint32_t desired_access,
|
| - uint32_t file_attributes,
|
| - uint32_t share_access,
|
| - uint32_t create_disposition,
|
| - uint32_t create_options,
|
| - HANDLE* handle,
|
| - NTSTATUS* nt_status,
|
| - ULONG_PTR* io_information) {
|
| - // The only action supported is ASK_BROKER which means create the requested
|
| - // file as specified.
|
| - if (ASK_BROKER != eval_result) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return false;
|
| - }
|
| - IO_STATUS_BLOCK io_block = {};
|
| - UNICODE_STRING uni_name = {};
|
| - OBJECT_ATTRIBUTES obj_attributes = {};
|
| - SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
|
| -
|
| - InitObjectAttribs(file, attributes, NULL, &obj_attributes,
|
| - &uni_name, IsPipe(file) ? &security_qos : NULL);
|
| - *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
|
| - &io_block, file_attributes, share_access,
|
| - create_disposition, create_options, NULL,
|
| - 0, client_info.process);
|
| -
|
| - *io_information = io_block.Information;
|
| - return true;
|
| -}
|
| -
|
| -bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
|
| - const ClientInfo& client_info,
|
| - const base::string16& file,
|
| - uint32_t attributes,
|
| - uint32_t desired_access,
|
| - uint32_t share_access,
|
| - uint32_t open_options,
|
| - HANDLE* handle,
|
| - NTSTATUS* nt_status,
|
| - ULONG_PTR* io_information) {
|
| - // The only action supported is ASK_BROKER which means open the requested
|
| - // file as specified.
|
| - if (ASK_BROKER != eval_result) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return true;
|
| - }
|
| - // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
|
| - // CreateDisposition = FILE_OPEN.
|
| - IO_STATUS_BLOCK io_block = {};
|
| - UNICODE_STRING uni_name = {};
|
| - OBJECT_ATTRIBUTES obj_attributes = {};
|
| - SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
|
| -
|
| - InitObjectAttribs(file, attributes, NULL, &obj_attributes,
|
| - &uni_name, IsPipe(file) ? &security_qos : NULL);
|
| - *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
|
| - &io_block, 0, share_access, FILE_OPEN,
|
| - open_options, NULL, 0,
|
| - client_info.process);
|
| -
|
| - *io_information = io_block.Information;
|
| - return true;
|
| -}
|
| -
|
| -bool FileSystemPolicy::QueryAttributesFileAction(
|
| - EvalResult eval_result,
|
| - const ClientInfo& client_info,
|
| - const base::string16& file,
|
| - uint32_t attributes,
|
| - FILE_BASIC_INFORMATION* file_info,
|
| - NTSTATUS* nt_status) {
|
| - // The only action supported is ASK_BROKER which means query the requested
|
| - // file as specified.
|
| - if (ASK_BROKER != eval_result) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return true;
|
| - }
|
| -
|
| - NtQueryAttributesFileFunction NtQueryAttributesFile = NULL;
|
| - ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
|
| -
|
| - UNICODE_STRING uni_name = {0};
|
| - OBJECT_ATTRIBUTES obj_attributes = {0};
|
| - SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
|
| -
|
| - InitObjectAttribs(file, attributes, NULL, &obj_attributes,
|
| - &uni_name, IsPipe(file) ? &security_qos : NULL);
|
| - *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool FileSystemPolicy::QueryFullAttributesFileAction(
|
| - EvalResult eval_result,
|
| - const ClientInfo& client_info,
|
| - const base::string16& file,
|
| - uint32_t attributes,
|
| - FILE_NETWORK_OPEN_INFORMATION* file_info,
|
| - NTSTATUS* nt_status) {
|
| - // The only action supported is ASK_BROKER which means query the requested
|
| - // file as specified.
|
| - if (ASK_BROKER != eval_result) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return true;
|
| - }
|
| -
|
| - NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = NULL;
|
| - ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
|
| -
|
| - UNICODE_STRING uni_name = {0};
|
| - OBJECT_ATTRIBUTES obj_attributes = {0};
|
| - SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
|
| -
|
| - InitObjectAttribs(file, attributes, NULL, &obj_attributes,
|
| - &uni_name, IsPipe(file) ? &security_qos : NULL);
|
| - *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool FileSystemPolicy::SetInformationFileAction(EvalResult eval_result,
|
| - const ClientInfo& client_info,
|
| - HANDLE target_file_handle,
|
| - void* file_info,
|
| - uint32_t length,
|
| - uint32_t info_class,
|
| - IO_STATUS_BLOCK* io_block,
|
| - NTSTATUS* nt_status) {
|
| - // The only action supported is ASK_BROKER which means open the requested
|
| - // file as specified.
|
| - if (ASK_BROKER != eval_result) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return true;
|
| - }
|
| -
|
| - NtSetInformationFileFunction NtSetInformationFile = NULL;
|
| - ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
|
| -
|
| - HANDLE local_handle = NULL;
|
| - if (!::DuplicateHandle(client_info.process, target_file_handle,
|
| - ::GetCurrentProcess(), &local_handle, 0, FALSE,
|
| - DUPLICATE_SAME_ACCESS)) {
|
| - *nt_status = STATUS_ACCESS_DENIED;
|
| - return true;
|
| - }
|
| -
|
| - base::win::ScopedHandle handle(local_handle);
|
| -
|
| - FILE_INFORMATION_CLASS file_info_class =
|
| - static_cast<FILE_INFORMATION_CLASS>(info_class);
|
| - *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
|
| - file_info_class);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool PreProcessName(base::string16* path) {
|
| - ConvertToLongPath(path);
|
| -
|
| - if (ERROR_NOT_A_REPARSE_POINT == IsReparsePoint(*path))
|
| - return true;
|
| -
|
| - // We can't process a reparsed file.
|
| - return false;
|
| -}
|
| -
|
| -base::string16 FixNTPrefixForMatch(const base::string16& name) {
|
| - base::string16 mod_name = name;
|
| -
|
| - // NT prefix escaped for rule matcher
|
| - const wchar_t kNTPrefixEscaped[] = L"\\/?/?\\";
|
| - const int kNTPrefixEscapedLen = arraysize(kNTPrefixEscaped) - 1;
|
| -
|
| - if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
|
| - if (0 != mod_name.compare(0, kNTPrefixEscapedLen, kNTPrefixEscaped)) {
|
| - // TODO(nsylvain): Find a better way to do name resolution. Right now we
|
| - // take the name and we expand it.
|
| - mod_name.insert(0, kNTPrefixEscaped);
|
| - }
|
| - } else {
|
| - // Start of name matches NT prefix, replace with escaped format
|
| - // Fixes bug: 334882
|
| - mod_name.replace(0, kNTPrefixLen, kNTPrefixEscaped);
|
| - }
|
| -
|
| - return mod_name;
|
| -}
|
| -
|
| -} // namespace sandbox
|
|
|