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 <string>
6
7 #include "sandbox/win/src/registry_policy.h"
8
9 #include "base/logging.h"
10 #include "sandbox/win/src/ipc_tags.h"
11 #include "sandbox/win/src/policy_engine_opcodes.h"
12 #include "sandbox/win/src/policy_params.h"
13 #include "sandbox/win/src/sandbox_utils.h"
14 #include "sandbox/win/src/sandbox_types.h"
15 #include "sandbox/win/src/win_utils.h"
16
17 namespace {
18
19 static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS |
20 KEY_NOTIFY | KEY_READ | GENERIC_READ |
21 GENERIC_EXECUTE | READ_CONTROL;
22
23 // Opens the key referenced by |obj_attributes| with |access| and
24 // checks what permission was given. Remove the WRITE flags and update
25 // |access| with the new value.
TranslateMaximumAllowed(OBJECT_ATTRIBUTES * obj_attributes,DWORD * access)26 NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
27 DWORD* access) {
28 NtOpenKeyFunction NtOpenKey = NULL;
29 ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
30
31 NtCloseFunction NtClose = NULL;
32 ResolveNTFunctionPtr("NtClose", &NtClose);
33
34 NtQueryObjectFunction NtQueryObject = NULL;
35 ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
36
37 // Open the key.
38 HANDLE handle;
39 NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes);
40 if (!NT_SUCCESS(status))
41 return status;
42
43 OBJECT_BASIC_INFORMATION info = {0};
44 status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info),
45 NULL);
46 NtClose(handle);
47 if (!NT_SUCCESS(status))
48 return status;
49
50 *access = info.GrantedAccess & kAllowedRegFlags;
51 return STATUS_SUCCESS;
52 }
53
NtCreateKeyInTarget(HANDLE * target_key_handle,ACCESS_MASK desired_access,OBJECT_ATTRIBUTES * obj_attributes,ULONG title_index,UNICODE_STRING * class_name,ULONG create_options,ULONG * disposition,HANDLE target_process)54 NTSTATUS NtCreateKeyInTarget(HANDLE* target_key_handle,
55 ACCESS_MASK desired_access,
56 OBJECT_ATTRIBUTES* obj_attributes,
57 ULONG title_index,
58 UNICODE_STRING* class_name,
59 ULONG create_options,
60 ULONG* disposition,
61 HANDLE target_process) {
62 NtCreateKeyFunction NtCreateKey = NULL;
63 ResolveNTFunctionPtr("NtCreateKey", &NtCreateKey);
64
65 if (MAXIMUM_ALLOWED & desired_access) {
66 NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
67 if (!NT_SUCCESS(status))
68 return STATUS_ACCESS_DENIED;
69 }
70
71 HANDLE local_handle = INVALID_HANDLE_VALUE;
72 NTSTATUS status = NtCreateKey(&local_handle, desired_access, obj_attributes,
73 title_index, class_name, create_options,
74 disposition);
75 if (!NT_SUCCESS(status))
76 return status;
77
78 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
79 target_process, target_key_handle, 0, FALSE,
80 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
81 return STATUS_ACCESS_DENIED;
82 }
83 return STATUS_SUCCESS;
84 }
85
NtOpenKeyInTarget(HANDLE * target_key_handle,ACCESS_MASK desired_access,OBJECT_ATTRIBUTES * obj_attributes,HANDLE target_process)86 NTSTATUS NtOpenKeyInTarget(HANDLE* target_key_handle,
87 ACCESS_MASK desired_access,
88 OBJECT_ATTRIBUTES* obj_attributes,
89 HANDLE target_process) {
90 NtOpenKeyFunction NtOpenKey = NULL;
91 ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
92
93 if (MAXIMUM_ALLOWED & desired_access) {
94 NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
95 if (!NT_SUCCESS(status))
96 return STATUS_ACCESS_DENIED;
97 }
98
99 HANDLE local_handle = INVALID_HANDLE_VALUE;
100 NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes);
101
102 if (!NT_SUCCESS(status))
103 return status;
104
105 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
106 target_process, target_key_handle, 0, FALSE,
107 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
108 return STATUS_ACCESS_DENIED;
109 }
110 return STATUS_SUCCESS;
111 }
112
113 }
114
115 namespace sandbox {
116
GenerateRules(const wchar_t * name,TargetPolicy::Semantics semantics,LowLevelPolicy * policy)117 bool RegistryPolicy::GenerateRules(const wchar_t* name,
118 TargetPolicy::Semantics semantics,
119 LowLevelPolicy* policy) {
120 base::string16 resovled_name(name);
121 if (resovled_name.empty()) {
122 return false;
123 }
124
125 if (!ResolveRegistryName(resovled_name, &resovled_name))
126 return false;
127
128 name = resovled_name.c_str();
129
130 EvalResult result = ASK_BROKER;
131
132 PolicyRule open(result);
133 PolicyRule create(result);
134
135 switch (semantics) {
136 case TargetPolicy::REG_ALLOW_READONLY: {
137 // We consider all flags that are not known to be readonly as potentially
138 // used for write. Here we also support MAXIMUM_ALLOWED, but we are going
139 // to expand it to read-only before the call.
140 DWORD restricted_flags = ~(kAllowedRegFlags | MAXIMUM_ALLOWED);
141 open.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
142 create.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
143 break;
144 }
145 case TargetPolicy::REG_ALLOW_ANY: {
146 break;
147 }
148 default: {
149 NOTREACHED();
150 return false;
151 }
152 }
153
154 if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
155 !policy->AddRule(IPC_NTCREATEKEY_TAG, &create)) {
156 return false;
157 }
158
159 if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
160 !policy->AddRule(IPC_NTOPENKEY_TAG, &open)) {
161 return false;
162 }
163
164 return true;
165 }
166
CreateKeyAction(EvalResult eval_result,const ClientInfo & client_info,const base::string16 & key,uint32 attributes,HANDLE root_directory,uint32 desired_access,uint32 title_index,uint32 create_options,HANDLE * handle,NTSTATUS * nt_status,ULONG * disposition)167 bool RegistryPolicy::CreateKeyAction(EvalResult eval_result,
168 const ClientInfo& client_info,
169 const base::string16 &key,
170 uint32 attributes,
171 HANDLE root_directory,
172 uint32 desired_access,
173 uint32 title_index,
174 uint32 create_options,
175 HANDLE* handle,
176 NTSTATUS* nt_status,
177 ULONG* disposition) {
178 // The only action supported is ASK_BROKER which means create the requested
179 // file as specified.
180 if (ASK_BROKER != eval_result) {
181 *nt_status = STATUS_ACCESS_DENIED;
182 return false;
183 }
184
185 // We don't support creating link keys, volatile keys or backup/restore.
186 if (create_options) {
187 *nt_status = STATUS_ACCESS_DENIED;
188 return false;
189 }
190
191 UNICODE_STRING uni_name = {0};
192 OBJECT_ATTRIBUTES obj_attributes = {0};
193 InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
194 &uni_name);
195 *nt_status = NtCreateKeyInTarget(handle, desired_access, &obj_attributes,
196 title_index, NULL, create_options,
197 disposition, client_info.process);
198 return true;
199 }
200
OpenKeyAction(EvalResult eval_result,const ClientInfo & client_info,const base::string16 & key,uint32 attributes,HANDLE root_directory,uint32 desired_access,HANDLE * handle,NTSTATUS * nt_status)201 bool RegistryPolicy::OpenKeyAction(EvalResult eval_result,
202 const ClientInfo& client_info,
203 const base::string16 &key,
204 uint32 attributes,
205 HANDLE root_directory,
206 uint32 desired_access,
207 HANDLE* handle,
208 NTSTATUS* nt_status) {
209 // The only action supported is ASK_BROKER which means open the requested
210 // file as specified.
211 if (ASK_BROKER != eval_result) {
212 *nt_status = STATUS_ACCESS_DENIED;
213 return true;
214 }
215
216 UNICODE_STRING uni_name = {0};
217 OBJECT_ATTRIBUTES obj_attributes = {0};
218 InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
219 &uni_name);
220 *nt_status = NtOpenKeyInTarget(handle, desired_access, &obj_attributes,
221 client_info.process);
222 return true;
223 }
224
225 } // namespace sandbox
226