1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/registry_policy.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,225 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include <string> 1.9 + 1.10 +#include "sandbox/win/src/registry_policy.h" 1.11 + 1.12 +#include "base/logging.h" 1.13 +#include "sandbox/win/src/ipc_tags.h" 1.14 +#include "sandbox/win/src/policy_engine_opcodes.h" 1.15 +#include "sandbox/win/src/policy_params.h" 1.16 +#include "sandbox/win/src/sandbox_utils.h" 1.17 +#include "sandbox/win/src/sandbox_types.h" 1.18 +#include "sandbox/win/src/win_utils.h" 1.19 + 1.20 +namespace { 1.21 + 1.22 +static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | 1.23 + KEY_NOTIFY | KEY_READ | GENERIC_READ | 1.24 + GENERIC_EXECUTE | READ_CONTROL; 1.25 + 1.26 +// Opens the key referenced by |obj_attributes| with |access| and 1.27 +// checks what permission was given. Remove the WRITE flags and update 1.28 +// |access| with the new value. 1.29 +NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes, 1.30 + DWORD* access) { 1.31 + NtOpenKeyFunction NtOpenKey = NULL; 1.32 + ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey); 1.33 + 1.34 + NtCloseFunction NtClose = NULL; 1.35 + ResolveNTFunctionPtr("NtClose", &NtClose); 1.36 + 1.37 + NtQueryObjectFunction NtQueryObject = NULL; 1.38 + ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject); 1.39 + 1.40 + // Open the key. 1.41 + HANDLE handle; 1.42 + NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes); 1.43 + if (!NT_SUCCESS(status)) 1.44 + return status; 1.45 + 1.46 + OBJECT_BASIC_INFORMATION info = {0}; 1.47 + status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info), 1.48 + NULL); 1.49 + NtClose(handle); 1.50 + if (!NT_SUCCESS(status)) 1.51 + return status; 1.52 + 1.53 + *access = info.GrantedAccess & kAllowedRegFlags; 1.54 + return STATUS_SUCCESS; 1.55 +} 1.56 + 1.57 +NTSTATUS NtCreateKeyInTarget(HANDLE* target_key_handle, 1.58 + ACCESS_MASK desired_access, 1.59 + OBJECT_ATTRIBUTES* obj_attributes, 1.60 + ULONG title_index, 1.61 + UNICODE_STRING* class_name, 1.62 + ULONG create_options, 1.63 + ULONG* disposition, 1.64 + HANDLE target_process) { 1.65 + NtCreateKeyFunction NtCreateKey = NULL; 1.66 + ResolveNTFunctionPtr("NtCreateKey", &NtCreateKey); 1.67 + 1.68 + if (MAXIMUM_ALLOWED & desired_access) { 1.69 + NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access); 1.70 + if (!NT_SUCCESS(status)) 1.71 + return STATUS_ACCESS_DENIED; 1.72 + } 1.73 + 1.74 + HANDLE local_handle = INVALID_HANDLE_VALUE; 1.75 + NTSTATUS status = NtCreateKey(&local_handle, desired_access, obj_attributes, 1.76 + title_index, class_name, create_options, 1.77 + disposition); 1.78 + if (!NT_SUCCESS(status)) 1.79 + return status; 1.80 + 1.81 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.82 + target_process, target_key_handle, 0, FALSE, 1.83 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.84 + return STATUS_ACCESS_DENIED; 1.85 + } 1.86 + return STATUS_SUCCESS; 1.87 +} 1.88 + 1.89 +NTSTATUS NtOpenKeyInTarget(HANDLE* target_key_handle, 1.90 + ACCESS_MASK desired_access, 1.91 + OBJECT_ATTRIBUTES* obj_attributes, 1.92 + HANDLE target_process) { 1.93 + NtOpenKeyFunction NtOpenKey = NULL; 1.94 + ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey); 1.95 + 1.96 + if (MAXIMUM_ALLOWED & desired_access) { 1.97 + NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access); 1.98 + if (!NT_SUCCESS(status)) 1.99 + return STATUS_ACCESS_DENIED; 1.100 + } 1.101 + 1.102 + HANDLE local_handle = INVALID_HANDLE_VALUE; 1.103 + NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes); 1.104 + 1.105 + if (!NT_SUCCESS(status)) 1.106 + return status; 1.107 + 1.108 + if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 1.109 + target_process, target_key_handle, 0, FALSE, 1.110 + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 1.111 + return STATUS_ACCESS_DENIED; 1.112 + } 1.113 + return STATUS_SUCCESS; 1.114 +} 1.115 + 1.116 +} 1.117 + 1.118 +namespace sandbox { 1.119 + 1.120 +bool RegistryPolicy::GenerateRules(const wchar_t* name, 1.121 + TargetPolicy::Semantics semantics, 1.122 + LowLevelPolicy* policy) { 1.123 + std::wstring resovled_name(name); 1.124 + if (resovled_name.empty()) { 1.125 + return false; 1.126 + } 1.127 + 1.128 + if (!ResolveRegistryName(resovled_name, &resovled_name)) 1.129 + return false; 1.130 + 1.131 + name = resovled_name.c_str(); 1.132 + 1.133 + EvalResult result = ASK_BROKER; 1.134 + 1.135 + PolicyRule open(result); 1.136 + PolicyRule create(result); 1.137 + 1.138 + switch (semantics) { 1.139 + case TargetPolicy::REG_ALLOW_READONLY: { 1.140 + // We consider all flags that are not known to be readonly as potentially 1.141 + // used for write. Here we also support MAXIMUM_ALLOWED, but we are going 1.142 + // to expand it to read-only before the call. 1.143 + DWORD restricted_flags = ~(kAllowedRegFlags | MAXIMUM_ALLOWED); 1.144 + open.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND); 1.145 + create.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND); 1.146 + break; 1.147 + } 1.148 + case TargetPolicy::REG_ALLOW_ANY: { 1.149 + break; 1.150 + } 1.151 + default: { 1.152 + NOTREACHED(); 1.153 + return false; 1.154 + } 1.155 + } 1.156 + 1.157 + if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) || 1.158 + !policy->AddRule(IPC_NTCREATEKEY_TAG, &create)) { 1.159 + return false; 1.160 + } 1.161 + 1.162 + if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) || 1.163 + !policy->AddRule(IPC_NTOPENKEY_TAG, &open)) { 1.164 + return false; 1.165 + } 1.166 + 1.167 + return true; 1.168 +} 1.169 + 1.170 +bool RegistryPolicy::CreateKeyAction(EvalResult eval_result, 1.171 + const ClientInfo& client_info, 1.172 + const std::wstring &key, 1.173 + uint32 attributes, 1.174 + HANDLE root_directory, 1.175 + uint32 desired_access, 1.176 + uint32 title_index, 1.177 + uint32 create_options, 1.178 + HANDLE* handle, 1.179 + NTSTATUS* nt_status, 1.180 + ULONG* disposition) { 1.181 + // The only action supported is ASK_BROKER which means create the requested 1.182 + // file as specified. 1.183 + if (ASK_BROKER != eval_result) { 1.184 + *nt_status = STATUS_ACCESS_DENIED; 1.185 + return false; 1.186 + } 1.187 + 1.188 + // We don't support creating link keys, volatile keys or backup/restore. 1.189 + if (create_options) { 1.190 + *nt_status = STATUS_ACCESS_DENIED; 1.191 + return false; 1.192 + } 1.193 + 1.194 + UNICODE_STRING uni_name = {0}; 1.195 + OBJECT_ATTRIBUTES obj_attributes = {0}; 1.196 + InitObjectAttribs(key, attributes, root_directory, &obj_attributes, 1.197 + &uni_name); 1.198 + *nt_status = NtCreateKeyInTarget(handle, desired_access, &obj_attributes, 1.199 + title_index, NULL, create_options, 1.200 + disposition, client_info.process); 1.201 + return true; 1.202 +} 1.203 + 1.204 +bool RegistryPolicy::OpenKeyAction(EvalResult eval_result, 1.205 + const ClientInfo& client_info, 1.206 + const std::wstring &key, 1.207 + uint32 attributes, 1.208 + HANDLE root_directory, 1.209 + uint32 desired_access, 1.210 + HANDLE* handle, 1.211 + NTSTATUS* nt_status) { 1.212 + // The only action supported is ASK_BROKER which means open the requested 1.213 + // file as specified. 1.214 + if (ASK_BROKER != eval_result) { 1.215 + *nt_status = STATUS_ACCESS_DENIED; 1.216 + return true; 1.217 + } 1.218 + 1.219 + UNICODE_STRING uni_name = {0}; 1.220 + OBJECT_ATTRIBUTES obj_attributes = {0}; 1.221 + InitObjectAttribs(key, attributes, root_directory, &obj_attributes, 1.222 + &uni_name); 1.223 + *nt_status = NtOpenKeyInTarget(handle, desired_access, &obj_attributes, 1.224 + client_info.process); 1.225 + return true; 1.226 +} 1.227 + 1.228 +} // namespace sandbox