Crash after ObQueryNameString

Hey guys,

I have a file system driver that has implemented a RegistryCallback via CmRegisterCallbackEx.

When I get the callback, I attempt to get the name of the registry object using
ObQueryNameString. It returns STATUS_SUCCESS, I check for null on the returned string (and it isn’t), and then I attempt to do a string compare on it, at which time I get a bugcheck 135.

I assume I’m accessing unpaged memory by running past the end of the string, but I’m doing everything I can to guard against that. What’s even stranger is when I analyze the crash dump (full crash dump, not just kernel) in WinDBG, the string’s value is
“0xfffff8800a4f6b60 "--- memory read error at address 0x000007fef98f9178 —” struct _UNICODE_STRING *". I am unsure whether that is WinDBG, or what I was actually given at runtime.

Below is the code:

pRegDeleteValueKeyInfo = (REG_DELETE_VALUE_KEY_INFORMATION *)Argument2;
OBJECT_NAME_INFORMATION *pObjectNameInfo = (OBJECT_NAME_INFORMATION *)pExtension->deviceHeap;

if ( ObQueryNameString( pRegDeleteValueKeyInfo->Object, pObjectNameInfo, DEVICE_HEAP_SIZE, &returnLength ) != STATUS_SUCCESS ) break;

if ( !pObjectNameInfo->Name.Buffer ) break;

if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L"\REGISTRY\", pObjectNameInfo->Name.Length / sizeof( WHCAR ) ) )

pExtension->deviceHeap is basically a scratch buffer 2kb in size that I use in place of memory allocation. When I evaluate that in WinDBG, as a WCHAR *, it looks fine.
One thing to note, however, is that if I cast it to a UNICODE_STRING *, I do get another ‘memory read error’ value. Not sure if this is related.

I’m at a loss as to why this would crash, since I’m testing for a valid return and using the provided length of the buffer (not assuming null terminated).

Any help would be GREATLY appreciated.

Thank you!

> if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L"\REGISTRY\",

pObjectNameInfo->Name.Length / sizeof( WHCAR ) ) )

I guess it is reading pObjectNameInfo->Name.Length / sizeof(WCHAR) bytes
beyond L"\REGISTRY\" . Look, you have ptr1 and ptr2 and size of ptr1 which
is s1. You pass ptr1 and ptr2 into function f(…) and specify to check size
s1. But what if data pointed by ptr2 is less than s1?

I would change this code to the following:

if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L"\REGISTRY\“,
min(pObjectNameInfo->Name.Length / sizeof( WHCAR ),
sizeof(L”\REGISTRY\")/sizeof(WCHAR)) ) )

where min is a macro which takes minimum from two values, i.e.

#define min(a, b) (((a) < (b)) ? (a) : (b))


Volodymyr

a écrit dans le message de groupe de discussion :
xxxxx@ntdev…
> Hey guys,
>
> I have a file system driver that has implemented a RegistryCallback via
> CmRegisterCallbackEx.
>
> When I get the callback, I attempt to get the name of the registry object
> using
> ObQueryNameString. It returns STATUS_SUCCESS, I check for null on the
> returned string (and it isn’t), and then I attempt to do a string compare
> on it, at which time I get a bugcheck 135.
>
> I assume I’m accessing unpaged memory by running past the end of the
> string, but I’m doing everything I can to guard against that. What’s even
> stranger is when I analyze the crash dump (full crash dump, not just
> kernel) in WinDBG, the string’s value is
> “0xfffff8800a4f6b60 "--- memory read error at address <br>&gt; 0x000007fef98f9178 —” struct _UNICODE_STRING *“. I am unsure whether
> that is WinDBG, or what I was actually given at runtime.
>
> Below is the code:
>
> pRegDeleteValueKeyInfo = (REG_DELETE_VALUE_KEY_INFORMATION *)Argument2;
> OBJECT_NAME_INFORMATION *pObjectNameInfo = (OBJECT_NAME_INFORMATION
> *)pExtension->deviceHeap;
>
> if ( ObQueryNameString( pRegDeleteValueKeyInfo->Object, pObjectNameInfo,
> DEVICE_HEAP_SIZE, &returnLength ) != STATUS_SUCCESS ) break;
>
> if ( !pObjectNameInfo->Name.Buffer ) break;
>
> if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L”\REGISTRY\",
> pObjectNameInfo->Name.Length / sizeof( WHCAR ) ) )
>
> pExtension->deviceHeap is basically a scratch buffer 2kb in size that I
> use in place of memory allocation. When I evaluate that in WinDBG, as a
> WCHAR *, it looks fine.
> One thing to note, however, is that if I cast it to a UNICODE_STRING *, I
> do get another ‘memory read error’ value. Not sure if this is related.
>
> I’m at a loss as to why this would crash, since I’m testing for a valid
> return and using the provided length of the buffer (not assuming null
> terminated).
>
> Any help would be GREATLY appreciated.
>
> Thank you!
>

