OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/win/src/process_mitigations_win32k_interception.h" | 5 #include "sandbox/win/src/process_mitigations_win32k_interception.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/win/scoped_handle.h" |
| 10 #include "sandbox/win/src/crosscall_client.h" |
| 11 #include "sandbox/win/src/ipc_tags.h" |
| 12 #include "sandbox/win/src/policy_params.h" |
| 13 #include "sandbox/win/src/policy_target.h" |
| 14 #include "sandbox/win/src/sandbox_factory.h" |
| 15 #include "sandbox/win/src/sandbox_nt_util.h" |
| 16 #include "sandbox/win/src/sharedmem_ipc_client.h" |
| 17 #include "sandbox/win/src/target_services.h" |
| 18 |
7 namespace sandbox { | 19 namespace sandbox { |
8 | 20 |
| 21 namespace { |
| 22 |
| 23 // Implement a simple shared memory class as we can't use the base one. |
| 24 class ScopedSharedMemory { |
| 25 public: |
| 26 ScopedSharedMemory(uint32_t size) : memory_(nullptr) { |
| 27 handle_.Set(::CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, |
| 28 PAGE_READWRITE | SEC_COMMIT, 0, size, |
| 29 nullptr)); |
| 30 if (handle_.IsValid()) { |
| 31 memory_ = ::MapViewOfFile(handle_.Get(), FILE_MAP_READ | FILE_MAP_WRITE, |
| 32 0, 0, size); |
| 33 } |
| 34 } |
| 35 ~ScopedSharedMemory() { |
| 36 if (memory_) |
| 37 ::UnmapViewOfFile(memory_); |
| 38 } |
| 39 |
| 40 void* handle() { return handle_.Get(); } |
| 41 void* memory() { return memory_; } |
| 42 bool IsValid() { return handle_.IsValid(); } |
| 43 |
| 44 private: |
| 45 base::win::ScopedHandle handle_; |
| 46 void* memory_; |
| 47 }; |
| 48 |
| 49 void UnicodeStringToString(PUNICODE_STRING unicode_string, |
| 50 base::string16* result) { |
| 51 *result = base::string16( |
| 52 unicode_string->Buffer, |
| 53 unicode_string->Buffer + (unicode_string->Length / sizeof(WCHAR))); |
| 54 } |
| 55 |
| 56 } // namespace |
| 57 |
9 BOOL WINAPI TargetGdiDllInitialize( | 58 BOOL WINAPI TargetGdiDllInitialize( |
10 GdiDllInitializeFunction orig_gdi_dll_initialize, | 59 GdiDllInitializeFunction orig_gdi_dll_initialize, |
11 HANDLE dll, | 60 HANDLE dll, |
12 DWORD reason) { | 61 DWORD reason) { |
13 return TRUE; | 62 return TRUE; |
14 } | 63 } |
15 | 64 |
16 HGDIOBJ WINAPI TargetGetStockObject( | 65 HGDIOBJ WINAPI TargetGetStockObject( |
17 GetStockObjectFunction orig_get_stock_object, | 66 GetStockObjectFunction orig_get_stock_object, |
18 int object) { | 67 int object) { |
19 return reinterpret_cast<HGDIOBJ>(NULL); | 68 return reinterpret_cast<HGDIOBJ>(NULL); |
20 } | 69 } |
21 | 70 |
22 ATOM WINAPI TargetRegisterClassW( | 71 ATOM WINAPI TargetRegisterClassW( |
23 RegisterClassWFunction orig_register_class_function, | 72 RegisterClassWFunction orig_register_class_function, |
24 const WNDCLASS* wnd_class) { | 73 const WNDCLASS* wnd_class) { |
25 return TRUE; | 74 return TRUE; |
26 } | 75 } |
27 | 76 |
| 77 BOOL WINAPI TargetEnumDisplayMonitors(EnumDisplayMonitorsFunction, |
| 78 HDC hdc, |
| 79 LPCRECT lprcClip, |
| 80 MONITORENUMPROC lpfnEnum, |
| 81 LPARAM dwData) { |
| 82 if (!lpfnEnum || hdc || lprcClip) { |
| 83 return FALSE; |
| 84 } |
| 85 |
| 86 // We don't trust that the IPC can work this early. |
| 87 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 88 return FALSE; |
| 89 |
| 90 void* ipc_memory = GetGlobalIPCMemory(); |
| 91 if (ipc_memory == NULL) |
| 92 return FALSE; |
| 93 |
| 94 CrossCallReturn answer = {0}; |
| 95 answer.nt_status = 0; |
| 96 EnumMonitorsResult result = {}; |
| 97 InOutCountedBuffer result_buffer(&result, sizeof(EnumMonitorsResult)); |
| 98 SharedMemIPCClient ipc(ipc_memory); |
| 99 ResultCode code = |
| 100 CrossCall(ipc, IPC_USER_ENUMDISPLAYMONITORS_TAG, result_buffer, &answer); |
| 101 |
| 102 if (code != SBOX_ALL_OK) { |
| 103 return FALSE; |
| 104 } |
| 105 |
| 106 if (answer.win32_result) { |
| 107 return FALSE; |
| 108 } |
| 109 |
| 110 if (result.monitor_count > kMaxEnumMonitors) { |
| 111 return FALSE; |
| 112 } |
| 113 |
| 114 for (uint32_t monitor_pos = 0; monitor_pos < result.monitor_count; |
| 115 ++monitor_pos) { |
| 116 BOOL continue_enum = |
| 117 lpfnEnum(result.monitors[monitor_pos], nullptr, nullptr, dwData); |
| 118 if (!continue_enum) |
| 119 return FALSE; |
| 120 } |
| 121 |
| 122 return TRUE; |
| 123 } |
| 124 |
| 125 BOOL WINAPI TargetEnumDisplayDevicesA(EnumDisplayDevicesAFunction, |
| 126 LPCSTR lpDevice, |
| 127 DWORD iDevNum, |
| 128 PDISPLAY_DEVICEA lpDisplayDevice, |
| 129 DWORD dwFlags) { |
| 130 return FALSE; |
| 131 } |
| 132 |
| 133 static BOOL CallMonitorInfo(HMONITOR monitor, LPMONITORINFO monitor_info_ptr) { |
| 134 // We don't trust that the IPC can work this early. |
| 135 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 136 return FALSE; |
| 137 |
| 138 void* ipc_memory = GetGlobalIPCMemory(); |
| 139 if (ipc_memory == NULL) |
| 140 return FALSE; |
| 141 |
| 142 CrossCallReturn answer = {}; |
| 143 SharedMemIPCClient ipc(ipc_memory); |
| 144 InOutCountedBuffer buffer(monitor_info_ptr, monitor_info_ptr->cbSize); |
| 145 ResultCode code = CrossCall(ipc, IPC_USER_GETMONITORINFO_TAG, |
| 146 static_cast<void*>(monitor), buffer, &answer); |
| 147 |
| 148 if (code != SBOX_ALL_OK) { |
| 149 return FALSE; |
| 150 } |
| 151 |
| 152 if (answer.win32_result != ERROR_SUCCESS) |
| 153 return FALSE; |
| 154 |
| 155 return TRUE; |
| 156 } |
| 157 |
| 158 BOOL WINAPI TargetGetMonitorInfoA(GetMonitorInfoFunction, |
| 159 HMONITOR monitor, |
| 160 LPMONITORINFO monitor_info_ptr) { |
| 161 if (!monitor_info_ptr || |
| 162 (monitor_info_ptr->cbSize != sizeof(MONITORINFO) && |
| 163 monitor_info_ptr->cbSize != sizeof(MONITORINFOEXA))) { |
| 164 return FALSE; |
| 165 } |
| 166 return CallMonitorInfo(monitor, monitor_info_ptr); |
| 167 } |
| 168 |
| 169 BOOL WINAPI TargetGetMonitorInfoW(GetMonitorInfoFunction, |
| 170 HMONITOR monitor, |
| 171 LPMONITORINFO monitor_info_ptr) { |
| 172 if (!monitor_info_ptr || |
| 173 (monitor_info_ptr->cbSize != sizeof(MONITORINFO) && |
| 174 monitor_info_ptr->cbSize != sizeof(MONITORINFOEXW))) { |
| 175 return FALSE; |
| 176 } |
| 177 return CallMonitorInfo(monitor, monitor_info_ptr); |
| 178 } |
| 179 |
| 180 NTSTATUS WINAPI TargetGetCertificate(GetCertificateFunction, |
| 181 PUNICODE_STRING device_name, |
| 182 DXGKMDT_CERTIFICATE_TYPE certificate_type, |
| 183 BYTE* certificate, |
| 184 ULONG certificate_size) { |
| 185 // Don't support arbitrarily large certificate buffers. |
| 186 if (certificate_size > kProtectedVideoOutputSectionSize) |
| 187 return STATUS_INVALID_PARAMETER; |
| 188 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) |
| 189 return STATUS_INVALID_PARAMETER; |
| 190 |
| 191 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 192 return STATUS_ACCESS_DENIED; |
| 193 void* ipc_memory = GetGlobalIPCMemory(); |
| 194 if (ipc_memory == NULL) |
| 195 return STATUS_ACCESS_DENIED; |
| 196 |
| 197 ScopedSharedMemory buffer(sizeof(certificate_size)); |
| 198 if (!buffer.IsValid()) |
| 199 return STATUS_INVALID_PARAMETER; |
| 200 base::string16 device_name_str; |
| 201 UnicodeStringToString(device_name, &device_name_str); |
| 202 CrossCallReturn answer = {}; |
| 203 SharedMemIPCClient ipc(ipc_memory); |
| 204 ResultCode code = CrossCall(ipc, IPC_GDI_GETCERTIFICATE_TAG, |
| 205 device_name_str.c_str(), buffer.handle(), |
| 206 static_cast<uint32_t>(certificate_size), &answer); |
| 207 |
| 208 if (code != SBOX_ALL_OK) { |
| 209 return STATUS_ACCESS_DENIED; |
| 210 } |
| 211 |
| 212 if (!answer.nt_status) |
| 213 memcpy(certificate, buffer.memory(), certificate_size); |
| 214 |
| 215 return answer.nt_status; |
| 216 } |
| 217 |
| 218 NTSTATUS WINAPI |
| 219 TargetGetCertificateSize(GetCertificateSizeFunction, |
| 220 PUNICODE_STRING device_name, |
| 221 DXGKMDT_CERTIFICATE_TYPE certificate_type, |
| 222 ULONG* certificate_length) { |
| 223 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) |
| 224 return STATUS_INVALID_PARAMETER; |
| 225 |
| 226 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 227 return STATUS_ACCESS_DENIED; |
| 228 void* ipc_memory = GetGlobalIPCMemory(); |
| 229 if (ipc_memory == NULL) |
| 230 return STATUS_ACCESS_DENIED; |
| 231 |
| 232 CrossCallReturn answer = {}; |
| 233 SharedMemIPCClient ipc(ipc_memory); |
| 234 base::string16 device_name_str; |
| 235 UnicodeStringToString(device_name, &device_name_str); |
| 236 ResultCode code = CrossCall(ipc, IPC_GDI_GETCERTIFICATESIZE_TAG, |
| 237 device_name_str.c_str(), &answer); |
| 238 |
| 239 if (code != SBOX_ALL_OK) { |
| 240 return STATUS_ACCESS_DENIED; |
| 241 } |
| 242 |
| 243 if (!answer.nt_status) |
| 244 *certificate_length = answer.extended[0].unsigned_int; |
| 245 |
| 246 return answer.nt_status; |
| 247 } |
| 248 |
| 249 NTSTATUS WINAPI |
| 250 TargetDestroyOPMProtectedOutput(DestroyOPMProtectedOutputFunction, |
| 251 OPM_PROTECTED_OUTPUT_HANDLE protected_output) { |
| 252 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 253 return STATUS_ACCESS_DENIED; |
| 254 void* ipc_memory = GetGlobalIPCMemory(); |
| 255 if (ipc_memory == NULL) |
| 256 return STATUS_ACCESS_DENIED; |
| 257 |
| 258 CrossCallReturn answer = {}; |
| 259 SharedMemIPCClient ipc(ipc_memory); |
| 260 ResultCode code = CrossCall(ipc, IPC_GDI_DESTROYOPMPROTECTEDOUTPUT_TAG, |
| 261 static_cast<void*>(protected_output), &answer); |
| 262 |
| 263 if (code != SBOX_ALL_OK) { |
| 264 return STATUS_ACCESS_DENIED; |
| 265 } |
| 266 |
| 267 return answer.nt_status; |
| 268 } |
| 269 |
| 270 NTSTATUS WINAPI TargetConfigureOPMProtectedOutput( |
| 271 ConfigureOPMProtectedOutputFunction, |
| 272 OPM_PROTECTED_OUTPUT_HANDLE protected_output, |
| 273 const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters, |
| 274 ULONG additional_parameters_size, |
| 275 const BYTE* additional_parameters) { |
| 276 // Don't support additional parameters. |
| 277 if (additional_parameters_size > 0) |
| 278 return STATUS_INVALID_PARAMETER; |
| 279 |
| 280 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 281 return STATUS_ACCESS_DENIED; |
| 282 void* ipc_memory = GetGlobalIPCMemory(); |
| 283 if (ipc_memory == NULL) |
| 284 return STATUS_ACCESS_DENIED; |
| 285 |
| 286 ScopedSharedMemory buffer(sizeof(DXGKMDT_OPM_CONFIGURE_PARAMETERS)); |
| 287 if (!buffer.IsValid()) |
| 288 return STATUS_INVALID_PARAMETER; |
| 289 memcpy(buffer.memory(), parameters, sizeof(DXGKMDT_OPM_CONFIGURE_PARAMETERS)); |
| 290 CrossCallReturn answer = {}; |
| 291 SharedMemIPCClient ipc(ipc_memory); |
| 292 ResultCode code = |
| 293 CrossCall(ipc, IPC_GDI_CONFIGUREOPMPROTECTEDOUTPUT_TAG, |
| 294 static_cast<void*>(protected_output), buffer.handle(), &answer); |
| 295 |
| 296 if (code != SBOX_ALL_OK) { |
| 297 return STATUS_ACCESS_DENIED; |
| 298 } |
| 299 |
| 300 return answer.nt_status; |
| 301 } |
| 302 |
| 303 NTSTATUS WINAPI TargetGetOPMInformation( |
| 304 GetOPMInformationFunction, |
| 305 OPM_PROTECTED_OUTPUT_HANDLE protected_output, |
| 306 const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters, |
| 307 DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information) { |
| 308 size_t max_size = std::max(sizeof(DXGKMDT_OPM_GET_INFO_PARAMETERS), |
| 309 sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION)); |
| 310 |
| 311 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 312 return STATUS_ACCESS_DENIED; |
| 313 void* ipc_memory = GetGlobalIPCMemory(); |
| 314 if (ipc_memory == NULL) |
| 315 return STATUS_ACCESS_DENIED; |
| 316 |
| 317 ScopedSharedMemory buffer(static_cast<uint32_t>(max_size)); |
| 318 if (!buffer.IsValid()) |
| 319 return STATUS_INVALID_PARAMETER; |
| 320 memcpy(buffer.memory(), parameters, sizeof(DXGKMDT_OPM_GET_INFO_PARAMETERS)); |
| 321 CrossCallReturn answer = {}; |
| 322 SharedMemIPCClient ipc(ipc_memory); |
| 323 ResultCode code = |
| 324 CrossCall(ipc, IPC_GDI_GETOPMINFORMATION_TAG, |
| 325 static_cast<void*>(protected_output), buffer.handle(), &answer); |
| 326 |
| 327 if (code != SBOX_ALL_OK) { |
| 328 return STATUS_ACCESS_DENIED; |
| 329 } |
| 330 if (!answer.nt_status) |
| 331 memcpy(requested_information, buffer.memory(), |
| 332 sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION)); |
| 333 |
| 334 return answer.nt_status; |
| 335 } |
| 336 |
| 337 NTSTATUS WINAPI |
| 338 TargetGetOPMRandomNumber(GetOPMRandomNumberFunction, |
| 339 OPM_PROTECTED_OUTPUT_HANDLE protected_output, |
| 340 DXGKMDT_OPM_RANDOM_NUMBER* random_number) { |
| 341 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 342 return STATUS_ACCESS_DENIED; |
| 343 void* ipc_memory = GetGlobalIPCMemory(); |
| 344 if (ipc_memory == NULL) |
| 345 return STATUS_ACCESS_DENIED; |
| 346 |
| 347 CrossCallReturn answer = {}; |
| 348 SharedMemIPCClient ipc(ipc_memory); |
| 349 InOutCountedBuffer buffer(random_number, sizeof(DXGKMDT_OPM_RANDOM_NUMBER)); |
| 350 ResultCode code = |
| 351 CrossCall(ipc, IPC_GDI_GETOPMRANDOMNUMBER_TAG, |
| 352 static_cast<void*>(protected_output), buffer, &answer); |
| 353 |
| 354 if (code != SBOX_ALL_OK) { |
| 355 return STATUS_ACCESS_DENIED; |
| 356 } |
| 357 |
| 358 return answer.nt_status; |
| 359 } |
| 360 |
| 361 NTSTATUS WINAPI TargetGetSuggestedOPMProtectedOutputArraySize( |
| 362 GetSuggestedOPMProtectedOutputArraySizeFunction, |
| 363 PUNICODE_STRING device_name, |
| 364 DWORD* suggested_output_size) { |
| 365 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 366 return STATUS_ACCESS_DENIED; |
| 367 void* ipc_memory = GetGlobalIPCMemory(); |
| 368 if (ipc_memory == NULL) |
| 369 return STATUS_ACCESS_DENIED; |
| 370 |
| 371 CrossCallReturn answer = {}; |
| 372 SharedMemIPCClient ipc(ipc_memory); |
| 373 base::string16 device_name_str; |
| 374 UnicodeStringToString(device_name, &device_name_str); |
| 375 ResultCode code = |
| 376 CrossCall(ipc, IPC_GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_TAG, |
| 377 device_name_str.c_str(), &answer); |
| 378 |
| 379 if (code != SBOX_ALL_OK) { |
| 380 return STATUS_ACCESS_DENIED; |
| 381 } |
| 382 |
| 383 if (!answer.nt_status) |
| 384 *suggested_output_size = answer.extended[0].unsigned_int; |
| 385 |
| 386 return answer.nt_status; |
| 387 } |
| 388 |
| 389 NTSTATUS WINAPI TargetSetOPMSigningKeyAndSequenceNumbers( |
| 390 SetOPMSigningKeyAndSequenceNumbersFunction, |
| 391 OPM_PROTECTED_OUTPUT_HANDLE protected_output, |
| 392 const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) { |
| 393 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 394 return STATUS_ACCESS_DENIED; |
| 395 void* ipc_memory = GetGlobalIPCMemory(); |
| 396 if (ipc_memory == NULL) |
| 397 return STATUS_ACCESS_DENIED; |
| 398 |
| 399 DXGKMDT_OPM_ENCRYPTED_PARAMETERS temp_parameters = *parameters; |
| 400 |
| 401 CrossCallReturn answer = {}; |
| 402 SharedMemIPCClient ipc(ipc_memory); |
| 403 InOutCountedBuffer buffer(&temp_parameters, |
| 404 sizeof(DXGKMDT_OPM_ENCRYPTED_PARAMETERS)); |
| 405 ResultCode code = |
| 406 CrossCall(ipc, IPC_GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS_TAG, |
| 407 static_cast<void*>(protected_output), buffer, &answer); |
| 408 |
| 409 if (code != SBOX_ALL_OK) { |
| 410 return STATUS_ACCESS_DENIED; |
| 411 } |
| 412 |
| 413 return answer.nt_status; |
| 414 } |
| 415 |
| 416 NTSTATUS WINAPI |
| 417 TargetCreateOPMProtectedOutputs(CreateOPMProtectedOutputsFunction, |
| 418 PUNICODE_STRING device_name, |
| 419 DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos, |
| 420 DWORD outputs_array_size, |
| 421 DWORD* output_size, |
| 422 OPM_PROTECTED_OUTPUT_HANDLE* outputs_array) { |
| 423 if (vos != DXGKMDT_OPM_VOS_OPM_SEMANTICS) |
| 424 return STATUS_INVALID_PARAMETER; |
| 425 |
| 426 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
| 427 return STATUS_ACCESS_DENIED; |
| 428 void* ipc_memory = GetGlobalIPCMemory(); |
| 429 if (ipc_memory == NULL) |
| 430 return STATUS_ACCESS_DENIED; |
| 431 |
| 432 CrossCallReturn answer = {}; |
| 433 SharedMemIPCClient ipc(ipc_memory); |
| 434 InOutCountedBuffer buffer(outputs_array, outputs_array_size * sizeof(HANDLE)); |
| 435 base::string16 device_name_str; |
| 436 UnicodeStringToString(device_name, &device_name_str); |
| 437 ResultCode code = CrossCall(ipc, IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG, |
| 438 device_name_str.c_str(), buffer, &answer); |
| 439 |
| 440 if (code != SBOX_ALL_OK) { |
| 441 return STATUS_ACCESS_DENIED; |
| 442 } |
| 443 |
| 444 if (!answer.nt_status) |
| 445 *output_size = answer.extended[0].unsigned_int; |
| 446 |
| 447 return answer.nt_status; |
| 448 } |
| 449 |
28 } // namespace sandbox | 450 } // namespace sandbox |
29 | 451 |
OLD | NEW |