|
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 std::wstring& name, |
|
24 std::wstring* 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, std::wstring* name, DWORD attributes, HANDLE root, |
|
76 DWORD desired_access, DWORD title_index, DWORD create_options) { |
|
77 base::win::ScopedHandle root_handle; |
|
78 std::wstring 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, std::wstring* name, |
|
121 DWORD attributes, HANDLE root, |
|
122 DWORD desired_access) { |
|
123 base::win::ScopedHandle root_handle; |
|
124 std::wstring 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 |