WMI fails

Hello all.

I am playing with WMI implementing simple data provider. With the following MOF:

class WmiCls0
{
[key, read]
string InstanceName;

[read] boolean Active;

[WmiDataId(3),
Description(“The Answer to the Ultimate Question”)]
uint32 TheAnswer;

[WmiDataId(2),
Description(“The Data”)]
uint32 TheData;

[WmiDataId(1),
Description(“The Question to the Ultimate Question”)]
uint32 TheQuestion;

[WmiDataId(4),
Description(“The question to the Ultimate Question”)]
string TheQuestionText;
};

The driver gets request about size of data available in DpWmiQueryDataBlock. Driver fails the IRP with status STATUS_BUFFER_TOO_SMALL and BufferUsed of 0x4E. The next request supplies buffer of size 0x98 (why this strange number?). The driver fills the buffer as following:

86706c48 0000000d 00000011 0000002a 00440018
86706c58 00660065 00750061 0074006c 00540020
86706c68 00780065 00310074 0000000d 00000011
86706c78 0000002a 00440018 00660065 00750061
86706c88 0074006c 00540020 00780065 00720074

The buffer contains two instances of class WmiCls0 with data
0xD,
0x11,
0x2A.
“Default Text”

The the driver complete the IRP with success and BufferUsed = 0x4E. The client application (I use WMI Explorer) messages error saying ‘Invalid object’. I also tried to run the following script:

Set Service = GetObject(“winmgmts:{impersonationLevel=impersonate}!root/wmi”)

Set enumSet = Service.InstancesOf (“WmiCls0”)
for each instance in enumSet
MsgBox(" InstanceName=" & instance.InstanceName)
next 'instance

and get the following error message:


Windows Script Host

Script: F:\1.vbs
Line: 5
Char: 1
Error: 0x8004100F
Code: 8004100F
Source: (null)


OK

Ok, I give up. No ideas why the client fails to read the information. The instances look good, aligned and so on. What may be a problem here?


Thaking In Advance,
Mikae.

Are you handling wmi irps directly or using some abstraction like wmilib or a port driver? Are you using pdo naming or static naming?

d

debt from my phone


From: xxxxx@yahoo.com
Sent: 6/24/2012 2:14 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] WMI fails

Hello all.

I am playing with WMI implementing simple data provider. With the following MOF:

class WmiCls0
{
[key, read]
string InstanceName;

[read] boolean Active;

[WmiDataId(3),
Description(“The Answer to the Ultimate Question”)]
uint32 TheAnswer;

[WmiDataId(2),
Description(“The Data”)]
uint32 TheData;

[WmiDataId(1),
Description(“The Question to the Ultimate Question”)]
uint32 TheQuestion;

[WmiDataId(4),
Description(“The question to the Ultimate Question”)]
string TheQuestionText;
};

The driver gets request about size of data available in DpWmiQueryDataBlock. Driver fails the IRP with status STATUS_BUFFER_TOO_SMALL and BufferUsed of 0x4E. The next request supplies buffer of size 0x98 (why this strange number?). The driver fills the buffer as following:

86706c48 0000000d 00000011 0000002a 00440018
86706c58 00660065 00750061 0074006c 00540020
86706c68 00780065 00310074 0000000d 00000011
86706c78 0000002a 00440018 00660065 00750061
86706c88 0074006c 00540020 00780065 00720074

The buffer contains two instances of class WmiCls0 with data
0xD,
0x11,
0x2A.
“Default Text”

The the driver complete the IRP with success and BufferUsed = 0x4E. The client application (I use WMI Explorer) messages error saying ‘Invalid object’. I also tried to run the following script:

Set Service = GetObject(“winmgmts:{impersonationLevel=impersonate}!root/wmi”)

Set enumSet = Service.InstancesOf (“WmiCls0”)
for each instance in enumSet
MsgBox(" InstanceName=" & instance.InstanceName)
next 'instance

and get the following error message:


Windows Script Host

