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 "sandbox/win/src/registry_dispatcher.h" 6 7#include "base/win/scoped_handle.h" 8#include "base/win/windows_version.h" 9#include "sandbox/win/src/crosscall_client.h" 10#include "sandbox/win/src/interception.h" 11#include "sandbox/win/src/interceptors.h" 12#include "sandbox/win/src/ipc_tags.h" 13#include "sandbox/win/src/sandbox_nt_util.h" 14#include "sandbox/win/src/policy_broker.h" 15#include "sandbox/win/src/policy_params.h" 16#include "sandbox/win/src/sandbox.h" 17#include "sandbox/win/src/registry_interception.h" 18#include "sandbox/win/src/registry_policy.h" 19 20namespace { 21 22// Builds a path using the root directory and the name. 23bool GetCompletePath(HANDLE root, const base::string16& name, 24 base::string16* complete_name) { 25 if (root) { 26 if (!sandbox::GetPathFromHandle(root, complete_name)) 27 return false; 28 29 *complete_name += L"\\"; 30 *complete_name += name; 31 } else { 32 *complete_name = name; 33 } 34 35 return true; 36} 37 38} 39 40namespace sandbox { 41 42RegistryDispatcher::RegistryDispatcher(PolicyBase* policy_base) 43 : policy_base_(policy_base) { 44 static const IPCCall create_params = { 45 {IPC_NTCREATEKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE, 46 ULONG_TYPE, ULONG_TYPE}, 47 reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtCreateKey) 48 }; 49 50 static const IPCCall open_params = { 51 {IPC_NTOPENKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE}, 52 reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtOpenKey) 53 }; 54 55 ipc_calls_.push_back(create_params); 56 ipc_calls_.push_back(open_params); 57} 58 59bool RegistryDispatcher::SetupService(InterceptionManager* manager, 60 int service) { 61 if (IPC_NTCREATEKEY_TAG == service) 62 return INTERCEPT_NT(manager, NtCreateKey, CREATE_KEY_ID, 32); 63 64 if (IPC_NTOPENKEY_TAG == service) { 65 bool result = INTERCEPT_NT(manager, NtOpenKey, OPEN_KEY_ID, 16); 66 if (base::win::GetVersion() >= base::win::VERSION_WIN7 || 67 (base::win::GetVersion() == base::win::VERSION_VISTA && 68 base::win::OSInfo::GetInstance()->version_type() == 69 base::win::SUITE_SERVER)) 70 result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20); 71 return result; 72 } 73 74 return false; 75} 76 77bool RegistryDispatcher::NtCreateKey( 78 IPCInfo* ipc, base::string16* name, DWORD attributes, HANDLE root, 79 DWORD desired_access, DWORD title_index, DWORD create_options) { 80 base::win::ScopedHandle root_handle; 81 base::string16 real_path = *name; 82 83 // If there is a root directory, we need to duplicate the handle to make 84 // it valid in this process. 85 if (root) { 86 if (!::DuplicateHandle(ipc->client_info->process, root, 87 ::GetCurrentProcess(), &root, 0, FALSE, 88 DUPLICATE_SAME_ACCESS)) 89 return false; 90 91 root_handle.Set(root); 92 } 93 94 if (!GetCompletePath(root, *name, &real_path)) 95 return false; 96 97 const wchar_t* regname = real_path.c_str(); 98 CountedParameterSet<OpenKey> params; 99 params[OpenKey::NAME] = ParamPickerMake(regname); 100 params[OpenKey::ACCESS] = ParamPickerMake(desired_access); 101 102 EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG, 103 params.GetBase()); 104 105 HANDLE handle; 106 NTSTATUS nt_status; 107 ULONG disposition = 0; 108 if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name, 109 attributes, root, desired_access, 110 title_index, create_options, &handle, 111 &nt_status, &disposition)) { 112 ipc->return_info.nt_status = STATUS_ACCESS_DENIED; 113 return true; 114 } 115 116 // Return operation status on the IPC. 117 ipc->return_info.extended[0].unsigned_int = disposition; 118 ipc->return_info.nt_status = nt_status; 119 ipc->return_info.handle = handle; 120 return true; 121} 122 123bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc, base::string16* name, 124 DWORD attributes, HANDLE root, 125 DWORD desired_access) { 126 base::win::ScopedHandle root_handle; 127 base::string16 real_path = *name; 128 129 // If there is a root directory, we need to duplicate the handle to make 130 // it valid in this process. 131 if (root) { 132 if (!::DuplicateHandle(ipc->client_info->process, root, 133 ::GetCurrentProcess(), &root, 0, FALSE, 134 DUPLICATE_SAME_ACCESS)) 135 return false; 136 root_handle.Set(root); 137 } 138 139 if (!GetCompletePath(root, *name, &real_path)) 140 return false; 141 142 const wchar_t* regname = real_path.c_str(); 143 CountedParameterSet<OpenKey> params; 144 params[OpenKey::NAME] = ParamPickerMake(regname); 145 params[OpenKey::ACCESS] = ParamPickerMake(desired_access); 146 147 EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG, 148 params.GetBase()); 149 HANDLE handle; 150 NTSTATUS nt_status; 151 if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name, 152 attributes, root, desired_access, &handle, 153 &nt_status)) { 154 ipc->return_info.nt_status = STATUS_ACCESS_DENIED; 155 return true; 156 } 157 158 // Return operation status on the IPC. 159 ipc->return_info.nt_status = nt_status; 160 ipc->return_info.handle = handle; 161 return true; 162} 163 164} // namespace sandbox 165