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