Reading pageable memory at HIGH_LEVEL

Forum for discussion about kernel-mode development.
Post Reply
pwl
Posts: 6
Joined: Sat Jul 01, 2017 7:44 pm

Reading pageable memory at HIGH_LEVEL

Post by pwl » Fri Jul 07, 2017 6:22 pm

I've a small hypervisor that is able to intercept some exceptions. Let's call it exception EXC. When EXC is raised in kernelmode, hypervisor gets control via VmExit and I'm able to dereference memory at GUEST_RIP (pointing to kernelspace) to find out what instruction raised EXC. When GUEST_RIP points to userspace, attempts to deref this memory ends with bugcheck 0xD1:

Code: Select all

The DRIVER_IRQL_NOT_LESS_OR_EQUAL bug check has a value of 0x000000D1. This indicates that a kernel-mode driver attempted to access pageable memory at a process IRQL that was too high.
My questions are:
1. Is it safe to simply dereference kernel memory inside a kernel driver?
2. How to solve the bugcheck issue?
3. Assuming GUEST_RIP points to userspace, is it necessary to set cr3 to GUEST_CR3 before reading GUEST_RIP memory? Guest's RIP comes from a random userspace process and each process has its own cr3 value.

pwl
Posts: 6
Joined: Sat Jul 01, 2017 7:44 pm

Re: Reading pageable memory at HIGH_LEVEL

Post by pwl » Sun Jul 09, 2017 9:30 am

I tried this:

Code: Select all


NTSTATUS
ReadPageableMemory(
	PVOID VirtualAddress,
	ULONG Length,
	PUCHAR DestBuffer
)
{
	mdl = IoAllocateMdl(VirtualAddress, Length, FALSE, FALSE, NULL);
	if (!mdl)
	{
		...
	}
	try {		
		MmProbeAndLockPages(mdl, UserMode, IoReadAccess);
	}
	except(EXCEPTION_EXECUTE_HANDLER)
	{
		...
	}
	SrcBuffer = MmGetSystemAddressForMdlSafe(mdl, HighPagePriority | MdlMappingNoExecute);
	if (!SrcBuffer) {
		...
	}
	RtlCopyMemory(DestBuffer, SrcBuffer, Length);
	MmUnlockPages(mdl);
	IoFreeMdl(mdl);
        ...
I invoke it like this

Code: Select all

KeLowerIrql(GuestIrql);
HostCr3 = __readcr3();
__writecr3(VmxRead(GUEST_CR3));
ReadPageableMemory((PVOID)GuestRip, sizeof(GuestInstrBuf), GuestInstrBuf);
KeRaiseIrql(HIGH_LEVEL, &GuestIrql);
__writecr3(HostCr3);
The result is, the hypervisor works for some time (seconds), then either:
- vmware hangs
- VmxReads from VMCS start to fail without providing error codes
- BugCheck 101 happens with processors stuck in ReadPageableMemory (apparently TLB flushes happen inside and it's time consuming)

I just need to read few bytes to identify the instruction at GuestRIP.

User avatar
m5home
Posts: 82
Joined: Wed Jun 06, 2012 1:21 am

Re: Reading pageable memory at HIGH_LEVEL

Post by m5home » Sat Sep 02, 2017 1:50 pm

I don't think anyone can read the pageable memory when IRQL is higher than APC_LEVEL.
The woman of my avatar: MiYue, the first empress dowager of China. In the TV series "The Legend of MiYue", my favourite movie star SunLi plays MiYue.

User avatar
Vrtule
Posts: 455
Joined: Sat Mar 13, 2010 9:14 pm
Location: Czech Republic
Contact:

Re: Reading pageable memory at HIGH_LEVEL

Post by Vrtule » Sat Sep 02, 2017 2:38 pm

1) No, the restrictions are the same as for user mode memory – you cannot safely dereference pageable kernel memory at IRQL >= DISPATCH_LEVEL.
2) your routine actually does it – you can describe the target memory region by a MDL and lock the region, so the memory won't go away (into the page file etc.). However, you need to do this at reasonably low IRQL and you still may run into a bugcheck if the target memory region does not exist.

Why is your hypervisor running at IRQL = HIGH_LEVEL?

Post Reply