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.
7 #include "sandbox/src/registry_policy.h"
9 #include "base/logging.h"
10 #include "sandbox/src/ipc_tags.h"
11 #include "sandbox/src/policy_engine_opcodes.h"
12 #include "sandbox/src/policy_params.h"
13 #include "sandbox/src/sandbox_utils.h"
14 #include "sandbox/src/sandbox_types.h"
15 #include "sandbox/src/win_utils.h"
19 static const DWORD kAllowedRegFlags
= KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
|
20 KEY_NOTIFY
| KEY_READ
| GENERIC_READ
|
21 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
,
28 NtOpenKeyFunction NtOpenKey
= NULL
;
29 ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey
);
31 NtCloseFunction NtClose
= NULL
;
32 ResolveNTFunctionPtr("NtClose", &NtClose
);
34 NtQueryObjectFunction NtQueryObject
= NULL
;
35 ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject
);
39 NTSTATUS status
= NtOpenKey(&handle
, *access
, obj_attributes
);
40 if (!NT_SUCCESS(status
))
43 OBJECT_BASIC_INFORMATION info
= {0};
44 status
= NtQueryObject(handle
, ObjectBasicInformation
, &info
, sizeof(info
),
47 if (!NT_SUCCESS(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
,
58 UNICODE_STRING
* class_name
,
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
,
75 if (!NT_SUCCESS(status
))
78 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle
,
79 target_process
, target_key_handle
, 0, FALSE
,
80 DUPLICATE_CLOSE_SOURCE
| DUPLICATE_SAME_ACCESS
)) {
81 ::CloseHandle(local_handle
);
82 return STATUS_ACCESS_DENIED
;
84 return STATUS_SUCCESS
;
87 NTSTATUS
NtOpenKeyInTarget(HANDLE
* target_key_handle
,
88 ACCESS_MASK desired_access
,
89 OBJECT_ATTRIBUTES
* obj_attributes
,
90 HANDLE target_process
) {
91 NtOpenKeyFunction NtOpenKey
= NULL
;
92 ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey
);
94 if (MAXIMUM_ALLOWED
& desired_access
) {
95 NTSTATUS status
= TranslateMaximumAllowed(obj_attributes
, &desired_access
);
96 if (!NT_SUCCESS(status
))
97 return STATUS_ACCESS_DENIED
;
100 HANDLE local_handle
= INVALID_HANDLE_VALUE
;
101 NTSTATUS status
= NtOpenKey(&local_handle
, desired_access
, obj_attributes
);
103 if (!NT_SUCCESS(status
))
106 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle
,
107 target_process
, target_key_handle
, 0, FALSE
,
108 DUPLICATE_CLOSE_SOURCE
| DUPLICATE_SAME_ACCESS
)) {
109 ::CloseHandle(local_handle
);
110 return STATUS_ACCESS_DENIED
;
112 return STATUS_SUCCESS
;
119 bool RegistryPolicy::GenerateRules(const wchar_t* name
,
120 TargetPolicy::Semantics semantics
,
121 LowLevelPolicy
* policy
) {
122 std::wstring
resovled_name(name
);
123 if (resovled_name
.empty()) {
127 if (!ResolveRegistryName(resovled_name
, &resovled_name
))
130 name
= resovled_name
.c_str();
132 EvalResult result
= ASK_BROKER
;
134 PolicyRule
open(result
);
135 PolicyRule
create(result
);
138 case TargetPolicy::REG_ALLOW_READONLY
: {
139 // We consider all flags that are not known to be readonly as potentially
140 // used for write. Here we also support MAXIMUM_ALLOWED, but we are going
141 // to expand it to read-only before the call.
142 DWORD restricted_flags
= ~(kAllowedRegFlags
| MAXIMUM_ALLOWED
);
143 open
.AddNumberMatch(IF_NOT
, OpenKey::ACCESS
, restricted_flags
, AND
);
144 create
.AddNumberMatch(IF_NOT
, OpenKey::ACCESS
, restricted_flags
, AND
);
147 case TargetPolicy::REG_ALLOW_ANY
: {
156 if (!create
.AddStringMatch(IF
, OpenKey::NAME
, name
, CASE_INSENSITIVE
) ||
157 !policy
->AddRule(IPC_NTCREATEKEY_TAG
, &create
)) {
161 if (!open
.AddStringMatch(IF
, OpenKey::NAME
, name
, CASE_INSENSITIVE
) ||
162 !policy
->AddRule(IPC_NTOPENKEY_TAG
, &open
)) {
169 bool RegistryPolicy::CreateKeyAction(EvalResult eval_result
,
170 const ClientInfo
& client_info
,
171 const std::wstring
&key
,
173 HANDLE root_directory
,
174 uint32 desired_access
,
176 uint32 create_options
,
179 ULONG
* disposition
) {
180 // The only action supported is ASK_BROKER which means create the requested
181 // file as specified.
182 if (ASK_BROKER
!= eval_result
) {
183 *nt_status
= STATUS_ACCESS_DENIED
;
187 // We don't support creating link keys, volatile keys or backup/restore.
188 if (create_options
) {
189 *nt_status
= STATUS_ACCESS_DENIED
;
193 UNICODE_STRING uni_name
= {0};
194 OBJECT_ATTRIBUTES obj_attributes
= {0};
195 InitObjectAttribs(key
, attributes
, root_directory
, &obj_attributes
,
197 *nt_status
= NtCreateKeyInTarget(handle
, desired_access
, &obj_attributes
,
198 title_index
, NULL
, create_options
,
199 disposition
, client_info
.process
);
203 bool RegistryPolicy::OpenKeyAction(EvalResult eval_result
,
204 const ClientInfo
& client_info
,
205 const std::wstring
&key
,
207 HANDLE root_directory
,
208 uint32 desired_access
,
210 NTSTATUS
* nt_status
) {
211 // The only action supported is ASK_BROKER which means open the requested
212 // file as specified.
213 if (ASK_BROKER
!= eval_result
) {
214 *nt_status
= STATUS_ACCESS_DENIED
;
218 UNICODE_STRING uni_name
= {0};
219 OBJECT_ATTRIBUTES obj_attributes
= {0};
220 InitObjectAttribs(key
, attributes
, root_directory
, &obj_attributes
,
222 *nt_status
= NtOpenKeyInTarget(handle
, desired_access
, &obj_attributes
,
223 client_info
.process
);
227 } // namespace sandbox