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 "sandbox/win/src/filesystem_interception.h" 6 7 #include "sandbox/win/src/crosscall_client.h" 8 #include "sandbox/win/src/ipc_tags.h" 9 #include "sandbox/win/src/policy_params.h" 10 #include "sandbox/win/src/policy_target.h" 11 #include "sandbox/win/src/sandbox_factory.h" 12 #include "sandbox/win/src/sandbox_nt_util.h" 13 #include "sandbox/win/src/sharedmem_ipc_client.h" 14 #include "sandbox/win/src/target_services.h" 15 16 namespace sandbox { 17 18 NTSTATUS WINAPI TargetNtCreateFile(NtCreateFileFunction orig_CreateFile, 19 PHANDLE file, ACCESS_MASK desired_access, 20 POBJECT_ATTRIBUTES object_attributes, 21 PIO_STATUS_BLOCK io_status, 22 PLARGE_INTEGER allocation_size, 23 ULONG file_attributes, ULONG sharing, 24 ULONG disposition, ULONG options, 25 PVOID ea_buffer, ULONG ea_length) { 26 // Check if the process can open it first. 27 NTSTATUS status = orig_CreateFile(file, desired_access, object_attributes, 28 io_status, allocation_size, 29 file_attributes, sharing, disposition, 30 options, ea_buffer, ea_length); 31 if (STATUS_ACCESS_DENIED != status) 32 return status; 33 34 // We don't trust that the IPC can work this early. 35 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) 36 return status; 37 38 do { 39 if (!ValidParameter(file, sizeof(HANDLE), WRITE)) 40 break; 41 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) 42 break; 43 44 void* memory = GetGlobalIPCMemory(); 45 if (NULL == memory) 46 break; 47 48 wchar_t* name; 49 uint32 attributes = 0; 50 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, 51 NULL); 52 if (!NT_SUCCESS(ret) || NULL == name) 53 break; 54 55 ULONG broker = FALSE; 56 CountedParameterSet<OpenFile> params; 57 params[OpenFile::NAME] = ParamPickerMake(name); 58 params[OpenFile::ACCESS] = ParamPickerMake(desired_access); 59 params[OpenFile::OPTIONS] = ParamPickerMake(options); 60 params[OpenFile::BROKER] = ParamPickerMake(broker); 61 62 if (!QueryBroker(IPC_NTCREATEFILE_TAG, params.GetBase())) 63 break; 64 65 SharedMemIPCClient ipc(memory); 66 CrossCallReturn answer = {0}; 67 // The following call must match in the parameters with 68 // FilesystemDispatcher::ProcessNtCreateFile. 69 ResultCode code = CrossCall(ipc, IPC_NTCREATEFILE_TAG, name, attributes, 70 desired_access, file_attributes, sharing, 71 disposition, options, &answer); 72 73 operator delete(name, NT_ALLOC); 74 75 if (SBOX_ALL_OK != code) 76 break; 77 78 if (!NT_SUCCESS(answer.nt_status)) 79 return answer.nt_status; 80 81 __try { 82 *file = answer.handle; 83 io_status->Status = answer.nt_status; 84 io_status->Information = answer.extended[0].ulong_ptr; 85 status = io_status->Status; 86 } __except(EXCEPTION_EXECUTE_HANDLER) { 87 break; 88 } 89 } while (false); 90 91 return status; 92 } 93 94 NTSTATUS WINAPI TargetNtOpenFile(NtOpenFileFunction orig_OpenFile, PHANDLE file, 95 ACCESS_MASK desired_access, 96 POBJECT_ATTRIBUTES object_attributes, 97 PIO_STATUS_BLOCK io_status, ULONG sharing, 98 ULONG options) { 99 // Check if the process can open it first. 100 NTSTATUS status = orig_OpenFile(file, desired_access, object_attributes, 101 io_status, sharing, options); 102 if (STATUS_ACCESS_DENIED != status) 103 return status; 104 105 // We don't trust that the IPC can work this early. 106 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) 107 return status; 108 109 do { 110 if (!ValidParameter(file, sizeof(HANDLE), WRITE)) 111 break; 112 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) 113 break; 114 115 void* memory = GetGlobalIPCMemory(); 116 if (NULL == memory) 117 break; 118 119 wchar_t* name; 120 uint32 attributes; 121 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, 122 NULL); 123 if (!NT_SUCCESS(ret) || NULL == name) 124 break; 125 126 ULONG broker = FALSE; 127 CountedParameterSet<OpenFile> params; 128 params[OpenFile::NAME] = ParamPickerMake(name); 129 params[OpenFile::ACCESS] = ParamPickerMake(desired_access); 130 params[OpenFile::OPTIONS] = ParamPickerMake(options); 131 params[OpenFile::BROKER] = ParamPickerMake(broker); 132 133 if (!QueryBroker(IPC_NTOPENFILE_TAG, params.GetBase())) 134 break; 135 136 SharedMemIPCClient ipc(memory); 137 CrossCallReturn answer = {0}; 138 ResultCode code = CrossCall(ipc, IPC_NTOPENFILE_TAG, name, attributes, 139 desired_access, sharing, options, &answer); 140 141 operator delete(name, NT_ALLOC); 142 143 if (SBOX_ALL_OK != code) 144 break; 145 146 if (!NT_SUCCESS(answer.nt_status)) 147 return answer.nt_status; 148 149 __try { 150 *file = answer.handle; 151 io_status->Status = answer.nt_status; 152 io_status->Information = answer.extended[0].ulong_ptr; 153 status = io_status->Status; 154 } __except(EXCEPTION_EXECUTE_HANDLER) { 155 break; 156 } 157 } while (false); 158 159 return status; 160 } 161 162 NTSTATUS WINAPI TargetNtQueryAttributesFile( 163 NtQueryAttributesFileFunction orig_QueryAttributes, 164 POBJECT_ATTRIBUTES object_attributes, 165 PFILE_BASIC_INFORMATION file_attributes) { 166 // Check if the process can query it first. 167 NTSTATUS status = orig_QueryAttributes(object_attributes, file_attributes); 168 if (STATUS_ACCESS_DENIED != status) 169 return status; 170 171 // We don't trust that the IPC can work this early. 172 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) 173 return status; 174 175 do { 176 if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE)) 177 break; 178 179 void* memory = GetGlobalIPCMemory(); 180 if (NULL == memory) 181 break; 182 183 wchar_t* name = NULL; 184 uint32 attributes = 0; 185 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, 186 NULL); 187 if (!NT_SUCCESS(ret) || NULL == name) 188 break; 189 190 InOutCountedBuffer file_info(file_attributes, 191 sizeof(FILE_BASIC_INFORMATION)); 192 193 ULONG broker = FALSE; 194 CountedParameterSet<FileName> params; 195 params[FileName::NAME] = ParamPickerMake(name); 196 params[FileName::BROKER] = ParamPickerMake(broker); 197 198 if (!QueryBroker(IPC_NTQUERYATTRIBUTESFILE_TAG, params.GetBase())) 199 break; 200 201 SharedMemIPCClient ipc(memory); 202 CrossCallReturn answer = {0}; 203 ResultCode code = CrossCall(ipc, IPC_NTQUERYATTRIBUTESFILE_TAG, name, 204 attributes, file_info, &answer); 205 206 operator delete(name, NT_ALLOC); 207 208 if (SBOX_ALL_OK != code) 209 break; 210 211 return answer.nt_status; 212 213 } while (false); 214 215 return status; 216 } 217 218 NTSTATUS WINAPI TargetNtQueryFullAttributesFile( 219 NtQueryFullAttributesFileFunction orig_QueryFullAttributes, 220 POBJECT_ATTRIBUTES object_attributes, 221 PFILE_NETWORK_OPEN_INFORMATION file_attributes) { 222 // Check if the process can query it first. 223 NTSTATUS status = orig_QueryFullAttributes(object_attributes, 224 file_attributes); 225 if (STATUS_ACCESS_DENIED != status) 226 return status; 227 228 // We don't trust that the IPC can work this early. 229 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) 230 return status; 231 232 do { 233 if (!ValidParameter(file_attributes, sizeof(FILE_NETWORK_OPEN_INFORMATION), 234 WRITE)) 235 break; 236 237 void* memory = GetGlobalIPCMemory(); 238 if (NULL == memory) 239 break; 240 241 wchar_t* name = NULL; 242 uint32 attributes = 0; 243 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, 244 NULL); 245 if (!NT_SUCCESS(ret) || NULL == name) 246 break; 247 248 InOutCountedBuffer file_info(file_attributes, 249 sizeof(FILE_NETWORK_OPEN_INFORMATION)); 250 251 ULONG broker = FALSE; 252 CountedParameterSet<FileName> params; 253 params[FileName::NAME] = ParamPickerMake(name); 254 params[FileName::BROKER] = ParamPickerMake(broker); 255 256 if (!QueryBroker(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase())) 257 break; 258 259 SharedMemIPCClient ipc(memory); 260 CrossCallReturn answer = {0}; 261 ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG, name, 262 attributes, file_info, &answer); 263 264 operator delete(name, NT_ALLOC); 265 266 if (SBOX_ALL_OK != code) 267 break; 268 269 return answer.nt_status; 270 } while (false); 271 272 return status; 273 } 274 275 NTSTATUS WINAPI TargetNtSetInformationFile( 276 NtSetInformationFileFunction orig_SetInformationFile, HANDLE file, 277 PIO_STATUS_BLOCK io_status, PVOID file_info, ULONG length, 278 FILE_INFORMATION_CLASS file_info_class) { 279 // Check if the process can open it first. 280 NTSTATUS status = orig_SetInformationFile(file, io_status, file_info, length, 281 file_info_class); 282 if (STATUS_ACCESS_DENIED != status) 283 return status; 284 285 // We don't trust that the IPC can work this early. 286 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) 287 return status; 288 289 do { 290 void* memory = GetGlobalIPCMemory(); 291 if (NULL == memory) 292 break; 293 294 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) 295 break; 296 297 if (!ValidParameter(file_info, length, READ)) 298 break; 299 300 FILE_RENAME_INFORMATION* file_rename_info = 301 reinterpret_cast<FILE_RENAME_INFORMATION*>(file_info); 302 OBJECT_ATTRIBUTES object_attributes; 303 UNICODE_STRING object_name; 304 InitializeObjectAttributes(&object_attributes, &object_name, 0, NULL, NULL); 305 306 __try { 307 if (!IsSupportedRenameCall(file_rename_info, length, file_info_class)) 308 break; 309 310 object_attributes.RootDirectory = file_rename_info->RootDirectory; 311 object_name.Buffer = file_rename_info->FileName; 312 object_name.Length = object_name.MaximumLength = 313 static_cast<USHORT>(file_rename_info->FileNameLength); 314 } __except(EXCEPTION_EXECUTE_HANDLER) { 315 break; 316 } 317 318 wchar_t* name; 319 NTSTATUS ret = AllocAndCopyName(&object_attributes, &name, NULL, NULL); 320 if (!NT_SUCCESS(ret) || !name) 321 break; 322 323 ULONG broker = FALSE; 324 CountedParameterSet<FileName> params; 325 params[FileName::NAME] = ParamPickerMake(name); 326 params[FileName::BROKER] = ParamPickerMake(broker); 327 328 if (!QueryBroker(IPC_NTSETINFO_RENAME_TAG, params.GetBase())) 329 break; 330 331 InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK)); 332 // This is actually not an InOut buffer, only In, but using InOut facility 333 // really helps to simplify the code. 334 InOutCountedBuffer file_info_buffer(file_info, length); 335 336 SharedMemIPCClient ipc(memory); 337 CrossCallReturn answer = {0}; 338 ResultCode code = CrossCall(ipc, IPC_NTSETINFO_RENAME_TAG, file, 339 io_status_buffer, file_info_buffer, length, 340 file_info_class, &answer); 341 342 if (SBOX_ALL_OK != code) 343 break; 344 345 status = answer.nt_status; 346 } while (false); 347 348 return status; 349 } 350 351 } // namespace sandbox 352