VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp@ 51941

Last change on this file since 51941 was 51941, checked in by vboxsync, 11 years ago

SUPDrv-win.cpp: Use the RTTerm/RTOnce stuff to clean up that default random number generator instance the driver verifier is upset about (leak).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 149.8 KB
Line 
1/* $Id: SUPDrv-win.cpp 51941 2014-07-08 17:50:10Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define IPRT_NT_MAP_TO_ZW
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#include "../SUPDrvInternal.h"
33#include <excpt.h>
34#include <ntimage.h>
35
36#include <iprt/assert.h>
37#include <iprt/avl.h>
38#include <iprt/ctype.h>
39#include <iprt/initterm.h>
40#include <iprt/mem.h>
41#include <iprt/process.h>
42#include <iprt/power.h>
43#include <iprt/spinlock.h>
44#include <iprt/string.h>
45#include <VBox/log.h>
46#include <VBox/err.h>
47
48#include <iprt/asm-amd64-x86.h>
49
50#ifdef VBOX_WITH_HARDENING
51# include "SUPHardenedVerify-win.h"
52#endif
53
54
55/*******************************************************************************
56* Defined Constants And Macros *
57*******************************************************************************/
58/** The support service name. */
59#define SERVICE_NAME "VBoxDrv"
60/** The Pool tag (VBox). */
61#define SUPDRV_NT_POOL_TAG 'xoBV'
62
63/** Win32 device name for system access. */
64#define DEVICE_NAME_SYS "\\\\.\\VBoxDrv"
65/** NT device name for system access. */
66#define DEVICE_NAME_NT_SYS L"\\Device\\VBoxDrv"
67/** Win Symlink name for system access. */
68#define DEVICE_NAME_DOS_SYS L"\\DosDevices\\VBoxDrv"
69
70/** Win32 device name for user access. */
71#define DEVICE_NAME_USR "\\\\.\\VBoxDrvU"
72/** NT device name for user access. */
73#define DEVICE_NAME_NT_USR L"\\Device\\VBoxDrvU"
74/** Win Symlink name for user access. */
75#define DEVICE_NAME_DOS_USR L"\\DosDevices\\VBoxDrvU"
76
77#ifdef VBOX_WITH_HARDENING
78/** Win32 device name for hardened stub access. */
79# define DEVICE_NAME_STUB "\\\\.\\VBoxDrvStub"
80/** NT device name for hardened stub access. */
81# define DEVICE_NAME_NT_STUB L"\\Device\\VBoxDrvStub"
82///** Win Symlink name for hardened stub access. */
83//# define DEVICE_NAME_DOS_STUB L"\\DosDevices\\VBoxDrvStub"
84
85/** Macro for checking for deflecting calls to the stub device. */
86# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
87 do { if ((a_pDevObj) == g_pDevObjStub) supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); } while (0)
88#else
89# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
90#endif
91
92/** Enables the fast I/O control code path. */
93#define VBOXDRV_WITH_FAST_IO
94
95
96/*******************************************************************************
97* Structures and Typedefs *
98*******************************************************************************/
99/**
100 * Device extension used by VBoxDrvU.
101 */
102typedef struct SUPDRVDEVEXTUSR
103{
104 /** Global cookie (same location as in SUPDRVDEVEXT, different value). */
105 uint32_t u32Cookie;
106 /** Pointer to the main driver extension. */
107 PSUPDRVDEVEXT pMainDrvExt;
108} SUPDRVDEVEXTUSR;
109AssertCompileMembersAtSameOffset(SUPDRVDEVEXT, u32Cookie, SUPDRVDEVEXTUSR, u32Cookie);
110/** Pointer to the VBoxDrvU device extension. */
111typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
112/** Value of SUPDRVDEVEXTUSR::u32Cookie. */
113#define SUPDRVDEVEXTUSR_COOKIE UINT32_C(0x12345678)
114
115/** Get the main device extension. */
116#define SUPDRVNT_GET_DEVEXT(pDevObj) \
117 ( pDevObj != g_pDevObjUsr \
118 ? (PSUPDRVDEVEXT)pDevObj->DeviceExtension \
119 : ((PSUPDRVDEVEXTUSR)pDevObj->DeviceExtension)->pMainDrvExt )
120
121#ifdef VBOX_WITH_HARDENING
122
123/**
124 * Device extension used by VBoxDrvS.
125 */
126typedef struct SUPDRVDEVEXTSTUB
127{
128 /** Common header. */
129 SUPDRVDEVEXTUSR Common;
130} SUPDRVDEVEXTSTUB;
131/** Pointer to the VBoxDrvS device extension. */
132typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
133/** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
134#define SUPDRVDEVEXTSTUB_COOKIE UINT32_C(0x90abcdef)
135
136
137/**
138 * The kind of process we're protecting.
139 */
140typedef enum SUPDRVNTPROTECTKIND
141{
142 kSupDrvNtProtectKind_Invalid = 0,
143
144 /** Stub process protection while performing process verification.
145 * Next: StubSpawning (or free) */
146 kSupDrvNtProtectKind_StubUnverified,
147 /** Stub process protection before it creates the VM process.
148 * Next: StubParent, StubDead. */
149 kSupDrvNtProtectKind_StubSpawning,
150 /** Stub process protection while having a VM process as child.
151 * Next: StubDead */
152 kSupDrvNtProtectKind_StubParent,
153 /** Dead stub process. */
154 kSupDrvNtProtectKind_StubDead,
155
156 /** Potential VM process.
157 * Next: VmProcessConfirmed, VmProcessDead. */
158 kSupDrvNtProtectKind_VmProcessUnconfirmed,
159 /** Confirmed VM process.
160 * Next: VmProcessDead. */
161 kSupDrvNtProtectKind_VmProcessConfirmed,
162 /** Dead VM process. */
163 kSupDrvNtProtectKind_VmProcessDead,
164
165 /** End of valid protection kinds. */
166 kSupDrvNtProtectKind_End
167} SUPDRVNTPROTECTKIND;
168
169/**
170 * A NT process protection structure.
171 */
172typedef struct SUPDRVNTPROTECT
173{
174 /** The AVL node core structure. The process ID is the pid. */
175 AVLPVNODECORE AvlCore;
176 /** Magic value (SUPDRVNTPROTECT_MAGIC). */
177 uint32_t volatile u32Magic;
178 /** Reference counter. */
179 uint32_t volatile cRefs;
180 /** The kind of process we're protecting. */
181 SUPDRVNTPROTECTKIND volatile enmProcessKind;
182 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
183 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
184 bool fFirstProcessCreateHandle : 1;
185 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
186 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
187 bool fFirstThreadCreateHandle : 1;
188 /** 8.1: Hack to allow more rights to the handle returned by
189 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
190 bool fCsrssFirstProcessCreateHandle : 1;
191 /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSR
192 * during process creation. Only applicable to VmProcessUnconfirmed. */
193 bool fCsrssFirstProcessDuplicateHandle : 1;
194 /** 7,: Hack to allow the supid themes service duplicate handle privileges to
195 * our process. */
196 bool fThemesFirstProcessCreateHandle : 1;
197
198 /** The parent PID for VM processes, otherwise NULL. */
199 HANDLE hParentPid;
200 /** The PID of the CSRSS process associated with this process. */
201 HANDLE hCsrssPid;
202 /** Pointer to the CSRSS process structure (referenced). */
203 PEPROCESS pCsrssProcess;
204 /** State dependent data. */
205 union
206 {
207 /** A stub process in the StubParent state will keep a reference to a child
208 * while it's in the VmProcessUnconfirmed state so that it can be cleaned up
209 * correctly if things doesn't work out. */
210 struct SUPDRVNTPROTECT *pChild;
211 /** A process in the VmProcessUnconfirmed state will keep a weak
212 * reference to the parent's protection structure so it can clean up the pChild
213 * refernece the parent has to it. */
214 struct SUPDRVNTPROTECT *pParent;
215 } u;
216} SUPDRVNTPROTECT;
217/** Pointer to a NT process protection record. */
218typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
219/** The SUPDRVNTPROTECT::u32Magic value (Robert A. Heinlein). */
220# define SUPDRVNTPROTECT_MAGIC UINT32_C(0x19070707)
221/** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
222# define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
223
224/** Pointer to ObRegisterCallbacks. */
225typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
226/** Pointer to ObUnregisterCallbacks. */
227typedef VOID (NTAPI *PFNOBUNREGISTERCALLBACKS)(PVOID);
228/** Pointer to PsSetCreateProcessNotifyRoutineEx. */
229typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
230/** Pointer to PsReferenceProcessFilePointer. */
231typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
232/** Pointer to PsIsProtectedProcessLight. */
233typedef BOOLEAN (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
234
235#endif /* VBOX_WITH_HARDENINIG */
236
237
238/*******************************************************************************
239* Internal Functions *
240*******************************************************************************/
241static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
242static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
243static NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
244static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
245#ifdef VBOXDRV_WITH_FAST_IO
246static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
247 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
248 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj);
249#endif
250static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
251static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
252static NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
253static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
254static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
255static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
256#ifdef VBOX_WITH_HARDENING
257static NTSTATUS supdrvNtProtectInit(void);
258static void supdrvNtProtectTerm(void);
259static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid,
260 SUPDRVNTPROTECTKIND enmProcessKind, bool fLink);
261static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect);
262static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid);
263static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect);
264static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
265
266static bool supdrvNtIsDebuggerAttached(void);
267#endif
268
269
270/*******************************************************************************
271* Exported Functions *
272*******************************************************************************/
273RT_C_DECLS_BEGIN
274ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
275RT_C_DECLS_END
276
277
278/*******************************************************************************
279* Global Variables *
280*******************************************************************************/
281/** Pointer to the system device instance. */
282static PDEVICE_OBJECT g_pDevObjSys = NULL;
283/** Pointer to the user device instance. */
284static PDEVICE_OBJECT g_pDevObjUsr = NULL;
285#ifdef VBOXDRV_WITH_FAST_IO
286/** Fast I/O dispatch table. */
287static FAST_IO_DISPATCH const g_VBoxDrvFastIoDispatch =
288{
289 /* .SizeOfFastIoDispatch = */ sizeof(g_VBoxDrvFastIoDispatch),
290 /* .FastIoCheckIfPossible = */ NULL,
291 /* .FastIoRead = */ NULL,
292 /* .FastIoWrite = */ NULL,
293 /* .FastIoQueryBasicInfo = */ NULL,
294 /* .FastIoQueryStandardInfo = */ NULL,
295 /* .FastIoLock = */ NULL,
296 /* .FastIoUnlockSingle = */ NULL,
297 /* .FastIoUnlockAll = */ NULL,
298 /* .FastIoUnlockAllByKey = */ NULL,
299 /* .FastIoDeviceControl = */ VBoxDrvNtFastIoDeviceControl,
300 /* .AcquireFileForNtCreateSection = */ NULL,
301 /* .ReleaseFileForNtCreateSection = */ NULL,
302 /* .FastIoDetachDevice = */ NULL,
303 /* .FastIoQueryNetworkOpenInfo = */ NULL,
304 /* .AcquireForModWrite = */ NULL,
305 /* .MdlRead = */ NULL,
306 /* .MdlReadComplete = */ NULL,
307 /* .PrepareMdlWrite = */ NULL,
308 /* .MdlWriteComplete = */ NULL,
309 /* .FastIoReadCompressed = */ NULL,
310 /* .FastIoWriteCompressed = */ NULL,
311 /* .MdlReadCompleteCompressed = */ NULL,
312 /* .MdlWriteCompleteCompressed = */ NULL,
313 /* .FastIoQueryOpen = */ NULL,
314 /* .ReleaseForModWrite = */ NULL,
315 /* .AcquireForCcFlush = */ NULL,
316 /* .ReleaseForCcFlush = */ NULL,
317};
318#endif /* VBOXDRV_WITH_FAST_IO */
319
320#ifdef VBOX_WITH_HARDENING
321/** Pointer to the stub device instance. */
322static PDEVICE_OBJECT g_pDevObjStub = NULL;
323/** Spinlock protecting g_NtProtectTree as well as the releasing of protection
324 * structures. */
325static RTSPINLOCK g_hNtProtectLock = NIL_RTSPINLOCK;
326/** AVL tree of SUPDRVNTPROTECT structures. */
327static AVLPVTREE g_NtProtectTree = NULL;
328/** Cookie returned by ObRegisterCallbacks for the callbacks. */
329static PVOID g_pvObCallbacksCookie = NULL;
330/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
331uint32_t g_uNtVerCombined = 0;
332/** Pointer to ObRegisterCallbacks if available.. */
333static PFNOBREGISTERCALLBACKS g_pfnObRegisterCallbacks = NULL;
334/** Pointer to ObUnregisterCallbacks if available.. */
335static PFNOBUNREGISTERCALLBACKS g_pfnObUnRegisterCallbacks = NULL;
336/** Pointer to PsSetCreateProcessNotifyRoutineEx if available.. */
337static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutineEx = NULL;
338/** Pointer to PsReferenceProcessFilePointer if available. */
339static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
340/** Pointer to PsIsProtectedProcessLight. */
341static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
342
343# ifdef RT_ARCH_AMD64
344extern "C" {
345/** Pointer to KiServiceLinkage (used to fake missing ZwQueryVirtualMemory on
346 * XP64 / W2K3-64). */
347PFNRT g_pfnKiServiceLinkage = NULL;
348/** Pointer to KiServiceInternal (used to fake missing ZwQueryVirtualMemory on
349 * XP64 / W2K3-64) */
350PFNRT g_pfnKiServiceInternal = NULL;
351}
352# endif
353#endif
354
355
356/**
357 * Takes care of creating the devices and their symbolic links.
358 *
359 * @returns NT status code.
360 * @param pDrvObj Pointer to driver object.
361 */
362static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
363{
364 /*
365 * System device.
366 */
367 UNICODE_STRING DevName;
368 RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_SYS);
369 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
370 if (NT_SUCCESS(rcNt))
371 {
372 UNICODE_STRING DosNameSys;
373 RtlInitUnicodeString(&DosNameSys, DEVICE_NAME_DOS_SYS);
374 rcNt = IoCreateSymbolicLink(&DosNameSys, &DevName);
375 if (NT_SUCCESS(rcNt))
376 {
377 /*
378 * User device.
379 */
380 RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_USR);
381 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
382 if (NT_SUCCESS(rcNt))
383 {
384 UNICODE_STRING DosNameUsr;
385 RtlInitUnicodeString(&DosNameUsr, DEVICE_NAME_DOS_USR);
386 rcNt = IoCreateSymbolicLink(&DosNameUsr, &DevName);
387 if (NT_SUCCESS(rcNt))
388 {
389 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
390 pDevExtUsr->pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
391 pDevExtUsr->u32Cookie = SUPDRVDEVEXTUSR_COOKIE;
392
393#ifdef VBOX_WITH_HARDENING
394 /*
395 * Hardened stub device.
396 */
397 RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_STUB);
398 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
399 if (NT_SUCCESS(rcNt))
400 {
401 //UNICODE_STRING DosNameStub;
402 //RtlInitUnicodeString(&DosNameStub, DEVICE_NAME_DOS_STUB);
403 //rcNt = IoCreateSymbolicLink(&DosNameStub, &DevName);
404 if (NT_SUCCESS(rcNt))
405 {
406 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
407 pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
408 pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTSTUB_COOKIE;
409#endif
410
411 /* Done. */
412 return rcNt;
413#ifdef VBOX_WITH_HARDENING
414 }
415
416 /* Bail out. */
417 IoDeleteDevice(g_pDevObjStub);
418 g_pDevObjUsr = NULL;
419 }
420 IoDeleteSymbolicLink(&DosNameUsr);
421#endif
422 }
423 IoDeleteDevice(g_pDevObjUsr);
424 g_pDevObjUsr = NULL;
425 }
426 IoDeleteSymbolicLink(&DosNameSys);
427 }
428 IoDeleteDevice(g_pDevObjSys);
429 g_pDevObjSys = NULL;
430 }
431 return rcNt;
432}
433
434/**
435 * Destroys the devices and links created by vboxdrvNtCreateDevices.
436 */
437static void vboxdrvNtDestroyDevices(void)
438{
439 UNICODE_STRING DosName;
440 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS_SYS);
441 NTSTATUS rcNt = IoDeleteSymbolicLink(&DosName);
442
443 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS_USR);
444 rcNt = IoDeleteSymbolicLink(&DosName);
445
446#ifdef VBOX_WITH_HARDENING
447 //RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS_STUB);
448 //rcNt = IoDeleteSymbolicLink(&DosName);
449#endif
450
451 if (g_pDevObjUsr)
452 {
453 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
454 pDevExtUsr->pMainDrvExt = NULL;
455 }
456#ifdef VBOX_WITH_HARDENING
457 if (g_pDevObjStub)
458 {
459 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
460 pDevExtStub->Common.pMainDrvExt = NULL;
461 }
462#endif
463
464#ifdef VBOX_WITH_HARDENING
465 IoDeleteDevice(g_pDevObjStub);
466 g_pDevObjStub = NULL;
467#endif
468 IoDeleteDevice(g_pDevObjUsr);
469 g_pDevObjUsr = NULL;
470 IoDeleteDevice(g_pDevObjSys);
471 g_pDevObjSys = NULL;
472}
473
474
475/**
476 * Driver entry point.
477 *
478 * @returns appropriate status code.
479 * @param pDrvObj Pointer to driver object.
480 * @param pRegPath Registry base path.
481 */
482ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
483{
484 /*
485 * Sanity checks.
486 */
487#ifdef VBOXDRV_WITH_FAST_IO
488 if (g_VBoxDrvFastIoDispatch.FastIoDeviceControl != VBoxDrvNtFastIoDeviceControl)
489 {
490 DbgPrint("VBoxDrv: FastIoDeviceControl=%p instead of %p\n",
491 g_VBoxDrvFastIoDispatch.FastIoDeviceControl, VBoxDrvNtFastIoDeviceControl);
492 return STATUS_INTERNAL_ERROR;
493 }
494#endif
495
496 /*
497 * Initialize the runtime (IPRT).
498 */
499 NTSTATUS rcNt;
500 int vrc = RTR0Init(0);
501 if (RT_SUCCESS(vrc))
502 {
503 Log(("VBoxDrv::DriverEntry\n"));
504
505#ifdef VBOX_WITH_HARDENING
506 /*
507 * Initialize process protection.
508 */
509 rcNt = supdrvNtProtectInit();
510 if (NT_SUCCESS(rcNt))
511#endif
512 {
513 /*
514 * Create device.
515 * (That means creating a device object and a symbolic link so the DOS
516 * subsystems (OS/2, win32, ++) can access the device.)
517 */
518 rcNt = vboxdrvNtCreateDevices(pDrvObj);
519 if (NT_SUCCESS(rcNt))
520 {
521 /*
522 * Initialize the device extension.
523 */
524 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
525 memset(pDevExt, 0, sizeof(*pDevExt));
526
527 vrc = supdrvInitDevExt(pDevExt, sizeof(SUPDRVSESSION));
528 if (!vrc)
529 {
530 /*
531 * Setup the driver entry points in pDrvObj.
532 */
533 pDrvObj->DriverUnload = VBoxDrvNtUnload;
534 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
535 pDrvObj->MajorFunction[IRP_MJ_CLEANUP] = VBoxDrvNtCleanup;
536 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
537 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
538 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
539 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtNotSupportedStub;
540 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
541
542#ifdef VBOXDRV_WITH_FAST_IO
543 /* Fast I/O to speed up guest execution roundtrips. */
544 pDrvObj->FastIoDispatch = (PFAST_IO_DISPATCH)&g_VBoxDrvFastIoDispatch;
545#endif
546
547 /*
548 * Register ourselves for power state changes. We don't
549 * currently care if this fails.
550 */
551 UNICODE_STRING CallbackName;
552 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
553
554 OBJECT_ATTRIBUTES Attr;
555 InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
556
557 rcNt = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
558 if (rcNt == STATUS_SUCCESS)
559 pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback,
560 VBoxPowerDispatchCallback,
561 g_pDevObjSys);
562
563 /*
564 * Done! Returning success!
565 */
566 Log(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
567 return STATUS_SUCCESS;
568 }
569
570 Log(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
571 rcNt = VBoxDrvNtErr2NtStatus(vrc);
572
573 vboxdrvNtDestroyDevices();
574 }
575#ifdef VBOX_WITH_HARDENING
576 supdrvNtProtectTerm();
577#endif
578 }
579 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
580 RTR0Term();
581 }
582 else
583 {
584 Log(("RTR0Init failed with vrc=%d!\n", vrc));
585 rcNt = VBoxDrvNtErr2NtStatus(vrc);
586 }
587 if (NT_SUCCESS(rcNt))
588 rcNt = STATUS_INVALID_PARAMETER;
589 return rcNt;
590}
591
592
593/**
594 * Unload the driver.
595 *
596 * @param pDrvObj Driver object.
597 */
598void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
599{
600 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
601
602 Log(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
603
604 /* Clean up the power callback registration. */
605 if (pDevExt->hPowerCallback)
606 ExUnregisterCallback(pDevExt->hPowerCallback);
607 if (pDevExt->pObjPowerCallback)
608 ObDereferenceObject(pDevExt->pObjPowerCallback);
609
610 /*
611 * We ASSUME that it's not possible to unload a driver with open handles.
612 */
613 supdrvDeleteDevExt(pDevExt);
614#ifdef VBOX_WITH_HARDENING
615 supdrvNtProtectTerm();
616#endif
617 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
618 RTR0Term();
619 vboxdrvNtDestroyDevices();
620
621 NOREF(pDrvObj);
622}
623
624
625/**
626 * For simplifying request completion into a simple return statement, extended
627 * version.
628 *
629 * @returns rcNt
630 * @param rcNt The status code.
631 * @param uInfo Extra info value.
632 * @param pIrp The IRP.
633 */
634DECLINLINE(NTSTATUS) supdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
635{
636 pIrp->IoStatus.Status = rcNt;
637 pIrp->IoStatus.Information = uInfo;
638 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
639 return rcNt;
640}
641
642
643/**
644 * For simplifying request completion into a simple return statement.
645 *
646 * @returns rcNt
647 * @param rcNt The status code.
648 * @param pIrp The IRP.
649 */
650DECLINLINE(NTSTATUS) supdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
651{
652 return supdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
653}
654
655
656/**
657 * Create (i.e. Open) file entry point.
658 *
659 * @param pDevObj Device object.
660 * @param pIrp Request packet.
661 */
662NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
663{
664 Log(("VBoxDrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
665 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
666 PFILE_OBJECT pFileObj = pStack->FileObject;
667 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
668
669 /*
670 * We are not remotely similar to a directory...
671 * (But this is possible.)
672 */
673 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
674 return supdrvNtCompleteRequest(STATUS_NOT_A_DIRECTORY, pIrp);
675
676 /*
677 * Don't create a session for kernel clients, they'll close the handle
678 * immediately and work with the file object via
679 * VBoxDrvNtInternalDeviceControl. The first request will be one to
680 * create a session.
681 */
682 NTSTATUS rcNt;
683 if (pIrp->RequestorMode == KernelMode)
684 {
685 if (pDevObj == g_pDevObjSys)
686 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
687
688 rcNt = STATUS_ACCESS_DENIED;
689 }
690 else
691 {
692#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
693 /*
694 * Make sure no debuggers are attached to non-user processes.
695 */
696 if ( pDevObj != g_pDevObjUsr
697 && supdrvNtIsDebuggerAttached())
698 {
699 LogRel(("vboxdrv: Process %p is being debugged, access to vboxdrv / vboxdrvu declined.\n",
700 PsGetProcessId(PsGetCurrentProcess())));
701 rcNt = STATUS_TRUST_FAILURE;
702 }
703 else
704#endif
705 {
706 int rc = VINF_SUCCESS;
707
708#ifdef VBOX_WITH_HARDENING
709 /*
710 * Access to the stub device is only granted to processes which
711 * passes verification.
712 *
713 * Note! The stub device has no need for a SUPDRVSESSION structure,
714 * so the it uses the SUPDRVNTPROTECT directly instead.
715 */
716 if (pDevObj == g_pDevObjStub)
717 {
718 PSUPDRVNTPROTECT pNtProtect = NULL;
719 rc = supdrvNtProtectCreate(&pNtProtect, PsGetProcessId(PsGetCurrentProcess()),
720 kSupDrvNtProtectKind_StubUnverified, true /*fLink*/);
721 if (RT_SUCCESS(rc))
722 {
723 rc = supdrvNtProtectFindAssociatedCsrss(pNtProtect);
724 if (RT_SUCCESS(rc))
725 rc = supdrvNtProtectVerifyProcess(pNtProtect);
726 if (RT_SUCCESS(rc))
727 {
728 pFileObj->FsContext = pNtProtect; /* Keeps reference. */
729 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
730 }
731
732 supdrvNtProtectRelease(pNtProtect);
733 }
734 LogRel(("vboxdrv: Declined %p access to VBoxDrvStub: rc=%d\n", PsGetProcessId(PsGetCurrentProcess()), rc));
735 }
736 /*
737 * Unrestricted access is only granted to a process in the
738 * VmProcessUnconfirmed state that checks out correctly and is
739 * allowed to transition to VmProcessConfirmed. Again, only one
740 * session per process.
741 */
742 else if (pDevObj != g_pDevObjUsr)
743 {
744 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(PsGetCurrentProcess()));
745 if (pNtProtect)
746 {
747 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
748 {
749 rc = supdrvNtProtectVerifyProcess(pNtProtect);
750 if (RT_SUCCESS(rc))
751 {
752 /* Create a session. */
753 PSUPDRVSESSION pSession;
754 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/,
755 &pSession);
756 if (RT_SUCCESS(rc))
757 {
758 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
759 supdrvSessionRelease(pSession);
760 if (RT_SUCCESS(rc))
761 {
762 pSession->pNtProtect = pNtProtect; /* Keeps reference. */
763 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
764 }
765 }
766
767 /* No second attempt. */
768 RTSpinlockAcquire(g_hNtProtectLock);
769 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
770 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
771 RTSpinlockRelease(g_hNtProtectLock);
772
773 LogRel(("vboxdrv: supdrvCreateSession failed for process %p: rc=%d.\n",
774 PsGetProcessId(PsGetCurrentProcess()), rc));
775 }
776 else
777 LogRel(("vboxdrv: Process %p failed process verification: rc=%d.\n",
778 PsGetProcessId(PsGetCurrentProcess()), rc));
779 }
780 else
781 {
782 LogRel(("vboxdrv: %p is not a budding VM process (enmProcessKind=%d).\n",
783 PsGetProcessId(PsGetCurrentProcess()), pNtProtect->enmProcessKind));
784 rc = VERR_ACCESS_DENIED;
785 }
786 supdrvNtProtectRelease(pNtProtect);
787 }
788 else
789 {
790 LogRel(("vboxdrv: %p is not a budding VM process.\n", PsGetProcessId(PsGetCurrentProcess())));
791 rc = VERR_ACCESS_DENIED;
792 }
793 }
794 /*
795 * Call common code to create an unprivileged session.
796 */
797 else
798 {
799 PSUPDRVSESSION pSession;
800 rc = supdrvCreateSession(pDevExt, true /*fUser*/, false /*fUnrestricted*/, &pSession);
801 if (RT_SUCCESS(rc))
802 {
803 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
804 supdrvSessionRelease(pSession);
805 if (RT_SUCCESS(rc))
806 {
807 pFileObj->FsContext = pSession; /* Keeps reference. No race. */
808 pSession->pNtProtect = NULL;
809 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
810 }
811 }
812 }
813
814#else /* !VBOX_WITH_HARDENING */
815 /*
816 * Call common code to create a session.
817 */
818 pFileObj->FsContext = NULL;
819 PSUPDRVSESSION pSession;
820 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/, &pSession);
821 if (RT_SUCCESS(rc))
822 {
823 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
824 supdrvSessionRelease(pSession);
825 if (RT_SUCCESS(rc))
826 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
827
828 }
829#endif /* !VBOX_WITH_HARDENING */
830
831 /* bail out */
832 rcNt = VBoxDrvNtErr2NtStatus(rc);
833 }
834 }
835
836 Assert(!NT_SUCCESS(rcNt));
837 pFileObj->FsContext = NULL;
838 return supdrvNtCompleteRequest(rcNt, pIrp); /* Note. the IoStatus is completely ignored on error. */
839}
840
841
842/**
843 * Clean up file handle entry point.
844 *
845 * @param pDevObj Device object.
846 * @param pIrp Request packet.
847 */
848NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
849{
850 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
851 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
852 PFILE_OBJECT pFileObj = pStack->FileObject;
853
854#ifdef VBOX_WITH_HARDENING
855 if (pDevObj == g_pDevObjStub)
856 {
857 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
858 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
859 if (pNtProtect)
860 {
861 supdrvNtProtectRelease(pNtProtect);
862 pFileObj->FsContext = NULL;
863 }
864 }
865 else
866#endif
867 {
868 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
869 (PSUPDRVSESSION *)&pFileObj->FsContext);
870 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
871 if (pSession)
872 {
873 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
874 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
875 }
876 }
877
878 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
879}
880
881
882/**
883 * Close file entry point.
884 *
885 * @param pDevObj Device object.
886 * @param pIrp Request packet.
887 */
888NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
889{
890 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
891 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
892 PFILE_OBJECT pFileObj = pStack->FileObject;
893
894#ifdef VBOX_WITH_HARDENING
895 if (pDevObj == g_pDevObjStub)
896 {
897 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
898 Log(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
899 if (pNtProtect)
900 {
901 supdrvNtProtectRelease(pNtProtect);
902 pFileObj->FsContext = NULL;
903 }
904 }
905 else
906#endif
907 {
908 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
909 (PSUPDRVSESSION *)&pFileObj->FsContext);
910 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
911 if (pSession)
912 {
913 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
914 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
915 }
916 }
917
918 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
919}
920
921
922#ifdef VBOXDRV_WITH_FAST_IO
923/**
924 * Fast I/O device control callback.
925 *
926 * This performs no buffering, neither on the way in or out.
927 *
928 * @returns TRUE if handled, FALSE if the normal I/O control routine should be
929 * called.
930 * @param pFileObj The file object.
931 * @param fWait Whether it's a blocking call
932 * @param pvInput The input buffer as specified by the user.
933 * @param cbInput The size of the input buffer.
934 * @param pvOutput The output buffer as specfied by the user.
935 * @param cbOutput The size of the output buffer.
936 * @param uFunction The function.
937 * @param pIoStatus Where to return the status of the operation.
938 * @param pDevObj The device object..
939 */
940static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
941 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
942 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
943{
944 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
945
946 /*
947 * Check the input a little bit and get a the session references.
948 */
949 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
950 (PSUPDRVSESSION *)&pFileObj->FsContext);
951 if (!pSession)
952 {
953 pIoStatus->Status = STATUS_TRUST_FAILURE;
954 pIoStatus->Information = 0;
955 return TRUE;
956 }
957
958 if (pSession->fUnrestricted)
959 {
960#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
961 if (supdrvNtIsDebuggerAttached())
962 {
963 pIoStatus->Status = STATUS_TRUST_FAILURE;
964 pIoStatus->Information = 0;
965 supdrvSessionRelease(pSession);
966 return TRUE;
967 }
968#endif
969
970 /*
971 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
972 * the session and iCmd, and does not return anything.
973 */
974 if ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
975 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
976 || uCmd == SUP_IOCTL_FAST_DO_NOP)
977 {
978 int rc = supdrvIOCtlFast(uCmd, (unsigned)(uintptr_t)pvOutput/* VMCPU id */, pDevExt, pSession);
979 pIoStatus->Status = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
980 pIoStatus->Information = 0; /* Could be used to pass rc if we liked. */
981 supdrvSessionRelease(pSession);
982 return TRUE;
983 }
984 }
985
986 /*
987 * The normal path.
988 */
989 NTSTATUS rcNt;
990 unsigned cbOut = 0;
991 int rc = 0;
992 Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
993 pDevExt, uCmd, pvInput, cbInput, pvOutput, cbOutput, pSession));
994
995# ifdef RT_ARCH_AMD64
996 /* Don't allow 32-bit processes to do any I/O controls. */
997 if (!IoIs32bitProcess(NULL))
998# endif
999 {
1000 /*
1001 * In this fast I/O device control path we have to do our own buffering.
1002 */
1003 /* Verify that the I/O control function matches our pattern. */
1004 if ((uCmd & 0x3) == METHOD_BUFFERED)
1005 {
1006 /* Get the header so we can validate it a little bit against the
1007 parameters before allocating any memory kernel for the reqest. */
1008 SUPREQHDR Hdr;
1009 if (cbInput >= sizeof(Hdr) && cbOutput >= sizeof(Hdr))
1010 {
1011 __try
1012 {
1013 RtlCopyMemory(&Hdr, pvInput, sizeof(Hdr));
1014 rcNt = STATUS_SUCCESS;
1015 }
1016 __except(EXCEPTION_EXECUTE_HANDLER)
1017 {
1018 rcNt = GetExceptionCode();
1019 }
1020 }
1021 else
1022 rcNt = STATUS_INVALID_PARAMETER;
1023 if (NT_SUCCESS(rcNt))
1024 {
1025 /* Verify that the sizes in the request header are correct. */
1026 ULONG cbBuf = RT_MAX(cbInput, cbOutput);
1027 if ( cbInput == Hdr.cbIn
1028 && cbOutput == Hdr.cbOut
1029 && cbBuf < _1M*16)
1030 {
1031 /* Allocate a buffer and copy all the input into it. */
1032 PSUPREQHDR pHdr = (PSUPREQHDR)ExAllocatePoolWithTag(NonPagedPool, cbBuf, 'VBox');
1033 if (pHdr)
1034 {
1035 __try
1036 {
1037 RtlCopyMemory(pHdr, pvInput, cbInput);
1038 if (cbInput < cbBuf)
1039 RtlZeroMemory((uint8_t *)pHdr + cbInput, cbBuf - cbInput);
1040 rcNt = STATUS_SUCCESS;
1041 }
1042 __except(EXCEPTION_EXECUTE_HANDLER)
1043 {
1044 rcNt = GetExceptionCode();
1045 }
1046 }
1047 else
1048 rcNt = STATUS_NO_MEMORY;
1049 if (NT_SUCCESS(rcNt))
1050 {
1051 /*
1052 * Now call the common code to do the real work.
1053 */
1054 rc = supdrvIOCtl(uCmd, pDevExt, pSession, pHdr);
1055 if (RT_SUCCESS(rc))
1056 {
1057 /*
1058 * Copy back the result.
1059 */
1060 cbOut = pHdr->cbOut;
1061 if (cbOut > cbOutput)
1062 {
1063 cbOut = cbOutput;
1064 OSDBGPRINT(("VBoxDrvNtFastIoDeviceControl: too much output! %#x > %#x; uCmd=%#x!\n",
1065 pHdr->cbOut, cbOut, uCmd));
1066 }
1067 if (cbOut)
1068 {
1069 __try
1070 {
1071 RtlCopyMemory(pvOutput, pHdr, cbOut);
1072 rcNt = STATUS_SUCCESS;
1073 }
1074 __except(EXCEPTION_EXECUTE_HANDLER)
1075 {
1076 rcNt = GetExceptionCode();
1077 }
1078 }
1079 else
1080 rcNt = STATUS_SUCCESS;
1081 }
1082 else if (rc == VERR_INVALID_PARAMETER)
1083 rcNt = STATUS_INVALID_PARAMETER;
1084 else
1085 rcNt = STATUS_NOT_SUPPORTED;
1086 Log2(("VBoxDrvNtFastIoDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1087 }
1088 ExFreePoolWithTag(pHdr, 'VBox');
1089 }
1090 else
1091 {
1092 Log(("VBoxDrvNtFastIoDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1093 uCmd, Hdr.cbIn, Hdr.cbOut, cbInput, cbOutput));
1094 rcNt = STATUS_INVALID_PARAMETER;
1095 }
1096 }
1097 }
1098 else
1099 {
1100 Log(("VBoxDrvNtFastIoDeviceControl: not buffered request (%#x) - not supported\n", uCmd));
1101 rcNt = STATUS_NOT_SUPPORTED;
1102 }
1103 }
1104# ifdef RT_ARCH_AMD64
1105 else
1106 {
1107 Log(("VBoxDrvNtFastIoDeviceControl: WOW64 req - not supported\n"));
1108 rcNt = STATUS_NOT_SUPPORTED;
1109 }
1110# endif
1111
1112 /* complete the request. */
1113 pIoStatus->Status = rcNt;
1114 pIoStatus->Information = cbOut;
1115 supdrvSessionRelease(pSession);
1116 return TRUE; /* handled. */
1117}
1118#endif /* VBOXDRV_WITH_FAST_IO */
1119
1120
1121/**
1122 * Device I/O Control entry point.
1123 *
1124 * @param pDevObj Device object.
1125 * @param pIrp Request packet.
1126 */
1127NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1128{
1129 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
1130
1131 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1132 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1133 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1134 (PSUPDRVSESSION *)&pStack->FileObject->FsContext);
1135
1136 if (!RT_VALID_PTR(pSession))
1137 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1138
1139 /*
1140 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1141 * the session and iCmd, and does not return anything.
1142 */
1143 if (pSession->fUnrestricted)
1144 {
1145#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1146 if (supdrvNtIsDebuggerAttached())
1147 {
1148 supdrvSessionRelease(pSession);
1149 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1150 }
1151#endif
1152
1153 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
1154 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1155 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
1156 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
1157 {
1158 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
1159
1160 /* Complete the I/O request. */
1161 supdrvSessionRelease(pSession);
1162 return supdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
1163 }
1164 }
1165
1166 return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
1167}
1168
1169
1170/**
1171 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
1172 *
1173 * @returns NT status code.
1174 *
1175 * @param pDevObj Device object.
1176 * @param pSession The session.
1177 * @param pIrp Request packet.
1178 * @param pStack The stack location containing the DeviceControl parameters.
1179 */
1180static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
1181{
1182 NTSTATUS rcNt;
1183 unsigned cbOut = 0;
1184 int rc = 0;
1185 Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1186 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1187 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1188 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1189
1190#ifdef RT_ARCH_AMD64
1191 /* Don't allow 32-bit processes to do any I/O controls. */
1192 if (!IoIs32bitProcess(pIrp))
1193#endif
1194 {
1195 /* Verify that it's a buffered CTL. */
1196 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1197 {
1198 /* Verify that the sizes in the request header are correct. */
1199 PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1200 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1201 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
1202 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
1203 {
1204 /*
1205 * Do the job.
1206 */
1207 rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
1208 if (!rc)
1209 {
1210 rcNt = STATUS_SUCCESS;
1211 cbOut = pHdr->cbOut;
1212 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
1213 {
1214 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1215 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
1216 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
1217 }
1218 }
1219 else
1220 rcNt = STATUS_INVALID_PARAMETER;
1221 Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1222 }
1223 else
1224 {
1225 Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1226 pStack->Parameters.DeviceIoControl.IoControlCode,
1227 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
1228 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
1229 pStack->Parameters.DeviceIoControl.InputBufferLength,
1230 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1231 rcNt = STATUS_INVALID_PARAMETER;
1232 }
1233 }
1234 else
1235 {
1236 Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
1237 pStack->Parameters.DeviceIoControl.IoControlCode));
1238 rcNt = STATUS_NOT_SUPPORTED;
1239 }
1240 }
1241#ifdef RT_ARCH_AMD64
1242 else
1243 {
1244 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
1245 rcNt = STATUS_NOT_SUPPORTED;
1246 }
1247#endif
1248
1249 /* complete the request. */
1250 pIrp->IoStatus.Status = rcNt;
1251 pIrp->IoStatus.Information = cbOut;
1252 supdrvSessionRelease(pSession);
1253 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1254 return rcNt;
1255}
1256
1257
1258/**
1259 * Internal Device I/O Control entry point, used for IDC.
1260 *
1261 * @param pDevObj Device object.
1262 * @param pIrp Request packet.
1263 */
1264NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1265{
1266 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
1267
1268 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1269 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1270 PFILE_OBJECT pFileObj = pStack ? pStack->FileObject : NULL;
1271 PSUPDRVSESSION pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
1272 NTSTATUS rcNt;
1273 unsigned cbOut = 0;
1274 int rc = 0;
1275 Log2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1276 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1277 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1278 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1279
1280 /* Verify that it's a buffered CTL. */
1281 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1282 {
1283 /* Verify the pDevExt in the session. */
1284 if ( pStack->Parameters.DeviceIoControl.IoControlCode != SUPDRV_IDC_REQ_CONNECT
1285 ? VALID_PTR(pSession) && pSession->pDevExt == pDevExt
1286 : !pSession
1287 )
1288 {
1289 /* Verify that the size in the request header is correct. */
1290 PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1291 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1292 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cb
1293 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
1294 {
1295 /*
1296 * Call the generic code.
1297 *
1298 * Note! Connect and disconnect requires some extra attention
1299 * in order to get the session handling right.
1300 */
1301 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1302 pFileObj->FsContext = NULL;
1303
1304 rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
1305 if (!rc)
1306 {
1307 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
1308 pFileObj->FsContext = ((PSUPDRVIDCREQCONNECT)pHdr)->u.Out.pSession;
1309
1310 rcNt = STATUS_SUCCESS;
1311 cbOut = pHdr->cb;
1312 }
1313 else
1314 {
1315 rcNt = STATUS_INVALID_PARAMETER;
1316 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1317 pFileObj->FsContext = pSession;
1318 }
1319 Log2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
1320 }
1321 else
1322 {
1323 Log(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
1324 pStack->Parameters.DeviceIoControl.IoControlCode,
1325 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
1326 pStack->Parameters.DeviceIoControl.InputBufferLength,
1327 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1328 rcNt = STATUS_INVALID_PARAMETER;
1329 }
1330 }
1331 else
1332 rcNt = STATUS_NOT_SUPPORTED;
1333 }
1334 else
1335 {
1336 Log(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
1337 pStack->Parameters.DeviceIoControl.IoControlCode));
1338 rcNt = STATUS_NOT_SUPPORTED;
1339 }
1340
1341 /* complete the request. */
1342 pIrp->IoStatus.Status = rcNt;
1343 pIrp->IoStatus.Information = cbOut;
1344 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1345 return rcNt;
1346}
1347
1348
1349/**
1350 * Stub function for functions we don't implemented.
1351 *
1352 * @returns STATUS_NOT_SUPPORTED
1353 * @param pDevObj Device object.
1354 * @param pIrp IRP.
1355 */
1356NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1357{
1358 Log(("VBoxDrvNtNotSupportedStub\n"));
1359 NOREF(pDevObj);
1360
1361 pIrp->IoStatus.Information = 0;
1362 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1363 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1364
1365 return STATUS_NOT_SUPPORTED;
1366}
1367
1368
1369/**
1370 * ExRegisterCallback handler for power events
1371 *
1372 * @param pCallbackContext User supplied parameter (pDevObj)
1373 * @param pArgument1 First argument
1374 * @param pArgument2 Second argument
1375 */
1376VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2)
1377{
1378 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;
1379
1380 Log(("VBoxPowerDispatchCallback: %x %x\n", pArgument1, pArgument2));
1381
1382 /* Power change imminent? */
1383 if ((unsigned)pArgument1 == PO_CB_SYSTEM_STATE_LOCK)
1384 {
1385 if ((unsigned)pArgument2 == 0)
1386 Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
1387 else
1388 Log(("VBoxPowerDispatchCallback: resumed!\n"));
1389
1390 /* Inform any clients that have registered themselves with IPRT. */
1391 RTPowerSignalEvent(((unsigned)pArgument2 == 0) ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
1392 }
1393}
1394
1395
1396/**
1397 * Called to clean up the session structure before it's freed.
1398 *
1399 * @param pDevExt The device globals.
1400 * @param pSession The session that's being cleaned up.
1401 */
1402void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1403{
1404#ifdef VBOX_WITH_HARDENING
1405 if (pSession->pNtProtect)
1406 {
1407 supdrvNtProtectRelease(pSession->pNtProtect);
1408 pSession->pNtProtect = NULL;
1409 }
1410#endif
1411}
1412
1413
1414void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1415{
1416 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1417}
1418
1419
1420void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1421{
1422 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1423}
1424
1425
1426/**
1427 * Initializes any OS specific object creator fields.
1428 */
1429void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1430{
1431 NOREF(pObj);
1432 NOREF(pSession);
1433}
1434
1435
1436/**
1437 * Checks if the session can access the object.
1438 *
1439 * @returns true if a decision has been made.
1440 * @returns false if the default access policy should be applied.
1441 *
1442 * @param pObj The object in question.
1443 * @param pSession The session wanting to access the object.
1444 * @param pszObjName The object name, can be NULL.
1445 * @param prc Where to store the result when returning true.
1446 */
1447bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1448{
1449 NOREF(pObj);
1450 NOREF(pSession);
1451 NOREF(pszObjName);
1452 NOREF(prc);
1453 return false;
1454}
1455
1456
1457/**
1458 * Force async tsc mode (stub).
1459 */
1460bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1461{
1462 return false;
1463}
1464
1465
1466#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
1467#define MY_SystemUnloadGdiDriverInformation 27
1468
1469typedef struct MYSYSTEMGDIDRIVERINFO
1470{
1471 UNICODE_STRING Name; /**< In: image file name. */
1472 PVOID ImageAddress; /**< Out: the load address. */
1473 PVOID SectionPointer; /**< Out: section object. */
1474 PVOID EntryPointer; /**< Out: entry point address. */
1475 PVOID ExportSectionPointer; /**< Out: export directory/section. */
1476 ULONG ImageLength; /**< Out: SizeOfImage. */
1477} MYSYSTEMGDIDRIVERINFO;
1478
1479extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
1480
1481int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1482{
1483 pImage->pvNtSectionObj = NULL;
1484 pImage->hMemLock = NIL_RTR0MEMOBJ;
1485
1486#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
1487# ifndef RT_ARCH_X86
1488# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
1489# endif
1490 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
1491 return VERR_NOT_SUPPORTED;
1492
1493#else
1494 /*
1495 * Convert the filename from DOS UTF-8 to NT UTF-16.
1496 */
1497 size_t cwcFilename;
1498 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
1499 if (RT_FAILURE(rc))
1500 return rc;
1501
1502 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
1503 if (!pwcsFilename)
1504 return VERR_NO_TMP_MEMORY;
1505
1506 pwcsFilename[0] = '\\';
1507 pwcsFilename[1] = '?';
1508 pwcsFilename[2] = '?';
1509 pwcsFilename[3] = '\\';
1510 PRTUTF16 pwcsTmp = &pwcsFilename[4];
1511 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
1512 if (RT_SUCCESS(rc))
1513 {
1514 /*
1515 * Try load it.
1516 */
1517 MYSYSTEMGDIDRIVERINFO Info;
1518 RtlInitUnicodeString(&Info.Name, pwcsFilename);
1519 Info.ImageAddress = NULL;
1520 Info.SectionPointer = NULL;
1521 Info.EntryPointer = NULL;
1522 Info.ExportSectionPointer = NULL;
1523 Info.ImageLength = 0;
1524
1525 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
1526 if (NT_SUCCESS(rcNt))
1527 {
1528 pImage->pvImage = Info.ImageAddress;
1529 pImage->pvNtSectionObj = Info.SectionPointer;
1530 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
1531 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
1532# ifdef DEBUG_bird
1533 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ws'\n",
1534 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
1535# endif
1536 if (pImage->cbImageBits == Info.ImageLength)
1537 {
1538 /*
1539 * Lock down the entire image, just to be on the safe side.
1540 */
1541 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
1542 if (RT_FAILURE(rc))
1543 {
1544 pImage->hMemLock = NIL_RTR0MEMOBJ;
1545 supdrvOSLdrUnload(pDevExt, pImage);
1546 }
1547 }
1548 else
1549 {
1550 supdrvOSLdrUnload(pDevExt, pImage);
1551 rc = VERR_LDR_MISMATCH_NATIVE;
1552 }
1553 }
1554 else
1555 {
1556 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
1557 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
1558 switch (rcNt)
1559 {
1560 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
1561# ifdef RT_ARCH_AMD64
1562 /* Unwind will crash and BSOD, so no fallback here! */
1563 rc = VERR_NOT_IMPLEMENTED;
1564# else
1565 /*
1566 * Use the old way of loading the modules.
1567 *
1568 * Note! We do *NOT* try class 26 because it will probably
1569 * not work correctly on terminal servers and such.
1570 */
1571 rc = VERR_NOT_SUPPORTED;
1572# endif
1573 break;
1574 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
1575 rc = VERR_MODULE_NOT_FOUND;
1576 break;
1577 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
1578 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
1579 break;
1580 case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
1581 rc = VERR_LDR_IMAGE_HASH;
1582 break;
1583 case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
1584 Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
1585 rc = VERR_ALREADY_LOADED;
1586 break;
1587 default:
1588 rc = VERR_LDR_GENERAL_FAILURE;
1589 break;
1590 }
1591
1592 pImage->pvNtSectionObj = NULL;
1593 }
1594 }
1595
1596 RTMemTmpFree(pwcsFilename);
1597 NOREF(pDevExt);
1598 return rc;
1599#endif
1600}
1601
1602
1603void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1604{
1605 NOREF(pDevExt); NOREF(pImage);
1606}
1607
1608
1609int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
1610{
1611 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
1612 return VINF_SUCCESS;
1613}
1614
1615
1616/**
1617 * memcmp + log.
1618 *
1619 * @returns Same as memcmp.
1620 * @param pImage The image.
1621 * @param pbImageBits The image bits ring-3 uploads.
1622 * @param uRva The RVA to start comparing at.
1623 * @param cb The number of bytes to compare.
1624 */
1625static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb)
1626{
1627 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
1628 if (iDiff)
1629 {
1630 uint32_t cbLeft = cb;
1631 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
1632 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
1633 if (pbNativeBits[off] != pbImageBits[off])
1634 {
1635 char szBytes[128];
1636 RTStrPrintf(szBytes, sizeof(szBytes), "native: %.*Rhxs our: %.*Rhxs",
1637 RT_MIN(12, cbLeft), &pbNativeBits[off],
1638 RT_MIN(12, cbLeft), &pbImageBits[off]);
1639 SUPR0Printf("VBoxDrv: Mismatch at %#x of %s: %s\n", off, pImage->szName, szBytes);
1640 break;
1641 }
1642 }
1643 return iDiff;
1644}
1645
1646int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1647{
1648 NOREF(pDevExt); NOREF(pReq);
1649 if (pImage->pvNtSectionObj)
1650 {
1651 /*
1652 * Usually, the entire image matches exactly.
1653 */
1654 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
1655 return VINF_SUCCESS;
1656
1657 /*
1658 * However, on Windows Server 2003 (sp2 x86) both import thunk tables
1659 * are fixed up and we typically get a mismatch in the INIT section.
1660 *
1661 * So, lets see if everything matches when excluding the
1662 * OriginalFirstThunk tables. To make life simpler, set the max number
1663 * of imports to 16 and just record and sort the locations that needs
1664 * to be excluded from the comparison.
1665 */
1666 IMAGE_NT_HEADERS const *pNtHdrs;
1667 pNtHdrs = (IMAGE_NT_HEADERS const *)(pbImageBits
1668 + ( *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
1669 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
1670 : 0));
1671 if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
1672 && pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
1673 && pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
1674 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
1675 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
1676 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
1677 )
1678 {
1679 struct MyRegion
1680 {
1681 uint32_t uRva;
1682 uint32_t cb;
1683 } aExcludeRgns[16];
1684 unsigned cExcludeRgns = 0;
1685 uint32_t cImpsLeft = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
1686 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
1687 IMAGE_IMPORT_DESCRIPTOR const *pImp;
1688 pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits
1689 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1690 while ( cImpsLeft-- > 0
1691 && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
1692 {
1693 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
1694 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
1695 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
1696 && uRvaThunk != pImp->FirstThunk)
1697 {
1698 /* Find the size of the thunk table. */
1699 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
1700 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
1701 uint32_t cThunks = 0;
1702 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
1703 cThunks++;
1704
1705 /* Ordered table insert. */
1706 unsigned i = 0;
1707 for (; i < cExcludeRgns; i++)
1708 if (uRvaThunk < aExcludeRgns[i].uRva)
1709 break;
1710 if (i != cExcludeRgns)
1711 memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
1712 aExcludeRgns[i].uRva = uRvaThunk;
1713 aExcludeRgns[i].cb = cThunks * sizeof(IMAGE_THUNK_DATA);
1714 cExcludeRgns++;
1715 }
1716
1717 /* advance */
1718 pImp++;
1719 }
1720
1721 /*
1722 * Ok, do the comparison.
1723 */
1724 int iDiff = 0;
1725 uint32_t uRvaNext = 0;
1726 for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
1727 {
1728 if (uRvaNext < aExcludeRgns[i].uRva)
1729 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext);
1730 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
1731 }
1732 if (!iDiff && uRvaNext < pImage->cbImageBits)
1733 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext);
1734 if (!iDiff)
1735 return VINF_SUCCESS;
1736 }
1737 else
1738 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits);
1739 return VERR_LDR_MISMATCH_NATIVE;
1740 }
1741 return VERR_INTERNAL_ERROR_4;
1742}
1743
1744
1745void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1746{
1747 if (pImage->pvNtSectionObj)
1748 {
1749 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
1750 {
1751 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
1752 pImage->hMemLock = NIL_RTR0MEMOBJ;
1753 }
1754
1755 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
1756 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
1757 if (rcNt != STATUS_SUCCESS)
1758 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
1759 pImage->pvNtSectionObj = NULL;
1760 }
1761 NOREF(pDevExt);
1762}
1763
1764
1765#ifdef SUPDRV_WITH_MSR_PROBER
1766
1767#if 1
1768/** @todo make this selectable. */
1769# define AMD_MSR_PASSCODE 0x9c5a203a
1770#else
1771# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
1772# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
1773#endif
1774
1775
1776/**
1777 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
1778 */
1779typedef struct SUPDRVNTMSPROBERARGS
1780{
1781 uint32_t uMsr;
1782 uint64_t uValue;
1783 bool fGp;
1784} SUPDRVNTMSPROBERARGS;
1785
1786/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
1787static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1788{
1789 /*
1790 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
1791 * (At least on 32-bit XP.)
1792 */
1793 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
1794 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
1795 __try
1796 {
1797 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
1798 pArgs->fGp = false;
1799 }
1800 __except(EXCEPTION_EXECUTE_HANDLER)
1801 {
1802 pArgs->fGp = true;
1803 pArgs->uValue = 0;
1804 }
1805 ASMSetFlags(fOldFlags);
1806}
1807
1808
1809int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1810{
1811 SUPDRVNTMSPROBERARGS Args;
1812 Args.uMsr = uMsr;
1813 Args.uValue = 0;
1814 Args.fGp = true;
1815
1816 if (idCpu == NIL_RTCPUID)
1817 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
1818 else
1819 {
1820 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
1821 if (RT_FAILURE(rc))
1822 return rc;
1823 }
1824
1825 if (Args.fGp)
1826 return VERR_ACCESS_DENIED;
1827 *puValue = Args.uValue;
1828 return VINF_SUCCESS;
1829}
1830
1831
1832/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
1833static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1834{
1835 /*
1836 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
1837 * (At least on 32-bit XP.)
1838 */
1839 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
1840 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
1841 __try
1842 {
1843 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
1844 pArgs->fGp = false;
1845 }
1846 __except(EXCEPTION_EXECUTE_HANDLER)
1847 {
1848 pArgs->fGp = true;
1849 }
1850 ASMSetFlags(fOldFlags);
1851}
1852
1853int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1854{
1855 SUPDRVNTMSPROBERARGS Args;
1856 Args.uMsr = uMsr;
1857 Args.uValue = uValue;
1858 Args.fGp = true;
1859
1860 if (idCpu == NIL_RTCPUID)
1861 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
1862 else
1863 {
1864 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
1865 if (RT_FAILURE(rc))
1866 return rc;
1867 }
1868
1869 if (Args.fGp)
1870 return VERR_ACCESS_DENIED;
1871 return VINF_SUCCESS;
1872}
1873
1874/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
1875static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1876{
1877 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1878 register uint32_t uMsr = pReq->u.In.uMsr;
1879 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1880 uint64_t uBefore = 0;
1881 uint64_t uWritten = 0;
1882 uint64_t uAfter = 0;
1883 bool fBeforeGp = true;
1884 bool fModifyGp = true;
1885 bool fAfterGp = true;
1886 bool fRestoreGp = true;
1887 RTCCUINTREG fOldFlags;
1888
1889 /*
1890 * Do the job.
1891 */
1892 fOldFlags = ASMIntDisableFlags();
1893 ASMCompilerBarrier(); /* paranoia */
1894 if (!fFaster)
1895 ASMWriteBackAndInvalidateCaches();
1896
1897 __try
1898 {
1899 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
1900 fBeforeGp = false;
1901 }
1902 __except(EXCEPTION_EXECUTE_HANDLER)
1903 {
1904 fBeforeGp = true;
1905 }
1906 if (!fBeforeGp)
1907 {
1908 register uint64_t uRestore = uBefore;
1909
1910 /* Modify. */
1911 uWritten = uRestore;
1912 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1913 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1914 __try
1915 {
1916 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
1917 fModifyGp = false;
1918 }
1919 __except(EXCEPTION_EXECUTE_HANDLER)
1920 {
1921 fModifyGp = true;
1922 }
1923
1924 /* Read modified value. */
1925 __try
1926 {
1927 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
1928 fAfterGp = false;
1929 }
1930 __except(EXCEPTION_EXECUTE_HANDLER)
1931 {
1932 fAfterGp = true;
1933 }
1934
1935 /* Restore original value. */
1936 __try
1937 {
1938 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
1939 fRestoreGp = false;
1940 }
1941 __except(EXCEPTION_EXECUTE_HANDLER)
1942 {
1943 fRestoreGp = true;
1944 }
1945
1946 /* Invalid everything we can. */
1947 if (!fFaster)
1948 {
1949 ASMWriteBackAndInvalidateCaches();
1950 ASMReloadCR3();
1951 ASMNopPause();
1952 }
1953 }
1954
1955 ASMCompilerBarrier(); /* paranoia */
1956 ASMSetFlags(fOldFlags);
1957
1958 /*
1959 * Write out the results.
1960 */
1961 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1962 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1963 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1964 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
1965 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
1966 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
1967 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
1968 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1969}
1970
1971
1972int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1973{
1974 if (idCpu == NIL_RTCPUID)
1975 {
1976 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
1977 return VINF_SUCCESS;
1978 }
1979 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
1980}
1981
1982#endif /* SUPDRV_WITH_MSR_PROBER */
1983
1984
1985/**
1986 * Converts an IPRT error code to an nt status code.
1987 *
1988 * @returns corresponding nt status code.
1989 * @param rc IPRT error status code.
1990 */
1991static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
1992{
1993 switch (rc)
1994 {
1995 case VINF_SUCCESS: return STATUS_SUCCESS;
1996 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
1997 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
1998 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
1999 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
2000 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
2001 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
2002 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
2003 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
2004 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
2005 }
2006
2007 if (rc < 0)
2008 {
2009 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2010 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2011 }
2012 return STATUS_UNSUCCESSFUL;
2013}
2014
2015
2016
2017/** @todo use the nocrt stuff? */
2018int VBOXCALL mymemcmp(const void *pv1, const void *pv2, size_t cb)
2019{
2020 const uint8_t *pb1 = (const uint8_t *)pv1;
2021 const uint8_t *pb2 = (const uint8_t *)pv2;
2022 for (; cb > 0; cb--, pb1++, pb2++)
2023 if (*pb1 != *pb2)
2024 return *pb1 - *pb2;
2025 return 0;
2026}
2027
2028
2029#if 0 /* See alternative in SUPDrvA-win.asm */
2030/**
2031 * Alternative version of SUPR0Printf for Windows.
2032 *
2033 * @returns 0.
2034 * @param pszFormat The format string.
2035 */
2036SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2037{
2038 va_list va;
2039 char szMsg[512];
2040
2041 va_start(va, pszFormat);
2042 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2043 szMsg[sizeof(szMsg) - 1] = '\0';
2044 va_end(va);
2045
2046 RTLogWriteDebugger(szMsg, cch);
2047 return 0;
2048}
2049#endif
2050
2051
2052#ifdef VBOX_WITH_HARDENING
2053
2054/** @name Identifying Special Processes: CSRSS.EXE
2055 * @{ */
2056
2057
2058/**
2059 * Checks if the process is a system32 process by the given name.
2060 *
2061 * @returns true / false.
2062 * @param pProcess The process to check.
2063 * @param pszName The lower case process name (no path!).
2064 */
2065static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2066{
2067 Assert(strlen(pszName) < 16); /* see buffer below */
2068
2069 /*
2070 * This test works on XP+.
2071 */
2072 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2073 if (!pszImageFile)
2074 return false;
2075
2076 if (RTStrICmp(pszImageFile, pszName) != 0)
2077 return false;
2078
2079 /*
2080 * This test requires a Vista+ API.
2081 */
2082 if (g_pfnPsReferenceProcessFilePointer)
2083 {
2084 PFILE_OBJECT pFile = NULL;
2085 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2086 if (!NT_SUCCESS(rcNt))
2087 return false;
2088
2089 union
2090 {
2091 OBJECT_NAME_INFORMATION Info;
2092 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2093 } Buf;
2094 ULONG cbIgn;
2095 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2096 ObDereferenceObject(pFile);
2097 if (!NT_SUCCESS(rcNt))
2098 return false;
2099
2100 /* Terminate the name. */
2101 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2102 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2103
2104 /* Match the name against the system32 directory path. */
2105 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2106 if (Buf.Info.Name.Length < cbSystem32)
2107 return false;
2108 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2109 return false;
2110 pwszName += cbSystem32 / sizeof(RTUTF16);
2111 if (*pwszName++ != '\\')
2112 return false;
2113
2114 /* Compare the name. */
2115 const char *pszRight = pszName;
2116 for (;;)
2117 {
2118 WCHAR wchLeft = *pwszName++;
2119 char chRight = *pszRight++;
2120 Assert(chRight == RT_C_TO_LOWER(chRight));
2121
2122 if ( wchLeft != chRight
2123 && RT_C_TO_LOWER(wchLeft) != chRight)
2124 return false;
2125 if (!chRight)
2126 break;
2127 }
2128 }
2129
2130 return true;
2131}
2132
2133
2134/**
2135 * Checks if the current process is likely to be CSRSS.
2136 *
2137 * @returns true/false.
2138 * @param pProcess The process.
2139 */
2140static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2141{
2142 /*
2143 * On Windows 8.1 CSRSS.EXE is a protected process.
2144 */
2145 if (g_pfnPsIsProtectedProcessLight)
2146 {
2147 if (!g_pfnPsIsProtectedProcessLight(pProcess))
2148 return false;
2149 }
2150
2151 /*
2152 * The name tests.
2153 */
2154 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2155 return false;
2156
2157 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2158 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2159
2160 return true;
2161}
2162
2163
2164/**
2165 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
2166 * current process.
2167 *
2168 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
2169 * additional access right so we need to make 101% sure we correctly identify
2170 * the CSRSS process a process is associated with.
2171 *
2172 * @returns IPRT status code.
2173 * @param pNtProtect The NT protected process structure. The
2174 * hCsrssPid member will be updated on success.
2175 */
2176static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
2177{
2178 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
2179 Assert(pNtProtect->pCsrssProcess == NULL);
2180 Assert(pNtProtect->hCsrssPid == NULL);
2181
2182 /*
2183 * We'll try use the ApiPort LPC object for the session we're in to track
2184 * down the CSRSS process. So, we start by constructing a path to it.
2185 */
2186 int rc;
2187 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
2188 WCHAR wszApiPort[48];
2189 if (uSessionId == 0)
2190 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2191 else
2192 {
2193 char szTmp[64];
2194 ssize_t cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), uSessionId, 10, 0, 0, 0);
2195 AssertReturn(cchTmp > 0, (int)cchTmp);
2196 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
2197 if (RT_SUCCESS(rc))
2198 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szTmp);
2199 if (RT_SUCCESS(rc))
2200 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2201 }
2202 AssertRCReturn(rc, rc);
2203
2204 UNICODE_STRING ApiPortStr;
2205 ApiPortStr.Buffer = wszApiPort;
2206 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
2207 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
2208
2209 /*
2210 * The object cannot be opened, but we can reference it by name.
2211 */
2212 void *pvApiPortObj = NULL;
2213 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
2214 0,
2215 NULL /*pAccessState*/,
2216 STANDARD_RIGHTS_READ,
2217 *LpcPortObjectType,
2218 KernelMode,
2219 NULL /*pvParseContext*/,
2220 &pvApiPortObj);
2221 if (!NT_SUCCESS(rcNt))
2222 {
2223 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
2224 return VERR_SUPDRV_APIPORT_OPEN_ERROR;
2225 }
2226
2227 /*
2228 * Query the processes in the system so we can locate CSRSS.EXE candidates.
2229 * Note! Attempts at using SystemSessionProcessInformation failed with
2230 * STATUS_ACCESS_VIOLATION.
2231 * Note! The 32 bytes on the size of to counteract the allocation header
2232 * that rtR0MemAllocEx slaps on everything.
2233 */
2234 ULONG cbNeeded = _64K - 32;
2235 uint32_t cbBuf;
2236 uint8_t *pbBuf = NULL;
2237 do
2238 {
2239 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
2240 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
2241 if (!pbBuf)
2242 break;
2243
2244 cbNeeded = 0;
2245#if 0 /* doesn't work. */
2246 SYSTEM_SESSION_PROCESS_INFORMATION Req;
2247 Req.SessionId = uSessionId;
2248 Req.BufferLength = cbBuf;
2249 Req.Buffer = pbBuf;
2250 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
2251#else
2252 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
2253#endif
2254 if (NT_SUCCESS(rcNt))
2255 break;
2256
2257 RTMemFree(pbBuf);
2258 pbBuf = NULL;
2259 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
2260 && cbNeeded > cbBuf
2261 && cbNeeded < 32U*_1M);
2262
2263 if ( pbBuf
2264 && NT_SUCCESS(rcNt)
2265 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
2266 {
2267 /*
2268 * Walk the returned data and look for the process associated with the
2269 * ApiPort object. The ApiPort object keeps the EPROCESS address of
2270 * the owner process (i.e. CSRSS) relatively early in the structure. On
2271 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
2272 * pointer to likely CSRSS processes and check for a match in the first
2273 * 0x40 bytes of the ApiPort object.
2274 */
2275 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
2276 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
2277 {
2278 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
2279 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
2280 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
2281 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
2282 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
2283 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
2284 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
2285 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
2286 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
2287 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
2288 && pProcInfo->ProcessName.Buffer[5] == '.'
2289 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
2290 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
2291 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
2292 {
2293
2294 /* Get the process structure and perform some more thorough
2295 process checks. */
2296 PEPROCESS pProcess;
2297 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
2298 if (NT_SUCCESS(rcNt))
2299 {
2300 if (supdrvNtProtectIsCsrssByProcess(pProcess))
2301 {
2302 if (PsGetProcessSessionId(pProcess) == uSessionId)
2303 {
2304 /* Final test, check the ApiPort.
2305 Note! The old LPC (pre Vista) objects has the PID
2306 much earlier in the structure. Might be
2307 worth looking for it instead. */
2308 bool fThatsIt = false;
2309 __try
2310 {
2311 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
2312 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
2313 do
2314 {
2315 fThatsIt = *ppPortProc == pProcess;
2316 ppPortProc++;
2317 } while (!fThatsIt && --cTests > 0);
2318 }
2319 __except(EXCEPTION_EXECUTE_HANDLER)
2320 {
2321 fThatsIt = false;
2322 }
2323 if (fThatsIt)
2324 {
2325 /* Ok, we found it! Keep the process structure
2326 reference as well as the PID so we can
2327 safely identify it later on. */
2328 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
2329 pNtProtect->pCsrssProcess = pProcess;
2330 rc = VINF_SUCCESS;
2331 break;
2332 }
2333 }
2334 }
2335
2336 ObDereferenceObject(pProcess);
2337 }
2338 }
2339
2340 /* Advance. */
2341 if (!pProcInfo->NextEntryOffset)
2342 break;
2343 offBuf += pProcInfo->NextEntryOffset;
2344 }
2345 }
2346 else
2347 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
2348 RTMemFree(pbBuf);
2349 ObDereferenceObject(pvApiPortObj);
2350 return rc;
2351}
2352
2353
2354/**
2355 * Checks that the given process is the CSRSS process associated with protected
2356 * process.
2357 *
2358 * @returns true / false.
2359 * @param pNtProtect The NT protection structure.
2360 * @param pCsrss The process structure of the alleged CSRSS.EXE
2361 * process.
2362 */
2363static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
2364{
2365 if (pNtProtect->pCsrssProcess == pCsrss)
2366 {
2367 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
2368 {
2369 return true;
2370 }
2371 }
2372 return false;
2373}
2374
2375
2376/**
2377 * Checks if the given process is the stupid themes service.
2378 *
2379 * The caller does some screening of access masks and what not. We do the rest.
2380 *
2381 * @returns true / false.
2382 * @param pNtProtect The NT protection structure.
2383 * @param pAnnoyingProcess The process structure of an process that might
2384 * happen to be the annoying themes process.
2385 */
2386static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
2387{
2388 /*
2389 * Check the process name.
2390 */
2391 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
2392 return false;
2393
2394 /** @todo Come up with more checks. */
2395
2396 return true;
2397}
2398
2399
2400/** @} */
2401
2402
2403/** @name Process Creation Callbacks.
2404 * @{ */
2405
2406/**
2407 * Common worker used by the process creation hooks as well as the process
2408 * handle creation hooks to check if a VM process is being created.
2409 *
2410 * @returns true if likely to be a VM process, false if not.
2411 * @param pNtStub The NT protection structure for the possible
2412 * stub process.
2413 * @param hParentPid The parent pid.
2414 * @param hChildPid The child pid.
2415 */
2416static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
2417{
2418 bool fRc = false;
2419 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
2420 {
2421 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
2422 {
2423 /* Compare short names. */
2424 PEPROCESS pStubProcess;
2425 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
2426 if (NT_SUCCESS(rcNt))
2427 {
2428 PEPROCESS pChildProcess;
2429 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
2430 if (NT_SUCCESS(rcNt))
2431 {
2432 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
2433 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
2434 fRc = pszStub != NULL
2435 && pszChild != NULL
2436 && strcmp(pszStub, pszChild) == 0;
2437
2438 /** @todo check that the full image names matches. */
2439
2440 ObDereferenceObject(pChildProcess);
2441 }
2442 ObDereferenceObject(pStubProcess);
2443 }
2444 }
2445 }
2446 return fRc;
2447}
2448
2449
2450/**
2451 * Common code used by the notifies to protect a child process.
2452 *
2453 * @returns VBox status code.
2454 * @param pNtStub The NT protect structure for the parent.
2455 * @param hChildPid The child pid.
2456 */
2457static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
2458{
2459 /*
2460 * Create a child protection struction.
2461 */
2462 PSUPDRVNTPROTECT pNtChild;
2463 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
2464 if (RT_SUCCESS(rc))
2465 {
2466 pNtChild->fFirstProcessCreateHandle = true;
2467 pNtChild->fFirstThreadCreateHandle = true;
2468 pNtChild->fCsrssFirstProcessCreateHandle = true;
2469 pNtChild->fCsrssFirstProcessDuplicateHandle = true;
2470 pNtChild->fThemesFirstProcessCreateHandle = true;
2471 pNtChild->hParentPid = pNtParent->AvlCore.Key;
2472 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
2473 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
2474 if (pNtChild->pCsrssProcess)
2475 ObReferenceObject(pNtChild->pCsrssProcess);
2476
2477 /*
2478 * Take the spinlock, recheck parent conditions and link things.
2479 */
2480 RTSpinlockAcquire(g_hNtProtectLock);
2481 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
2482 {
2483 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
2484 if (fSuccess)
2485 {
2486 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
2487 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
2488 pNtChild->u.pParent = pNtParent;
2489
2490 RTSpinlockRelease(g_hNtProtectLock);
2491 return VINF_SUCCESS;
2492 }
2493
2494 rc = VERR_INTERNAL_ERROR_2;
2495 }
2496 else
2497 rc = VERR_WRONG_ORDER;
2498 RTSpinlockRelease(g_hNtProtectLock);
2499
2500 supdrvNtProtectRelease(pNtChild);
2501 }
2502 return rc;
2503}
2504
2505
2506/**
2507 * Common process termination code.
2508 *
2509 * Transitions protected process to the dead states, protecting against handle
2510 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
2511 *
2512 * @param hDeadPid The PID of the dead process.
2513 */
2514static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
2515{
2516 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
2517 if (pNtProtect)
2518 {
2519 PSUPDRVNTPROTECT pNtChild = NULL;
2520
2521 RTSpinlockAcquire(g_hNtProtectLock);
2522
2523 /*
2524 * If this is an unconfirmed VM process, we must release the reference
2525 * the parent structure holds.
2526 */
2527 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
2528 {
2529 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
2530 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
2531 pNtParent->u.pChild = NULL;
2532 pNtProtect->u.pParent = NULL;
2533 pNtChild = pNtProtect;
2534 }
2535 /*
2536 * If this is a stub exitting before the VM process gets confirmed,
2537 * release the protection of the potential VM process as this is not
2538 * the prescribed behavior.
2539 */
2540 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
2541 && pNtProtect->u.pChild)
2542 {
2543 pNtChild = pNtProtect->u.pChild;
2544 pNtProtect->u.pChild = NULL;
2545 pNtChild->u.pParent = NULL;
2546 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
2547 }
2548
2549 /*
2550 * Transition it to the dead state to prevent it from opening the
2551 * support driver again or be posthumously abused as a vm process parent.
2552 */
2553 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2554 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
2555 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
2556 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
2557 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
2558 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
2559 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
2560
2561 RTSpinlockRelease(g_hNtProtectLock);
2562
2563 supdrvNtProtectRelease(pNtProtect);
2564 supdrvNtProtectRelease(pNtChild);
2565
2566 /*
2567 * Do session cleanups.
2568 */
2569 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
2570 if (g_pDevObjSys)
2571 {
2572 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
2573 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
2574 RTR0ProcHandleSelf(), NULL);
2575 if (pSession)
2576 {
2577 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
2578 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
2579 }
2580 }
2581 }
2582}
2583
2584
2585/**
2586 * Common worker for the process creation callback that verifies a new child
2587 * being created by the handle creation callback code.
2588 *
2589 * @param pNtStub The parent.
2590 * @param pNtVm The child.
2591 * @param fCallerChecks The result of any additional tests the caller made.
2592 * This is in order to avoid duplicating the failure
2593 * path code.
2594 */
2595static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
2596{
2597 if ( fCallerChecks
2598 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
2599 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2600 && pNtVm->u.pParent == pNtStub
2601 && pNtStub->u.pChild == pNtVm)
2602 {
2603 /* Fine, nothing to do. */
2604 return;
2605 }
2606
2607 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
2608 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
2609 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
2610}
2611
2612
2613/**
2614 * Old style callback (since forever).
2615 *
2616 * @param hParentPid The parent PID.
2617 * @param hNewPid The PID of the new child.
2618 * @param fCreated TRUE if it's a creation notification,
2619 * FALSE if termination.
2620 * @remarks ASSUMES this arrives before the handle creation callback.
2621 */
2622static VOID __stdcall
2623supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
2624{
2625 /*
2626 * Is it a new process that needs protection?
2627 */
2628 if (fCreated)
2629 {
2630 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
2631 if (pNtStub)
2632 {
2633 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
2634 if (!pNtVm)
2635 {
2636 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
2637 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
2638 }
2639 else
2640 {
2641 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
2642 supdrvNtProtectRelease(pNtVm);
2643 }
2644 supdrvNtProtectRelease(pNtStub);
2645 }
2646 }
2647 /*
2648 * Process termination, do clean ups.
2649 */
2650 else
2651 supdrvNtProtectUnprotectDeadProcess(hNewPid);
2652}
2653
2654
2655/**
2656 * New style callback (Vista SP1+ / w2k8).
2657 *
2658 * @param pNewProcess The new process.
2659 * @param hNewPid The PID of the new process.
2660 * @param pInfo Process creation details. NULL if process
2661 * termination notification.
2662 * @remarks ASSUMES this arrives before the handle creation callback.
2663 */
2664static VOID __stdcall
2665supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
2666{
2667 /*
2668 * Is it a new process that needs protection?
2669 */
2670 if (pInfo)
2671 {
2672 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
2673
2674 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
2675 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
2676 hNewPid, pInfo->ParentProcessId,
2677 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
2678 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
2679 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
2680
2681 if (pNtStub)
2682 {
2683 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
2684 if (!pNtVm)
2685 {
2686 /* Parent must be creator. */
2687 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
2688 {
2689 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
2690 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
2691 }
2692 }
2693 else
2694 {
2695 /* Parent must be creator (as above). */
2696 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
2697 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
2698 supdrvNtProtectRelease(pNtVm);
2699 }
2700 supdrvNtProtectRelease(pNtStub);
2701 }
2702 }
2703 /*
2704 * Process termination, do clean ups.
2705 */
2706 else
2707 supdrvNtProtectUnprotectDeadProcess(hNewPid);
2708}
2709
2710/** @} */
2711
2712
2713/** @name Process Handle Callbacks.
2714 * @{ */
2715
2716/** Process rights that we allow for handles to stub and VM processes. */
2717# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
2718 ( PROCESS_TERMINATE \
2719 | PROCESS_VM_READ \
2720 | PROCESS_QUERY_INFORMATION \
2721 | PROCESS_QUERY_LIMITED_INFORMATION \
2722 | PROCESS_SUSPEND_RESUME \
2723 | DELETE \
2724 | READ_CONTROL \
2725 | SYNCHRONIZE)
2726
2727/** Evil process rights. */
2728# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
2729 ( PROCESS_CREATE_THREAD \
2730 | PROCESS_SET_SESSIONID /*?*/ \
2731 | PROCESS_VM_OPERATION \
2732 | PROCESS_VM_WRITE \
2733 | PROCESS_DUP_HANDLE \
2734 | PROCESS_CREATE_PROCESS /*?*/ \
2735 | PROCESS_SET_QUOTA /*?*/ \
2736 | PROCESS_SET_INFORMATION \
2737 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
2738 | 0)
2739AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
2740
2741
2742static OB_PREOP_CALLBACK_STATUS __stdcall
2743supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
2744{
2745 Assert(pvUser == NULL);
2746 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
2747 Assert(pOpInfo->ObjectType == *PsProcessType);
2748
2749 /*
2750 * Protected? Kludge required for NtOpenProcess calls comming in before
2751 * the create process hook triggers on Windows 8.1 (possibly others too).
2752 */
2753 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
2754 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
2755 if (!pNtProtect)
2756 {
2757 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
2758 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
2759 if (pNtStub)
2760 {
2761 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
2762 {
2763 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
2764 pNtProtect = supdrvNtProtectLookup(hObjPid);
2765 }
2766 supdrvNtProtectRelease(pNtStub);
2767 }
2768 }
2769 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
2770 if (pNtProtect)
2771 {
2772 /*
2773 * Ok, it's a protected process. Strip rights as required or possible.
2774 */
2775 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
2776 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
2777
2778 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
2779 {
2780 /* Don't restrict the process accessing itself. */
2781 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
2782 {
2783 pOpInfo->CallContext = NULL; /* don't assert */
2784 pNtProtect->fFirstProcessCreateHandle = false;
2785
2786 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
2787 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
2788 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
2789 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
2790 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
2791 }
2792 else
2793 {
2794 /* Special case 1 on Vista, 7 & 8:
2795 The CreateProcess code passes the handle over to CSRSS.EXE
2796 and the code inBaseSrvCreateProcess will duplicate the
2797 handle with 0x1fffff as access mask. NtDuplicateObject will
2798 fail this call before it ever gets down here.
2799
2800 Special case 2 on 8.1:
2801 The CreateProcess code requires additional rights for
2802 something, we'll drop these in the stub code. */
2803 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2804 && pNtProtect->fFirstProcessCreateHandle
2805 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()))
2806 {
2807 if ( !pOpInfo->KernelHandle
2808 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
2809 {
2810 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
2811 fAllowedRights |= s_fCsrssStupidDesires;
2812 else
2813 fAllowedRights = fAllowedRights
2814 | PROCESS_VM_OPERATION
2815 | PROCESS_VM_WRITE
2816 | PROCESS_SET_INFORMATION
2817 | PROCESS_SET_LIMITED_INFORMATION
2818 | 0;
2819 pOpInfo->CallContext = NULL; /* don't assert this. */
2820 }
2821 pNtProtect->fFirstProcessCreateHandle = false;
2822 }
2823
2824 /* Special case 3 on 8.1:
2825 The interaction between the CreateProcess code and CSRSS.EXE
2826 has changed to the better with Windows 8.1. CSRSS.EXE no
2827 longer duplicates the process (thread too) handle, but opens
2828 it, thus allowing us to do our job. */
2829 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
2830 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2831 && pNtProtect->fCsrssFirstProcessCreateHandle
2832 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess())
2833 )
2834 {
2835 pNtProtect->fCsrssFirstProcessCreateHandle = false;
2836 if (pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
2837 {
2838 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
2839 PROCESS_CREATE_PROCESS */
2840 fAllowedRights = fAllowedRights
2841 | PROCESS_VM_OPERATION
2842 | PROCESS_VM_WRITE
2843 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
2844 | 0;
2845 pOpInfo->CallContext = NULL; /* don't assert this. */
2846 }
2847 }
2848
2849 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
2850 The Themes service requires PROCESS_DUP_HANDLE access to our
2851 process or we won't get any menus and dialogs will be half
2852 unreadable. This is _very_ unfortunate and more work will
2853 go into making this more secure. */
2854 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
2855 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
2856 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
2857 && pNtProtect->fThemesFirstProcessCreateHandle
2858 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()))
2859 {
2860 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
2861 fAllowedRights |= PROCESS_DUP_HANDLE;
2862 pOpInfo->CallContext = NULL; /* don't assert this. */
2863 }
2864
2865 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s\n",
2866 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
2867 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
2868 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
2869 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
2870 PsGetProcessImageFileName(PsGetCurrentProcess())));
2871
2872 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
2873 }
2874 }
2875 else
2876 {
2877 /* Don't restrict the process accessing itself. */
2878 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
2879 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
2880 {
2881 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
2882 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
2883 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
2884 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
2885 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
2886 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
2887 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
2888 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
2889
2890 pOpInfo->CallContext = NULL; /* don't assert */
2891 }
2892 else
2893 {
2894 /* Special case 5 on Vista, 7 & 8:
2895 This is the CSRSS.EXE end of special case #1. */
2896 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
2897 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2898 && pNtProtect->fCsrssFirstProcessDuplicateHandle
2899 && pNtProtect->hParentPid
2900 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
2901 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
2902 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess())
2903 )
2904 {
2905 pNtProtect->fCsrssFirstProcessDuplicateHandle = false;
2906 if (pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
2907 {
2908 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
2909 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
2910 fAllowedRights = fAllowedRights
2911 | PROCESS_VM_OPERATION
2912 | PROCESS_VM_WRITE
2913 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
2914 | 0;
2915 pOpInfo->CallContext = NULL; /* don't assert this. */
2916 }
2917 }
2918
2919 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
2920 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
2921 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
2922 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
2923 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
2924 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
2925 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
2926 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
2927
2928 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
2929 }
2930 }
2931 supdrvNtProtectRelease(pNtProtect);
2932 }
2933
2934 return OB_PREOP_SUCCESS;
2935}
2936
2937
2938static VOID __stdcall
2939supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
2940{
2941 Assert(pvUser == NULL);
2942 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
2943 Assert(pOpInfo->ObjectType == *PsProcessType);
2944
2945 if ( pOpInfo->CallContext
2946 && NT_SUCCESS(pOpInfo->ReturnStatus))
2947 {
2948 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
2949 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
2950 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
2951 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
2952 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
2953 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
2954 /*| PROCESS_UNKNOWN_8000 */ ) )
2955 || pOpInfo->KernelHandle,
2956 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
2957 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
2958 }
2959}
2960
2961# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
2962
2963/** @} */
2964
2965
2966/** @name Thread Handle Callbacks
2967 * @{ */
2968
2969/* From ntifs.h */
2970extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
2971
2972/** Thread rights that we allow for handles to stub and VM processes. */
2973# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
2974 ( THREAD_TERMINATE \
2975 | THREAD_GET_CONTEXT \
2976 | THREAD_QUERY_INFORMATION \
2977 | THREAD_QUERY_LIMITED_INFORMATION \
2978 | DELETE \
2979 | READ_CONTROL \
2980 | SYNCHRONIZE)
2981/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
2982
2983/** Evil thread rights.
2984 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
2985 * Windows 8.1, at least for some processes. We dont' actively
2986 * allow it though, just tollerate it when forced to. */
2987# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
2988 ( THREAD_SUSPEND_RESUME \
2989 | THREAD_SET_CONTEXT \
2990 | THREAD_SET_INFORMATION \
2991 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
2992 | THREAD_SET_THREAD_TOKEN /*?*/ \
2993 | THREAD_IMPERSONATE /*?*/ \
2994 | THREAD_DIRECT_IMPERSONATION /*?*/ \
2995 /*| THREAD_RESUME - see remarks. */ \
2996 | 0)
2997AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
2998
2999
3000static OB_PREOP_CALLBACK_STATUS __stdcall
3001supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3002{
3003 Assert(pvUser == NULL);
3004 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3005 Assert(pOpInfo->ObjectType == *PsThreadType);
3006
3007 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
3008 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
3009 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3010 if (pNtProtect)
3011 {
3012 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3013 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
3014
3015 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3016 {
3017 /* Don't restrict the process accessing its own threads. */
3018 if (pProcess == PsGetCurrentProcess())
3019 {
3020 Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
3021 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3022 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3023 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
3024 pOpInfo->CallContext = NULL; /* don't assert */
3025 pNtProtect->fFirstThreadCreateHandle = false;
3026 }
3027 else
3028 {
3029 /* Special case 1 on Vista, 7, 8:
3030 The CreateProcess code passes the handle over to CSRSS.EXE
3031 and the code inBaseSrvCreateProcess will duplicate the
3032 handle with 0x1fffff as access mask. NtDuplicateObject will
3033 fail this call before it ever gets down here. */
3034 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3035 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3036 && pNtProtect->fFirstThreadCreateHandle
3037 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()))
3038 {
3039 if ( !pOpInfo->KernelHandle
3040 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3041 {
3042 fAllowedRights |= s_fCsrssStupidDesires;
3043 pOpInfo->CallContext = NULL; /* don't assert this. */
3044 }
3045 pNtProtect->fFirstThreadCreateHandle = false;
3046 }
3047
3048 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
3049 When creating a process like VBoxTestOGL from the VM process,
3050 CSRSS.EXE will try talk to the calling thread and, it
3051 appears, impersonate it. We unfortunately need to allow
3052 this or there will be no 3D support. Typical DbgPrint:
3053 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
3054 SUPDRVNTPROTECTKIND enmProcessKind;
3055 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3056 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3057 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3058 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3059 {
3060 fAllowedRights |= THREAD_IMPERSONATE;
3061 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3062 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3063 pOpInfo->CallContext = NULL; /* don't assert this. */
3064 }
3065
3066 Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3067 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3068 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3069 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3070 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3071 PsGetProcessImageFileName(PsGetCurrentProcess())));
3072
3073 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3074 }
3075 }
3076 else
3077 {
3078 /* Don't restrict the process accessing its own threads. */
3079 if ( pProcess == PsGetCurrentProcess()
3080 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
3081 {
3082 Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
3083 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3084 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3085 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3086 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3087 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3088 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3089 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3090 pOpInfo->CallContext = NULL; /* don't assert */
3091 }
3092 else
3093 {
3094 /* Special case 3 on Vista, 7, 8:
3095 This is the follow up to special case 1. */
3096 SUPDRVNTPROTECTKIND enmProcessKind;
3097 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3098 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3099 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3100 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3101 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3102 {
3103 fAllowedRights |= THREAD_IMPERSONATE;
3104 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3105 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3106 pOpInfo->CallContext = NULL; /* don't assert this. */
3107 }
3108
3109 Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3110 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3111 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3112 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3113 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3114 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3115 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3116 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
3117 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3118
3119 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3120 }
3121 }
3122
3123 supdrvNtProtectRelease(pNtProtect);
3124 }
3125
3126 return OB_PREOP_SUCCESS;
3127}
3128
3129
3130static VOID __stdcall
3131supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3132{
3133 Assert(pvUser == NULL);
3134 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3135 Assert(pOpInfo->ObjectType == *PsThreadType);
3136
3137 if ( pOpInfo->CallContext
3138 && NT_SUCCESS(pOpInfo->ReturnStatus))
3139 {
3140 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
3141 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3142 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3143 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
3144 ) )
3145 || pOpInfo->KernelHandle,
3146 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3147 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
3148 }
3149}
3150
3151# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3152
3153/** @} */
3154
3155
3156/**
3157 * Creates a new process protection structure.
3158 *
3159 * @returns VBox status code.
3160 * @param ppNtProtect Where to return the pointer to the structure
3161 * on success.
3162 * @param hPid The process ID of the process to protect.
3163 * @param enmProcessKind The kind of process we're protecting.
3164 * @param fLink Whether to link the structure into the tree.
3165 */
3166static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
3167{
3168 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
3169
3170 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
3171 if (!pNtProtect)
3172 return VERR_NO_MEMORY;
3173
3174 pNtProtect->AvlCore.Key = hPid;
3175 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
3176 pNtProtect->cRefs = 1;
3177 pNtProtect->enmProcessKind = enmProcessKind;
3178 pNtProtect->hParentPid = NULL;
3179 pNtProtect->hCsrssPid = NULL;
3180 pNtProtect->pCsrssProcess = NULL;
3181
3182 if (fLink)
3183 {
3184 RTSpinlockAcquire(g_hNtProtectLock);
3185 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
3186 RTSpinlockRelease(g_hNtProtectLock);
3187
3188 if (!fSuccess)
3189 {
3190 /* Duplicate entry, fail. */
3191 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
3192 RTMemFree(pNtProtect);
3193 return VERR_ACCESS_DENIED;
3194 }
3195 }
3196
3197 *ppNtProtect = pNtProtect;
3198 return VINF_SUCCESS;
3199}
3200
3201
3202/**
3203 * Releases a reference to a NT protection structure.
3204 *
3205 * @param pNtProtect The NT protection structure.
3206 */
3207static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
3208{
3209 if (!pNtProtect)
3210 return;
3211 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
3212
3213 RTSpinlockAcquire(g_hNtProtectLock);
3214 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
3215 if (cRefs != 0)
3216 RTSpinlockRelease(g_hNtProtectLock);
3217 else
3218 {
3219 /*
3220 * That was the last reference. Remove it from the tree, invalidate it
3221 * and free the resources associated with it. Also, release any
3222 * child/parent references related to this protection structure.
3223 */
3224 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
3225 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
3226
3227 PSUPDRVNTPROTECT pRemovedChild = NULL;
3228 PSUPDRVNTPROTECT pChild = NULL;
3229 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
3230 {
3231 pChild = pNtProtect->u.pChild;
3232 if (pChild)
3233 {
3234 pNtProtect->u.pChild = NULL;
3235 pChild->u.pParent = NULL;
3236 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3237 uint32_t cChildRefs = ASMAtomicIncU32(&pChild->cRefs);
3238 if (!cChildRefs)
3239 pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
3240 else
3241 pChild = NULL;
3242 }
3243 }
3244 else
3245 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
3246
3247 RTSpinlockRelease(g_hNtProtectLock);
3248 Assert(pRemoved == pNtProtect);
3249 Assert(pRemovedChild == pChild);
3250
3251 if (pNtProtect->pCsrssProcess)
3252 {
3253 ObDereferenceObject(pNtProtect->pCsrssProcess);
3254 pNtProtect->pCsrssProcess = NULL;
3255 }
3256
3257 RTMemFree(pNtProtect);
3258 if (pChild)
3259 RTMemFree(pChild);
3260 }
3261}
3262
3263
3264/**
3265 * Looks up a PID in the NT protect tree.
3266 *
3267 * @returns Pointer to a NT protection structure (with a referenced) on success,
3268 * NULL if not found.
3269 * @param hPid The process ID.
3270 */
3271static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
3272{
3273 RTSpinlockAcquire(g_hNtProtectLock);
3274 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
3275 if (pFound)
3276 ASMAtomicIncU32(&pFound->cRefs);
3277 RTSpinlockRelease(g_hNtProtectLock);
3278 return pFound;
3279}
3280
3281
3282/**
3283 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
3284 * process and its thread.
3285 *
3286 * @returns VBox status code.
3287 * @param pNtProtect The NT protect structure for getting information
3288 * about special processes.
3289 */
3290static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect)
3291{
3292 /*
3293 * What to protect.
3294 */
3295 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
3296 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
3297 PETHREAD pProtectedThread = PsGetCurrentThread();
3298 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
3299
3300 /*
3301 * Take a snapshot of all the handles in the system.
3302 * Note! The 32 bytes on the size of to counteract the allocation header
3303 * that rtR0MemAllocEx slaps on everything.
3304 */
3305 uint32_t cbBuf = _256K - 32;
3306 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3307 ULONG cbNeeded = cbBuf;
3308 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
3309 if (!NT_SUCCESS(rcNt))
3310 {
3311 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3312 && cbNeeded > cbBuf
3313 && cbBuf <= 32U*_1M)
3314 {
3315 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
3316 RTMemFree(pbBuf);
3317 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3318 if (!pbBuf)
3319 return VERR_NO_MEMORY;
3320 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
3321 }
3322 if (!NT_SUCCESS(rcNt))
3323 {
3324 RTMemFree(pbBuf);
3325 return RTErrConvertFromNtStatus(rcNt);
3326 }
3327 }
3328
3329 /*
3330 * Walk the information and look for handles to the two objects we're protecting.
3331 */
3332 int rc = VINF_SUCCESS;
3333
3334 uint32_t cCsrssProcessHandles = 0;
3335 uint32_t cSystemProcessHandles = 0;
3336 uint32_t cEvilProcessHandles = 0;
3337 uint32_t cBenignProcessHandles = 0;
3338
3339 uint32_t cCsrssThreadHandles = 0;
3340 uint32_t cEvilThreadHandles = 0;
3341 uint32_t cBenignThreadHandles = 0;
3342
3343 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
3344 ULONG_PTR i = pInfo->NumberOfHandles;
3345 AssertRelease(RT_OFFSETOF(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
3346 while (i-- > 0)
3347 {
3348 const char *pszType;
3349 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
3350 if (pHandleInfo->Object == pProtectedProcess)
3351 {
3352 /* Handles within the protected process is fine. */
3353 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
3354 || pHandleInfo->UniqueProcessId == hProtectedPid)
3355 {
3356 cBenignProcessHandles++;
3357 continue;
3358 }
3359
3360 /* CSRSS is allowed to have one evil process handle.
3361 See the special cases in the hook code. */
3362 if ( cCsrssProcessHandles < 1
3363 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
3364 {
3365 cCsrssProcessHandles++;
3366 continue;
3367 }
3368
3369 /* The system process is allowed having one open process handle in
3370 Windows 8.1 and later. */
3371 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3372 && cSystemProcessHandles < 1
3373 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
3374 {
3375 cSystemProcessHandles++;
3376 continue;
3377 }
3378
3379 cEvilProcessHandles++;
3380 pszType = "process";
3381 }
3382 else if (pHandleInfo->Object == pProtectedThread)
3383 {
3384 /* Handles within the protected process is fine. */
3385 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
3386 || pHandleInfo->UniqueProcessId == hProtectedPid)
3387 {
3388 cBenignThreadHandles++;
3389 continue;
3390 }
3391
3392 /* CSRSS is allowed to have one evil handle to the primary thread
3393 for LPC purposes. See the hook for special case. */
3394 if ( cCsrssThreadHandles < 1
3395 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
3396 {
3397 cCsrssThreadHandles++;
3398 continue;
3399 }
3400
3401 cEvilThreadHandles++;
3402 pszType = "thread";
3403 }
3404 else
3405 continue;
3406
3407 /* Found evil handle. Currently ignoring on pre-Vista. */
3408# ifndef VBOX_WITH_VISTA_NO_SP
3409 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
3410# else
3411 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
3412# endif
3413 || g_pfnObRegisterCallbacks)
3414 {
3415 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
3416 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
3417 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
3418 rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
3419 }
3420 }
3421
3422 RTMemFree(pbBuf);
3423 return rc;
3424}
3425
3426
3427/**
3428 * Checks if the current process checks out as a VM process stub.
3429 *
3430 * @returns VBox status code.
3431 * @param pNtProtect The NT protect structure. This is upgraded to a
3432 * final protection kind (state) on success.
3433 */
3434static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
3435{
3436 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
3437
3438 /*
3439 * Do the verification. The handle restriction checks are only preformed
3440 * on VM processes.
3441 */
3442 int rc = VINF_SUCCESS;
3443 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
3444 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect);
3445 if (RT_SUCCESS(rc))
3446 {
3447 char szErr[256];
3448 RT_ZERO(szErr);
3449 RTERRINFO ErrInfo;
3450 RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
3451
3452 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), &ErrInfo);
3453 if (RT_FAILURE(rc))
3454 RTLogWriteDebugger(szErr, strlen(szErr));
3455 }
3456
3457 /*
3458 * Upgrade and return.
3459 */
3460 RTSpinlockAcquire(g_hNtProtectLock);
3461
3462 /* Stub process verficiation is pretty much straight forward. */
3463 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3464 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
3465
3466 /* The VM process verification is a little bit more complicated
3467 because we need to drop the parent process reference as well. */
3468 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3469 {
3470 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
3471 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
3472 AssertRelease(pParent);
3473 AssertRelease(pParent->u.pParent == pNtProtect);
3474 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
3475 pParent->u.pParent = NULL;
3476
3477 pNtProtect->u.pParent = NULL;
3478 ASMAtomicDecU32(&pNtProtect->cRefs);
3479
3480 if (RT_SUCCESS(rc))
3481 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
3482 else
3483 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3484 }
3485
3486 /* Since the stub and VM processes are only supposed to have one thread,
3487 we're not supposed to be subject to any races from within the processes.
3488
3489 There is a race between VM process verification and the stub process
3490 exiting, though. We require the stub process to be alive until the new
3491 VM process has made it thru the validation. So, when the stub
3492 terminates the notification handler will change the state of both stub
3493 and VM process to dead.
3494
3495 Also, I'm not entirely certain where the process
3496 termination notification is triggered from, so that can theorically
3497 create a race in both cases. */
3498 else
3499 {
3500 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
3501 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
3502 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
3503 if (RT_SUCCESS(rc))
3504 rc = VERR_INVALID_STATE; /* There should be no races here. */
3505 }
3506
3507 RTSpinlockRelease(g_hNtProtectLock);
3508 return rc;
3509}
3510
3511
3512# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
3513
3514/**
3515 * Checks if the current process is being debugged.
3516 * @return @c true if debugged, @c false if not.
3517 */
3518static bool supdrvNtIsDebuggerAttached(void)
3519{
3520 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
3521}
3522
3523# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
3524
3525
3526/**
3527 * Terminates the hardening bits.
3528 */
3529static void supdrvNtProtectTerm(void)
3530{
3531 /*
3532 * Stop intercepting process and thread handle creation calls.
3533 */
3534 if (g_pvObCallbacksCookie)
3535 {
3536 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
3537 g_pvObCallbacksCookie = NULL;
3538 }
3539
3540 /*
3541 * Stop intercepting process creation and termination notifications.
3542 */
3543 NTSTATUS rcNt;
3544 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
3545 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
3546 else
3547 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
3548 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
3549
3550 Assert(g_NtProtectTree == NULL);
3551
3552 /*
3553 * Clean up globals.
3554 */
3555 RTSpinlockDestroy(g_hNtProtectLock);
3556 g_NtProtectTree = NIL_RTSPINLOCK;
3557
3558 supHardenedWinTermImageVerifier();
3559}
3560
3561# ifdef RT_ARCH_X86
3562DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
3563DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
3564DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
3565DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
3566DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
3567DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
3568DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
3569DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
3570DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
3571DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
3572DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
3573DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
3574DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
3575DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
3576DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
3577DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
3578# elif defined(RT_ARCH_AMD64)
3579DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
3580DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
3581DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
3582DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
3583DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
3584extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
3585# endif
3586
3587/**
3588 * Initalizes the hardening bits.
3589 *
3590 * @returns NT status code.
3591 */
3592static NTSTATUS supdrvNtProtectInit(void)
3593{
3594 /*
3595 * Initialize the globals.
3596 */
3597
3598 /* The NT version. */
3599 ULONG uMajor, uMinor, uBuild;
3600 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
3601 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
3602
3603 /* Resolve methods we want but isn't available everywhere. */
3604 UNICODE_STRING RoutineName;
3605
3606 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
3607 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
3608
3609 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
3610 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
3611
3612 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
3613 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
3614
3615 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
3616 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
3617
3618 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
3619 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
3620
3621 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
3622 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
3623 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
3624 {
3625 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
3626 few alternative in the assembly helper file that uses the code in
3627 ZwQueryVolumeInformationFile with a different eax value. */
3628# ifdef RT_ARCH_X86
3629 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
3630 if (*pbCode == 0xb8) /* mov eax, dword */
3631 switch (*(uint32_t const *)&pbCode[1])
3632 {
3633 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
3634 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
3635 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
3636 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
3637 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
3638 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
3639 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
3640 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
3641 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
3642 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
3643 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
3644 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
3645 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
3646 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
3647 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
3648 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
3649 }
3650# elif defined(RT_ARCH_AMD64)
3651 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
3652 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
3653 && pbCode[ 1] == 0x8b
3654 && pbCode[ 2] == 0xc4
3655 && pbCode[ 3] == 0xfa /* cli */
3656 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
3657 && pbCode[ 5] == 0x83
3658 && pbCode[ 6] == 0xec
3659 && pbCode[ 7] == 0x10
3660 && pbCode[ 8] == 0x50 /* push rax */
3661 && pbCode[ 9] == 0x9c /* pushfq */
3662 && pbCode[10] == 0x6a /* push 10 */
3663 && pbCode[11] == 0x10
3664 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
3665 && pbCode[13] == 0x8d
3666 && pbCode[14] == 0x05
3667 && pbCode[19] == 0x50 /* push rax */
3668 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
3669 /*&& pbCode[21] == 0x1f*/
3670 && pbCode[22] == 0x00
3671 && pbCode[23] == 0x00
3672 && pbCode[24] == 0x00
3673 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
3674 )
3675 {
3676 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
3677 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
3678 if (*pbKiServiceLinkage == 0xc3)
3679 {
3680 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
3681 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
3682 switch (pbCode[21])
3683 {
3684 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
3685 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
3686 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
3687 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
3688 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
3689 }
3690 }
3691 }
3692# endif
3693 }
3694 if (!g_pfnNtQueryVirtualMemory)
3695 {
3696 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
3697 return STATUS_PROCEDURE_NOT_FOUND;
3698 }
3699
3700
3701 /* The spinlock protecting our structures. */
3702 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
3703 if (RT_FAILURE(rc))
3704 return VBoxDrvNtErr2NtStatus(rc);
3705 g_NtProtectTree = NULL;
3706
3707 /* Image stuff + certificates. */
3708 NTSTATUS rcNt;
3709 rc = supHardenedWinInitImageVerifier(NULL);
3710 if (RT_SUCCESS(rc))
3711 {
3712 /*
3713 * Intercept process creation and termination.
3714 */
3715 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
3716 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
3717 else
3718 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
3719 if (NT_SUCCESS(rcNt))
3720 {
3721 /*
3722 * Intercept process and thread handle creation calls.
3723 * The preferred method is only available on Vista SP1+.
3724 */
3725 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
3726 {
3727 static OB_OPERATION_REGISTRATION s_aObOperations[] =
3728 {
3729 {
3730 PsProcessType,
3731 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
3732 supdrvNtProtectCallback_ProcessHandlePre,
3733 supdrvNtProtectCallback_ProcessHandlePost,
3734 },
3735 {
3736 PsThreadType,
3737 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
3738 supdrvNtProtectCallback_ThreadHandlePre,
3739 supdrvNtProtectCallback_ThreadHandlePost,
3740 },
3741 };
3742 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
3743 {
3744 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
3745 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
3746 /* .Altitude.Length = */ 0,
3747 /* .Altitude.MaximumLength = */ 0,
3748 /* .Altitude.Buffer = */ NULL,
3749 /* .RegistrationContext = */ NULL,
3750 /* .OperationRegistration = */ &s_aObOperations[0]
3751 };
3752 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
3753 {
3754 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
3755 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
3756 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
3757 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
3758 };
3759
3760 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
3761 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
3762 {
3763 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
3764 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
3765 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
3766
3767 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
3768 if (NT_SUCCESS(rcNt))
3769 {
3770 /*
3771 * Happy ending.
3772 */
3773 return STATUS_SUCCESS;
3774 }
3775 }
3776 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
3777 g_pvObCallbacksCookie = NULL;
3778 }
3779 else
3780 {
3781 /*
3782 * For the time being, we do not implement extra process
3783 * protection on pre-Vista-SP1 systems as they are lacking
3784 * necessary KPIs. XP is end of life, we do not wish to
3785 * spend more time on it, so we don't put up a fuss there.
3786 * Vista users without SP1 can install SP1 (or later), darn it,
3787 * so refuse to load.
3788 */
3789 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
3790 * stuff to a couple of object types. */
3791# ifndef VBOX_WITH_VISTA_NO_SP
3792 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
3793# else
3794 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
3795# endif
3796 {
3797 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
3798 rcNt = STATUS_SXS_VERSION_CONFLICT;
3799 }
3800 else
3801 {
3802 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
3803 return rcNt = STATUS_SUCCESS;
3804 }
3805 g_pvObCallbacksCookie = NULL;
3806 }
3807
3808 /*
3809 * Drop process create/term notifications.
3810 */
3811 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
3812 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
3813 else
3814 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
3815 }
3816 else
3817 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
3818 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
3819 supHardenedWinTermImageVerifier();
3820 }
3821 else
3822 rcNt = VBoxDrvNtErr2NtStatus(rc);
3823
3824 RTSpinlockDestroy(g_hNtProtectLock);
3825 g_NtProtectTree = NIL_RTSPINLOCK;
3826 return rcNt;
3827}
3828
3829#endif /* VBOX_WITH_HARDENING */
3830
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette