| Index: sandbox/win/src/process_mitigations_win32k_policy.cc
|
| diff --git a/sandbox/win/src/process_mitigations_win32k_policy.cc b/sandbox/win/src/process_mitigations_win32k_policy.cc
|
| index af18c5413c2815499f21e413403d6f9fd082daec..6d12d828dba90f4c25b0806f900d603a12c59643 100644
|
| --- a/sandbox/win/src/process_mitigations_win32k_policy.cc
|
| +++ b/sandbox/win/src/process_mitigations_win32k_policy.cc
|
| @@ -2,10 +2,141 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <stddef.h>
|
| +
|
| +#include "sandbox/win/src/process_mitigations_win32k_interception.h"
|
| #include "sandbox/win/src/process_mitigations_win32k_policy.h"
|
|
|
| namespace sandbox {
|
|
|
| +namespace {
|
| +
|
| +// Define GUIDs for OPM APIs
|
| +const GUID DXGKMDT_OPM_GET_CONNECTOR_TYPE = {
|
| + 0x81d0bfd5,
|
| + 0x6afe,
|
| + 0x48c2,
|
| + {0x99, 0xc0, 0x95, 0xa0, 0x8f, 0x97, 0xc5, 0xda}};
|
| +const GUID DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES = {
|
| + 0x38f2a801,
|
| + 0x9a6c,
|
| + 0x48bb,
|
| + {0x91, 0x07, 0xb6, 0x69, 0x6e, 0x6f, 0x17, 0x97}};
|
| +const GUID DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL = {
|
| + 0xb2075857,
|
| + 0x3eda,
|
| + 0x4d5d,
|
| + {0x88, 0xdb, 0x74, 0x8f, 0x8c, 0x1a, 0x05, 0x49}};
|
| +const GUID DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL = {
|
| + 0x1957210a,
|
| + 0x7766,
|
| + 0x452a,
|
| + {0xb9, 0x9a, 0xd2, 0x7a, 0xed, 0x54, 0xf0, 0x3a}};
|
| +const GUID DXGKMDT_OPM_SET_PROTECTION_LEVEL = {
|
| + 0x9bb9327c,
|
| + 0x4eb5,
|
| + 0x4727,
|
| + {0x9f, 0x00, 0xb4, 0x2b, 0x09, 0x19, 0xc0, 0xda}};
|
| +
|
| +void StringToUnicodeString(PUNICODE_STRING unicode_string,
|
| + const base::string16& device_name) {
|
| + static RtlInitUnicodeStringFunction RtlInitUnicodeString;
|
| + if (!RtlInitUnicodeString) {
|
| + HMODULE ntdll = ::GetModuleHandle(kNtdllName);
|
| + RtlInitUnicodeString = reinterpret_cast<RtlInitUnicodeStringFunction>(
|
| + GetProcAddress(ntdll, "RtlInitUnicodeString"));
|
| + }
|
| + RtlInitUnicodeString(unicode_string, device_name.c_str());
|
| +}
|
| +
|
| +struct MonitorListState {
|
| + HMONITOR* monitor_list;
|
| + uint32_t monitor_list_size;
|
| + uint32_t monitor_list_pos;
|
| +};
|
| +
|
| +BOOL CALLBACK DisplayMonitorEnumProc(HMONITOR monitor,
|
| + HDC hdc_monitor,
|
| + LPRECT rect_monitor,
|
| + LPARAM data) {
|
| + MonitorListState* state = reinterpret_cast<MonitorListState*>(data);
|
| + if (state->monitor_list_pos >= state->monitor_list_size)
|
| + return FALSE;
|
| + state->monitor_list[state->monitor_list_pos++] = monitor;
|
| + return TRUE;
|
| +}
|
| +
|
| +template <typename T>
|
| +T GetExportedFunc(const wchar_t* libname, const char* name) {
|
| + OverrideForTestFunction test_override =
|
| + ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback();
|
| + if (test_override)
|
| + return reinterpret_cast<T>(test_override(name));
|
| +
|
| + static T func = nullptr;
|
| + if (!func) {
|
| + func =
|
| + reinterpret_cast<T>(::GetProcAddress(::GetModuleHandle(libname), name));
|
| + DCHECK(!!func);
|
| + }
|
| + return func;
|
| +}
|
| +
|
| +#define GDIFUNC(name) GetExportedFunc<name##Function>(L"gdi32.dll", #name)
|
| +#define USERFUNC(name) GetExportedFunc<name##Function>(L"user32.dll", #name)
|
| +
|
| +struct ValidateMonitorParams {
|
| + HMONITOR monitor;
|
| + base::string16 device_name;
|
| + bool result;
|
| +};
|
| +
|
| +bool GetMonitorDeviceName(HMONITOR monitor, base::string16* device_name) {
|
| + MONITORINFOEXW monitor_info = {};
|
| + monitor_info.cbSize = sizeof(monitor_info);
|
| + if (!USERFUNC(GetMonitorInfoW)(monitor, &monitor_info))
|
| + return false;
|
| + if (monitor_info.szDevice[CCHDEVICENAME - 1] != 0)
|
| + return false;
|
| + *device_name = monitor_info.szDevice;
|
| + return true;
|
| +}
|
| +
|
| +BOOL CALLBACK ValidateMonitorEnumProc(HMONITOR monitor,
|
| + HDC,
|
| + LPRECT,
|
| + LPARAM data) {
|
| + ValidateMonitorParams* valid_params =
|
| + reinterpret_cast<ValidateMonitorParams*>(data);
|
| + base::string16 device_name;
|
| + bool result = false;
|
| + if (valid_params->device_name.empty()) {
|
| + result = monitor == valid_params->monitor;
|
| + } else if (GetMonitorDeviceName(monitor, &device_name)) {
|
| + result = device_name == valid_params->device_name;
|
| + }
|
| + valid_params->result = result;
|
| + if (!result)
|
| + return TRUE;
|
| + return FALSE;
|
| +}
|
| +
|
| +bool IsValidMonitorOrDeviceName(HMONITOR monitor, const wchar_t* device_name) {
|
| + ValidateMonitorParams params = {};
|
| + params.monitor = monitor;
|
| + if (device_name)
|
| + params.device_name = device_name;
|
| + USERFUNC(EnumDisplayMonitors)
|
| + (nullptr, nullptr, ValidateMonitorEnumProc,
|
| + reinterpret_cast<LPARAM>(¶ms));
|
| + return params.result;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +OverrideForTestFunction
|
| + ProcessMitigationsWin32KLockdownPolicy::override_callback_;
|
| +
|
| bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
|
| const wchar_t* name,
|
| TargetPolicy::Semantics semantics,
|
| @@ -17,8 +148,263 @@ bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
|
| return false;
|
| if (!policy->AddRule(IPC_USER_REGISTERCLASSW_TAG, &rule))
|
| return false;
|
| + if (semantics != TargetPolicy::IMPLEMENT_OPM_APIS)
|
| + return true;
|
| + if (!policy->AddRule(IPC_USER_ENUMDISPLAYMONITORS_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_USER_ENUMDISPLAYDEVICES_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_USER_GETMONITORINFO_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_GETCERTIFICATE_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_GETCERTIFICATESIZE_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_DESTROYOPMPROTECTEDOUTPUT_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_CONFIGUREOPMPROTECTEDOUTPUT_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_GETOPMINFORMATION_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_GETOPMRANDOMNUMBER_TAG, &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_TAG,
|
| + &rule))
|
| + return false;
|
| + if (!policy->AddRule(IPC_GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS_TAG, &rule))
|
| + return false;
|
| return true;
|
| }
|
|
|
| +uint32_t ProcessMitigationsWin32KLockdownPolicy::EnumDisplayMonitorsAction(
|
| + const ClientInfo& client_info,
|
| + HMONITOR* monitor_list,
|
| + uint32_t monitor_list_size) {
|
| + MonitorListState state = {monitor_list, monitor_list_size, 0};
|
| + USERFUNC(EnumDisplayMonitors)
|
| + (nullptr, nullptr, DisplayMonitorEnumProc, reinterpret_cast<LPARAM>(&state));
|
| + return state.monitor_list_pos;
|
| +}
|
| +
|
| +BOOL ProcessMitigationsWin32KLockdownPolicy::GetMonitorInfoAction(
|
| + const ClientInfo& client_info,
|
| + HMONITOR monitor,
|
| + MONITORINFO* monitor_info_ptr) {
|
| + if (!IsValidMonitorOrDeviceName(monitor, nullptr))
|
| + return FALSE;
|
| + MONITORINFOEXW monitor_info = {};
|
| + monitor_info.cbSize = sizeof(MONITORINFOEXW);
|
| +
|
| + BOOL success = USERFUNC(GetMonitorInfoW)(
|
| + monitor, reinterpret_cast<MONITORINFO*>(&monitor_info));
|
| + if (success)
|
| + memcpy(monitor_info_ptr, &monitor_info, sizeof(monitor_info));
|
| + return success;
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
|
| + GetSuggestedOPMProtectedOutputArraySizeAction(
|
| + const ClientInfo& client_info,
|
| + const base::string16& device_name,
|
| + uint32_t* suggested_array_size) {
|
| + if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
|
| + return STATUS_ACCESS_DENIED;
|
| + }
|
| + UNICODE_STRING unicode_device_name;
|
| + StringToUnicodeString(&unicode_device_name, device_name);
|
| + DWORD suggested_array_size_dword = 0;
|
| + NTSTATUS status = GDIFUNC(GetSuggestedOPMProtectedOutputArraySize)(
|
| + &unicode_device_name, &suggested_array_size_dword);
|
| + if (!status)
|
| + *suggested_array_size = suggested_array_size_dword;
|
| + return status;
|
| +}
|
| +
|
| +NTSTATUS
|
| +ProcessMitigationsWin32KLockdownPolicy::CreateOPMProtectedOutputsAction(
|
| + const ClientInfo& client_info,
|
| + const base::string16& device_name,
|
| + HANDLE* protected_outputs,
|
| + uint32_t array_input_size,
|
| + uint32_t* array_output_size) {
|
| + if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
|
| + return STATUS_ACCESS_DENIED;
|
| + }
|
| +
|
| + UNICODE_STRING unicode_device_name;
|
| + StringToUnicodeString(&unicode_device_name, device_name);
|
| + DWORD output_size = 0;
|
| +
|
| + NTSTATUS status = GDIFUNC(CreateOPMProtectedOutputs)(
|
| + &unicode_device_name, DXGKMDT_OPM_VOS_OPM_SEMANTICS, array_input_size,
|
| + &output_size,
|
| + reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE*>(protected_outputs));
|
| + if (!status)
|
| + *array_output_size = output_size;
|
| + return status;
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeAction(
|
| + const ClientInfo& client_info,
|
| + const base::string16& device_name,
|
| + uint32_t* cert_size) {
|
| + if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
|
| + return STATUS_ACCESS_DENIED;
|
| + }
|
| + UNICODE_STRING unicode_device_name;
|
| + StringToUnicodeString(&unicode_device_name, device_name);
|
| +
|
| + return GDIFUNC(GetCertificateSize)(&unicode_device_name,
|
| + DXGKMDT_OPM_CERTIFICATE,
|
| + reinterpret_cast<DWORD*>(cert_size));
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateAction(
|
| + const ClientInfo& client_info,
|
| + const base::string16& device_name,
|
| + BYTE* cert_data,
|
| + uint32_t cert_size) {
|
| + if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
|
| + return STATUS_ACCESS_DENIED;
|
| + }
|
| + UNICODE_STRING unicode_device_name;
|
| + StringToUnicodeString(&unicode_device_name, device_name);
|
| +
|
| + return GDIFUNC(GetCertificate)(&unicode_device_name, DXGKMDT_OPM_CERTIFICATE,
|
| + cert_data, cert_size);
|
| +}
|
| +
|
| +NTSTATUS
|
| +ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeByHandleAction(
|
| + const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + uint32_t* cert_size) {
|
| + auto get_certificate_size_func = GDIFUNC(GetCertificateSizeByHandle);
|
| + if (get_certificate_size_func) {
|
| + return get_certificate_size_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
|
| + reinterpret_cast<DWORD*>(cert_size));
|
| + }
|
| + return STATUS_NOT_IMPLEMENTED;
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateByHandleAction(
|
| + const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + BYTE* cert_data,
|
| + uint32_t cert_size) {
|
| + auto get_certificate_func = GDIFUNC(GetCertificateByHandle);
|
| + if (get_certificate_func) {
|
| + return get_certificate_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
|
| + cert_data, cert_size);
|
| + }
|
| + return STATUS_NOT_IMPLEMENTED;
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMRandomNumberAction(
|
| + const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + void* random_number) {
|
| + return GDIFUNC(GetOPMRandomNumber)(
|
| + protected_output, static_cast<DXGKMDT_OPM_RANDOM_NUMBER*>(random_number));
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
|
| + SetOPMSigningKeyAndSequenceNumbersAction(const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + void* parameters) {
|
| + return GDIFUNC(SetOPMSigningKeyAndSequenceNumbers)(
|
| + protected_output,
|
| + static_cast<DXGKMDT_OPM_ENCRYPTED_PARAMETERS*>(parameters));
|
| +}
|
| +
|
| +NTSTATUS
|
| +ProcessMitigationsWin32KLockdownPolicy::ConfigureOPMProtectedOutputAction(
|
| + const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + void* parameters_ptr) {
|
| + DXGKMDT_OPM_CONFIGURE_PARAMETERS parameters;
|
| + memcpy(¶meters, parameters_ptr, sizeof(parameters));
|
| + if (parameters.guidSetting != DXGKMDT_OPM_SET_PROTECTION_LEVEL ||
|
| + parameters.cbParametersSize !=
|
| + sizeof(DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS)) {
|
| + return STATUS_INVALID_PARAMETER;
|
| + }
|
| +
|
| + DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS prot_level;
|
| + memcpy(&prot_level, parameters.abParameters, sizeof(prot_level));
|
| + if (prot_level.Reserved || prot_level.Reserved2)
|
| + return STATUS_INVALID_PARAMETER;
|
| +
|
| + if (prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_HDCP &&
|
| + prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
|
| + return STATUS_INVALID_PARAMETER;
|
| + }
|
| +
|
| + // Protection levels are same for HDCP and DPCP.
|
| + if (prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_OFF &&
|
| + prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_ON) {
|
| + return STATUS_INVALID_PARAMETER;
|
| + }
|
| +
|
| + return GDIFUNC(ConfigureOPMProtectedOutput)(protected_output, ¶meters, 0,
|
| + nullptr);
|
| +}
|
| +
|
| +NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMInformationAction(
|
| + const ClientInfo& client_info,
|
| + HANDLE protected_output,
|
| + void* parameters_ptr,
|
| + void* requested_info_ptr) {
|
| + DXGKMDT_OPM_GET_INFO_PARAMETERS parameters;
|
| + memcpy(¶meters, parameters_ptr, sizeof(parameters));
|
| +
|
| + bool valid_parameters = false;
|
| + // Validate sizes based on the type being requested.
|
| + if ((parameters.guidInformation == DXGKMDT_OPM_GET_CONNECTOR_TYPE ||
|
| + parameters.guidInformation ==
|
| + DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES) &&
|
| + parameters.cbParametersSize == 0) {
|
| + valid_parameters = true;
|
| + } else if ((parameters.guidInformation ==
|
| + DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL ||
|
| + parameters.guidInformation ==
|
| + DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL) &&
|
| + parameters.cbParametersSize == sizeof(uint32_t)) {
|
| + uint32_t param_value;
|
| + memcpy(¶m_value, parameters.abParameters, sizeof(param_value));
|
| + if (param_value == DXGKMDT_OPM_PROTECTION_TYPE_HDCP ||
|
| + param_value == DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
|
| + valid_parameters = true;
|
| + }
|
| + }
|
| + if (!valid_parameters)
|
| + return STATUS_INVALID_PARAMETER;
|
| + DXGKMDT_OPM_REQUESTED_INFORMATION requested_info = {};
|
| + NTSTATUS status = GDIFUNC(GetOPMInformation)(protected_output, ¶meters,
|
| + &requested_info);
|
| + if (!status)
|
| + memcpy(requested_info_ptr, &requested_info, sizeof(requested_info));
|
| +
|
| + return status;
|
| +}
|
| +
|
| +NTSTATUS
|
| +ProcessMitigationsWin32KLockdownPolicy::DestroyOPMProtectedOutputAction(
|
| + HANDLE protected_output) {
|
| + return GDIFUNC(DestroyOPMProtectedOutput)(protected_output);
|
| +}
|
| +
|
| +void ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
|
| + OverrideForTestFunction callback) {
|
| + override_callback_ = callback;
|
| +}
|
| +
|
| +OverrideForTestFunction
|
| +ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback() {
|
| + return override_callback_;
|
| +}
|
| +
|
| } // namespace sandbox
|
|
|
|
|