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