BCryptGenRandom with paged buffer

Hello,

I have problem with BCryptGenRandom using paged buffer. The function is called at PASSIVE_LEVEL with buffer allocated from paged pool. But the data are copied at DISPATCH_LEVEL - sometimes I receive bugcheck IRQL_NOT_LESS_OR_EQUAL, IRQL 2.
It seems that buffer is used under spinlock.

I think it is not normal behaviour.

Petr Borsodi

Post the !analyze -v output.

-scott
OSR
@OSRDrivers

wrote in message news:xxxxx@ntdev…

Hello,

I have problem with BCryptGenRandom using paged buffer. The function is
called at PASSIVE_LEVEL with buffer allocated from paged pool. But the data
are copied at DISPATCH_LEVEL - sometimes I receive bugcheck
IRQL_NOT_LESS_OR_EQUAL, IRQL 2.
It seems that buffer is used under spinlock.

I think it is not normal behaviour.

Petr Borsodi

kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

IRQL_NOT_LESS_OR_EQUAL (a)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If a kernel debugger is available get the stack backtrace.
Arguments:
Arg1: 99ebb000, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000001, bitfield :
bit 0 : value 0 = read operation, 1 = write operation
bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status)
Arg4: 82c598bc, address which referenced memory

Debugging Details:

WRITE_ADDRESS: 99ebb000 Paged pool

CURRENT_IRQL: 2

FAULTING_IP:
nt!memcpy+11c
82c598bc 89448ff0 mov dword ptr [edi+ecx*4-10h],eax

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0xA

PROCESS_NAME: System

TRAP_FRAME: 8812b690 – (.trap 0xffffffff8812b690)
ErrCode = 00000002
eax=1a6aea16 ebx=8a743f50 ecx=00000004 edx=00000000 esi=8812b944 edi=99ebb000
eip=82c598bc esp=8812b704 ebp=8812b70c iopl=0 nv up ei ng nz ac pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010297
nt!memcpy+0x11c:
82c598bc 89448ff0 mov dword ptr [edi+ecx*4-10h],eax ds:0023:99ebb000=???
Resetting default scope

LAST_CONTROL_TRANSFER: from 82cf7e71 to 82c86394

STACK_TEXT:
8812b25c 82cf7e71 00000003 e08703b4 00000065 nt!RtlpBreakWithStatusInstruction
8812b2ac 82cf896d 00000003 99ebb000 82c598bc nt!KiBugCheckDebugBreak+0x1c
8812b670 82c617eb 0000000a 99ebb000 00000002 nt!KeBugCheck2+0x68b
8812b670 82c598bc 0000000a 99ebb000 00000002 nt!KiTrap0E+0x2cf
8812b70c 85c39647 99ebb000 8812b944 00000010 nt!memcpy+0x11c
8812b958 85c28423 8a743f50 00000000 00000000 cng!AesCtrRng_Generate+0x100
8812ba28 85c290a3 8a743f30 99ebb000 00000400 cng!MSCryptAesCtrGen+0x127
8812ba64 85c129c3 94c332d0 99ebb000 00010000 cng!MSCryptGenRandom+0xd9
8812ba80 85c1892f 8a6b20a0 99ebb000 00010000 cng!BCryptGenRandom+0x5d
8812baa0 85c1299b 99ebb000 00010000 00000000 cng!BCryptGenSystemPreferredRandom+0x2b
8812bab8 95601074 00000000 99ebb000 00010000 cng!BCryptGenRandom+0x35
8812bad8 82dbe728 8a6b2f38 8616e000 00000000 TestBC!DriverEntry+0x54 [c:\tmp\testbc\testbc.c @ 33]
8812bcbc 82dbc499 00000001 00000000 8812bce4 nt!IopLoadDriver+0x7ed
8812bd00 82c88f2b 807ffcd0 00000000 857aed48 nt!IopLoadUnloadDriver+0x70
8812bd50 82e2966d 00000001 e0870c88 00000000 nt!ExpWorkerThread+0x10d
8812bd90 82cdb0d9 82c88e1e 00000001 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19

STACK_COMMAND: kb

FOLLOWUP_IP:
cng!AesCtrRng_Generate+100
85c39647 0175b4 add dword ptr [ebp-4Ch],esi

SYMBOL_STACK_INDEX: 5

SYMBOL_NAME: cng!AesCtrRng_Generate+100

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: cng

IMAGE_NAME: cng.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 4a5bc427

FAILURE_BUCKET_ID: 0xA_VRF_cng!AesCtrRng_Generate+100

BUCKET_ID: 0xA_VRF_cng!AesCtrRng_Generate+100

Followup: MachineOwner

kd> !pool 0x99ebb000
Pool page 99ebb000 region is Paged pool
*99ebb000 : large page allocation, Tag is CBsT, size is 0x10000 bytes

Show your code from DriverEntry to the function call.

p = ExAllocatePoolWithTag (PagedPool, 65536, ‘TsBC’);

for (i = 0; i < 10000; i++) {
BCryptGenRandom (NULL, p, 65536, BCRYPT_USE_SYSTEM_PREFERRED_RNG);

}

ExFreePool (p);

Are you sure you are allowed to pass a null BCRYPT_ALG_HANDLE ?

Create one and do not set the BCRYPT_PROV_DISPATCH flag on BCryptOpenAlgorithmProvider invocation. You will see what happens.

The docs for this parameter look pretty broken. They show this as an in/out… I have trouble believing the function writes to hAlgorithm.

I expect what they meant is “In, Opt”… Note the SAL notation for this function:

_checkReturn
NTSTATUS
WINAPI
BCryptGenRandom(
__in_opt BCRYPT_ALG_HANDLE hAlgorithm,
__inout_bcount_full(cbBuffer) PUCHAR pbBuffer,
__in ULONG cbBuffer,
__in ULONG dwFlags);

Peter
OSR
@OSRDrivers

The doc says:

BCRYPT_USE_SYSTEM_PREFERRED_RNG
0x00000002
Use the system-preferred random number generator algorithm. The hAlgorithm parameter must be NULL.

What OS do you test?

The OS is Windows 7, x86
The problem occurs on Windows 7, amd64 too.

Are you setting BCRYPT_PROV_DISPATCH? If so, it’s reasonable to assume that
CNG would access your buffer at DISPATCH_LEVEL.

-scott
OSR
@OSRDrivers

wrote in message news:xxxxx@ntdev…

The OS is Windows 7, x86
The problem occurs on Windows 7, amd64 too.

>Are you setting BCRYPT_PROV_DISPATCH? If so, it’s reasonable to assume that
CNG would access your buffer at DISPATCH_LEVEL.

My understanding of that flag is that it just causes the provider’s pageable code section to be locked in memory.

xxxxx@i.cz wrote:

p = ExAllocatePoolWithTag (PagedPool, 65536, ‘TsBC’);

for (i = 0; i < 10000; i++) {
BCryptGenRandom (NULL, p, 65536, BCRYPT_USE_SYSTEM_PREFERRED_RNG);

}

ExFreePool (p);

That’s probably not ALL the code in DriverEntry. Can you show us the rest?


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

The code seems legitimate according to the documentation as Mr. Grig stated.

The only left question mark is: what library are you linking the driver with ?


To call this function in kernel mode, use Cng.lib, which is part of the Driver Development Kit (DDK). For more information, see WDK and Developer Tools.

Windows Server 2008 and Windows Vista: To call this function in kernel mode, use Ksecdd.lib.

PS: Why are you using 64Ko of paged memory to generate a random number ? Wouldn’t 8 bytes on the stack or from non-paged pool be enougth ?

No, I don’t use BCRYPT_PROV_DISPATCH flag (it is used via BCryptOpenAlgorithmProvider function).
I haven’t requirement to call BCryptGenRandom at the DISPATCH_LEVEL so I use simple form of call (without explicit using BCryptOpenAlgorithmProvider, with BCRYPT_USE_SYSTEM_PREFERRED_RNG flag).
The docs says “buffer must be non-paged” only for case of using function at the DISPATCH_LEVEL
(see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375458(v=vs.85).aspx )

It means that I can use paged buffer otherwise.

IMHO it is simply a bug in the CNG driver. As is apparent from the analysis the data are copied to the output buffer at the DISPATCH_LEVEL. This is obvious mistake.

It is possible it is documentation bug only, but I think it is too restrictive to call BCryptGenRandom with non-paged buffers only.

Reads this thread someone from Microsoft?

The disassembly shows that when the default algorithm provider is used, BCryptGenRandom gets called from a critical region while sharing a resource lite. I think the paging must still work in that context.

  1. Check that you actually call the function on PASSIVE_LEVEL.
  2. Set a breakpoint at cng!AesCtrRng_Generate and see at which IRQL it gets called by your driver.

Sometimes the path of least resistance is to accommodate the observed
behavior rather than insist that the behavior conform to how it is
documented.

Allocate using nonpaged pool.

Mark Roddy

On Tue, Nov 25, 2014 at 12:45 PM, wrote:

> No, I don’t use BCRYPT_PROV_DISPATCH flag (it is used via
> BCryptOpenAlgorithmProvider function).
> I haven’t requirement to call BCryptGenRandom at the DISPATCH_LEVEL so I
> use simple form of call (without explicit using
> BCryptOpenAlgorithmProvider, with BCRYPT_USE_SYSTEM_PREFERRED_RNG flag).
> The docs says “buffer must be non-paged” only for case of using function
> at the DISPATCH_LEVEL
> (see
> http://msdn.microsoft.com/en-us/library/windows/desktop/aa375458(v=vs.85).aspx
> )
>
> It means that I can use paged buffer otherwise.
>
> IMHO it is simply a bug in the CNG driver. As is apparent from the
> analysis the data are copied to the output buffer at the DISPATCH_LEVEL.
> This is obvious mistake.
>
> It is possible it is documentation bug only, but I think it is too
> restrictive to call BCryptGenRandom with non-paged buffers only.
>
> Reads this thread someone from Microsoft?
>
>
> —
> 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
>

Or if you don’t know that the buffer you’re using is non-paged you can always lock it down yourself with MmProbeAndLockPages.

-p

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark Roddy
Sent: Tuesday, November 25, 2014 12:59 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] BCryptGenRandom with paged buffer

Sometimes the path of least resistance is to accommodate the observed behavior rather than insist that the behavior conform to how it is documented.

Allocate using nonpaged pool.

Mark Roddy

On Tue, Nov 25, 2014 at 12:45 PM, > wrote:
No, I don’t use BCRYPT_PROV_DISPATCH flag (it is used via BCryptOpenAlgorithmProvider function).
I haven’t requirement to call BCryptGenRandom at the DISPATCH_LEVEL so I use simple form of call (without explicit using BCryptOpenAlgorithmProvider, with BCRYPT_USE_SYSTEM_PREFERRED_RNG flag).
The docs says “buffer must be non-paged” only for case of using function at the DISPATCH_LEVEL
(see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375458(v=vs.85).aspx )

It means that I can use paged buffer otherwise.

IMHO it is simply a bug in the CNG driver. As is apparent from the analysis the data are copied to the output buffer at the DISPATCH_LEVEL. This is obvious mistake.

It is possible it is documentation bug only, but I think it is too restrictive to call BCryptGenRandom with non-paged buffers only.

Reads this thread someone from Microsoft?


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

— 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

>MmProbeAndLockPages.

Am I wrong that this does not make the PTEs nonpaged and does not prevent the BSODs?

The above call will lock pages, but what about PTEs?

I was under impression that PTEs are still considered paged, and thus the BSOD will follow, and that remap of the MDL to system PTEs is a must to really access the pages from DISPATCH_LEVEL.

Am I wrong?


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

I was going to write a reply that started with the equivalent of “Bah! Ridiculous! How could you SAY such a thing, Mr. Shatskih!!”

But the more I thought about it, the more it caused me to wonder. PTEs are certainly pageable, I think we all know and agree that.

And thinking of the cases when we exercise this capability most regularly: MmGetSystemAddressForMdl (the address comes from system space, and the PTE is presumably not paged) and DMA (we don’t care about the PTE, just the page itself).

Mr. Shatskih may very well be correct. A little edge condition that I had not previously considered.

Peter
OSR
@OSRDrivers