Script: F:\1.vbs
Line: 5
Char: 1
Error: 0x8004100F
Code: 8004100F
Source: (null)


OK

Ok, I give up. No ideas why the client fails to read the information. The instances look good, aligned and so on. What may be a problem here?


Thaking In Advance,
Mikae.


NTDEV is sponsored by OSR

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

Ah, sorry, didn’t write. I use WMILIB and static naming. Here goes my registration handler:

NTSTATUS WmiQueryRegInfo(PDEVICE_OBJECT pDeviceObject,
PULONG pulFlags,
PUNICODE_STRING pusInstName,
PUNICODE_STRING *ppusRegPath,
PUNICODE_STRING pusResName,
PDEVICE_OBJECT *ppPdo)
{
NTSTATUS status;

DbgPrint(“WmiQueryRegInfo - begins\n”);

status = STATUS_SUCCESS;

pusInstName ->Buffer = (PWCH)ExAllocatePool(NonPagedPool, wcslen(pwchWmiBaseName) * sizeof(WCHAR) + sizeof(WCHAR));

if (!pusInstName ->Buffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;

goto LocRet;
}

*pulFlags |= WMIREG_FLAG_INSTANCE_BASENAME;

pusInstName ->MaximumLength = wcslen(pwchWmiBaseName) * sizeof(WCHAR);

pusInstName ->Length = pusInstName ->MaximumLength;

wcscpy(pusInstName ->Buffer, pwchWmiBaseName);

*ppusRegPath = &usRegPath;

*ppPdo = NULL;

RtlInitUnicodeString(pusResName, L"MofResource");

LocRet:
DbgPrint(“WmiQueryRegInfo - ends\n”);

return status;
}

You’re only using 0x23 bytes of the buffer. Why you’re saying 0x4E?

Alex, there are two instances of the class (as I wrote above). Each instance is 0x26 bytes. Because of alignment of each instance by 8, I use 0x4E bytes of buffer.

Pretty sure that pusInstName ->Length should not include the null character

d

debt from my phone


From: xxxxx@yahoo.com
Sent: 6/25/2012 4:29 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] WMI fails

Ah, sorry, didn’t write. I use WMILIB and static naming. Here goes my registration handler:

NTSTATUS WmiQueryRegInfo(PDEVICE_OBJECT pDeviceObject,
PULONG pulFlags,
PUNICODE_STRING pusInstName,
PUNICODE_STRING *ppusRegPath,
PUNICODE_STRING pusResName,
PDEVICE_OBJECT *ppPdo)
{
NTSTATUS status;

DbgPrint(“WmiQueryRegInfo - begins\n”);

status = STATUS_SUCCESS;

pusInstName ->Buffer = (PWCH)ExAllocatePool(NonPagedPool, wcslen(pwchWmiBaseName) * sizeof(WCHAR) + sizeof(WCHAR));

if (!pusInstName ->Buffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;

goto LocRet;
}

*pulFlags |= WMIREG_FLAG_INSTANCE_BASENAME;

pusInstName ->MaximumLength = wcslen(pwchWmiBaseName) * sizeof(WCHAR);

pusInstName ->Length = pusInstName ->MaximumLength;

wcscpy(pusInstName ->Buffer, pwchWmiBaseName);

*ppusRegPath = &usRegPath;

*ppPdo = NULL;

RtlInitUnicodeString(pusResName, L"MofResource");

LocRet:
DbgPrint(“WmiQueryRegInfo - ends\n”);

return status;
}


NTDEV is sponsored by OSR

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

Do you fill InstanceLengthArray?

Alex, thank you, I think I forgot to fill the array while was concentrated on another things. Will check later today.

Doron Holan wrote:

Pretty sure that pusInstName ->Length should not include the null
character

It doesn’t. The allocated space has room for it, and he copies it, but
Length and MaximumLength don’t include it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

