SIGN IN SIGN UP

Reject device control requests above PASSIVE_LEVEL

IOCTL_PIO_LOAD_BINARY runs the module signature check inline on the
calling thread: vm_load_binary_internal calls check_signature, which
calls calculate_sha256 and verify_sig, which call
BCryptOpenAlgorithmProvider, BCryptCreateHash and BCryptImportKeyPair.
Those require PASSIVE_LEVEL. IOCTL_PIO_EXECUTE_FN has the same
requirement one step removed, since vm_execute_function takes the
context's FAST_MUTEX.

Nothing checked. A kernel-mode sender that built the request with
IoBuildDeviceIoControlRequest and issued it at DISPATCH_LEVEL went
straight into CNG at the wrong IRQL.

Guard the whole IRP_MJ_DEVICE_CONTROL arm rather than the two ioctls,
so a new ioctl cannot be added without the check. IRP_MJ_CREATE and
IRP_MJ_CLOSE are deliberately left alone: CREATE only returns success,
and failing CLOSE would leak the context and its pool.

No user-mode caller is affected -- a device control IRP that originates
from NtDeviceIoControlFile is always dispatched at PASSIVE_LEVEL.
Confirmed by running the full test module against the installed build:
ioctl_test_callback and ioctl_test both return success and PawnIOUtil
exits 0.

The rejection itself is not measured. Producing a DISPATCH_LEVEL sender
means a second driver, and the obvious way to write one is a trap: an
IRP built with a stack-local KEVENT and IO_STATUS_BLOCK is completed by
a special kernel APC that runs after the frame is gone, which bugchecks
0x1E in nt!KiApcInterrupt with the caller's stack already destroyed. It
is not worth another kernel probe to observe a four-line guard, so this
rests on the code and on the regression run above.
N
namazso committed
9d2780667690ede585bbe86ac4f7ded6960d3b01
Parent: 46a58a4