michael@0: // Copyright (c) 2011 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "sandbox/win/src/registry_dispatcher.h" michael@0: michael@0: #include "base/win/scoped_handle.h" michael@0: #include "base/win/windows_version.h" michael@0: #include "sandbox/win/src/crosscall_client.h" michael@0: #include "sandbox/win/src/interception.h" michael@0: #include "sandbox/win/src/interceptors.h" michael@0: #include "sandbox/win/src/ipc_tags.h" michael@0: #include "sandbox/win/src/sandbox_nt_util.h" michael@0: #include "sandbox/win/src/policy_broker.h" michael@0: #include "sandbox/win/src/policy_params.h" michael@0: #include "sandbox/win/src/sandbox.h" michael@0: #include "sandbox/win/src/registry_interception.h" michael@0: #include "sandbox/win/src/registry_policy.h" michael@0: michael@0: namespace { michael@0: michael@0: // Builds a path using the root directory and the name. michael@0: bool GetCompletePath(HANDLE root, const std::wstring& name, michael@0: std::wstring* complete_name) { michael@0: if (root) { michael@0: if (!sandbox::GetPathFromHandle(root, complete_name)) michael@0: return false; michael@0: michael@0: *complete_name += L"\\"; michael@0: *complete_name += name; michael@0: } else { michael@0: *complete_name = name; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: } michael@0: michael@0: namespace sandbox { michael@0: michael@0: RegistryDispatcher::RegistryDispatcher(PolicyBase* policy_base) michael@0: : policy_base_(policy_base) { michael@0: static const IPCCall create_params = { michael@0: {IPC_NTCREATEKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE, michael@0: ULONG_TYPE, ULONG_TYPE}, michael@0: reinterpret_cast(&RegistryDispatcher::NtCreateKey) michael@0: }; michael@0: michael@0: static const IPCCall open_params = { michael@0: {IPC_NTOPENKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE}, michael@0: reinterpret_cast(&RegistryDispatcher::NtOpenKey) michael@0: }; michael@0: michael@0: ipc_calls_.push_back(create_params); michael@0: ipc_calls_.push_back(open_params); michael@0: } michael@0: michael@0: bool RegistryDispatcher::SetupService(InterceptionManager* manager, michael@0: int service) { michael@0: if (IPC_NTCREATEKEY_TAG == service) michael@0: return INTERCEPT_NT(manager, NtCreateKey, CREATE_KEY_ID, 32); michael@0: michael@0: if (IPC_NTOPENKEY_TAG == service) { michael@0: bool result = INTERCEPT_NT(manager, NtOpenKey, OPEN_KEY_ID, 16); michael@0: if (base::win::GetVersion() >= base::win::VERSION_WIN7) michael@0: result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20); michael@0: return result; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool RegistryDispatcher::NtCreateKey( michael@0: IPCInfo* ipc, std::wstring* name, DWORD attributes, HANDLE root, michael@0: DWORD desired_access, DWORD title_index, DWORD create_options) { michael@0: base::win::ScopedHandle root_handle; michael@0: std::wstring real_path = *name; michael@0: michael@0: // If there is a root directory, we need to duplicate the handle to make michael@0: // it valid in this process. michael@0: if (root) { michael@0: if (!::DuplicateHandle(ipc->client_info->process, root, michael@0: ::GetCurrentProcess(), &root, 0, FALSE, michael@0: DUPLICATE_SAME_ACCESS)) michael@0: return false; michael@0: michael@0: root_handle.Set(root); michael@0: } michael@0: michael@0: if (!GetCompletePath(root, *name, &real_path)) michael@0: return false; michael@0: michael@0: const wchar_t* regname = real_path.c_str(); michael@0: CountedParameterSet params; michael@0: params[OpenKey::NAME] = ParamPickerMake(regname); michael@0: params[OpenKey::ACCESS] = ParamPickerMake(desired_access); michael@0: michael@0: EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG, michael@0: params.GetBase()); michael@0: michael@0: HANDLE handle; michael@0: NTSTATUS nt_status; michael@0: ULONG disposition = 0; michael@0: if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name, michael@0: attributes, root, desired_access, michael@0: title_index, create_options, &handle, michael@0: &nt_status, &disposition)) { michael@0: ipc->return_info.nt_status = STATUS_ACCESS_DENIED; michael@0: return true; michael@0: } michael@0: michael@0: // Return operation status on the IPC. michael@0: ipc->return_info.extended[0].unsigned_int = disposition; michael@0: ipc->return_info.nt_status = nt_status; michael@0: ipc->return_info.handle = handle; michael@0: return true; michael@0: } michael@0: michael@0: bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc, std::wstring* name, michael@0: DWORD attributes, HANDLE root, michael@0: DWORD desired_access) { michael@0: base::win::ScopedHandle root_handle; michael@0: std::wstring real_path = *name; michael@0: michael@0: // If there is a root directory, we need to duplicate the handle to make michael@0: // it valid in this process. michael@0: if (root) { michael@0: if (!::DuplicateHandle(ipc->client_info->process, root, michael@0: ::GetCurrentProcess(), &root, 0, FALSE, michael@0: DUPLICATE_SAME_ACCESS)) michael@0: return false; michael@0: root_handle.Set(root); michael@0: } michael@0: michael@0: if (!GetCompletePath(root, *name, &real_path)) michael@0: return false; michael@0: michael@0: const wchar_t* regname = real_path.c_str(); michael@0: CountedParameterSet params; michael@0: params[OpenKey::NAME] = ParamPickerMake(regname); michael@0: params[OpenKey::ACCESS] = ParamPickerMake(desired_access); michael@0: michael@0: EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG, michael@0: params.GetBase()); michael@0: HANDLE handle; michael@0: NTSTATUS nt_status; michael@0: if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name, michael@0: attributes, root, desired_access, &handle, michael@0: &nt_status)) { michael@0: ipc->return_info.nt_status = STATUS_ACCESS_DENIED; michael@0: return true; michael@0: } michael@0: michael@0: // Return operation status on the IPC. michael@0: ipc->return_info.nt_status = nt_status; michael@0: ipc->return_info.handle = handle; michael@0: return true; michael@0: } michael@0: michael@0: } // namespace sandbox