IDB: Make readonly transactions wait for earlier readwrite transactions
[chromium-blink-merge.git] / sandbox / win / src / registry_policy.cc
blob4c75d23716af37e9700663d8c6106f1dbd4d692f
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.
5 #include <string>
7 #include "sandbox/win/src/registry_policy.h"
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"
17 namespace {
19 static const uint32 kAllowedRegFlags =
20 KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_READ |
21 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
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.
26 NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
27 DWORD* access) {
28 NtOpenKeyFunction NtOpenKey = NULL;
29 ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
31 NtCloseFunction NtClose = NULL;
32 ResolveNTFunctionPtr("NtClose", &NtClose);
34 NtQueryObjectFunction NtQueryObject = NULL;
35 ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
37 // Open the key.
38 HANDLE handle;
39 NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes);
40 if (!NT_SUCCESS(status))
41 return status;
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;
50 *access = info.GrantedAccess & kAllowedRegFlags;
51 return STATUS_SUCCESS;
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);
65 if (MAXIMUM_ALLOWED & desired_access) {
66 NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
67 if (!NT_SUCCESS(status))
68 return STATUS_ACCESS_DENIED;
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;
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;
83 return STATUS_SUCCESS;
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);
93 if (MAXIMUM_ALLOWED & desired_access) {
94 NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
95 if (!NT_SUCCESS(status))
96 return STATUS_ACCESS_DENIED;
99 HANDLE local_handle = INVALID_HANDLE_VALUE;
100 NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes);
102 if (!NT_SUCCESS(status))
103 return status;
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;
110 return STATUS_SUCCESS;
115 namespace sandbox {
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;
125 if (!ResolveRegistryName(resovled_name, &resovled_name))
126 return false;
128 name = resovled_name.c_str();
130 EvalResult result = ASK_BROKER;
132 PolicyRule open(result);
133 PolicyRule create(result);
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 uint32 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;
145 case TargetPolicy::REG_ALLOW_ANY: {
146 break;
148 default: {
149 NOTREACHED();
150 return false;
154 if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
155 !policy->AddRule(IPC_NTCREATEKEY_TAG, &create)) {
156 return false;
159 if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
160 !policy->AddRule(IPC_NTOPENKEY_TAG, &open)) {
161 return false;
164 return true;
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;
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;
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;
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;
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;
225 } // namespace sandbox