From a9adb201ccf42e22277561b2e00e990f41eeadda Mon Sep 17 00:00:00 2001 From: Victorien Molle Date: Wed, 30 Aug 2023 16:04:05 +0200 Subject: [PATCH 1/6] Driver: reorder code and add socket selection --- ScaphandreDrv/Driver.c | 93 ++++++++++++++++++++++++------------------ ScaphandreDrv/Driver.h | 5 +++ 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/ScaphandreDrv/Driver.c b/ScaphandreDrv/Driver.c index b897261..68a8116 100644 --- a/ScaphandreDrv/Driver.c +++ b/ScaphandreDrv/Driver.c @@ -6,16 +6,13 @@ #pragma alloc_text (INIT, DriverEntry) #endif -NTSTATUS -DriverEntry( - _In_ PDRIVER_OBJECT DriverObject, - _In_ PUNICODE_STRING RegistryPath - ) +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) { - NTSTATUS status; PDEVICE_OBJECT device_object; UNICODE_STRING device_name; UNICODE_STRING sym_name; + NTSTATUS status; DbgPrint("Registry path address: %p\n", RegistryPath); @@ -55,14 +52,16 @@ NTSTATUS DispatchCreate(PDEVICE_OBJECT device, PIRP irp) memset(manufacturer, 0, sizeof(manufacturer)); __cpuid(cpu_regs, 0); memcpy(manufacturer, &cpu_regs[1], sizeof(unsigned __int32)); - memcpy(manufacturer + sizeof(unsigned __int32), &cpu_regs[3], sizeof(unsigned __int32)); - memcpy(manufacturer + 2 * sizeof(unsigned __int32), &cpu_regs[2], sizeof(unsigned __int32)); + memcpy(manufacturer + sizeof(unsigned __int32), &cpu_regs[3], + sizeof(unsigned __int32)); + memcpy(manufacturer + 2 * sizeof(unsigned __int32), &cpu_regs[2], + sizeof(unsigned __int32)); - if (strncmp(manufacturer, "GenuineIntel", sizeof(manufacturer) - 1) == 0) + if (!strncmp(manufacturer, "GenuineIntel", sizeof(manufacturer) - 1)) machine_type = E_MACHINE_INTEL; - else if (strncmp(manufacturer, "AMDisbetter!", sizeof(manufacturer) - 1) == 0) + else if (!strncmp(manufacturer, "AMDisbetter!", sizeof(manufacturer) - 1)) machine_type = E_MACHINE_AMD; - else if (strncmp(manufacturer, "AuthenticAMD", sizeof(manufacturer) - 1) == 0) + else if (!strncmp(manufacturer, "AuthenticAMD", sizeof(manufacturer) - 1)) machine_type = E_MACHINE_AMD; else machine_type = E_MACHINE_UNK; @@ -96,44 +95,60 @@ NTSTATUS DispatchCleanup(PDEVICE_OBJECT device, PIRP irp) NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT device, PIRP irp) { - NTSTATUS ntStatus; - UINT32 msrRegister; - ULONG inputBufferLength; - ULONG outputBufferLength; + GROUP_AFFINITY affinity, old; + PIO_STACK_LOCATION stackLoc; + PROCESSOR_NUMBER pnumber; ULONGLONG msrResult; - PIO_STACK_LOCATION stackLocation; + NTSTATUS ntStatus; + struct data data; + size_t inLength; - stackLocation = irp->Tail.Overlay.CurrentStackLocation; - inputBufferLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength; - outputBufferLength = stackLocation->Parameters.DeviceIoControl.OutputBufferLength; + stackLoc = irp->Tail.Overlay.CurrentStackLocation; + inLength = stackLoc->Parameters.DeviceIoControl.InputBufferLength; DbgPrint("Received event for driver %s... \n", device->DriverObject->DriverName); - /* METHOD_BUFFERED */ - if (inputBufferLength == sizeof(ULONGLONG)) - { - /* MSR register codes provided by userland must not exceed 8 bytes */ - memcpy(&msrRegister, irp->AssociatedIrp.SystemBuffer, sizeof(ULONGLONG)); - if (validate_msr_lookup(msrRegister) != 0) - { - DbgPrint("Requested MSR register (%08x) access is not allowed!\n", msrRegister); - ntStatus = STATUS_INVALID_DEVICE_REQUEST; - } - else - { - /* Call readmsr instruction */ - msrResult = __readmsr(msrRegister); - memcpy(irp->AssociatedIrp.SystemBuffer, &msrResult, sizeof(ULONGLONG)); - ntStatus = STATUS_SUCCESS; - irp->IoStatus.Information = sizeof(ULONGLONG); - } + if (inLength != sizeof(data)) { + DbgPrint("Bad input length provided. Expected %zu bytes, got %zu.\n", + sizeof(data), inLength); + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + goto error; } - else + + /* Convert input data into structure */ + memcpy(&data, irp->AssociatedIrp.SystemBuffer, sizeof(data)); + if (validate_msr_lookup(data.msrRegister) != 0) { - DbgPrint("Bad input length provided. Expected %u bytes, got %u.\n", sizeof(ULONGLONG), inputBufferLength); + DbgPrint("Requested MSR register (%04x) access is not allowed!\n", + data.msrRegister); ntStatus = STATUS_INVALID_DEVICE_REQUEST; + goto error; + } + + /* Run code on the specified socket */ + if ((ntStatus = KeGetProcessorNumberFromIndex(data.cpuIndex, &pnumber)) + != STATUS_SUCCESS) { + DbgPrint("Failed to get processor info!\n"); + goto error; } + /* Set affinity */ + memset(&affinity, 0, sizeof(GROUP_AFFINITY)); + affinity.Group = pnumber.Group; + KeSetSystemGroupAffinityThread(&affinity, &old); + + /* Call readmsr instruction */ + msrResult = __readmsr(data.msrRegister); + + /* Restore affinity */ + KeRevertToUserGroupAffinityThread(&old); + + /* Save result */ + memcpy(irp->AssociatedIrp.SystemBuffer, &msrResult, sizeof(data)); + irp->IoStatus.Information = sizeof(data); + ntStatus = STATUS_SUCCESS; + +error: irp->IoStatus.Status = ntStatus; IofCompleteRequest(irp, IO_NO_INCREMENT); diff --git a/ScaphandreDrv/Driver.h b/ScaphandreDrv/Driver.h index da4ad7d..3a8a146 100644 --- a/ScaphandreDrv/Driver.h +++ b/ScaphandreDrv/Driver.h @@ -29,6 +29,11 @@ DRIVER_INITIALIZE DriverEntry; EXTERN_C_END +struct data { + UINT32 msrRegister; + UINT32 cpuIndex; +}; + void DriverUnload(PDRIVER_OBJECT driver); NTSTATUS DispatchCreate(PDEVICE_OBJECT device, PIRP irp); NTSTATUS DispatchClose(PDEVICE_OBJECT device, PIRP irp); From 18cb52b66082905047eacbf4d95390a4fa3785a1 Mon Sep 17 00:00:00 2001 From: bpetit Date: Fri, 1 Sep 2023 10:25:04 +0200 Subject: [PATCH 2/6] feat: adding psys/platform rapl msrs addresses --- ScaphandreDrv/msr.c | 2 ++ ScaphandreDrv/msr.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/ScaphandreDrv/msr.c b/ScaphandreDrv/msr.c index c75e37f..efb6e63 100644 --- a/ScaphandreDrv/msr.c +++ b/ScaphandreDrv/msr.c @@ -25,6 +25,8 @@ int validate_msr_lookup(unsigned __int64 msrRegister) case MSR_PP1_POWER_LIMIT: case MSR_PP1_ENERGY_STATUS: case MSR_PP1_POLICY: + case MSR_PLATFORM_ENERGY_STATUS: + case MSR_PLATFORM_POWER_LIMIT: err = 0; break; diff --git a/ScaphandreDrv/msr.h b/ScaphandreDrv/msr.h index 12e4554..593de18 100644 --- a/ScaphandreDrv/msr.h +++ b/ScaphandreDrv/msr.h @@ -28,6 +28,9 @@ #define MSR_AMD_CORE_ENERGY_STATUS 0xc001029a #define MSR_AMD_PKG_ENERGY_STATUS 0xc001029b +#define MSR_PLATFORM_ENERGY_STATUS 0x0000064d +#define MSR_PLATFORM_POWER_LIMIT 0x0000065c + typedef enum { E_MACHINE_INTEL, From abbe5fa941e1b6b9bcb511b70968354dd6b0adfc Mon Sep 17 00:00:00 2001 From: Victorien Molle Date: Wed, 11 Oct 2023 18:58:58 +0200 Subject: [PATCH 3/6] Driver: query the maximum number of CPU cores Get the maximum number of CPU cores. If the requested index is equal or above the maximum core number, default it to the maximum number of cores - 1. --- ScaphandreDrv/Driver.c | 8 ++++++++ ScaphandreDrv/msr.h | 1 + 2 files changed, 9 insertions(+) diff --git a/ScaphandreDrv/Driver.c b/ScaphandreDrv/Driver.c index 68a8116..1c7cdd3 100644 --- a/ScaphandreDrv/Driver.c +++ b/ScaphandreDrv/Driver.c @@ -66,6 +66,9 @@ NTSTATUS DispatchCreate(PDEVICE_OBJECT device, PIRP irp) else machine_type = E_MACHINE_UNK; + /* Get the number of virtual processors */ + max_processors = KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS); + irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = STATUS_SUCCESS; IofCompleteRequest(irp, IO_NO_INCREMENT); @@ -125,6 +128,11 @@ NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT device, PIRP irp) goto error; } + /* Check the requested CPU index is not above the maximum CPU available + * Otherwise, cap to max_processors - 1 + */ + data.cpuIndex = (data.cpuIndex >= max_processors) ? (max_processors - 1) : data.cpuIndex; + /* Run code on the specified socket */ if ((ntStatus = KeGetProcessorNumberFromIndex(data.cpuIndex, &pnumber)) != STATUS_SUCCESS) { diff --git a/ScaphandreDrv/msr.h b/ScaphandreDrv/msr.h index 593de18..cb28540 100644 --- a/ScaphandreDrv/msr.h +++ b/ScaphandreDrv/msr.h @@ -40,6 +40,7 @@ typedef enum { static e_machine_type machine_type; +static unsigned long max_processors; int validate_msr_lookup(unsigned __int64 msrRegister); From 1ed88736da14ac364bc072a988af5f153c819505 Mon Sep 17 00:00:00 2001 From: Victorien Molle Date: Wed, 11 Oct 2023 19:01:20 +0200 Subject: [PATCH 4/6] Driver: add documentation about logical processors --- ScaphandreDrv/Driver.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ScaphandreDrv/Driver.c b/ScaphandreDrv/Driver.c index 1c7cdd3..459fca4 100644 --- a/ScaphandreDrv/Driver.c +++ b/ScaphandreDrv/Driver.c @@ -133,7 +133,10 @@ NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT device, PIRP irp) */ data.cpuIndex = (data.cpuIndex >= max_processors) ? (max_processors - 1) : data.cpuIndex; - /* Run code on the specified socket */ + /* Run code on the specified socket + * MSDN says: 'Systems with fewer than 64 logical processors always have a single group, Group 0.' + * https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups + */ if ((ntStatus = KeGetProcessorNumberFromIndex(data.cpuIndex, &pnumber)) != STATUS_SUCCESS) { DbgPrint("Failed to get processor info!\n"); From e630b9e7787affbe0025b0bae28ccb8aa957b406 Mon Sep 17 00:00:00 2001 From: Victorien Molle Date: Wed, 11 Oct 2023 19:02:39 +0200 Subject: [PATCH 5/6] Driver: secure MSRs access with try/except combination Some MSRs that Intel's documentation says it's available, aren't. An example of that is the MSR register 0x641 (MSR_PP1_ENERGY_STATUS) which is available for the Haswell CPU series. Accessing this register on a Intel Xeon E5-2630v3 CPU results in a unhandled kernel exception which crashes the whole system because this particular CPU does not have an integrated graphics chipset (as well as all Xeon CPU variant). In order to avoid this behavior, secure MSRs access (via rdmsr instruction) with a try/except combination. If the exception occurs, the userland has to check the driver reply using the 'GetLastError' API and check if the error code is STATUS_IO_DEVICE_ERROR. --- ScaphandreDrv/Driver.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ScaphandreDrv/Driver.c b/ScaphandreDrv/Driver.c index 459fca4..13bb91c 100644 --- a/ScaphandreDrv/Driver.c +++ b/ScaphandreDrv/Driver.c @@ -143,16 +143,22 @@ NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT device, PIRP irp) goto error; } - /* Set affinity */ - memset(&affinity, 0, sizeof(GROUP_AFFINITY)); - affinity.Group = pnumber.Group; - KeSetSystemGroupAffinityThread(&affinity, &old); + try { + /* Set affinity */ + memset(&affinity, 0, sizeof(GROUP_AFFINITY)); + affinity.Group = pnumber.Group; + KeSetSystemGroupAffinityThread(&affinity, &old); - /* Call readmsr instruction */ - msrResult = __readmsr(data.msrRegister); + /* Call readmsr instruction */ + msrResult = __readmsr(data.msrRegister); - /* Restore affinity */ - KeRevertToUserGroupAffinityThread(&old); + /* Restore affinity */ + KeRevertToUserGroupAffinityThread(&old); + } + except (EXCEPTION_EXECUTE_HANDLER) { + ntStatus = STATUS_IO_DEVICE_ERROR; + goto error; + } /* Save result */ memcpy(irp->AssociatedIrp.SystemBuffer, &msrResult, sizeof(data)); From 91620ca8e83bd09082d56fb340a137f77d7a8b20 Mon Sep 17 00:00:00 2001 From: Victorien Molle Date: Wed, 11 Oct 2023 19:11:39 +0200 Subject: [PATCH 6/6] Driver: set the affinity mask value to the requested core index --- ScaphandreDrv/Driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ScaphandreDrv/Driver.c b/ScaphandreDrv/Driver.c index 13bb91c..149cc60 100644 --- a/ScaphandreDrv/Driver.c +++ b/ScaphandreDrv/Driver.c @@ -147,6 +147,7 @@ NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT device, PIRP irp) /* Set affinity */ memset(&affinity, 0, sizeof(GROUP_AFFINITY)); affinity.Group = pnumber.Group; + affinity.Mask = data.cpuIndex; KeSetSystemGroupAffinityThread(&affinity, &old); /* Call readmsr instruction */