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/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"
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
,
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 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
))
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
;
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()) {
125 if (!ResolveRegistryName(resovled_name
, &resovled_name
))
128 name
= resovled_name
.c_str();
130 EvalResult result
= ASK_BROKER
;
132 PolicyRule
open(result
);
133 PolicyRule
create(result
);
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
);
145 case TargetPolicy::REG_ALLOW_ANY
: {
154 if (!create
.AddStringMatch(IF
, OpenKey::NAME
, name
, CASE_INSENSITIVE
) ||
155 !policy
->AddRule(IPC_NTCREATEKEY_TAG
, &create
)) {
159 if (!open
.AddStringMatch(IF
, OpenKey::NAME
, name
, CASE_INSENSITIVE
) ||
160 !policy
->AddRule(IPC_NTOPENKEY_TAG
, &open
)) {
167 bool RegistryPolicy::CreateKeyAction(EvalResult eval_result
,
168 const ClientInfo
& client_info
,
169 const base::string16
&key
,
171 HANDLE root_directory
,
172 uint32 desired_access
,
174 uint32 create_options
,
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
;
185 // We don't support creating link keys, volatile keys or backup/restore.
186 if (create_options
) {
187 *nt_status
= STATUS_ACCESS_DENIED
;
191 UNICODE_STRING uni_name
= {0};
192 OBJECT_ATTRIBUTES obj_attributes
= {0};
193 InitObjectAttribs(key
, attributes
, root_directory
, &obj_attributes
,
195 *nt_status
= NtCreateKeyInTarget(handle
, desired_access
, &obj_attributes
,
196 title_index
, NULL
, create_options
,
197 disposition
, client_info
.process
);
201 bool RegistryPolicy::OpenKeyAction(EvalResult eval_result
,
202 const ClientInfo
& client_info
,
203 const base::string16
&key
,
205 HANDLE root_directory
,
206 uint32 desired_access
,
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
;
216 UNICODE_STRING uni_name
= {0};
217 OBJECT_ATTRIBUTES obj_attributes
= {0};
218 InitObjectAttribs(key
, attributes
, root_directory
, &obj_attributes
,
220 *nt_status
= NtOpenKeyInTarget(handle
, desired_access
, &obj_attributes
,
221 client_info
.process
);
225 } // namespace sandbox