If you ask for 0x26 bytes, you get 0x26 bytes. Any remaining space is not
valid for use. So you cannot “use” 0x4E bytes of buffer, you may only
“use” 0x26, no matter what you think you might have been given. Many test
and support tools will fill the remainder in with a special pattern and
expect to find that special pattern on release, so you can never, ever,
depend on having more space than you asked for. When they find the
pattern damaged, they will report a buffer overrun. I think DV does this.
I know in application space this happens.
joe

Alex, there are two instances of the class (as I wrote above). Each
instance is 0x26 bytes. Because of alignment of each instance by 8, I use
0x4E bytes of buffer.


NTDEV is sponsored by OSR

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

Ok, now it works, thank you Alex. I forgot to fill pulInstLength array. It is a bit strange that I see “MofResource” as 2nd instance’s name (the 1st instance’s is name is WMI_BASENAME), but everything else looks good, just have to debug the naming issue.

Joseph, I didn’t get what you mean. Instance’s size is 0x26. Due to alignment by 8 two instances require 0x4E bytes. This is what I return to WMILIB and get magic number 0x98 as buffer size. Pretty enough to copy all my instances with alignment.

Generally, it is considered poor practice if you have two objects of size
A and size B to allocate one chunk of memory that holds both, and handle
the internal alignment yourself. If you have two objects, you should acc
the allocator twice, once for each of them. The result is code that is
gratuitously complex, and probably fragile and unmaintainable. What is it
you think you are accomplishing by storing both objects in one memory
block? If you “Efficiency, not having to call the allocator twice” then
how many millions of times do you allocate and free these objects? (Note
that if the number is not an integer multiple of millions, you are
unlikely to be saving anything).

Drivers have enough intrinsic complexity that you should not introduce any
unless there is a compelling reason to do so. If you do not have
performance data, then there is zero evidence for adding complexity, and
zero is far from “compelling”.
joe

Ok, now it works, thank you Alex. I forgot to fill pulInstLength array. It
is a bit strange that I see “MofResource” as 2nd instance’s name (the 1st
instance’s is name is WMI_BASENAME), but everything else looks good, just
have to debug the naming issue.

Joseph, I didn’t get what you mean. Instance’s size is 0x26. Due to
alignment by 8 two instances require 0x4E bytes. This is what I return to
WMILIB and get magic number 0x98 as buffer size. Pretty enough to copy all
my instances with alignment.


NTDEV is sponsored by OSR

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

>Generally, it is considered poor practice if you have two objects of size A and size B to allocate one chunk of memory that holds both, and handle the internal alignment yourself. If you have two objects, you should call the allocator twice, once for each of them.

This is WMILIB, it sets the rules. And the rule is that for all instances query, the results are returned in a single buffer.

It was not at all clear what was going on here. I will go back and
re-read the question.

Note that I have actually seen people do what I described; I once spent 13
hours of CPU Runtime finding and fixing a bug cause by this
“optimization”. I worked out that the microseconds saved by the hack
would require that we run the program 24/7 for 13 years to break even with
the CPU time lost in finding the bug.

Sorry for the confusion.
joe

>Generally, it is considered poor practice if you have two objects of size
> A and size B to allocate one chunk of memory that holds both, and handle
> the internal alignment yourself. If you have two objects, you should
> call the allocator twice, once for each of them.

This is WMILIB, it sets the rules. And the rule is that for all instances
query, the results are returned in a single buffer.


NTDEV is sponsored by OSR

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

This is the way wmi works, wmilib and others have to deal with it and abstract it as best they can. wmilib is pretty raw and doesn’t abstract much, otoh kmdf models instances as their own objects and handles the one buffer for all objects underneath the covers…but only exposes pdo naming, not static naming

d

debt from my phone


From: xxxxx@flounder.com
Sent: 6/25/2012 6:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] WMI fails

Generally, it is considered poor practice if you have two objects of size
A and size B to allocate one chunk of memory that holds both, and handle
the internal alignment yourself. If you have two objects, you should acc
the allocator twice, once for each of them. The result is code that is
gratuitously complex, and probably fragile and unmaintainable. What is it
you think you are accomplishing by storing both objects in one memory
block? If you “Efficiency, not having to call the allocator twice” then
how many millions of times do you allocate and free these objects? (Note
that if the number is not an integer multiple of millions, you are
unlikely to be saving anything).

Drivers have enough intrinsic complexity that you should not introduce any
unless there is a compelling reason to do so. If you do not have
performance data, then there is zero evidence for adding complexity, and
zero is far from “compelling”.
joe

Ok, now it works, thank you Alex. I forgot to fill pulInstLength array. It
is a bit strange that I see “MofResource” as 2nd instance’s name (the 1st
instance’s is name is WMI_BASENAME), but everything else looks good, just
have to debug the naming issue.

Joseph, I didn’t get what you mean. Instance’s size is 0x26. Due to
alignment by 8 two instances require 0x4E bytes. This is what I return to
WMILIB and get magic number 0x98 as buffer size. Pretty enough to copy all
my instances with alignment.


NTDEV is sponsored by OSR

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


NTDEV is sponsored by OSR

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

I find that a lot of interfaces have this horrendous defect: they were
designed by people who appear to be very inexperienced, so the interfaces
are so bizarre that it is next to impossible to abstract anything from
them. What is strange is that the earlier parts of Windows seem to show
much more careful design and thoughtfulness than later additions, which
seem to be thrown together late at night, with no actual design review
process interfering with the implementation.
joe

This is the way wmi works, wmilib and others have to deal with it and
abstract it as best they can. wmilib is pretty raw and doesn’t abstract
much, otoh kmdf models instances as their own objects and handles the one
buffer for all objects underneath the covers…but only exposes pdo
naming, not static naming

d

debt from my phone


From: xxxxx@flounder.com
Sent: 6/25/2012 6:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] WMI fails

Generally, it is considered poor practice if you have two objects of size
A and size B to allocate one chunk of memory that holds both, and handle
the internal alignment yourself. If you have two objects, you should acc
the allocator twice, once for each of them. The result is code that is
gratuitously complex, and probably fragile and unmaintainable. What is it
you think you are accomplishing by storing both objects in one memory
block? If you “Efficiency, not having to call the allocator twice” then
how many millions of times do you allocate and free these objects? (Note
that if the number is not an integer multiple of millions, you are
unlikely to be saving anything).

Drivers have enough intrinsic complexity that you should not introduce any
unless there is a compelling reason to do so. If you do not have
performance data, then there is zero evidence for adding complexity, and
zero is far from “compelling”.
joe

> Ok, now it works, thank you Alex. I forgot to fill pulInstLength array.
> It
> is a bit strange that I see “MofResource” as 2nd instance’s name (the
> 1st
> instance’s is name is WMI_BASENAME), but everything else looks good,
> just
> have to debug the naming issue.
>
> Joseph, I didn’t get what you mean. Instance’s size is 0x26. Due to
> alignment by 8 two instances require 0x4E bytes. This is what I return
> to
> WMILIB and get magic number 0x98 as buffer size. Pretty enough to copy
> all
> my instances with alignment.
>
> —
> NTDEV is sponsored by OSR
>
> 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
>


NTDEV is sponsored by OSR

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


NTDEV is sponsored by OSR

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

Another warning:

If you target Win2003 and build with its WMILIB from the DDK, beware that there may be a bug in it, although I only saw it in SCSIWMI flavor of it. Not sure if their codebases are any related.

Anyway, original Win2003 SCSIWMI.LIB x64 will crash if you try to return more than 16 or 17 instances. The threshold may be higher in 32 bit lib. This happened because some internal variable was of UCHAR size.

Later “Fixed” SCSIWMI.LIB had a bug in ScsiPortWmiSetInstanceName and/or ScsiPortWmiSetData, in which BufferAwail returned incorrect. You have to check your data address against original buffer address and length to avoid the buffer overflow. Usually this is not a problem when the data query is done one time with a small buffer, and the second time with a buffer of size you request. This becomes a problem, though, when the size of required buffer increased between these calls (new instance appeared, or something else changed). I’ve had a support case about that; never heard about any resolution.