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. 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 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 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 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 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 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