1 // Copyright (c) 2006-2008 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_interception.h"
6
7 #include <stdint.h>
8
9 #include "sandbox/win/src/crosscall_client.h"
10 #include "sandbox/win/src/ipc_tags.h"
11 #include "sandbox/win/src/policy_params.h"
12 #include "sandbox/win/src/policy_target.h"
13 #include "sandbox/win/src/sandbox_factory.h"
14 #include "sandbox/win/src/sandbox_nt_util.h"
15 #include "sandbox/win/src/sharedmem_ipc_client.h"
16 #include "sandbox/win/src/target_services.h"
17 #include "mozilla/sandboxing/sandboxLogging.h"
18
19 namespace sandbox {
20
TargetNtCreateKey(NtCreateKeyFunction orig_CreateKey,PHANDLE key,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes,ULONG title_index,PUNICODE_STRING class_name,ULONG create_options,PULONG disposition)21 NTSTATUS WINAPI TargetNtCreateKey(NtCreateKeyFunction orig_CreateKey,
22 PHANDLE key,
23 ACCESS_MASK desired_access,
24 POBJECT_ATTRIBUTES object_attributes,
25 ULONG title_index,
26 PUNICODE_STRING class_name,
27 ULONG create_options,
28 PULONG disposition) {
29 // Check if the process can create it first.
30 NTSTATUS status =
31 orig_CreateKey(key, desired_access, object_attributes, title_index,
32 class_name, create_options, disposition);
33 if (NT_SUCCESS(status))
34 return status;
35
36 if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
37 mozilla::sandboxing::LogBlocked("NtCreateKey",
38 object_attributes->ObjectName->Buffer,
39 object_attributes->ObjectName->Length);
40 }
41
42 // We don't trust that the IPC can work this early.
43 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
44 return status;
45
46 do {
47 if (!ValidParameter(key, sizeof(HANDLE), WRITE))
48 break;
49
50 if (disposition && !ValidParameter(disposition, sizeof(ULONG), WRITE))
51 break;
52
53 // At this point we don't support class_name.
54 if (class_name && class_name->Buffer && class_name->Length)
55 break;
56
57 // We don't support creating link keys, volatile keys and backup/restore.
58 if (create_options)
59 break;
60
61 void* memory = GetGlobalIPCMemory();
62 if (!memory)
63 break;
64
65 std::unique_ptr<wchar_t, NtAllocDeleter> name;
66 uint32_t attributes = 0;
67 HANDLE root_directory = 0;
68 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
69 &root_directory);
70 if (!NT_SUCCESS(ret) || !name)
71 break;
72
73 uint32_t desired_access_uint32 = desired_access;
74 CountedParameterSet<OpenKey> params;
75 params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
76
77 bool query_broker = false;
78 {
79 std::unique_ptr<wchar_t, NtAllocDeleter> full_name;
80 const wchar_t* name_ptr = name.get();
81 const wchar_t* full_name_ptr = nullptr;
82
83 if (root_directory) {
84 ret = sandbox::AllocAndGetFullPath(root_directory, name.get(),
85 &full_name);
86 if (!NT_SUCCESS(ret) || !full_name)
87 break;
88 full_name_ptr = full_name.get();
89 params[OpenKey::NAME] = ParamPickerMake(full_name_ptr);
90 } else {
91 params[OpenKey::NAME] = ParamPickerMake(name_ptr);
92 }
93
94 query_broker = QueryBroker(IpcTag::NTCREATEKEY, params.GetBase());
95 }
96
97 if (!query_broker)
98 break;
99
100 SharedMemIPCClient ipc(memory);
101 CrossCallReturn answer = {0};
102
103 ResultCode code = CrossCall(ipc, IpcTag::NTCREATEKEY, name.get(),
104 attributes, root_directory, desired_access,
105 title_index, create_options, &answer);
106
107 if (SBOX_ALL_OK != code)
108 break;
109
110 if (!NT_SUCCESS(answer.nt_status))
111 // TODO(nsylvain): We should return answer.nt_status here instead
112 // of status. We can do this only after we checked the policy.
113 // otherwise we will returns ACCESS_DENIED for all paths
114 // that are not specified by a policy, even though your token allows
115 // access to that path, and the original call had a more meaningful
116 // error. Bug 4369
117 break;
118
119 __try {
120 *key = answer.handle;
121
122 if (disposition)
123 *disposition = answer.extended[0].unsigned_int;
124
125 status = answer.nt_status;
126 } __except (EXCEPTION_EXECUTE_HANDLER) {
127 break;
128 }
129 mozilla::sandboxing::LogAllowed("NtCreateKey",
130 object_attributes->ObjectName->Buffer,
131 object_attributes->ObjectName->Length);
132 } while (false);
133
134 return status;
135 }
136
CommonNtOpenKey(NTSTATUS status,PHANDLE key,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes)137 NTSTATUS WINAPI CommonNtOpenKey(NTSTATUS status,
138 PHANDLE key,
139 ACCESS_MASK desired_access,
140 POBJECT_ATTRIBUTES object_attributes) {
141 // We don't trust that the IPC can work this early.
142 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
143 return status;
144
145 do {
146 if (!ValidParameter(key, sizeof(HANDLE), WRITE))
147 break;
148
149 void* memory = GetGlobalIPCMemory();
150 if (!memory)
151 break;
152
153 std::unique_ptr<wchar_t, NtAllocDeleter> name;
154 uint32_t attributes;
155 HANDLE root_directory;
156 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
157 &root_directory);
158 if (!NT_SUCCESS(ret) || !name)
159 break;
160
161 uint32_t desired_access_uint32 = desired_access;
162 CountedParameterSet<OpenKey> params;
163 params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
164
165 bool query_broker = false;
166 {
167 std::unique_ptr<wchar_t, NtAllocDeleter> full_name;
168 const wchar_t* name_ptr = name.get();
169 const wchar_t* full_name_ptr = nullptr;
170
171 if (root_directory) {
172 ret = sandbox::AllocAndGetFullPath(root_directory, name.get(),
173 &full_name);
174 if (!NT_SUCCESS(ret) || !full_name)
175 break;
176 full_name_ptr = full_name.get();
177 params[OpenKey::NAME] = ParamPickerMake(full_name_ptr);
178 } else {
179 params[OpenKey::NAME] = ParamPickerMake(name_ptr);
180 }
181
182 query_broker = QueryBroker(IpcTag::NTOPENKEY, params.GetBase());
183 }
184
185 if (!query_broker)
186 break;
187
188 SharedMemIPCClient ipc(memory);
189 CrossCallReturn answer = {0};
190 ResultCode code = CrossCall(ipc, IpcTag::NTOPENKEY, name.get(), attributes,
191 root_directory, desired_access, &answer);
192
193 if (SBOX_ALL_OK != code)
194 break;
195
196 if (!NT_SUCCESS(answer.nt_status))
197 // TODO(nsylvain): We should return answer.nt_status here instead
198 // of status. We can do this only after we checked the policy.
199 // otherwise we will returns ACCESS_DENIED for all paths
200 // that are not specified by a policy, even though your token allows
201 // access to that path, and the original call had a more meaningful
202 // error. Bug 4369
203 break;
204
205 __try {
206 *key = answer.handle;
207 status = answer.nt_status;
208 } __except (EXCEPTION_EXECUTE_HANDLER) {
209 break;
210 }
211 mozilla::sandboxing::LogAllowed("NtOpenKey[Ex]",
212 object_attributes->ObjectName->Buffer,
213 object_attributes->ObjectName->Length);
214 } while (false);
215
216 return status;
217 }
218
TargetNtOpenKey(NtOpenKeyFunction orig_OpenKey,PHANDLE key,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes)219 NTSTATUS WINAPI TargetNtOpenKey(NtOpenKeyFunction orig_OpenKey,
220 PHANDLE key,
221 ACCESS_MASK desired_access,
222 POBJECT_ATTRIBUTES object_attributes) {
223 // Check if the process can open it first.
224 NTSTATUS status = orig_OpenKey(key, desired_access, object_attributes);
225 if (NT_SUCCESS(status))
226 return status;
227
228 if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
229 mozilla::sandboxing::LogBlocked("NtOpenKey",
230 object_attributes->ObjectName->Buffer,
231 object_attributes->ObjectName->Length);
232 }
233
234 return CommonNtOpenKey(status, key, desired_access, object_attributes);
235 }
236
TargetNtOpenKeyEx(NtOpenKeyExFunction orig_OpenKeyEx,PHANDLE key,ACCESS_MASK desired_access,POBJECT_ATTRIBUTES object_attributes,ULONG open_options)237 NTSTATUS WINAPI TargetNtOpenKeyEx(NtOpenKeyExFunction orig_OpenKeyEx,
238 PHANDLE key,
239 ACCESS_MASK desired_access,
240 POBJECT_ATTRIBUTES object_attributes,
241 ULONG open_options) {
242 // Check if the process can open it first.
243 NTSTATUS status =
244 orig_OpenKeyEx(key, desired_access, object_attributes, open_options);
245
246 // We do not support open_options at this time. The 2 current known values
247 // are REG_OPTION_CREATE_LINK, to open a symbolic link, and
248 // REG_OPTION_BACKUP_RESTORE to open the key with special privileges.
249 if (NT_SUCCESS(status) || open_options != 0)
250 return status;
251
252 if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
253 mozilla::sandboxing::LogBlocked("NtOpenKeyEx",
254 object_attributes->ObjectName->Buffer,
255 object_attributes->ObjectName->Length);
256 }
257
258 return CommonNtOpenKey(status, key, desired_access, object_attributes);
259 }
260
261 } // namespace sandbox
262