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