From ca35405421df549e75f1f241259bdda0c5b67d40 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Tue, 14 Jul 2026 16:59:45 +0200 Subject: [PATCH] Merge commit from fork Restrict caller-supplied object-manager and disk paths used by metadata IOCTLs to the forms required by VeraCrypt. Also force symlink access checks, remove the unused legacy geometry handler, authorize real-drive probing before name resolution, and gate cache wiping on successful emergency key clearing. Security advisory: https://github.com/veracrypt/VeraCrypt/security/advisories/GHSA-9mgv-w2fw-3m78/ --- src/Common/Apidrvr.h | 5 +- src/Driver/Ntdriver.c | 170 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 148 insertions(+), 27 deletions(-) diff --git a/src/Common/Apidrvr.h b/src/Common/Apidrvr.h index 0b5e5695..bf9f56a7 100644 --- a/src/Common/Apidrvr.h +++ b/src/Common/Apidrvr.h @@ -85,8 +85,7 @@ // TODO: need IOCTL_DISK_GET_PARTITION_INFO_EX to support GPT #define TC_IOCTL_GET_DRIVE_PARTITION_INFO TC_IOCTL (14) -// result IOCTL_DISK_GET_DRIVE_GEOMETRY -// IN OUT - DISK_GEOMETRY_STRUCT +// Legacy IOCTL number retained for compatibility, the driver handler has been removed. #define TC_IOCTL_GET_DRIVE_GEOMETRY TC_IOCTL (15) // result IOCTL_DISK_GET_LENGTH_INFO @@ -254,7 +253,7 @@ typedef struct WCHAR deviceName[TC_MAX_PATH]; DISK_GEOMETRY diskGeometry; } -DISK_GEOMETRY_STRUCT; +DISK_GEOMETRY_STRUCT; // unused legacy structure, retained for compatibility. typedef struct { diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index bcd6317a..5b32992e 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -463,6 +463,113 @@ static BOOL CheckStringLength (const wchar_t* str, size_t cchSize, size_t minLen return TRUE; } + +/* Exact object-manager path grammars accepted from user mode by metadata IOCTLs. */ +static BOOL ConsumePathLiteral (const wchar_t **path, const wchar_t *literal) +{ + const wchar_t *current = *path; + + while (*literal) + { + if (!*current || UpperCaseUnicodeChar (*current) != UpperCaseUnicodeChar (*literal)) + return FALSE; + + ++current; + ++literal; + } + + *path = current; + return TRUE; +} + + +static BOOL ConsumeDecimalNumber (const wchar_t **path, ULONG *value) +{ + const wchar_t *current = *path; + ULONG number = 0; + + if (*current < L'0' || *current > L'9') + return FALSE; + + do + { + ULONG digit = (ULONG) (*current - L'0'); + + if (number > (MAXULONG - digit) / 10) + return FALSE; + + number = number * 10 + digit; + ++current; + } while (*current >= L'0' && *current <= L'9'); + + *path = current; + if (value) + *value = number; + + return TRUE; +} + + +static BOOL IsHarddiskPartitionPath (const wchar_t *path, BOOL partitionZeroOnly) +{ + const wchar_t *current = path; + ULONG partitionNumber; + + if (!path + || !ConsumePathLiteral (¤t, L"\\Device\\Harddisk") + || !ConsumeDecimalNumber (¤t, NULL) + || !ConsumePathLiteral (¤t, L"\\Partition") + || !ConsumeDecimalNumber (¤t, &partitionNumber) + || *current != 0) + { + return FALSE; + } + + return !partitionZeroOnly || partitionNumber == 0; +} + + +static BOOL IsHarddiskVolumePath (const wchar_t *path) +{ + const wchar_t *current = path; + + return path + && ConsumePathLiteral (¤t, L"\\Device\\HarddiskVolume") + && ConsumeDecimalNumber (¤t, NULL) + && *current == 0; +} + + +static BOOL IsDriveLetterSymbolicLinkPath (const wchar_t *path) +{ + const wchar_t *current = path; + + if (!path) + return FALSE; + + if (!ConsumePathLiteral (¤t, L"\\DosDevices\\")) + { + current = path; + if (!ConsumePathLiteral (¤t, L"\\??\\")) + return FALSE; + } + + return ((current[0] >= L'A' && current[0] <= L'Z') + || (current[0] >= L'a' && current[0] <= L'z')) + && current[1] == L':' + && current[2] == 0; +} + + +static BOOL IsAllowedDevicePathForMetadata (const wchar_t *path, BOOL symbolicLink) +{ + if (IsHarddiskPartitionPath (path, FALSE)) + return TRUE; + + return symbolicLink ? IsDriveLetterSymbolicLinkPath (path) : IsHarddiskVolumePath (path); +} + + BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp); @@ -2588,6 +2695,12 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex NTSTATUS ntStatusLocal; EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName)); + if (!IsAllowedDevicePathForMetadata (resolve->symLinkName, TRUE)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + } ntStatusLocal = SymbolicLinkToTarget (resolve->symLinkName, resolve->targetName, @@ -2608,6 +2721,12 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex NTSTATUS ntStatusLocal; EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName)); + if (!IsAllowedDevicePathForMetadata (info->deviceName, FALSE)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + } ntStatusLocal = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi)); if (NT_SUCCESS(ntStatusLocal)) @@ -2660,36 +2779,25 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex } break; - case TC_IOCTL_GET_DRIVE_GEOMETRY: - if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput)) - { - DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - { - NTSTATUS ntStatusLocal; - - EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); - Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY on %ls\n", g->deviceName); - - ntStatusLocal = TCDeviceIoControl (g->deviceName, - IOCTL_DISK_GET_DRIVE_GEOMETRY, - NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry)); - - Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT); - Irp->IoStatus.Status = ntStatusLocal; - } - } - break; - case VC_IOCTL_GET_DRIVE_GEOMETRY_EX: if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_EX_STRUCT), ValidateInputOutput)) { DISK_GEOMETRY_EX_STRUCT *g = (DISK_GEOMETRY_EX_STRUCT *) Irp->AssociatedIrp.SystemBuffer; { NTSTATUS ntStatusLocal; - PVOID buffer = TCalloc (256); // enough for DISK_GEOMETRY_EX and padded data + PVOID buffer; + + EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); + if (!IsAllowedDevicePathForMetadata (g->deviceName, FALSE)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + } + + buffer = TCalloc (256); // enough for DISK_GEOMETRY_EX and padded data if (buffer) { - EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY_EX on %ls\n", g->deviceName); ntStatusLocal = TCDeviceIoControl (g->deviceName, @@ -2754,7 +2862,20 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; + if (!UserCanAccessDriveDevice()) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_ACCESS_DENIED; + break; + } + EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName)); + if (!IsHarddiskPartitionPath (request->DeviceName, TRUE)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + } RtlInitUnicodeString (&name, request->DeviceName); status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject); @@ -2886,7 +3007,8 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex case VC_IOCTL_EMERGENCY_CLEAR_ALL_KEYS: EmergencyClearAllKeys (Irp); - WipeCache(); + if (NT_SUCCESS (Irp->IoStatus.Status)) + WipeCache(); break; case TC_IOCTL_BOOT_ENCRYPTION_SETUP: @@ -4508,7 +4630,7 @@ NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTa HANDLE handle; RtlInitUnicodeString (&fullFileName, symlinkName); - InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK, NULL, NULL); ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes);