CmUnRegisterCallback and ObjectContext cleanup callback

Hi,

My driver filter registry calls for specific process. Problem is that CmUnRegisterCallback don’t call cleanup callbacks for object context so my driver leak resources.
Thanks for your help.

NTSTATUS
DriverEntry (
In PDRIVER_OBJECT DriverObject,
In PUNICODE_STRING RegistryPath
)
{
// other initialization routines

//
CmRegisterCallbackEx(EsuregCallback,
&RegistryAltitude,
EsuData.DriverObject,
NULL,
&RegistryCookie,
NULL);
}

NTSTATUS
EsuregCallback(
In PVOID CallbackContext,
In_opt PVOID Argument1,
In_opt PVOID Argument2
)
{
NTSTATUS status = STATUS_SUCCESS;
REG_NOTIFY_CLASS notifyClass;

UNREFERENCED_PARAMETER(CallbackContext);

notifyClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;

switch(notifyClass) {

case RegNtPreOpenKeyEx:
status = EsuregPreOpenKeyEx( (PREG_OPEN_KEY_INFORMATION) Argument2);
break;
case RegNtPostOpenKeyEx:
status = EsuregPostOpenKeyEx((PREG_POST_OPERATION_INFORMATION) Argument2);
break;
default:
break;
}

return status;
}

NTSTATUS
EsuregPreOpenKeyEx(
In PREG_OPEN_KEY_INFORMATION PreOpenInfo
)
{
PESU_REGISTRY_CONTEXT regContext = NULL;

// my context structure
regContext = ExAllocatePoolWithTag(PagedPool, sizeof(ESU_REGISTRY_CONTEXT), ESU_REG_CONTEXT_TAG);

PreOpenInfo->CallContext = regContext;

return STATUS_SUCCESS;
}

NTSTATUS
EsuregPostOpenKeyEx(
In PREG_POST_OPERATION_INFORMATION PostOpenInfo
)
{
NTSTATUS status = STATUS_SUCCESS;

if (PostOpenInfo->CallContext != NULL) {

if (PostOpenInfo->Status == STATUS_SUCCESS) {

status = CmSetCallbackObjectContext(
PostOpenInfo->Object,
&RegistryCookie,
PostOpenInfo->CallContext,
NULL);

if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(PostOpenInfo->CallContext, ESU_REG_CONTEXT_TAG);
}
else {
InterlockedIncrement(&callbackCounts); // 0 when driver loads
}
}
else {
ExFreePoolWithTag(PostOpenInfo->CallContext, ESU_REG_CONTEXT_TAG);
}
}

return status;
}

NTSTATUS
EsuregObjectContextCleanup(
In PREG_CALLBACK_CONTEXT_CLEANUP_INFORMATION RegCallbackContextCleanupInf
)
{
if (RegCallbackContextCleanupInf->ObjectContext != NULL) {
ExFreePoolWithTag(RegCallbackContextCleanupInf->ObjectContext, ESU_REG_CONTEXT_TAG);
}

InterlockedDecrement(&callbackCounts);
return STATUS_SUCCESS;
}

VOID
EsudrvPortDisconnect(
In_opt PVOID ConnectionCookie
)
{
UNREFERENCED_PARAMETER(ConnectionCookie);

// close client port and other details

//

// Unregister registry filter

if (NT_SUCCESS(CmUnRegisterCallback(RegistryCookie))) {
// callbackCounts = number of leaked context structures
DbgPrint(“Context Cleanup Callbacks %d \n”, callbackCounts );
}
}

Why would you expect it to cleanup the context. This is a PVOID there is
nothing that says it points to valid memory. You need to build your own
mechanism for tracking and freeing this memory, such as keeping it in a
linked list.

Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@centrum.sk
Sent: Wednesday, February 12, 2014 11:25 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] CmUnRegisterCallback and ObjectContext cleanup callback

Hi,

My driver filter registry calls for specific process. Problem is that
CmUnRegisterCallback don’t call cleanup callbacks for object context so my
driver leak resources.
Thanks for your help.

NTSTATUS
DriverEntry (
In PDRIVER_OBJECT DriverObject,
In PUNICODE_STRING RegistryPath
)
{
// other initialization routines

//
CmRegisterCallbackEx(EsuregCallback,
&RegistryAltitude,
EsuData.DriverObject,
NULL,
&RegistryCookie,
NULL);
}

