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