mirror of
https://github.com/reactos/reactos.git
synced 2024-06-30 01:42:30 +00:00
[NTOS:CM] Improve the capture of user-mode parameters.
- Improve the capture of OBJECT_ATTRIBUTES parameters that are passed (by pointer) to the Cm* helper functions, and the capture of UNICODE_STRINGs. - Correctly differentiate user-mode vs. kernel-mode root directory handles (in OBJECT_ATTRIBUTES): note that most of the Cm* APIs expect their parameters to be kernel-mode (pointers, handles...). CORE-13448
This commit is contained in:
parent
3290d4619b
commit
49e08b23ce
|
@ -17,6 +17,222 @@ BOOLEAN CmBootAcceptFirstTime = TRUE;
|
||||||
BOOLEAN CmFirstTime = TRUE;
|
BOOLEAN CmFirstTime = TRUE;
|
||||||
extern ULONG InitSafeBootMode;
|
extern ULONG InitSafeBootMode;
|
||||||
|
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation()
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
ReleaseCapturedObjectAttributes(
|
||||||
|
_In_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
|
||||||
|
_In_ KPROCESSOR_MODE AccessMode)
|
||||||
|
{
|
||||||
|
/* Check if we have a security descriptor */
|
||||||
|
if (CapturedObjectAttributes->SecurityDescriptor)
|
||||||
|
{
|
||||||
|
/* Release it */
|
||||||
|
SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor,
|
||||||
|
AccessMode,
|
||||||
|
TRUE);
|
||||||
|
CapturedObjectAttributes->SecurityDescriptor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we have an object name */
|
||||||
|
if (CapturedObjectAttributes->ObjectName)
|
||||||
|
{
|
||||||
|
/* Release it */
|
||||||
|
ReleaseCapturedUnicodeString(CapturedObjectAttributes->ObjectName, AccessMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation()
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
ProbeAndCaptureObjectAttributes(
|
||||||
|
_Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
|
||||||
|
_Out_ PUNICODE_STRING ObjectName,
|
||||||
|
_In_ KPROCESSOR_MODE AccessMode,
|
||||||
|
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
_In_ BOOLEAN CaptureSecurity)
|
||||||
|
{
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||||||
|
// PSECURITY_QUALITY_OF_SERVICE SecurityQos;
|
||||||
|
PUNICODE_STRING LocalObjectName = NULL;
|
||||||
|
|
||||||
|
/* Zero out the Capture Data */
|
||||||
|
RtlZeroMemory(CapturedObjectAttributes, sizeof(*CapturedObjectAttributes));
|
||||||
|
|
||||||
|
/* SEH everything here for protection */
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
/* Check if we got attributes */
|
||||||
|
if (ObjectAttributes)
|
||||||
|
{
|
||||||
|
/* Check if we're in user mode */
|
||||||
|
if (AccessMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Probe the attributes */
|
||||||
|
ProbeForRead(ObjectAttributes,
|
||||||
|
sizeof(OBJECT_ATTRIBUTES),
|
||||||
|
sizeof(ULONG));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate the Size and Attributes */
|
||||||
|
if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
|
||||||
|
(ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) // Understood as all the possible valid attributes
|
||||||
|
{
|
||||||
|
/* Invalid combination, fail */
|
||||||
|
_SEH2_YIELD(return STATUS_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set some Create Info and do not allow user-mode kernel handles */
|
||||||
|
CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
|
||||||
|
CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory;
|
||||||
|
CapturedObjectAttributes->Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, AccessMode);
|
||||||
|
LocalObjectName = ObjectAttributes->ObjectName;
|
||||||
|
SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
|
||||||
|
// SecurityQos = ObjectAttributes->SecurityQualityOfService;
|
||||||
|
|
||||||
|
/* Check if we have a security descriptor */
|
||||||
|
if (CaptureSecurity && SecurityDescriptor)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Capture it.
|
||||||
|
* Note: This has an implicit memory barrier due
|
||||||
|
* to the function call, so cleanup is safe here.
|
||||||
|
*/
|
||||||
|
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
|
||||||
|
AccessMode,
|
||||||
|
NonPagedPool,
|
||||||
|
TRUE,
|
||||||
|
&CapturedObjectAttributes->
|
||||||
|
SecurityDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Capture failed, quit */
|
||||||
|
CapturedObjectAttributes->SecurityDescriptor = NULL;
|
||||||
|
_SEH2_YIELD(return Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CapturedObjectAttributes->SecurityDescriptor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// We don't use the QoS!
|
||||||
|
|
||||||
|
/* Check if we have QoS */
|
||||||
|
if (SecurityQos)
|
||||||
|
{
|
||||||
|
/* Check if we came from user mode */
|
||||||
|
if (AccessMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Validate the QoS */
|
||||||
|
ProbeForRead(SecurityQos,
|
||||||
|
sizeof(SECURITY_QUALITY_OF_SERVICE),
|
||||||
|
sizeof(ULONG));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save Info */
|
||||||
|
CapturedObjectAttributes->SecurityQualityOfService = *SecurityQos;
|
||||||
|
CapturedObjectAttributes->SecurityQos =
|
||||||
|
&CapturedObjectAttributes->SecurityQualityOfService;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
CapturedObjectAttributes->SecurityQualityOfService = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We don't have a name */
|
||||||
|
LocalObjectName = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
||||||
|
{
|
||||||
|
/* Cleanup and return the exception code */
|
||||||
|
ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
|
||||||
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
/* Now check if the Object Attributes had an Object Name */
|
||||||
|
if (LocalObjectName)
|
||||||
|
{
|
||||||
|
Status = ProbeAndCaptureUnicodeString(ObjectName, AccessMode, LocalObjectName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Clear the string */
|
||||||
|
RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
|
||||||
|
|
||||||
|
/* It cannot have specified a Root Directory */
|
||||||
|
if (CapturedObjectAttributes->RootDirectory)
|
||||||
|
{
|
||||||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the caputured object attributes name pointer to the one the user gave to us */
|
||||||
|
CapturedObjectAttributes->ObjectName = ObjectName;
|
||||||
|
|
||||||
|
/* Cleanup if we failed */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return status to caller */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
NTSTATUS
|
||||||
|
CmpConvertHandleToKernelHandle(
|
||||||
|
_In_ HANDLE SourceHandle,
|
||||||
|
_In_opt_ POBJECT_TYPE ObjectType,
|
||||||
|
_In_ ACCESS_MASK DesiredAccess,
|
||||||
|
_In_ KPROCESSOR_MODE AccessMode,
|
||||||
|
_Out_ PHANDLE KernelHandle)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PVOID Object;
|
||||||
|
|
||||||
|
*KernelHandle = NULL;
|
||||||
|
|
||||||
|
/* NULL handle is valid */
|
||||||
|
if (SourceHandle == NULL)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* Get the object pointer */
|
||||||
|
Status = ObReferenceObjectByHandle(SourceHandle,
|
||||||
|
DesiredAccess,
|
||||||
|
ObjectType,
|
||||||
|
AccessMode,
|
||||||
|
&Object,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
/* Create a kernel handle from the pointer */
|
||||||
|
Status = ObOpenObjectByPointer(Object,
|
||||||
|
OBJ_KERNEL_HANDLE,
|
||||||
|
NULL,
|
||||||
|
DesiredAccess,
|
||||||
|
ObjectType,
|
||||||
|
KernelMode,
|
||||||
|
KernelHandle);
|
||||||
|
|
||||||
|
/* Dereference the object */
|
||||||
|
ObDereferenceObject(Object);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -231,7 +447,7 @@ NtDeleteKey(IN HANDLE KeyHandle)
|
||||||
CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
|
CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dereference the object */
|
/* Dereference and return status */
|
||||||
ObDereferenceObject(KeyObject);
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -402,6 +618,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
|
||||||
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
|
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dereference and return status */
|
||||||
ObDereferenceObject(KeyObject);
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -527,12 +744,12 @@ NtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
IN ULONG Length,
|
IN ULONG Length,
|
||||||
OUT PULONG ResultLength)
|
OUT PULONG ResultLength)
|
||||||
{
|
{
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
PCM_KEY_BODY KeyObject;
|
PCM_KEY_BODY KeyObject;
|
||||||
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
|
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
|
||||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||||
UNICODE_STRING ValueNameCopy = *ValueName;
|
UNICODE_STRING ValueNameCopy;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
@ -557,7 +774,8 @@ NtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
PreviousMode,
|
PreviousMode,
|
||||||
(PVOID*)&KeyObject,
|
(PVOID*)&KeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
if (PreviousMode != KernelMode)
|
if (PreviousMode != KernelMode)
|
||||||
{
|
{
|
||||||
|
@ -577,22 +795,25 @@ NtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
_SEH2_END;
|
_SEH2_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Capture the string */
|
||||||
|
Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
/* Make sure the name is aligned properly */
|
/* Make sure the name is aligned properly */
|
||||||
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
|
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
|
||||||
{
|
{
|
||||||
/* It isn't, so we'll fail */
|
/* It isn't, so we'll fail */
|
||||||
ObDereferenceObject(KeyObject);
|
Status = STATUS_INVALID_PARAMETER;
|
||||||
return STATUS_INVALID_PARAMETER;
|
goto Quit;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* Ignore any null characters at the end */
|
||||||
|
while ((ValueNameCopy.Length) &&
|
||||||
|
!(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
|
||||||
{
|
{
|
||||||
/* Ignore any null characters at the end */
|
/* Skip it */
|
||||||
while ((ValueNameCopy.Length) &&
|
ValueNameCopy.Length -= sizeof(WCHAR);
|
||||||
!(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
|
|
||||||
{
|
|
||||||
/* Skip it */
|
|
||||||
ValueNameCopy.Length -= sizeof(WCHAR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the callback */
|
/* Setup the callback */
|
||||||
|
@ -620,6 +841,10 @@ NtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
|
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
if (ValueNameCopy.Buffer)
|
||||||
|
ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
|
||||||
|
|
||||||
/* Dereference and return status */
|
/* Dereference and return status */
|
||||||
ObDereferenceObject(KeyObject);
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
|
@ -635,16 +860,26 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
IN ULONG DataSize)
|
IN ULONG DataSize)
|
||||||
{
|
{
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
PCM_KEY_BODY KeyObject = NULL;
|
KPROCESSOR_MODE PreviousMode;
|
||||||
|
PCM_KEY_BODY KeyObject;
|
||||||
REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
|
REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
|
||||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||||
UNICODE_STRING ValueNameCopy;
|
UNICODE_STRING ValueNameCopy;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
PreviousMode = ExGetPreviousMode();
|
||||||
|
|
||||||
|
/* Verify that the handle is valid and is a registry key */
|
||||||
|
Status = ObReferenceObjectByHandle(KeyHandle,
|
||||||
|
KEY_SET_VALUE,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
PreviousMode,
|
||||||
|
(PVOID*)&KeyObject,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
if (!DataSize)
|
if (!DataSize)
|
||||||
Data = NULL;
|
Data = NULL;
|
||||||
|
|
||||||
|
@ -653,7 +888,11 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
{
|
{
|
||||||
PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
|
PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
|
||||||
if (!DataCopy)
|
if (!DataCopy)
|
||||||
|
{
|
||||||
|
/* Dereference and return status */
|
||||||
|
ObDereferenceObject(KeyObject);
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
ProbeForRead(Data, DataSize, 1);
|
ProbeForRead(Data, DataSize, 1);
|
||||||
|
@ -667,7 +906,9 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
/* Dereference and return status */
|
||||||
ExFreePoolWithTag(DataCopy, TAG_CM);
|
ExFreePoolWithTag(DataCopy, TAG_CM);
|
||||||
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
Data = DataCopy;
|
Data = DataCopy;
|
||||||
|
@ -676,21 +917,11 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
/* Capture the string */
|
/* Capture the string */
|
||||||
Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
|
Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
goto end;
|
goto Quit;
|
||||||
|
|
||||||
DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
|
DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
|
||||||
KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
|
KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
|
||||||
|
|
||||||
/* Verify that the handle is valid and is a registry key */
|
|
||||||
Status = ObReferenceObjectByHandle(KeyHandle,
|
|
||||||
KEY_SET_VALUE,
|
|
||||||
CmpKeyObjectType,
|
|
||||||
PreviousMode,
|
|
||||||
(PVOID*)&KeyObject,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
/* Make sure the name is aligned, not too long, and the data under 4GB */
|
/* Make sure the name is aligned, not too long, and the data under 4GB */
|
||||||
if ( (ValueNameCopy.Length > 32767) ||
|
if ( (ValueNameCopy.Length > 32767) ||
|
||||||
((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
|
((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
|
||||||
|
@ -698,7 +929,7 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
{
|
{
|
||||||
/* Fail */
|
/* Fail */
|
||||||
Status = STATUS_INVALID_PARAMETER;
|
Status = STATUS_INVALID_PARAMETER;
|
||||||
goto end;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore any null characters at the end */
|
/* Ignore any null characters at the end */
|
||||||
|
@ -714,7 +945,7 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
{
|
{
|
||||||
/* Fail */
|
/* Fail */
|
||||||
Status = STATUS_ACCESS_DENIED;
|
Status = STATUS_ACCESS_DENIED;
|
||||||
goto end;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup callback */
|
/* Setup callback */
|
||||||
|
@ -742,13 +973,15 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
|
CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
Quit:
|
||||||
/* Dereference and return status */
|
if (ValueNameCopy.Buffer)
|
||||||
if (KeyObject)
|
ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
|
||||||
ObDereferenceObject(KeyObject);
|
|
||||||
ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
|
|
||||||
if ((PreviousMode != KernelMode) && Data)
|
if ((PreviousMode != KernelMode) && Data)
|
||||||
ExFreePoolWithTag(Data, TAG_CM);
|
ExFreePoolWithTag(Data, TAG_CM);
|
||||||
|
|
||||||
|
/* Dereference and return status */
|
||||||
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,12 +990,13 @@ NTAPI
|
||||||
NtDeleteValueKey(IN HANDLE KeyHandle,
|
NtDeleteValueKey(IN HANDLE KeyHandle,
|
||||||
IN PUNICODE_STRING ValueName)
|
IN PUNICODE_STRING ValueName)
|
||||||
{
|
{
|
||||||
PCM_KEY_BODY KeyObject;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
PCM_KEY_BODY KeyObject;
|
||||||
REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
|
REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
|
||||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
UNICODE_STRING ValueNameCopy = *ValueName;
|
UNICODE_STRING ValueNameCopy;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
/* Verify that the handle is valid and is a registry key */
|
/* Verify that the handle is valid and is a registry key */
|
||||||
|
@ -772,22 +1006,28 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
|
||||||
PreviousMode,
|
PreviousMode,
|
||||||
(PVOID*)&KeyObject,
|
(PVOID*)&KeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
/* Don't touch read-only keys */
|
/* Capture the string */
|
||||||
if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
|
Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
|
||||||
{
|
if (!NT_SUCCESS(Status))
|
||||||
/* Fail */
|
goto Quit;
|
||||||
ObDereferenceObject(KeyObject);
|
|
||||||
return STATUS_ACCESS_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure the name is aligned properly */
|
/* Make sure the name is aligned properly */
|
||||||
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
|
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
|
||||||
{
|
{
|
||||||
/* It isn't, so we'll fail */
|
/* It isn't, so we'll fail */
|
||||||
ObDereferenceObject(KeyObject);
|
Status = STATUS_INVALID_PARAMETER;
|
||||||
return STATUS_INVALID_PARAMETER;
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't touch read-only keys */
|
||||||
|
if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
Status = STATUS_ACCESS_DENIED;
|
||||||
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the callback */
|
/* Do the callback */
|
||||||
|
@ -807,7 +1047,11 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
|
||||||
&PostOperationInfo);
|
&PostOperationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dereference the key body */
|
Quit:
|
||||||
|
if (ValueNameCopy.Buffer)
|
||||||
|
ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
|
||||||
|
|
||||||
|
/* Dereference and return status */
|
||||||
ObDereferenceObject(KeyObject);
|
ObDereferenceObject(KeyObject);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -884,11 +1128,17 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
OBJECT_ATTRIBUTES CapturedTargetKey;
|
||||||
|
OBJECT_ATTRIBUTES CapturedSourceFile;
|
||||||
|
UNICODE_STRING TargetKeyName, SourceFileName;
|
||||||
|
HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL;
|
||||||
PCM_KEY_BODY KeyBody = NULL;
|
PCM_KEY_BODY KeyBody = NULL;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
/* Validate flags */
|
/* Validate flags */
|
||||||
if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
|
if (Flags & ~REG_NO_LAZY_FLUSH)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* Validate privilege */
|
/* Validate privilege */
|
||||||
if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
|
if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
|
||||||
|
@ -900,6 +1150,77 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
/* Block APCs */
|
/* Block APCs */
|
||||||
KeEnterCriticalRegion();
|
KeEnterCriticalRegion();
|
||||||
|
|
||||||
|
/* Check for user-mode caller */
|
||||||
|
if (PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Prepare to probe parameters */
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
/* Probe target key */
|
||||||
|
ProbeForRead(TargetKey,
|
||||||
|
sizeof(OBJECT_ATTRIBUTES),
|
||||||
|
sizeof(ULONG));
|
||||||
|
|
||||||
|
/* Probe source file */
|
||||||
|
ProbeForRead(SourceFile,
|
||||||
|
sizeof(OBJECT_ATTRIBUTES),
|
||||||
|
sizeof(ULONG));
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
/* Return the exception code */
|
||||||
|
Status = _SEH2_GetExceptionCode();
|
||||||
|
_SEH2_YIELD(goto Quit);
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Probe and capture the target key attributes, including the security */
|
||||||
|
Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey,
|
||||||
|
&TargetKeyName,
|
||||||
|
PreviousMode,
|
||||||
|
TargetKey,
|
||||||
|
TRUE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe and capture the source file attributes, but not the security.
|
||||||
|
* A proper security context is built by CmLoadKey().
|
||||||
|
*/
|
||||||
|
Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile,
|
||||||
|
&SourceFileName,
|
||||||
|
PreviousMode,
|
||||||
|
SourceFile,
|
||||||
|
FALSE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the target key root directory handle is a kernel handle */
|
||||||
|
Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
KEY_READ,
|
||||||
|
PreviousMode,
|
||||||
|
&KmTargetKeyRootDir);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Cleanup;
|
||||||
|
CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
|
||||||
|
CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
|
||||||
|
|
||||||
|
/* Make sure the source file root directory handle is a kernel handle */
|
||||||
|
Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory,
|
||||||
|
IoFileObjectType,
|
||||||
|
FILE_TRAVERSE,
|
||||||
|
PreviousMode,
|
||||||
|
&KmSourceFileRootDir);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Cleanup;
|
||||||
|
CapturedSourceFile.RootDirectory = KmSourceFileRootDir;
|
||||||
|
CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE;
|
||||||
|
|
||||||
/* Check if we have a trust class */
|
/* Check if we have a trust class */
|
||||||
if (TrustClassKey)
|
if (TrustClassKey)
|
||||||
{
|
{
|
||||||
|
@ -913,11 +1234,26 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the internal API */
|
/* Call the internal API */
|
||||||
Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
|
Status = CmLoadKey(&CapturedTargetKey,
|
||||||
|
&CapturedSourceFile,
|
||||||
|
Flags,
|
||||||
|
KeyBody);
|
||||||
|
|
||||||
/* Dereference the trust key, if any */
|
/* Dereference the trust key, if any */
|
||||||
if (KeyBody) ObDereferenceObject(KeyBody);
|
if (KeyBody) ObDereferenceObject(KeyBody);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
/* Close the local kernel handles */
|
||||||
|
if (KmSourceFileRootDir)
|
||||||
|
ObCloseHandle(KmSourceFileRootDir, KernelMode);
|
||||||
|
if (KmTargetKeyRootDir)
|
||||||
|
ObCloseHandle(KmTargetKeyRootDir, KernelMode);
|
||||||
|
|
||||||
|
/* Release the captured object attributes */
|
||||||
|
ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode);
|
||||||
|
ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
|
||||||
|
|
||||||
|
Quit:
|
||||||
/* Bring back APCs */
|
/* Bring back APCs */
|
||||||
KeLeaveCriticalRegion();
|
KeLeaveCriticalRegion();
|
||||||
|
|
||||||
|
@ -1272,6 +1608,7 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
|
||||||
IN ULONG Flags)
|
IN ULONG Flags)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
HANDLE KmFileHandle = NULL;
|
||||||
PCM_KEY_BODY KeyObject;
|
PCM_KEY_BODY KeyObject;
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
|
||||||
|
@ -1294,6 +1631,15 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
|
||||||
return STATUS_PRIVILEGE_NOT_HELD;
|
return STATUS_PRIVILEGE_NOT_HELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure the target file handle is a kernel handle */
|
||||||
|
Status = CmpConvertHandleToKernelHandle(FileHandle,
|
||||||
|
IoFileObjectType,
|
||||||
|
FILE_WRITE_DATA,
|
||||||
|
PreviousMode,
|
||||||
|
&KmFileHandle);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
/* Verify that the handle is valid and is a registry key */
|
/* Verify that the handle is valid and is a registry key */
|
||||||
Status = ObReferenceObjectByHandle(KeyHandle,
|
Status = ObReferenceObjectByHandle(KeyHandle,
|
||||||
KEY_READ,
|
KEY_READ,
|
||||||
|
@ -1301,12 +1647,20 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
|
||||||
PreviousMode,
|
PreviousMode,
|
||||||
(PVOID*)&KeyObject,
|
(PVOID*)&KeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
/* Call the internal API */
|
/* Call the internal API */
|
||||||
Status = CmSaveKey(KeyObject->KeyControlBlock, FileHandle, Flags);
|
Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
|
||||||
|
|
||||||
|
/* Dereference the registry key */
|
||||||
ObDereferenceObject(KeyObject);
|
ObDereferenceObject(KeyObject);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
/* Close the local kernel handle */
|
||||||
|
if (KmFileHandle)
|
||||||
|
ObCloseHandle(KmFileHandle, KernelMode);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1316,10 +1670,11 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
||||||
IN HANDLE LowPrecedenceKeyHandle,
|
IN HANDLE LowPrecedenceKeyHandle,
|
||||||
IN HANDLE FileHandle)
|
IN HANDLE FileHandle)
|
||||||
{
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
KPROCESSOR_MODE PreviousMode;
|
||||||
|
HANDLE KmFileHandle = NULL;
|
||||||
PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
|
PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
|
||||||
PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
|
PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
@ -1334,6 +1689,15 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
||||||
return STATUS_PRIVILEGE_NOT_HELD;
|
return STATUS_PRIVILEGE_NOT_HELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure the target file handle is a kernel handle */
|
||||||
|
Status = CmpConvertHandleToKernelHandle(FileHandle,
|
||||||
|
IoFileObjectType,
|
||||||
|
FILE_WRITE_DATA,
|
||||||
|
PreviousMode,
|
||||||
|
&KmFileHandle);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
/* Verify that the handles are valid and are registry keys */
|
/* Verify that the handles are valid and are registry keys */
|
||||||
Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
|
Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
|
||||||
KEY_READ,
|
KEY_READ,
|
||||||
|
@ -1342,7 +1706,7 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
||||||
(PVOID*)&HighPrecedenceKeyObject,
|
(PVOID*)&HighPrecedenceKeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
goto done;
|
goto Quit;
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
|
Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
|
||||||
KEY_READ,
|
KEY_READ,
|
||||||
|
@ -1351,20 +1715,24 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
||||||
(PVOID*)&LowPrecedenceKeyObject,
|
(PVOID*)&LowPrecedenceKeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
goto done;
|
goto Quit;
|
||||||
|
|
||||||
/* Call the internal API */
|
/* Call the internal API */
|
||||||
Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
|
Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
|
||||||
LowPrecedenceKeyObject->KeyControlBlock,
|
LowPrecedenceKeyObject->KeyControlBlock,
|
||||||
FileHandle);
|
KmFileHandle);
|
||||||
|
|
||||||
done:
|
Quit:
|
||||||
|
/* Dereference the opened key objects */
|
||||||
if (LowPrecedenceKeyObject)
|
if (LowPrecedenceKeyObject)
|
||||||
ObDereferenceObject(LowPrecedenceKeyObject);
|
ObDereferenceObject(LowPrecedenceKeyObject);
|
||||||
|
|
||||||
if (HighPrecedenceKeyObject)
|
if (HighPrecedenceKeyObject)
|
||||||
ObDereferenceObject(HighPrecedenceKeyObject);
|
ObDereferenceObject(HighPrecedenceKeyObject);
|
||||||
|
|
||||||
|
/* Close the local kernel handle */
|
||||||
|
if (KmFileHandle)
|
||||||
|
ObCloseHandle(KmFileHandle, KernelMode);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1392,8 +1760,9 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
IN ULONG Flags)
|
IN ULONG Flags)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES CapturedTargetKey;
|
||||||
UNICODE_STRING ObjectName;
|
UNICODE_STRING ObjectName;
|
||||||
|
HANDLE KmTargetKeyRootDir = NULL;
|
||||||
CM_PARSE_CONTEXT ParseContext = {0};
|
CM_PARSE_CONTEXT ParseContext = {0};
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
PCM_KEY_BODY KeyBody = NULL;
|
PCM_KEY_BODY KeyBody = NULL;
|
||||||
|
@ -1420,18 +1789,15 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
sizeof(OBJECT_ATTRIBUTES),
|
sizeof(OBJECT_ATTRIBUTES),
|
||||||
sizeof(ULONG));
|
sizeof(ULONG));
|
||||||
|
|
||||||
ObjectAttributes = *TargetKey;
|
CapturedTargetKey = *TargetKey;
|
||||||
|
|
||||||
/* Probe the string */
|
/* Probe the string */
|
||||||
ProbeForReadUnicodeString(&TargetKey->ObjectName);
|
ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName);
|
||||||
|
|
||||||
ObjectName = *TargetKey->ObjectName;
|
|
||||||
|
|
||||||
ProbeForRead(ObjectName.Buffer,
|
ProbeForRead(ObjectName.Buffer,
|
||||||
ObjectName.Length,
|
ObjectName.Length,
|
||||||
sizeof(WCHAR));
|
sizeof(WCHAR));
|
||||||
|
|
||||||
ObjectAttributes.ObjectName = &ObjectName;
|
CapturedTargetKey.ObjectName = &ObjectName;
|
||||||
}
|
}
|
||||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
|
@ -1443,38 +1809,54 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Save the target attributes directly */
|
/* Save the target attributes directly */
|
||||||
ObjectAttributes = *TargetKey;
|
CapturedTargetKey = *TargetKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure the target key root directory handle is a kernel handle */
|
||||||
|
Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
KEY_WRITE,
|
||||||
|
PreviousMode,
|
||||||
|
&KmTargetKeyRootDir);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
|
||||||
|
CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
|
||||||
|
|
||||||
/* Setup the parse context */
|
/* Setup the parse context */
|
||||||
ParseContext.CreateOperation = TRUE;
|
ParseContext.CreateOperation = TRUE;
|
||||||
ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
|
ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
|
||||||
|
|
||||||
/* Do the create */
|
/* Do the create */
|
||||||
Status = ObOpenObjectByName(&ObjectAttributes,
|
/* Open a local handle to the key */
|
||||||
|
Status = ObOpenObjectByName(&CapturedTargetKey,
|
||||||
CmpKeyObjectType,
|
CmpKeyObjectType,
|
||||||
KernelMode,
|
KernelMode,
|
||||||
NULL,
|
NULL,
|
||||||
KEY_WRITE,
|
KEY_WRITE,
|
||||||
&ParseContext,
|
&ParseContext,
|
||||||
&Handle);
|
&Handle);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Reference the key object */
|
||||||
|
Status = ObReferenceObjectByHandle(Handle,
|
||||||
|
KEY_WRITE,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
KernelMode,
|
||||||
|
(PVOID*)&KeyBody,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* Return if failure encountered */
|
/* Close the handle */
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
ObCloseHandle(Handle, KernelMode);
|
||||||
|
}
|
||||||
|
|
||||||
/* Reference it */
|
/* Close the local kernel handle */
|
||||||
Status = ObReferenceObjectByHandle(Handle,
|
if (KmTargetKeyRootDir)
|
||||||
KEY_WRITE,
|
ObCloseHandle(KmTargetKeyRootDir, KernelMode);
|
||||||
CmpKeyObjectType,
|
|
||||||
KernelMode,
|
|
||||||
(PVOID *)&KeyBody,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Close the handle */
|
/* Return if a failure was encountered */
|
||||||
ZwClose(Handle);
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
/* Return if failure encountered */
|
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
|
||||||
|
|
||||||
/* Acquire the lock depending on flags */
|
/* Acquire the lock depending on flags */
|
||||||
if (Flags == REG_FORCE_UNLOAD)
|
if (Flags == REG_FORCE_UNLOAD)
|
||||||
|
@ -1506,7 +1888,7 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
{
|
{
|
||||||
/* Return appropriate status */
|
/* Return appropriate status */
|
||||||
Status = STATUS_KEY_DELETED;
|
Status = STATUS_KEY_DELETED;
|
||||||
goto Quickie;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if it's a read-only key */
|
/* Check if it's a read-only key */
|
||||||
|
@ -1514,21 +1896,27 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
{
|
{
|
||||||
/* Return appropriate status */
|
/* Return appropriate status */
|
||||||
Status = STATUS_ACCESS_DENIED;
|
Status = STATUS_ACCESS_DENIED;
|
||||||
goto Quickie;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the internal API */
|
/* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
|
||||||
Status = CmUnloadKey(KeyBody->KeyControlBlock,
|
Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
|
||||||
Flags);
|
|
||||||
|
|
||||||
/* Check if we failed, but really need to succeed */
|
/* Check if we failed, but really need to succeed */
|
||||||
if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
|
if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
|
||||||
{
|
{
|
||||||
/* TODO: We should perform another attempt here */
|
/* TODO: We should perform another attempt here */
|
||||||
ASSERT(FALSE);
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If CmUnloadKey failed we need to unlock registry ourselves */
|
/* If CmUnloadKey() failed we need to unlock registry ourselves */
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
if (Flags != REG_FORCE_UNLOAD)
|
if (Flags != REG_FORCE_UNLOAD)
|
||||||
|
@ -1544,7 +1932,7 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
CmpUnlockRegistry();
|
CmpUnlockRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
Quickie:
|
Quit:
|
||||||
/* Dereference the key */
|
/* Dereference the key */
|
||||||
ObDereferenceObject(KeyBody);
|
ObDereferenceObject(KeyBody);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue