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/sync_policy.h" 8 9 #include "base/logging.h" 10 #include "base/strings/stringprintf.h" 11 #include "sandbox/win/src/ipc_tags.h" 12 #include "sandbox/win/src/nt_internals.h" 13 #include "sandbox/win/src/policy_engine_opcodes.h" 14 #include "sandbox/win/src/policy_params.h" 15 #include "sandbox/win/src/sandbox_types.h" 16 #include "sandbox/win/src/sandbox_utils.h" 17 #include "sandbox/win/src/sync_interception.h" 18 #include "sandbox/win/src/win_utils.h" 19 20 namespace sandbox { 21 22 // Provides functionality to resolve a symbolic link within the object 23 // directory passed in. 24 NTSTATUS ResolveSymbolicLink(const base::string16& directory_name, 25 const base::string16& name, 26 base::string16* target) { 27 NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL; 28 ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject); 29 30 NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = NULL; 31 ResolveNTFunctionPtr("NtQuerySymbolicLinkObject", 32 &NtQuerySymbolicLinkObject); 33 34 NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = NULL; 35 ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject); 36 37 NtCloseFunction NtClose = NULL; 38 ResolveNTFunctionPtr("NtClose", &NtClose); 39 40 OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {}; 41 UNICODE_STRING symbolic_link_directory_string = {}; 42 InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, NULL, 43 &symbolic_link_directory_attributes, 44 &symbolic_link_directory_string); 45 46 HANDLE symbolic_link_directory = NULL; 47 NTSTATUS status = NtOpenDirectoryObject(&symbolic_link_directory, 48 DIRECTORY_QUERY, 49 &symbolic_link_directory_attributes); 50 if (status != STATUS_SUCCESS) { 51 DLOG(ERROR) << "Failed to open symbolic link directory. Error: " 52 << status; 53 return status; 54 } 55 56 OBJECT_ATTRIBUTES symbolic_link_attributes = {}; 57 UNICODE_STRING name_string = {}; 58 InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory, 59 &symbolic_link_attributes, &name_string); 60 61 HANDLE symbolic_link = NULL; 62 status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ, 63 &symbolic_link_attributes); 64 NtClose(symbolic_link_directory); 65 if (status != STATUS_SUCCESS) { 66 DLOG(ERROR) << "Failed to open symbolic link Error: " << status; 67 return status; 68 } 69 70 UNICODE_STRING target_path = {}; 71 unsigned long target_length = 0; 72 status = NtQuerySymbolicLinkObject(symbolic_link, &target_path, 73 &target_length); 74 if (status != STATUS_BUFFER_TOO_SMALL) { 75 NtClose(symbolic_link); 76 DLOG(ERROR) << "Failed to get length for symbolic link target. Error: " 77 << status; 78 return status; 79 } 80 81 target_path.Buffer = new wchar_t[target_length + 1]; 82 target_path.Length = 0; 83 target_path.MaximumLength = target_length; 84 status = NtQuerySymbolicLinkObject(symbolic_link, &target_path, 85 &target_length); 86 if (status == STATUS_SUCCESS) { 87 target->assign(target_path.Buffer, target_length); 88 } else { 89 DLOG(ERROR) << "Failed to resolve symbolic link. Error: " << status; 90 } 91 92 NtClose(symbolic_link); 93 delete[] target_path.Buffer; 94 return status; 95 } 96 97 NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) { 98 static HANDLE base_named_objects_handle = NULL; 99 if (base_named_objects_handle) { 100 *directory = base_named_objects_handle; 101 return STATUS_SUCCESS; 102 } 103 104 NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL; 105 ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject); 106 107 DWORD session_id = 0; 108 ProcessIdToSessionId(::GetCurrentProcessId(), &session_id); 109 110 base::string16 base_named_objects_path; 111 112 NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS", 113 base::StringPrintf(L"%d", session_id), 114 &base_named_objects_path); 115 if (status != STATUS_SUCCESS) { 116 DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: " 117 << status; 118 return status; 119 } 120 121 UNICODE_STRING directory_name = {}; 122 OBJECT_ATTRIBUTES object_attributes = {}; 123 InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, NULL, 124 &object_attributes, &directory_name); 125 status = NtOpenDirectoryObject(&base_named_objects_handle, 126 DIRECTORY_ALL_ACCESS, 127 &object_attributes); 128 if (status == STATUS_SUCCESS) 129 *directory = base_named_objects_handle; 130 return status; 131 } 132 133 bool SyncPolicy::GenerateRules(const wchar_t* name, 134 TargetPolicy::Semantics semantics, 135 LowLevelPolicy* policy) { 136 base::string16 mod_name(name); 137 if (mod_name.empty()) { 138 return false; 139 } 140 141 if (TargetPolicy::EVENTS_ALLOW_ANY != semantics && 142 TargetPolicy::EVENTS_ALLOW_READONLY != semantics) { 143 // Other flags are not valid for sync policy yet. 144 NOTREACHED(); 145 return false; 146 } 147 148 // Add the open rule. 149 EvalResult result = ASK_BROKER; 150 PolicyRule open(result); 151 152 if (!open.AddStringMatch(IF, OpenEventParams::NAME, name, CASE_INSENSITIVE)) 153 return false; 154 155 if (TargetPolicy::EVENTS_ALLOW_READONLY == semantics) { 156 // We consider all flags that are not known to be readonly as potentially 157 // used for write. 158 DWORD allowed_flags = SYNCHRONIZE | GENERIC_READ | READ_CONTROL; 159 DWORD restricted_flags = ~allowed_flags; 160 open.AddNumberMatch(IF_NOT, OpenEventParams::ACCESS, restricted_flags, AND); 161 } 162 163 if (!policy->AddRule(IPC_OPENEVENT_TAG, &open)) 164 return false; 165 166 // If it's not a read only, add the create rule. 167 if (TargetPolicy::EVENTS_ALLOW_READONLY != semantics) { 168 PolicyRule create(result); 169 if (!create.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) 170 return false; 171 172 if (!policy->AddRule(IPC_CREATEEVENT_TAG, &create)) 173 return false; 174 } 175 176 return true; 177 } 178 179 DWORD SyncPolicy::CreateEventAction(EvalResult eval_result, 180 const ClientInfo& client_info, 181 const base::string16 &event_name, 182 uint32 event_type, 183 uint32 initial_state, 184 HANDLE *handle) { 185 NtCreateEventFunction NtCreateEvent = NULL; 186 ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent); 187 188 // The only action supported is ASK_BROKER which means create the requested 189 // file as specified. 190 if (ASK_BROKER != eval_result) 191 return false; 192 193 HANDLE object_directory = NULL; 194 NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory); 195 if (status != STATUS_SUCCESS) 196 return status; 197 198 UNICODE_STRING unicode_event_name = {}; 199 OBJECT_ATTRIBUTES object_attributes = {}; 200 InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory, 201 &object_attributes, &unicode_event_name); 202 203 HANDLE local_handle = NULL; 204 status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes, 205 static_cast<EVENT_TYPE>(event_type), initial_state); 206 if (NULL == local_handle) 207 return status; 208 209 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 210 client_info.process, handle, 0, FALSE, 211 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 212 return STATUS_ACCESS_DENIED; 213 } 214 return status; 215 } 216 217 DWORD SyncPolicy::OpenEventAction(EvalResult eval_result, 218 const ClientInfo& client_info, 219 const base::string16 &event_name, 220 uint32 desired_access, 221 HANDLE *handle) { 222 NtOpenEventFunction NtOpenEvent = NULL; 223 ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent); 224 225 // The only action supported is ASK_BROKER which means create the requested 226 // event as specified. 227 if (ASK_BROKER != eval_result) 228 return false; 229 230 HANDLE object_directory = NULL; 231 NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory); 232 if (status != STATUS_SUCCESS) 233 return status; 234 235 UNICODE_STRING unicode_event_name = {}; 236 OBJECT_ATTRIBUTES object_attributes = {}; 237 InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory, 238 &object_attributes, &unicode_event_name); 239 240 HANDLE local_handle = NULL; 241 status = NtOpenEvent(&local_handle, desired_access, &object_attributes); 242 if (NULL == local_handle) 243 return status; 244 245 if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, 246 client_info.process, handle, 0, FALSE, 247 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { 248 return STATUS_ACCESS_DENIED; 249 } 250 return status; 251 } 252 253 } // namespace sandbox 254