• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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