A few things:

First, please provide the full !analyze -v output so that we can see for
ourselves…

if ( ObQueryNameString( pRegDeleteValueKeyInfo->Object, pObjectNameInfo,
DEVICE_HEAP_SIZE, &returnLength ) !>= STATUS_SUCCESS ) break;

You should be checking for NT_SUCCESS, not just STATUS_SUCCESS. Not the bug
here, but just a general recommendation.

if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L"\REGISTRY\",
pObjectNameInfo->Name.Length / sizeof( >WHCAR ) ) )

I try to always use the Rtl routines when working with UNICODE_STRINGS, it’s
what they’re there for and makes it clear that the strings are not NULL
terminated. So, something like:

DECLARE_UNICODE_STRING(RegistryPrefix, L"\REGISTRY\");
if (RtlPrefixString(&RegistryPrefix, &uniString, TRUE)) {
do stuff…
}

So now you don’t have to worry about going off the end of the world on
either string.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> Hey guys,
>
> I have a file system driver that has implemented a RegistryCallback via
> CmRegisterCallbackEx.
>
> When I get the callback, I attempt to get the name of the registry object
> using
> ObQueryNameString. It returns STATUS_SUCCESS, I check for null on the
> returned string (and it isn’t), and then I attempt to do a string compare
> on it, at which time I get a bugcheck 135.
>
> I assume I’m accessing unpaged memory by running past the end of the
> string, but I’m doing everything I can to guard against that. What’s even
> stranger is when I analyze the crash dump (full crash dump, not just
> kernel) in WinDBG, the string’s value is
> “0xfffff8800a4f6b60 "--- memory read error at address <br>&gt; 0x000007fef98f9178 —” struct _UNICODE_STRING *“. I am unsure whether
> that is WinDBG, or what I was actually given at runtime.
>
> Below is the code:
>
> pRegDeleteValueKeyInfo = (REG_DELETE_VALUE_KEY_INFORMATION *)Argument2;
> OBJECT_NAME_INFORMATION *pObjectNameInfo = (OBJECT_NAME_INFORMATION
> *)pExtension->deviceHeap;
>
> if ( ObQueryNameString( pRegDeleteValueKeyInfo->Object, pObjectNameInfo,
> DEVICE_HEAP_SIZE, &returnLength ) != STATUS_SUCCESS ) break;
>
> if ( !pObjectNameInfo->Name.Buffer ) break;
>
> if ( !_wcsnicmp( pObjectNameInfo->Name.Buffer, L”\REGISTRY\",
> pObjectNameInfo->Name.Length / sizeof( WHCAR ) ) )
>
> pExtension->deviceHeap is basically a scratch buffer 2kb in size that I
> use in place of memory allocation. When I evaluate that in WinDBG, as a
> WCHAR *, it looks fine.
> One thing to note, however, is that if I cast it to a UNICODE_STRING *, I
> do get another ‘memory read error’ value. Not sure if this is related.
>
> I’m at a loss as to why this would crash, since I’m testing for a valid
> return and using the provided length of the buffer (not assuming null
> terminated).
>
> Any help would be GREATLY appreciated.
>
> Thank you!
>