NTSTATUS
EsuregCallback(
In PVOID CallbackContext,
In_opt PVOID Argument1,
In_opt PVOID Argument2
)
{
NTSTATUS status = STATUS_SUCCESS;
REG_NOTIFY_CLASS notifyClass;

UNREFERENCED_PARAMETER(CallbackContext);

notifyClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;

switch(notifyClass) {

case RegNtPreOpenKeyEx:
status = EsuregPreOpenKeyEx( (PREG_OPEN_KEY_INFORMATION)
Argument2);
break;
case RegNtPostOpenKeyEx:
status =
EsuregPostOpenKeyEx((PREG_POST_OPERATION_INFORMATION) Argument2);
break;
default:
break;
}

return status;
}

NTSTATUS
EsuregPreOpenKeyEx(
In PREG_OPEN_KEY_INFORMATION PreOpenInfo
)
{
PESU_REGISTRY_CONTEXT regContext = NULL;

// my context structure
regContext = ExAllocatePoolWithTag(PagedPool,
sizeof(ESU_REGISTRY_CONTEXT), ESU_REG_CONTEXT_TAG);

PreOpenInfo->CallContext = regContext;

return STATUS_SUCCESS;
}

NTSTATUS
EsuregPostOpenKeyEx(
In PREG_POST_OPERATION_INFORMATION PostOpenInfo
)
{
NTSTATUS status = STATUS_SUCCESS;

if (PostOpenInfo->CallContext != NULL) {

if (PostOpenInfo->Status == STATUS_SUCCESS) {

status = CmSetCallbackObjectContext(
PostOpenInfo->Object,
&RegistryCookie,
PostOpenInfo->CallContext,
NULL);

if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(PostOpenInfo->CallContext,
ESU_REG_CONTEXT_TAG);
}
else {
InterlockedIncrement(&callbackCounts); // 0
when driver loads
}
}
else {
ExFreePoolWithTag(PostOpenInfo->CallContext,
ESU_REG_CONTEXT_TAG);
}
}

return status;
}

NTSTATUS
EsuregObjectContextCleanup(
In PREG_CALLBACK_CONTEXT_CLEANUP_INFORMATION
RegCallbackContextCleanupInf
)
{
if (RegCallbackContextCleanupInf->ObjectContext != NULL) {

ExFreePoolWithTag(RegCallbackContextCleanupInf->ObjectContext,
ESU_REG_CONTEXT_TAG);
}

InterlockedDecrement(&callbackCounts);
return STATUS_SUCCESS;
}

VOID
EsudrvPortDisconnect(
In_opt PVOID ConnectionCookie
)
{
UNREFERENCED_PARAMETER(ConnectionCookie);

// close client port and other details

//

// Unregister registry filter

if (NT_SUCCESS(CmUnRegisterCallback(RegistryCookie))) {
// callbackCounts = number of leaked context structures
DbgPrint(“Context Cleanup Callbacks %d \n”, callbackCounts
);
}
}


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Oops, sorry. EsuregCallback was not correct.

NTSTATUS EsuregCallback( In PVOID CallbackContext, In_opt PVOID Argument1, In_opt PVOID Argument2 )
{
NTSTATUS status = STATUS_SUCCESS;
REG_NOTIFY_CLASS notifyClass;
UNREFERENCED_PARAMETER(CallbackContext);

notifyClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;

switch(notifyClass)
{
case RegNtPreOpenKeyEx:
status = EsuregPreOpenKeyEx( (PREG_OPEN_KEY_INFORMATION) Argument2); break;

case RegNtPostOpenKeyEx:
status = EsuregPostOpenKeyEx((PREG_POST_OPERATION_INFORMATION) Argument2); break;

case RegNtCallbackObjectContextCleanup:
status = EsuregObjectContextCleanup( (PREG_CALLBACK_CONTEXT_CLEANUP_INFORMATION) Argument2); break;

default: break;
}
return status;
}


From documentation:
“If a driver calls CmSetCallbackObjectContext, the driver’s RegistryCallback routine will receive a RegNtCallbackObjectContextCleanup notification after the key object’s handle has been closed or after the driver calls CmUnRegisterCallback to unregister the RegistryCallback routine.”

When my user-mode process close handle, EsuregObjectContextCleanup registry callback is called and everything is OK. But the process is not always so good and close registry key handle. So I think that when CmUnRegisterCallback is called my cleanup routine for this registry objects with object context will be called.