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 20 namespace { 21 22 // Builds a path using the root directory and the name. 23 bool 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 40 namespace sandbox { 41 42 RegistryDispatcher::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 59 bool 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 result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20); 68 return result; 69 } 70 71 return false; 72 } 73 74 bool RegistryDispatcher::NtCreateKey( 75 IPCInfo* ipc, base::string16* name, DWORD attributes, HANDLE root, 76 DWORD desired_access, DWORD title_index, DWORD create_options) { 77 base::win::ScopedHandle root_handle; 78 base::string16 real_path = *name; 79 80 // If there is a root directory, we need to duplicate the handle to make 81 // it valid in this process. 82 if (root) { 83 if (!::DuplicateHandle(ipc->client_info->process, root, 84 ::GetCurrentProcess(), &root, 0, FALSE, 85 DUPLICATE_SAME_ACCESS)) 86 return false; 87 88 root_handle.Set(root); 89 } 90 91 if (!GetCompletePath(root, *name, &real_path)) 92 return false; 93 94 const wchar_t* regname = real_path.c_str(); 95 CountedParameterSet<OpenKey> params; 96 params[OpenKey::NAME] = ParamPickerMake(regname); 97 params[OpenKey::ACCESS] = ParamPickerMake(desired_access); 98 99 EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG, 100 params.GetBase()); 101 102 HANDLE handle; 103 NTSTATUS nt_status; 104 ULONG disposition = 0; 105 if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name, 106 attributes, root, desired_access, 107 title_index, create_options, &handle, 108 &nt_status, &disposition)) { 109 ipc->return_info.nt_status = STATUS_ACCESS_DENIED; 110 return true; 111 } 112 113 // Return operation status on the IPC. 114 ipc->return_info.extended[0].unsigned_int = disposition; 115 ipc->return_info.nt_status = nt_status; 116 ipc->return_info.handle = handle; 117 return true; 118 } 119 120 bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc, base::string16* name, 121 DWORD attributes, HANDLE root, 122 DWORD desired_access) { 123 base::win::ScopedHandle root_handle; 124 base::string16 real_path = *name; 125 126 // If there is a root directory, we need to duplicate the handle to make 127 // it valid in this process. 128 if (root) { 129 if (!::DuplicateHandle(ipc->client_info->process, root, 130 ::GetCurrentProcess(), &root, 0, FALSE, 131 DUPLICATE_SAME_ACCESS)) 132 return false; 133 root_handle.Set(root); 134 } 135 136 if (!GetCompletePath(root, *name, &real_path)) 137 return false; 138 139 const wchar_t* regname = real_path.c_str(); 140 CountedParameterSet<OpenKey> params; 141 params[OpenKey::NAME] = ParamPickerMake(regname); 142 params[OpenKey::ACCESS] = ParamPickerMake(desired_access); 143 144 EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG, 145 params.GetBase()); 146 HANDLE handle; 147 NTSTATUS nt_status; 148 if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name, 149 attributes, root, desired_access, &handle, 150 &nt_status)) { 151 ipc->return_info.nt_status = STATUS_ACCESS_DENIED; 152 return true; 153 } 154 155 // Return operation status on the IPC. 156 ipc->return_info.nt_status = nt_status; 157 ipc->return_info.handle = handle; 158 return true; 159 } 160 161 } // namespace sandbox 162