VirtualBox

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

Revision 67954, 193.5 KB checked in by vboxsync, 3 months ago (diff)

win/SUPDrv-win*: Changed SUPR0Printf from directly passing the parameters to DbgPrint to format into a stack buffer like the rest. Fixed garbage caused by using in SUPR0Printf calls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* $Id$ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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/*********************************************************************************************************************************
29*   Header Files                                                                                                                 *
30*********************************************************************************************************************************/
31#define IPRT_NT_MAP_TO_ZW
32#define LOG_GROUP LOG_GROUP_SUP_DRV
33#include "../SUPDrvInternal.h"
34#include <excpt.h>
35#include <ntimage.h>
36
37#include <iprt/assert.h>
38#include <iprt/avl.h>
39#include <iprt/ctype.h>
40#include <iprt/initterm.h>
41#include <iprt/mem.h>
42#include <iprt/process.h>
43#include <iprt/power.h>
44#include <iprt/rand.h>
45#include <iprt/semaphore.h>
46#include <iprt/spinlock.h>
47#include <iprt/string.h>
48#include <VBox/log.h>
49#include <VBox/err.h>
50
51#include <iprt/asm-amd64-x86.h>
52
53#ifdef VBOX_WITH_HARDENING
54# include "SUPHardenedVerify-win.h"
55#endif
56
57
58/*********************************************************************************************************************************
59*   Defined Constants And Macros                                                                                                 *
60*********************************************************************************************************************************/
61/** The support service name. */
62#define SERVICE_NAME    "VBoxDrv"
63/** The Pool tag (VBox). */
64#define SUPDRV_NT_POOL_TAG  'xoBV'
65
66/** NT device name for user access. */
67#define DEVICE_NAME_NT_USR          L"\\Device\\VBoxDrvU"
68#ifdef VBOX_WITH_HARDENING
69/** Macro for checking for deflecting calls to the stub device. */
70# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
71    do { if ((a_pDevObj) == g_pDevObjStub) \
72            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
73    } while (0)
74/** Macro for checking for deflecting calls to the stub and error info
75 *  devices. */
76# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
77    do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
78            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
79    } while (0)
80#else
81# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp)                 do {} while (0)
82# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp)   do {} while (0)
83#endif
84
85/** Enables the fast I/O control code path. */
86#define VBOXDRV_WITH_FAST_IO
87
88
89/*********************************************************************************************************************************
90*   Structures and Typedefs                                                                                                      *
91*********************************************************************************************************************************/
92/**
93 * Device extension used by VBoxDrvU.
94 */
95typedef struct SUPDRVDEVEXTUSR
96{
97    /** Global cookie (same location as in SUPDRVDEVEXT, different value). */
98    uint32_t                        u32Cookie;
99    /** Pointer to the main driver extension. */
100    PSUPDRVDEVEXT                   pMainDrvExt;
101} SUPDRVDEVEXTUSR;
102AssertCompileMembersAtSameOffset(SUPDRVDEVEXT, u32Cookie, SUPDRVDEVEXTUSR, u32Cookie);
103/** Pointer to the VBoxDrvU device extension. */
104typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
105/** Value of SUPDRVDEVEXTUSR::u32Cookie. */
106#define SUPDRVDEVEXTUSR_COOKIE      UINT32_C(0x12345678)
107
108/** Get the main device extension. */
109#define SUPDRVNT_GET_DEVEXT(pDevObj) \
110    (  pDevObj != g_pDevObjUsr \
111     ? (PSUPDRVDEVEXT)pDevObj->DeviceExtension \
112     : ((PSUPDRVDEVEXTUSR)pDevObj->DeviceExtension)->pMainDrvExt )
113
114#ifdef VBOX_WITH_HARDENING
115
116/**
117 * Device extension used by VBoxDrvStub.
118 */
119typedef struct SUPDRVDEVEXTSTUB
120{
121    /** Common header. */
122    SUPDRVDEVEXTUSR     Common;
123} SUPDRVDEVEXTSTUB;
124/** Pointer to the VBoxDrvStub device extension. */
125typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
126/** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
127#define SUPDRVDEVEXTSTUB_COOKIE      UINT32_C(0x90abcdef)
128
129
130/**
131 * Device extension used by VBoxDrvErrorInfo.
132 */
133typedef struct SUPDRVDEVEXTERRORINFO
134{
135    /** Common header. */
136    SUPDRVDEVEXTUSR     Common;
137} SUPDRVDEVEXTERRORINFO;
138/** Pointer to the VBoxDrvErrorInfo device extension. */
139typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
140/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
141#define SUPDRVDEVEXTERRORINFO_COOKIE      UINT32_C(0xBadC0ca0)
142
143/**
144 * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
145 */
146typedef struct SUPDRVNTERRORINFO
147{
148    /** The list entry (in g_ErrorInfoHead). */
149    RTLISTNODE      ListEntry;
150    /** The ID of the process this error info belongs to.  */
151    HANDLE          hProcessId;
152    /** The ID of the thread owning this info. */
153    HANDLE          hThreadId;
154    /** Milliseconds createion timestamp (for cleaning up).  */
155    uint64_t        uCreatedMsTs;
156    /** Number of bytes of valid info. */
157    uint32_t        cchErrorInfo;
158    /** The error info. */
159    char            szErrorInfo[16384 - sizeof(RTLISTNODE) - sizeof(HANDLE)*2 - sizeof(uint64_t) - sizeof(uint32_t) - 0x20];
160} SUPDRVNTERRORINFO;
161/** Pointer to error info. */
162typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
163
164
165/**
166 * The kind of process we're protecting.
167 */
168typedef enum SUPDRVNTPROTECTKIND
169{
170    kSupDrvNtProtectKind_Invalid = 0,
171
172    /** Stub process protection while performing process verification.
173     * Next: StubSpawning (or free)  */
174    kSupDrvNtProtectKind_StubUnverified,
175    /** Stub process protection before it creates the VM process.
176     * Next: StubParent, StubDead. */
177    kSupDrvNtProtectKind_StubSpawning,
178    /** Stub process protection while having a VM process as child.
179     * Next: StubDead  */
180    kSupDrvNtProtectKind_StubParent,
181    /** Dead stub process. */
182    kSupDrvNtProtectKind_StubDead,
183
184    /** Potential VM process.
185     * Next: VmProcessConfirmed, VmProcessDead. */
186    kSupDrvNtProtectKind_VmProcessUnconfirmed,
187    /** Confirmed VM process.
188     * Next: VmProcessDead. */
189    kSupDrvNtProtectKind_VmProcessConfirmed,
190    /** Dead VM process. */
191    kSupDrvNtProtectKind_VmProcessDead,
192
193    /** End of valid protection kinds. */
194    kSupDrvNtProtectKind_End
195} SUPDRVNTPROTECTKIND;
196
197/**
198 * A NT process protection structure.
199 */
200typedef struct SUPDRVNTPROTECT
201{
202    /** The AVL node core structure.  The process ID is the pid. */
203    AVLPVNODECORE       AvlCore;
204    /** Magic value (SUPDRVNTPROTECT_MAGIC). */
205    uint32_t volatile   u32Magic;
206    /** Reference counter. */
207    uint32_t volatile   cRefs;
208    /** The kind of process we're protecting. */
209    SUPDRVNTPROTECTKIND volatile enmProcessKind;
210    /** Whether this structure is in the tree. */
211    bool                fInTree : 1;
212    /** 7,: Hack to allow the supid themes service duplicate handle privileges to
213     *  our process. */
214    bool                fThemesFirstProcessCreateHandle : 1;
215    /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
216     *  NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
217    bool                fFirstProcessCreateHandle : 1;
218    /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
219     *  NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
220    bool                fFirstThreadCreateHandle : 1;
221    /** 8.1: Hack to allow more rights to the handle returned by
222     *  NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
223    bool                fCsrssFirstProcessCreateHandle : 1;
224    /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSRSS
225     * during process creation. Only applicable to VmProcessUnconfirmed.  On
226     * 32-bit systems we allow two as ZoneAlarm's system call hooks has been
227     * observed to do some seemingly unnecessary duplication work. */
228    int32_t volatile    cCsrssFirstProcessDuplicateHandle;
229
230    /** The parent PID for VM processes, otherwise NULL. */
231    HANDLE              hParentPid;
232    /** The TID of the thread opening VBoxDrv or VBoxDrvStub, NULL if not opened. */
233    HANDLE              hOpenTid;
234    /** The PID of the CSRSS process associated with this process. */
235    HANDLE              hCsrssPid;
236    /** Pointer to the CSRSS process structure (referenced). */
237    PEPROCESS           pCsrssProcess;
238    /** State dependent data. */
239    union
240    {
241        /** A stub process in the StubParent state will keep a reference to a child
242         * while it's in the VmProcessUnconfirmed state so that it can be cleaned up
243         * correctly if things doesn't work out. */
244        struct SUPDRVNTPROTECT *pChild;
245        /** A process in the VmProcessUnconfirmed state will keep a weak
246         * reference to the parent's protection structure so it can clean up the pChild
247         * reference the parent has to it. */
248        struct SUPDRVNTPROTECT *pParent;
249    } u;
250} SUPDRVNTPROTECT;
251/** Pointer to a NT process protection record. */
252typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
253/** The SUPDRVNTPROTECT::u32Magic value (Robert A. Heinlein). */
254# define SUPDRVNTPROTECT_MAGIC      UINT32_C(0x19070707)
255/** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
256# define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
257
258/** Pointer to ObGetObjectType. */
259typedef POBJECT_TYPE (NTAPI *PFNOBGETOBJECTTYPE)(PVOID);
260/** Pointer to ObRegisterCallbacks. */
261typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
262/** Pointer to ObUnregisterCallbacks. */
263typedef VOID     (NTAPI *PFNOBUNREGISTERCALLBACKS)(PVOID);
264/** Pointer to PsSetCreateProcessNotifyRoutineEx. */
265typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
266/** Pointer to PsReferenceProcessFilePointer. */
267typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
268/** Pointer to PsIsProtectedProcessLight. */
269typedef BOOLEAN  (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
270/** Pointer to ZwAlpcCreatePort. */
271typedef NTSTATUS (NTAPI *PFNZWALPCCREATEPORT)(PHANDLE, POBJECT_ATTRIBUTES, struct _ALPC_PORT_ATTRIBUTES *);
272
273#endif /* VBOX_WITH_HARDENINIG */
274
275
276/*********************************************************************************************************************************
277*   Internal Functions                                                                                                           *
278*********************************************************************************************************************************/
279static void     _stdcall   VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
280static NTSTATUS _stdcall   VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
281static NTSTATUS _stdcall   VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
282static NTSTATUS _stdcall   VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
283#ifdef VBOXDRV_WITH_FAST_IO
284static BOOLEAN  _stdcall   VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
285                                                        PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
286                                                        PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj);
287#endif
288static NTSTATUS _stdcall   VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
289static int                 VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
290static NTSTATUS _stdcall   VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
291static VOID     _stdcall   VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
292static NTSTATUS _stdcall   VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
293static NTSTATUS _stdcall   VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
294static NTSTATUS            VBoxDrvNtErr2NtStatus(int rc);
295#ifdef VBOX_WITH_HARDENING
296static NTSTATUS             supdrvNtProtectInit(void);
297static void                 supdrvNtProtectTerm(void);
298static int                  supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid,
299                                                  SUPDRVNTPROTECTKIND enmProcessKind, bool fLink);
300static void                 supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect);
301static PSUPDRVNTPROTECT     supdrvNtProtectLookup(HANDLE hPid);
302static int                  supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect);
303static int                  supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
304
305static bool                 supdrvNtIsDebuggerAttached(void);
306static void                 supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
307
308#endif
309
310
311/*********************************************************************************************************************************
312*   Exported Functions                                                                                                           *
313*********************************************************************************************************************************/
314RT_C_DECLS_BEGIN
315NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
316RT_C_DECLS_END
317
318
319/*********************************************************************************************************************************
320*   Global Variables                                                                                                             *
321*********************************************************************************************************************************/
322/** Pointer to the system device instance. */
323static PDEVICE_OBJECT g_pDevObjSys = NULL;
324/** Pointer to the user device instance. */
325static PDEVICE_OBJECT g_pDevObjUsr = NULL;
326#ifdef VBOXDRV_WITH_FAST_IO
327/** Fast I/O dispatch table. */
328static FAST_IO_DISPATCH const g_VBoxDrvFastIoDispatch =
329{
330    /* .SizeOfFastIoDispatch            = */ sizeof(g_VBoxDrvFastIoDispatch),
331    /* .FastIoCheckIfPossible           = */ NULL,
332    /* .FastIoRead                      = */ NULL,
333    /* .FastIoWrite                     = */ NULL,
334    /* .FastIoQueryBasicInfo            = */ NULL,
335    /* .FastIoQueryStandardInfo         = */ NULL,
336    /* .FastIoLock                      = */ NULL,
337    /* .FastIoUnlockSingle              = */ NULL,
338    /* .FastIoUnlockAll                 = */ NULL,
339    /* .FastIoUnlockAllByKey            = */ NULL,
340    /* .FastIoDeviceControl             = */ VBoxDrvNtFastIoDeviceControl,
341    /* .AcquireFileForNtCreateSection   = */ NULL,
342    /* .ReleaseFileForNtCreateSection   = */ NULL,
343    /* .FastIoDetachDevice              = */ NULL,
344    /* .FastIoQueryNetworkOpenInfo      = */ NULL,
345    /* .AcquireForModWrite              = */ NULL,
346    /* .MdlRead                         = */ NULL,
347    /* .MdlReadComplete                 = */ NULL,
348    /* .PrepareMdlWrite                 = */ NULL,
349    /* .MdlWriteComplete                = */ NULL,
350    /* .FastIoReadCompressed            = */ NULL,
351    /* .FastIoWriteCompressed           = */ NULL,
352    /* .MdlReadCompleteCompressed       = */ NULL,
353    /* .MdlWriteCompleteCompressed      = */ NULL,
354    /* .FastIoQueryOpen                 = */ NULL,
355    /* .ReleaseForModWrite              = */ NULL,
356    /* .AcquireForCcFlush               = */ NULL,
357    /* .ReleaseForCcFlush               = */ NULL,
358};
359#endif /* VBOXDRV_WITH_FAST_IO */
360
361/** Default ZERO value. */
362static ULONG                        g_fOptDefaultZero = 0;
363/** Registry values.
364 * We wrap these in a struct to ensure they are followed by a little zero
365 * padding in order to limit the chance of trouble on unpatched systems.  */
366struct
367{
368    /** The ForceAsync registry value. */
369    ULONG                           fOptForceAsyncTsc;
370    /** Padding. */
371    uint64_t                        au64Padding[2];
372}                                   g_Options = { FALSE, 0, 0 };
373/** Registry query table for RtlQueryRegistryValues. */
374static RTL_QUERY_REGISTRY_TABLE     g_aRegValues[] =
375{
376    {
377        /* .QueryRoutine = */   NULL,
378        /* .Flags = */          RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK,
379        /* .Name = */           L"ForceAsyncTsc",
380        /* .EntryContext = */   &g_Options.fOptForceAsyncTsc,
381        /* .DefaultType = */    (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD,
382        /* .DefaultData = */    &g_fOptDefaultZero,
383        /* .DefaultLength = */  sizeof(g_fOptDefaultZero),
384    },
385    {   NULL, 0, NULL, NULL, 0, NULL, 0 } /* terminator entry. */
386};
387
388/** Pointer to KeQueryMaximumGroupCount. */
389static PFNKEQUERYMAXIMUMGROUPCOUNT      g_pfnKeQueryMaximumGroupCount = NULL;
390/** Pointer to KeGetProcessorIndexFromNumber. */
391static PFNKEGETPROCESSORINDEXFROMNUMBER g_pfnKeGetProcessorIndexFromNumber = NULL;
392/** Pointer to KeGetProcessorNumberFromIndex. */
393static PFNKEGETPROCESSORNUMBERFROMINDEX g_pfnKeGetProcessorNumberFromIndex = NULL;
394
395#ifdef VBOX_WITH_HARDENING
396/** Pointer to the stub device instance. */
397static PDEVICE_OBJECT               g_pDevObjStub = NULL;
398/** Spinlock protecting g_NtProtectTree as well as the releasing of protection
399 *  structures. */
400static RTSPINLOCK                   g_hNtProtectLock = NIL_RTSPINLOCK;
401/** AVL tree of SUPDRVNTPROTECT structures. */
402static AVLPVTREE                    g_NtProtectTree  = NULL;
403/** Cookie returned by ObRegisterCallbacks for the callbacks. */
404static PVOID                        g_pvObCallbacksCookie = NULL;
405/** Combined windows NT version number.  See SUP_MAKE_NT_VER_COMBINED. */
406uint32_t                            g_uNtVerCombined = 0;
407/** Pointer to ObGetObjectType if available.. */
408static PFNOBGETOBJECTTYPE           g_pfnObGetObjectType = NULL;
409/** Pointer to ObRegisterCallbacks if available.. */
410static PFNOBREGISTERCALLBACKS       g_pfnObRegisterCallbacks = NULL;
411/** Pointer to ObUnregisterCallbacks if available.. */
412static PFNOBUNREGISTERCALLBACKS     g_pfnObUnRegisterCallbacks = NULL;
413/** Pointer to PsSetCreateProcessNotifyRoutineEx if available.. */
414static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutineEx = NULL;
415/** Pointer to PsReferenceProcessFilePointer if available. */
416static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
417/** Pointer to PsIsProtectedProcessLight. */
418static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
419/** Pointer to ZwAlpcCreatePort. */
420static PFNZWALPCCREATEPORT          g_pfnZwAlpcCreatePort = NULL;
421
422# ifdef RT_ARCH_AMD64
423extern "C" {
424/** Pointer to KiServiceLinkage (used to fake missing ZwQueryVirtualMemory on
425 *  XP64 / W2K3-64). */
426PFNRT                               g_pfnKiServiceLinkage  = NULL;
427/** Pointer to KiServiceInternal (used to fake missing ZwQueryVirtualMemory on
428 *  XP64 / W2K3-64) */
429PFNRT                               g_pfnKiServiceInternal = NULL;
430}
431# endif
432/** The primary ALPC port object type. (LpcPortObjectType at init time.) */
433static POBJECT_TYPE                 g_pAlpcPortObjectType1 = NULL;
434/** The secondary ALPC port object type. (Sampled at runtime.) */
435static POBJECT_TYPE volatile        g_pAlpcPortObjectType2 = NULL;
436
437/** Pointer to the error information device instance. */
438static PDEVICE_OBJECT               g_pDevObjErrorInfo = NULL;
439/** Fast mutex semaphore protecting the error info list. */
440static RTSEMMUTEX                   g_hErrorInfoLock = NIL_RTSEMMUTEX;
441/** Head of the error info (SUPDRVNTERRORINFO). */
442static RTLISTANCHOR                 g_ErrorInfoHead;
443
444#endif
445
446
447/**
448 * Takes care of creating the devices and their symbolic links.
449 *
450 * @returns NT status code.
451 * @param   pDrvObj     Pointer to driver object.
452 */
453static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
454{
455    /*
456     * System device.
457     */
458    UNICODE_STRING DevName;
459    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
460    NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
461    if (NT_SUCCESS(rcNt))
462    {
463        /*
464         * User device.
465         */
466        RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
467        rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
468        if (NT_SUCCESS(rcNt))
469        {
470            PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
471            pDevExtUsr->pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
472            pDevExtUsr->u32Cookie   = SUPDRVDEVEXTUSR_COOKIE;
473
474#ifdef VBOX_WITH_HARDENING
475            /*
476             * Hardened stub device.
477             */
478            RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
479            rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
480            if (NT_SUCCESS(rcNt))
481            {
482                if (NT_SUCCESS(rcNt))
483                {
484                    PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
485                    pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
486                    pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTSTUB_COOKIE;
487
488                    /*
489                     * Hardened error information device.
490                     */
491                    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
492                    rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
493                                          &g_pDevObjErrorInfo);
494                    if (NT_SUCCESS(rcNt))
495                    {
496                        g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
497
498                        if (NT_SUCCESS(rcNt))
499                        {
500                            PSUPDRVDEVEXTERRORINFO pDevExtStub = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
501                            pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
502                            pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTERRORINFO_COOKIE;
503
504#endif
505                            /* Done. */
506                            return rcNt;
507#ifdef VBOX_WITH_HARDENING
508                        }
509
510                        /* Bail out. */
511                        IoDeleteDevice(g_pDevObjErrorInfo);
512                        g_pDevObjErrorInfo = NULL;
513                    }
514                }
515
516                /* Bail out. */
517                IoDeleteDevice(g_pDevObjStub);
518                g_pDevObjUsr = NULL;
519            }
520            IoDeleteDevice(g_pDevObjUsr);
521            g_pDevObjUsr = NULL;
522#endif
523        }
524        IoDeleteDevice(g_pDevObjSys);
525        g_pDevObjSys = NULL;
526    }
527    return rcNt;
528}
529
530/**
531 * Destroys the devices and links created by vboxdrvNtCreateDevices.
532 */
533static void vboxdrvNtDestroyDevices(void)
534{
535    if (g_pDevObjUsr)
536    {
537        PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
538        pDevExtUsr->pMainDrvExt = NULL;
539    }
540#ifdef VBOX_WITH_HARDENING
541    if (g_pDevObjStub)
542    {
543        PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
544        pDevExtStub->Common.pMainDrvExt = NULL;
545    }
546    if (g_pDevObjErrorInfo)
547    {
548        PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
549        pDevExtErrorInfo->Common.pMainDrvExt = NULL;
550    }
551#endif
552
553#ifdef VBOX_WITH_HARDENING
554    IoDeleteDevice(g_pDevObjErrorInfo);
555    g_pDevObjErrorInfo = NULL;
556    IoDeleteDevice(g_pDevObjStub);
557    g_pDevObjStub = NULL;
558#endif
559    IoDeleteDevice(g_pDevObjUsr);
560    g_pDevObjUsr = NULL;
561    IoDeleteDevice(g_pDevObjSys);
562    g_pDevObjSys = NULL;
563}
564
565
566/**
567 * Driver entry point.
568 *
569 * @returns appropriate status code.
570 * @param   pDrvObj     Pointer to driver object.
571 * @param   pRegPath    Registry base path.
572 */
573NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
574{
575    RT_NOREF1(pRegPath);
576
577    /*
578     * Sanity checks.
579     */
580#ifdef VBOXDRV_WITH_FAST_IO
581    if (g_VBoxDrvFastIoDispatch.FastIoDeviceControl != VBoxDrvNtFastIoDeviceControl)
582    {
583        DbgPrint("VBoxDrv: FastIoDeviceControl=%p instead of %p\n",
584                 g_VBoxDrvFastIoDispatch.FastIoDeviceControl, VBoxDrvNtFastIoDeviceControl);
585        return STATUS_INTERNAL_ERROR;
586    }
587#endif
588
589    /*
590     * Query options first so any overflows on unpatched machines will do less
591     * harm (see MS11-011 / 2393802 / 2011-03-18).
592     *
593     * Unfortunately, pRegPath isn't documented as zero terminated, even if it
594     * quite likely always is, so we have to make a copy here.
595     */
596    NTSTATUS rcNt;
597    PWSTR pwszCopy = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, pRegPath->Length + sizeof(WCHAR), 'VBox');
598    if (pwszCopy)
599    {
600        memcpy(pwszCopy, pRegPath->Buffer, pRegPath->Length);
601        pwszCopy[pRegPath->Length / sizeof(WCHAR)] = '\0';
602        rcNt = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, pwszCopy,
603                                      g_aRegValues, NULL /*pvContext*/, NULL /*pvEnv*/);
604        ExFreePoolWithTag(pwszCopy, 'VBox');
605        /* Probably safe to ignore rcNt here. */
606    }
607
608    /*
609     * Resolve methods we want but isn't available everywhere.
610     */
611    UNICODE_STRING RoutineName;
612    RtlInitUnicodeString(&RoutineName, L"KeQueryMaximumGroupCount");
613    g_pfnKeQueryMaximumGroupCount = (PFNKEQUERYMAXIMUMGROUPCOUNT)MmGetSystemRoutineAddress(&RoutineName);
614
615    RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber");
616    g_pfnKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName);
617
618    RtlInitUnicodeString(&RoutineName, L"KeGetProcessorNumberFromIndex");
619    g_pfnKeGetProcessorNumberFromIndex = (PFNKEGETPROCESSORNUMBERFROMINDEX)MmGetSystemRoutineAddress(&RoutineName);
620
621    Assert(   (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeGetProcessorIndexFromNumber != NULL)
622           && (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeQueryMaximumGroupCount != NULL)); /* all or nothing. */
623
624    /*
625     * Initialize the runtime (IPRT).
626     */
627    int vrc = RTR0Init(0);
628    if (RT_SUCCESS(vrc))
629    {
630        Log(("VBoxDrv::DriverEntry\n"));
631
632#ifdef VBOX_WITH_HARDENING
633        /*
634         * Initialize process protection.
635         */
636        rcNt = supdrvNtProtectInit();
637        if (NT_SUCCESS(rcNt))
638#endif
639        {
640            /*
641             * Create device.
642             * (That means creating a device object and a symbolic link so the DOS
643             * subsystems (OS/2, win32, ++) can access the device.)
644             */
645            rcNt = vboxdrvNtCreateDevices(pDrvObj);
646            if (NT_SUCCESS(rcNt))
647            {
648                /*
649                 * Initialize the device extension.
650                 */
651                PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
652                memset(pDevExt, 0, sizeof(*pDevExt));
653
654                vrc = supdrvInitDevExt(pDevExt, sizeof(SUPDRVSESSION));
655                if (!vrc)
656                {
657                    /*
658                     * Setup the driver entry points in pDrvObj.
659                     */
660                    pDrvObj->DriverUnload                                   = VBoxDrvNtUnload;
661                    pDrvObj->MajorFunction[IRP_MJ_CREATE]                   = VBoxDrvNtCreate;
662                    pDrvObj->MajorFunction[IRP_MJ_CLEANUP]                  = VBoxDrvNtCleanup;
663                    pDrvObj->MajorFunction[IRP_MJ_CLOSE]                    = VBoxDrvNtClose;
664                    pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = VBoxDrvNtDeviceControl;
665                    pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]  = VBoxDrvNtInternalDeviceControl;
666                    pDrvObj->MajorFunction[IRP_MJ_READ]                     = VBoxDrvNtRead;
667                    pDrvObj->MajorFunction[IRP_MJ_WRITE]                    = VBoxDrvNtNotSupportedStub;
668
669#ifdef VBOXDRV_WITH_FAST_IO
670                    /* Fast I/O to speed up guest execution roundtrips. */
671                    pDrvObj->FastIoDispatch = (PFAST_IO_DISPATCH)&g_VBoxDrvFastIoDispatch;
672#endif
673
674                    /*
675                     * Register ourselves for power state changes.  We don't
676                     * currently care if this fails.
677                     */
678                    UNICODE_STRING      CallbackName;
679                    RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
680
681                    OBJECT_ATTRIBUTES   Attr;
682                    InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
683
684                    rcNt = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
685                    if (rcNt == STATUS_SUCCESS)
686                        pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback,
687                                                                     VBoxPowerDispatchCallback,
688                                                                     g_pDevObjSys);
689
690                    /*
691                     * Done! Returning success!
692                     */
693                    Log(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
694                    return STATUS_SUCCESS;
695                }
696
697                Log(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
698                rcNt = VBoxDrvNtErr2NtStatus(vrc);
699
700                vboxdrvNtDestroyDevices();
701            }
702#ifdef VBOX_WITH_HARDENING
703            supdrvNtProtectTerm();
704#endif
705        }
706        RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
707        RTR0Term();
708    }
709    else
710    {
711        Log(("RTR0Init failed with vrc=%d!\n", vrc));
712        rcNt = VBoxDrvNtErr2NtStatus(vrc);
713    }
714    if (NT_SUCCESS(rcNt))
715        rcNt = STATUS_INVALID_PARAMETER;
716    return rcNt;
717}
718
719
720/**
721 * Unload the driver.
722 *
723 * @param   pDrvObj     Driver object.
724 */
725void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
726{
727    PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
728
729    Log(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
730
731    /* Clean up the power callback registration. */
732    if (pDevExt->hPowerCallback)
733        ExUnregisterCallback(pDevExt->hPowerCallback);
734    if (pDevExt->pObjPowerCallback)
735        ObDereferenceObject(pDevExt->pObjPowerCallback);
736
737    /*
738     * We ASSUME that it's not possible to unload a driver with open handles.
739     */
740    supdrvDeleteDevExt(pDevExt);
741#ifdef VBOX_WITH_HARDENING
742    supdrvNtProtectTerm();
743#endif
744    RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
745    RTR0Term();
746    vboxdrvNtDestroyDevices();
747
748    NOREF(pDrvObj);
749}
750
751
752/**
753 * For simplifying request completion into a simple return statement, extended
754 * version.
755 *
756 * @returns rcNt
757 * @param   rcNt                The status code.
758 * @param   uInfo               Extra info value.
759 * @param   pIrp                The IRP.
760 */
761DECLINLINE(NTSTATUS) supdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
762{
763    pIrp->IoStatus.Status       = rcNt;
764    pIrp->IoStatus.Information  = uInfo;
765    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
766    return rcNt;
767}
768
769
770/**
771 * For simplifying request completion into a simple return statement.
772 *
773 * @returns rcNt
774 * @param   rcNt                The status code.
775 * @param   pIrp                The IRP.
776 */
777DECLINLINE(NTSTATUS) supdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
778{
779    return supdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
780}
781
782
783/**
784 * Create (i.e. Open) file entry point.
785 *
786 * @param   pDevObj     Device object.
787 * @param   pIrp        Request packet.
788 */
789NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
790{
791    Log(("VBoxDrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
792    PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
793    PFILE_OBJECT        pFileObj = pStack->FileObject;
794    PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
795
796    /*
797     * We are not remotely similar to a directory...
798     * (But this is possible.)
799     */
800    if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
801        return supdrvNtCompleteRequest(STATUS_NOT_A_DIRECTORY, pIrp);
802
803    /*
804     * Don't create a session for kernel clients, they'll close the handle
805     * immediately and work with the file object via
806     * VBoxDrvNtInternalDeviceControl.  The first request will be one to
807     * create a session.
808     */
809    NTSTATUS rcNt;
810    if (pIrp->RequestorMode == KernelMode)
811    {
812        if (pDevObj == g_pDevObjSys)
813            return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
814
815        rcNt = STATUS_ACCESS_DENIED;
816    }
817#ifdef VBOX_WITH_HARDENING
818    /*
819     * Anyone can open the error device.
820     */
821    else if (pDevObj == g_pDevObjErrorInfo)
822    {
823        pFileObj->FsContext = NULL;
824        return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
825    }
826#endif
827    else
828    {
829#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
830        /*
831         * Make sure no debuggers are attached to non-user processes.
832         */
833        if (   pDevObj != g_pDevObjUsr
834            && supdrvNtIsDebuggerAttached())
835        {
836            LogRel(("vboxdrv: Process %p is being debugged, access to vboxdrv / vboxdrvu declined.\n",
837                    PsGetProcessId(PsGetCurrentProcess())));
838            rcNt = STATUS_TRUST_FAILURE;
839        }
840        else
841#endif
842        {
843            int rc = VINF_SUCCESS;
844
845#ifdef VBOX_WITH_HARDENING
846            /*
847             * Access to the stub device is only granted to processes which
848             * passes verification.
849             *
850             * Note! The stub device has no need for a SUPDRVSESSION structure,
851             *       so the it uses the SUPDRVNTPROTECT directly instead.
852             */
853            if (pDevObj == g_pDevObjStub)
854            {
855                PSUPDRVNTPROTECT pNtProtect = NULL;
856                rc = supdrvNtProtectCreate(&pNtProtect, PsGetProcessId(PsGetCurrentProcess()),
857                                           kSupDrvNtProtectKind_StubUnverified, true /*fLink*/);
858                if (RT_SUCCESS(rc))
859                {
860                    rc = supdrvNtProtectFindAssociatedCsrss(pNtProtect);
861                    if (RT_SUCCESS(rc))
862                        rc = supdrvNtProtectVerifyProcess(pNtProtect);
863                    if (RT_SUCCESS(rc))
864                    {
865                        pFileObj->FsContext = pNtProtect; /* Keeps reference. */
866                        return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
867                    }
868
869                    supdrvNtProtectRelease(pNtProtect);
870                }
871                LogRel(("vboxdrv: Declined %p access to VBoxDrvStub: rc=%d\n", PsGetProcessId(PsGetCurrentProcess()), rc));
872            }
873            /*
874             * Unrestricted access is only granted to a process in the
875             * VmProcessUnconfirmed state that checks out correctly and is
876             * allowed to transition to VmProcessConfirmed.  Again, only one
877             * session per process.
878             */
879            else if (pDevObj != g_pDevObjUsr)
880            {
881                PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(PsGetCurrentProcess()));
882                if (pNtProtect)
883                {
884                    if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
885                    {
886                        rc = supdrvNtProtectVerifyProcess(pNtProtect);
887                        if (RT_SUCCESS(rc))
888                        {
889                            /* Create a session. */
890                            PSUPDRVSESSION pSession;
891                            rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/,
892                                                     &pSession);
893                            if (RT_SUCCESS(rc))
894                            {
895                                rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
896                                supdrvSessionRelease(pSession);
897                                if (RT_SUCCESS(rc))
898                                {
899                                    pSession->pNtProtect = pNtProtect; /* Keeps reference. */
900                                    return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
901                                }
902                            }
903
904                            /* No second attempt. */
905                            RTSpinlockAcquire(g_hNtProtectLock);
906                            if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
907                                pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
908                            RTSpinlockRelease(g_hNtProtectLock);
909
910                            LogRel(("vboxdrv: supdrvCreateSession failed for process %p: rc=%d.\n",
911                                    PsGetProcessId(PsGetCurrentProcess()), rc));
912                        }
913                        else
914                            LogRel(("vboxdrv: Process %p failed process verification: rc=%d.\n",
915                                    PsGetProcessId(PsGetCurrentProcess()), rc));
916                    }
917                    else
918                    {
919                        LogRel(("vboxdrv: %p is not a budding VM process (enmProcessKind=%d).\n",
920                                PsGetProcessId(PsGetCurrentProcess()), pNtProtect->enmProcessKind));
921                        rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2;
922                    }
923                    supdrvNtProtectRelease(pNtProtect);
924                }
925                else
926                {
927                    LogRel(("vboxdrv: %p is not a budding VM process.\n", PsGetProcessId(PsGetCurrentProcess())));
928                    rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1;
929                }
930            }
931            /*
932             * Call common code to create an unprivileged session.
933             */
934            else
935            {
936                PSUPDRVSESSION pSession;
937                rc = supdrvCreateSession(pDevExt, true /*fUser*/, false /*fUnrestricted*/, &pSession);
938                if (RT_SUCCESS(rc))
939                {
940                    rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
941                    supdrvSessionRelease(pSession);
942                    if (RT_SUCCESS(rc))
943                    {
944                        pFileObj->FsContext  = pSession; /* Keeps reference. No race. */
945                        pSession->pNtProtect = NULL;
946                        return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
947                    }
948                }
949            }
950
951#else  /* !VBOX_WITH_HARDENING */
952            /*
953             * Call common code to create a session.
954             */
955            pFileObj->FsContext = NULL;
956            PSUPDRVSESSION pSession;
957            rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/, &pSession);
958            if (RT_SUCCESS(rc))
959            {
960                rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
961                supdrvSessionRelease(pSession);
962                if (RT_SUCCESS(rc))
963                    return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
964
965            }
966#endif /* !VBOX_WITH_HARDENING */
967
968            /* bail out */
969            rcNt = VBoxDrvNtErr2NtStatus(rc);
970        }
971    }
972
973    Assert(!NT_SUCCESS(rcNt));
974    pFileObj->FsContext = NULL;
975    return supdrvNtCompleteRequest(rcNt, pIrp); /* Note. the IoStatus is completely ignored on error. */
976}
977
978
979/**
980 * Clean up file handle entry point.
981 *
982 * @param   pDevObj     Device object.
983 * @param   pIrp        Request packet.
984 */
985NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
986{
987    PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
988    PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
989    PFILE_OBJECT        pFileObj = pStack->FileObject;
990
991#ifdef VBOX_WITH_HARDENING
992    if (pDevObj == g_pDevObjStub)
993    {
994        PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
995        Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
996        if (pNtProtect)
997        {
998            supdrvNtProtectRelease(pNtProtect);
999            pFileObj->FsContext = NULL;
1000        }
1001    }
1002    else if (pDevObj == g_pDevObjErrorInfo)
1003        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1004    else
1005#endif
1006    {
1007        PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1008                                                             (PSUPDRVSESSION *)&pFileObj->FsContext);
1009        Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1010        if (pSession)
1011        {
1012            supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1013            supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1014        }
1015    }
1016
1017    return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1018}
1019
1020
1021/**
1022 * Close file entry point.
1023 *
1024 * @param   pDevObj     Device object.
1025 * @param   pIrp        Request packet.
1026 */
1027NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1028{
1029    PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
1030    PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
1031    PFILE_OBJECT        pFileObj = pStack->FileObject;
1032
1033#ifdef VBOX_WITH_HARDENING
1034    if (pDevObj == g_pDevObjStub)
1035    {
1036        PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
1037        Log(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
1038        if (pNtProtect)
1039        {
1040            supdrvNtProtectRelease(pNtProtect);
1041            pFileObj->FsContext = NULL;
1042        }
1043    }
1044    else if (pDevObj == g_pDevObjErrorInfo)
1045        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1046    else
1047#endif
1048    {
1049        PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1050                                                             (PSUPDRVSESSION *)&pFileObj->FsContext);
1051        Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1052        if (pSession)
1053        {
1054            supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1055            supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1056        }
1057    }
1058
1059    return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1060}
1061
1062
1063#ifdef VBOXDRV_WITH_FAST_IO
1064/**
1065 * Fast I/O device control callback.
1066 *
1067 * This performs no buffering, neither on the way in or out.
1068 *
1069 * @returns TRUE if handled, FALSE if the normal I/O control routine should be
1070 *          called.
1071 * @param   pFileObj            The file object.
1072 * @param   fWait               Whether it's a blocking call
1073 * @param   pvInput             The input buffer as specified by the user.
1074 * @param   cbInput             The size of the input buffer.
1075 * @param   pvOutput            The output buffer as specfied by the user.
1076 * @param   cbOutput            The size of the output buffer.
1077 * @param   uCmd                The I/O command/function being invoked.
1078 * @param   pIoStatus           Where to return the status of the operation.
1079 * @param   pDevObj             The device object..
1080 */
1081static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
1082                                                     PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
1083                                                     PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
1084{
1085    RT_NOREF1(fWait);
1086
1087    /*
1088     * Only the normal devices, not the stub or error info ones.
1089     */
1090    if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
1091    {
1092        pIoStatus->Status      = STATUS_NOT_SUPPORTED;
1093        pIoStatus->Information = 0;
1094        return TRUE;
1095    }
1096
1097    /*
1098     * Check the input a little bit and get a the session references.
1099     */
1100    PSUPDRVDEVEXT  pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
1101    PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1102                                                         (PSUPDRVSESSION *)&pFileObj->FsContext);
1103    if (!pSession)
1104    {
1105        pIoStatus->Status      = STATUS_TRUST_FAILURE;
1106        pIoStatus->Information = 0;
1107        return TRUE;
1108    }
1109
1110    if (pSession->fUnrestricted)
1111    {
1112#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1113        if (supdrvNtIsDebuggerAttached())
1114        {
1115            pIoStatus->Status      = STATUS_TRUST_FAILURE;
1116            pIoStatus->Information = 0;
1117            supdrvSessionRelease(pSession);
1118            return TRUE;
1119        }
1120#endif
1121
1122        /*
1123         * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1124         * the session and iCmd, and does not return anything.
1125         */
1126        if (   uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1127            || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
1128            || uCmd == SUP_IOCTL_FAST_DO_NOP)
1129        {
1130            int rc = supdrvIOCtlFast(uCmd, (unsigned)(uintptr_t)pvOutput/* VMCPU id */, pDevExt, pSession);
1131            pIoStatus->Status      = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
1132            pIoStatus->Information = 0; /* Could be used to pass rc if we liked. */
1133            supdrvSessionRelease(pSession);
1134            return TRUE;
1135        }
1136    }
1137
1138    /*
1139     * The normal path.
1140     */
1141    NTSTATUS    rcNt;
1142    unsigned    cbOut = 0;
1143    int         rc = 0;
1144    Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
1145          pDevExt, uCmd, pvInput, cbInput, pvOutput, cbOutput, pSession));
1146
1147# ifdef RT_ARCH_AMD64
1148    /* Don't allow 32-bit processes to do any I/O controls. */
1149    if (!IoIs32bitProcess(NULL))
1150# endif
1151    {
1152        /*
1153         * In this fast I/O device control path we have to do our own buffering.
1154         */
1155        /* Verify that the I/O control function matches our pattern. */
1156        if ((uCmd & 0x3) == METHOD_BUFFERED)
1157        {
1158            /* Get the header so we can validate it a little bit against the
1159               parameters before allocating any memory kernel for the reqest. */
1160            SUPREQHDR Hdr;
1161            if (cbInput >= sizeof(Hdr) && cbOutput >= sizeof(Hdr))
1162            {
1163                __try
1164                {
1165                    RtlCopyMemory(&Hdr, pvInput, sizeof(Hdr));
1166                    rcNt = STATUS_SUCCESS;
1167                }
1168                __except(EXCEPTION_EXECUTE_HANDLER)
1169                {
1170                    rcNt = GetExceptionCode();
1171                    Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1172                }
1173            }
1174            else
1175            {
1176                Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1177                rcNt = STATUS_INVALID_PARAMETER;
1178            }
1179            if (NT_SUCCESS(rcNt))
1180            {
1181                /* Verify that the sizes in the request header are correct. */
1182                ULONG cbBuf = RT_MAX(cbInput, cbOutput);
1183                if (   cbInput  == Hdr.cbIn
1184                    && cbOutput == Hdr.cbOut
1185                    && cbBuf < _1M*16)
1186                {
1187                    /* Allocate a buffer and copy all the input into it. */
1188                    PSUPREQHDR pHdr = (PSUPREQHDR)ExAllocatePoolWithTag(NonPagedPool, cbBuf, 'VBox');
1189                    if (pHdr)
1190                    {
1191                        __try
1192                        {
1193                            RtlCopyMemory(pHdr, pvInput, cbInput);
1194                            if (cbInput < cbBuf)
1195                                RtlZeroMemory((uint8_t *)pHdr + cbInput, cbBuf - cbInput);
1196                            if (!memcmp(pHdr, &Hdr, sizeof(Hdr)))
1197                                rcNt = STATUS_SUCCESS;
1198                            else
1199                                rcNt = STATUS_INVALID_PARAMETER;
1200                        }
1201                        __except(EXCEPTION_EXECUTE_HANDLER)
1202                        {
1203                            rcNt = GetExceptionCode();
1204                        }
1205                        if (NT_SUCCESS(rcNt))
1206                        {
1207                            /*
1208                             * Now call the common code to do the real work.
1209                             */
1210                            rc = supdrvIOCtl(uCmd, pDevExt, pSession, pHdr, cbBuf);
1211                            if (RT_SUCCESS(rc))
1212                            {
1213                                /*
1214                                 * Copy back the result.
1215                                 */
1216                                cbOut = pHdr->cbOut;
1217                                if (cbOut > cbOutput)
1218                                {
1219                                    cbOut = cbOutput;
1220                                    OSDBGPRINT(("VBoxDrvNtFastIoDeviceControl: too much output! %#x > %#x; uCmd=%#x!\n",
1221                                                pHdr->cbOut, cbOut, uCmd));
1222                                }
1223                                if (cbOut)
1224                                {
1225                                    __try
1226                                    {
1227                                        RtlCopyMemory(pvOutput, pHdr, cbOut);
1228                                        rcNt = STATUS_SUCCESS;
1229                                    }
1230                                    __except(EXCEPTION_EXECUTE_HANDLER)
1231                                    {
1232                                        rcNt = GetExceptionCode();
1233                                    }
1234                                }
1235                                else
1236                                    rcNt = STATUS_SUCCESS;
1237                            }
1238                            else if (rc == VERR_INVALID_PARAMETER)
1239                                rcNt = STATUS_INVALID_PARAMETER;
1240                            else
1241                                rcNt = STATUS_NOT_SUPPORTED;
1242                            Log2(("VBoxDrvNtFastIoDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1243                        }
1244                        else
1245                            Log(("VBoxDrvNtFastIoDeviceControl: Error reading %u bytes of user memory at %p (uCmd=%#x)\n",
1246                                 cbInput, pvInput, uCmd));
1247                        ExFreePoolWithTag(pHdr, 'VBox');
1248                    }
1249                    else
1250                        rcNt = STATUS_NO_MEMORY;
1251                }
1252                else
1253                {
1254                    Log(("VBoxDrvNtFastIoDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1255                         uCmd, Hdr.cbIn, Hdr.cbOut, cbInput, cbOutput));
1256                    rcNt = STATUS_INVALID_PARAMETER;
1257                }
1258            }
1259        }
1260        else
1261        {
1262            Log(("VBoxDrvNtFastIoDeviceControl: not buffered request (%#x) - not supported\n", uCmd));
1263            rcNt = STATUS_NOT_SUPPORTED;
1264        }
1265    }
1266# ifdef RT_ARCH_AMD64
1267    else
1268    {
1269        Log(("VBoxDrvNtFastIoDeviceControl: WOW64 req - not supported\n"));
1270        rcNt = STATUS_NOT_SUPPORTED;
1271    }
1272# endif
1273
1274    /* complete the request. */
1275    pIoStatus->Status = rcNt;
1276    pIoStatus->Information = cbOut;
1277    supdrvSessionRelease(pSession);
1278    return TRUE; /* handled. */
1279}
1280#endif /* VBOXDRV_WITH_FAST_IO */
1281
1282
1283/**
1284 * Device I/O Control entry point.
1285 *
1286 * @param   pDevObj     Device object.
1287 * @param   pIrp        Request packet.
1288 */
1289NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1290{
1291    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1292
1293    PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
1294    PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
1295    PSUPDRVSESSION      pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1296                                                              (PSUPDRVSESSION *)&pStack->FileObject->FsContext);
1297
1298    if (!RT_VALID_PTR(pSession))
1299        return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1300
1301    /*
1302     * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1303     * the session and iCmd, and does not return anything.
1304     */
1305    if (pSession->fUnrestricted)
1306    {
1307#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1308        if (supdrvNtIsDebuggerAttached())
1309        {
1310            supdrvSessionRelease(pSession);
1311            return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1312        }
1313#endif
1314
1315        ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
1316        if (   ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1317            || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
1318            || ulCmd == SUP_IOCTL_FAST_DO_NOP)
1319        {
1320            int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
1321
1322            /* Complete the I/O request. */
1323            supdrvSessionRelease(pSession);
1324            return supdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
1325        }
1326    }
1327
1328    return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
1329}
1330
1331
1332/**
1333 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
1334 *
1335 * @returns NT status code.
1336 *
1337 * @param   pDevExt     Device extension.
1338 * @param   pSession    The session.
1339 * @param   pIrp        Request packet.
1340 * @param   pStack      The stack location containing the DeviceControl parameters.
1341 */
1342static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
1343{
1344    NTSTATUS    rcNt;
1345    unsigned    cbOut = 0;
1346    int         rc = 0;
1347    Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1348          pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1349          pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1350          pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1351
1352#ifdef RT_ARCH_AMD64
1353    /* Don't allow 32-bit processes to do any I/O controls. */
1354    if (!IoIs32bitProcess(pIrp))
1355#endif
1356    {
1357        /* Verify that it's a buffered CTL. */
1358        if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1359        {
1360            /* Verify that the sizes in the request header are correct. */
1361            PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1362            if (    pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1363                &&  pStack->Parameters.DeviceIoControl.InputBufferLength ==  pHdr->cbIn
1364                &&  pStack->Parameters.DeviceIoControl.OutputBufferLength ==  pHdr->cbOut)
1365            {
1366                /* Zero extra output bytes to make sure we don't leak anything. */
1367                if (pHdr->cbIn < pHdr->cbOut)
1368                    RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
1369
1370                /*
1371                 * Do the job.
1372                 */
1373                rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
1374                                 RT_MAX(pHdr->cbIn, pHdr->cbOut));
1375                if (!rc)
1376                {
1377                    rcNt = STATUS_SUCCESS;
1378                    cbOut = pHdr->cbOut;
1379                    if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
1380                    {
1381                        cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1382                        OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
1383                                    pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
1384                    }
1385                }
1386                else
1387                    rcNt = STATUS_INVALID_PARAMETER;
1388                Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1389            }
1390            else
1391            {
1392                Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1393                     pStack->Parameters.DeviceIoControl.IoControlCode,
1394                     pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
1395                     pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
1396                     pStack->Parameters.DeviceIoControl.InputBufferLength,
1397                     pStack->Parameters.DeviceIoControl.OutputBufferLength));
1398                rcNt = STATUS_INVALID_PARAMETER;
1399            }
1400        }
1401        else
1402        {
1403            Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
1404                 pStack->Parameters.DeviceIoControl.IoControlCode));
1405            rcNt = STATUS_NOT_SUPPORTED;
1406        }
1407    }
1408#ifdef RT_ARCH_AMD64
1409    else
1410    {
1411        Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
1412        rcNt = STATUS_NOT_SUPPORTED;
1413    }
1414#endif
1415
1416    /* complete the request. */
1417    pIrp->IoStatus.Status = rcNt;
1418    pIrp->IoStatus.Information = cbOut;
1419    supdrvSessionRelease(pSession);
1420    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1421    return rcNt;
1422}
1423
1424
1425/**
1426 * Internal Device I/O Control entry point, used for IDC.
1427 *
1428 * @param   pDevObj     Device object.
1429 * @param   pIrp        Request packet.
1430 */
1431NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1432{
1433    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1434
1435    PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
1436    PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
1437    PFILE_OBJECT        pFileObj = pStack ? pStack->FileObject : NULL;
1438    PSUPDRVSESSION      pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
1439    NTSTATUS            rcNt;
1440    unsigned            cbOut = 0;
1441    int                 rc = 0;
1442    Log2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1443          pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1444          pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1445          pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1446
1447    /* Verify that it's a buffered CTL. */
1448    if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1449    {
1450        /* Verify the pDevExt in the session. */
1451        if (  pStack->Parameters.DeviceIoControl.IoControlCode != SUPDRV_IDC_REQ_CONNECT
1452            ? VALID_PTR(pSession) && pSession->pDevExt == pDevExt
1453            : !pSession
1454           )
1455        {
1456            /* Verify that the size in the request header is correct. */
1457            PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1458            if (    pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1459                &&  pStack->Parameters.DeviceIoControl.InputBufferLength  == pHdr->cb
1460                &&  pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
1461            {
1462                /*
1463                 * Call the generic code.
1464                 *
1465                 * Note! Connect and disconnect requires some extra attention
1466                 *       in order to get the session handling right.
1467                 */
1468                if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1469                    pFileObj->FsContext = NULL;
1470
1471                rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
1472                if (!rc)
1473                {
1474                    if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
1475                        pFileObj->FsContext = ((PSUPDRVIDCREQCONNECT)pHdr)->u.Out.pSession;
1476
1477                    rcNt = STATUS_SUCCESS;
1478                    cbOut = pHdr->cb;
1479                }
1480                else
1481                {
1482                    rcNt = STATUS_INVALID_PARAMETER;
1483                    if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1484                        pFileObj->FsContext = pSession;
1485                }
1486                Log2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
1487            }
1488            else
1489            {
1490                Log(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
1491                     pStack->Parameters.DeviceIoControl.IoControlCode,
1492                     pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
1493                     pStack->Parameters.DeviceIoControl.InputBufferLength,
1494                     pStack->Parameters.DeviceIoControl.OutputBufferLength));
1495                rcNt = STATUS_INVALID_PARAMETER;
1496            }
1497        }
1498        else
1499            rcNt = STATUS_NOT_SUPPORTED;
1500    }
1501    else
1502    {
1503        Log(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
1504             pStack->Parameters.DeviceIoControl.IoControlCode));
1505        rcNt = STATUS_NOT_SUPPORTED;
1506    }
1507
1508    /* complete the request. */
1509    pIrp->IoStatus.Status = rcNt;
1510    pIrp->IoStatus.Information = cbOut;
1511    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1512    return rcNt;
1513}
1514
1515
1516/**
1517 * Implementation of the read major function for VBoxDrvErrorInfo.
1518 *
1519 * This is a stub function for the other devices.
1520 *
1521 * @returns NT status code.
1522 * @param   pDevObj             The device object.
1523 * @param   pIrp                The I/O request packet.
1524 */
1525NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1526{
1527    Log(("VBoxDrvNtRead\n"));
1528    RT_NOREF1(pDevObj);
1529
1530    NTSTATUS rcNt;
1531    pIrp->IoStatus.Information = 0;
1532
1533#ifdef VBOX_WITH_HARDENING
1534    /*
1535     * VBoxDrvErrorInfo?
1536     */
1537    if (pDevObj == g_pDevObjErrorInfo)
1538    {
1539        PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1540        if (   pStack
1541            && (pIrp->Flags & IRP_BUFFERED_IO))
1542        {
1543            /*
1544             * Look up the process error information.
1545             */
1546            HANDLE hCurThreadId  = PsGetCurrentThreadId();
1547            HANDLE hCurProcessId = PsGetCurrentProcessId();
1548            int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
1549            if (RT_SUCCESS(rc))
1550            {
1551                PSUPDRVNTERRORINFO  pCur;
1552                RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
1553                {
1554                    if (   pCur->hProcessId == hCurProcessId
1555                        && pCur->hThreadId  == hCurThreadId)
1556                        break;
1557                }
1558
1559                /*
1560                 * Did we find error info and is the caller requesting data within it?
1561                 * If so, check the destination buffer and copy the data into it.
1562                 */
1563                if (   pCur
1564                    && pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
1565                    && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
1566                {
1567                    PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1568                    if (pvDstBuf)
1569                    {
1570                        uint32_t offRead  = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
1571                        uint32_t cbToRead = pCur->cchErrorInfo - offRead;
1572                        if (cbToRead < pStack->Parameters.Read.Length)
1573                            RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
1574                        else
1575                            cbToRead = pStack->Parameters.Read.Length;
1576                        memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
1577                        pIrp->IoStatus.Information = cbToRead;
1578
1579                        rcNt = STATUS_SUCCESS;
1580                    }
1581                    else
1582                        rcNt = STATUS_INVALID_ADDRESS;
1583                }
1584                /*
1585                 * End of file. Free the info.
1586                 */
1587                else if (pCur)
1588                {
1589                    RTListNodeRemove(&pCur->ListEntry);
1590                    RTMemFree(pCur);
1591                    rcNt = STATUS_END_OF_FILE;
1592                }
1593                /*
1594                 * We found no error info. Return EOF.
1595                 */
1596                else
1597                    rcNt = STATUS_END_OF_FILE;
1598
1599                RTSemMutexRelease(g_hErrorInfoLock);
1600            }
1601            else
1602                rcNt = STATUS_UNSUCCESSFUL;
1603
1604            /* Paranoia: Clear the buffer on failure. */
1605            if (!NT_SUCCESS(rcNt))
1606            {
1607                PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1608                if (   pvDstBuf
1609                    && pStack->Parameters.Read.Length)
1610                    RT_BZERO(pvDstBuf, pStack->Parameters.Read.Length);
1611            }
1612        }
1613        else
1614            rcNt = STATUS_INVALID_PARAMETER;
1615    }
1616    else
1617#endif /* VBOX_WITH_HARDENING */
1618    {
1619        /*
1620         * Stub.
1621         */
1622        rcNt = STATUS_NOT_SUPPORTED;
1623    }
1624
1625    /*
1626     * Complete the request.
1627     */
1628    pIrp->IoStatus.Status = rcNt;
1629    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1630    return rcNt;
1631}
1632
1633
1634/**
1635 * Stub function for functions we don't implemented.
1636 *
1637 * @returns STATUS_NOT_SUPPORTED
1638 * @param   pDevObj     Device object.
1639 * @param   pIrp        IRP.
1640 */
1641NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1642{
1643    Log(("VBoxDrvNtNotSupportedStub\n"));
1644    NOREF(pDevObj);
1645
1646    pIrp->IoStatus.Information = 0;
1647    pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1648    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1649
1650    return STATUS_NOT_SUPPORTED;
1651}
1652
1653
1654/**
1655 * ExRegisterCallback handler for power events
1656 *
1657 * @param   pCallbackContext    User supplied parameter (pDevObj)
1658 * @param   pvArgument1         First argument
1659 * @param   pvArgument2         Second argument
1660 */
1661VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pvArgument1, PVOID pvArgument2)
1662{
1663    /*PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;*/ RT_NOREF1(pCallbackContext);
1664    Log(("VBoxPowerDispatchCallback: %x %x\n", pvArgument1, pvArgument2));
1665
1666    /* Power change imminent? */
1667    if ((uintptr_t)pvArgument1 == PO_CB_SYSTEM_STATE_LOCK)
1668    {
1669        if (pvArgument2 == NULL)
1670            Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
1671        else
1672            Log(("VBoxPowerDispatchCallback: resumed!\n"));
1673
1674        /* Inform any clients that have registered themselves with IPRT. */
1675        RTPowerSignalEvent(pvArgument2 == NULL ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
1676    }
1677}
1678
1679
1680/**
1681 * Called to clean up the session structure before it's freed.
1682 *
1683 * @param   pDevExt             The device globals.
1684 * @param   pSession            The session that's being cleaned up.
1685 */
1686void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1687{
1688#ifdef VBOX_WITH_HARDENING
1689    if (pSession->pNtProtect)
1690    {
1691        supdrvNtProtectRelease(pSession->pNtProtect);
1692        pSession->pNtProtect = NULL;
1693    }
1694    RT_NOREF1(pDevExt);
1695#else
1696    RT_NOREF2(pDevExt, pSession);
1697#endif
1698}
1699
1700
1701void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1702{
1703    NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1704}
1705
1706
1707void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1708{
1709    NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1710}
1711
1712
1713size_t VBOXCALL supdrvOSGipGetGroupTableSize(PSUPDRVDEVEXT pDevExt)
1714{
1715    NOREF(pDevExt);
1716    uint32_t cMaxCpus = RTMpGetCount();
1717    uint32_t cGroups  = RTMpGetMaxCpuGroupCount();
1718
1719    return cGroups * RT_OFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs)
1720         + RT_SIZEOFMEMB(SUPGIPCPUGROUP, aiCpuSetIdxs[0]) * cMaxCpus;
1721}
1722
1723
1724int VBOXCALL supdrvOSInitGipGroupTable(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, size_t cbGipCpuGroups)
1725{
1726    Assert(cbGipCpuGroups > 0); NOREF(cbGipCpuGroups); NOREF(pDevExt);
1727
1728    unsigned const  cGroups = RTMpGetMaxCpuGroupCount();
1729    AssertReturn(cGroups > 0 && cGroups < RT_ELEMENTS(pGip->aoffCpuGroup), VERR_INTERNAL_ERROR_2);
1730    pGip->cPossibleCpuGroups = cGroups;
1731
1732    PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)&pGip->aCPUs[pGip->cCpus];
1733    for (uint32_t idxGroup = 0; idxGroup < cGroups; idxGroup++)
1734    {
1735        uint32_t cActive  = 0;
1736        uint32_t cMax     = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1737        uint32_t cbNeeded = RT_OFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs[cMax]);
1738        AssertReturn(cbNeeded <= cbGipCpuGroups, VERR_INTERNAL_ERROR_3);
1739        AssertReturn(cActive <= cMax, VERR_INTERNAL_ERROR_4);
1740
1741        pGip->aoffCpuGroup[idxGroup] = (uint16_t)((uintptr_t)pGroup - (uintptr_t)pGip);
1742        pGroup->cMembers    = cActive;
1743        pGroup->cMaxMembers = cMax;
1744        for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1745        {
1746            pGroup->aiCpuSetIdxs[idxMember] = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1747            Assert((unsigned)pGroup->aiCpuSetIdxs[idxMember] < pGip->cPossibleCpus);
1748        }
1749
1750        /* advance. */
1751        cbGipCpuGroups -= cbNeeded;
1752        pGroup = (PSUPGIPCPUGROUP)&pGroup->aiCpuSetIdxs[cMax];
1753    }
1754
1755    return VINF_SUCCESS;
1756}
1757
1758
1759void VBOXCALL supdrvOSGipInitGroupBitsForCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu)
1760{
1761    NOREF(pDevExt);
1762
1763    /*
1764     * Translate the CPU index into a group and member.
1765     */
1766    PROCESSOR_NUMBER ProcNum = { 0, pGipCpu->iCpuSet, 0 };
1767    if (g_pfnKeGetProcessorNumberFromIndex)
1768    {
1769        NTSTATUS rcNt = g_pfnKeGetProcessorNumberFromIndex(pGipCpu->iCpuSet, &ProcNum);
1770        if (NT_SUCCESS(rcNt))
1771            Assert(ProcNum.Group < g_pfnKeQueryMaximumGroupCount());
1772        else
1773        {
1774            AssertFailed();
1775            ProcNum.Group  = 0;
1776            ProcNum.Number = pGipCpu->iCpuSet;
1777        }
1778    }
1779    pGipCpu->iCpuGroup       = ProcNum.Group;
1780    pGipCpu->iCpuGroupMember = ProcNum.Number;
1781
1782    /*
1783     * Update the group info.  Just do this wholesale for now (doesn't scale well).
1784     */
1785    for (uint32_t idxGroup = 0; idxGroup < pGip->cPossibleCpuGroups; idxGroup++)
1786        if (pGip->aoffCpuGroup[idxGroup] != UINT16_MAX)
1787        {
1788            PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)((uintptr_t)pGip + pGip->aoffCpuGroup[idxGroup]);
1789
1790            uint32_t cActive  = 0;
1791            uint32_t cMax     = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1792            AssertStmt(cMax == pGroup->cMaxMembers, cMax = pGroup->cMaxMembers);
1793            AssertStmt(cActive <= cMax, cActive = cMax);
1794            if (pGroup->cMembers != cActive)
1795                pGroup->cMembers = cActive;
1796
1797            for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1798            {
1799                int idxCpuSet = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1800                AssertMsg((unsigned)idxCpuSet < pGip->cPossibleCpus,
1801                          ("%d vs %d for %u.%u\n", idxCpuSet, pGip->cPossibleCpus, idxGroup, idxMember));
1802
1803                if (pGroup->aiCpuSetIdxs[idxMember] != idxCpuSet)
1804                    pGroup->aiCpuSetIdxs[idxMember] = idxCpuSet;
1805            }
1806        }
1807}
1808
1809
1810/**
1811 * Initializes any OS specific object creator fields.
1812 */
1813void VBOXCALL   supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1814{
1815    NOREF(pObj);
1816    NOREF(pSession);
1817}
1818
1819
1820/**
1821 * Checks if the session can access the object.
1822 *
1823 * @returns true if a decision has been made.
1824 * @returns false if the default access policy should be applied.
1825 *
1826 * @param   pObj        The object in question.
1827 * @param   pSession    The session wanting to access the object.
1828 * @param   pszObjName  The object name, can be NULL.
1829 * @param   prc         Where to store the result when returning true.
1830 */
1831bool VBOXCALL   supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1832{
1833    NOREF(pObj);
1834    NOREF(pSession);
1835    NOREF(pszObjName);
1836    NOREF(prc);
1837    return false;
1838}
1839
1840
1841/**
1842 * Force async tsc mode (stub).
1843 */
1844bool VBOXCALL  supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1845{
1846    RT_NOREF1(pDevExt);
1847    return g_Options.fOptForceAsyncTsc != 0;
1848}
1849
1850
1851/**
1852 * Whether the host takes CPUs offline during a suspend/resume operation.
1853 */
1854bool VBOXCALL  supdrvOSAreCpusOfflinedOnSuspend(void)
1855{
1856    return false;
1857}
1858
1859
1860/**
1861 * Whether the hardware TSC has been synchronized by the OS.
1862 */
1863bool VBOXCALL  supdrvOSAreTscDeltasInSync(void)
1864{
1865    /* If IPRT didn't find KeIpiGenericCall we pretend windows(, the firmware,
1866       or whoever) always configures TSCs perfectly. */
1867    return !RTMpOnPairIsConcurrentExecSupported();
1868}
1869
1870
1871#define MY_SystemLoadGdiDriverInSystemSpaceInformation  54
1872#define MY_SystemUnloadGdiDriverInformation             27
1873
1874typedef struct MYSYSTEMGDIDRIVERINFO
1875{
1876    UNICODE_STRING  Name;                   /**< In:  image file name. */
1877    PVOID           ImageAddress;           /**< Out: the load address. */
1878    PVOID           SectionPointer;         /**< Out: section object. */
1879    PVOID           EntryPointer;           /**< Out: entry point address. */
1880    PVOID           ExportSectionPointer;   /**< Out: export directory/section. */
1881    ULONG           ImageLength;            /**< Out: SizeOfImage. */
1882} MYSYSTEMGDIDRIVERINFO;
1883
1884extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
1885
1886int  VBOXCALL   supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1887{
1888    pImage->pvNtSectionObj = NULL;
1889    pImage->hMemLock = NIL_RTR0MEMOBJ;
1890
1891#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
1892# ifndef RT_ARCH_X86
1893#  error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
1894# endif
1895    NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
1896    return VERR_NOT_SUPPORTED;
1897
1898#else
1899    /*
1900     * Convert the filename from DOS UTF-8 to NT UTF-16.
1901     */
1902    size_t cwcFilename;
1903    int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
1904    if (RT_FAILURE(rc))
1905        return rc;
1906
1907    PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
1908    if (!pwcsFilename)
1909        return VERR_NO_TMP_MEMORY;
1910
1911    pwcsFilename[0] = '\\';
1912    pwcsFilename[1] = '?';
1913    pwcsFilename[2] = '?';
1914    pwcsFilename[3] = '\\';
1915    PRTUTF16 pwcsTmp = &pwcsFilename[4];
1916    rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
1917    if (RT_SUCCESS(rc))
1918    {
1919        /*
1920         * Try load it.
1921         */
1922        MYSYSTEMGDIDRIVERINFO Info;
1923        RtlInitUnicodeString(&Info.Name, pwcsFilename);
1924        Info.ImageAddress           = NULL;
1925        Info.SectionPointer         = NULL;
1926        Info.EntryPointer           = NULL;
1927        Info.ExportSectionPointer   = NULL;
1928        Info.ImageLength            = 0;
1929
1930        NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
1931        if (NT_SUCCESS(rcNt))
1932        {
1933            pImage->pvImage = Info.ImageAddress;
1934            pImage->pvNtSectionObj = Info.SectionPointer;
1935            Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
1936                 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
1937# ifdef DEBUG_bird
1938            SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ws'\n",
1939                        Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
1940# endif
1941            if (pImage->cbImageBits == Info.ImageLength)
1942            {
1943                /*
1944                 * Lock down the entire image, just to be on the safe side.
1945                 */
1946                rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
1947                if (RT_FAILURE(rc))
1948                {
1949                    pImage->hMemLock = NIL_RTR0MEMOBJ;
1950                    supdrvOSLdrUnload(pDevExt, pImage);
1951                }
1952            }
1953            else
1954            {
1955                supdrvOSLdrUnload(pDevExt, pImage);
1956                rc = VERR_LDR_MISMATCH_NATIVE;
1957            }
1958        }
1959        else
1960        {
1961            Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
1962            SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
1963            switch (rcNt)
1964            {
1965                case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
1966# ifdef RT_ARCH_AMD64
1967                    /* Unwind will crash and BSOD, so no fallback here! */
1968                    rc = VERR_NOT_IMPLEMENTED;
1969# else
1970                    /*
1971                     * Use the old way of loading the modules.
1972                     *
1973                     * Note! We do *NOT* try class 26 because it will probably
1974                     *       not work correctly on terminal servers and such.
1975                     */
1976                    rc = VERR_NOT_SUPPORTED;
1977# endif
1978                    break;
1979                case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
1980                    rc = VERR_MODULE_NOT_FOUND;
1981                    break;
1982                case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
1983                    rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
1984                    break;
1985                case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
1986                    rc = VERR_LDR_IMAGE_HASH;
1987                    break;
1988                case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
1989                    Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
1990                    rc = VERR_ALREADY_LOADED;
1991                    break;
1992                default:
1993                    rc = VERR_LDR_GENERAL_FAILURE;
1994                    break;
1995            }
1996
1997            pImage->pvNtSectionObj = NULL;
1998        }
1999    }
2000
2001    RTMemTmpFree(pwcsFilename);
2002    NOREF(pDevExt);
2003    return rc;
2004#endif
2005}
2006
2007
2008void VBOXCALL   supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
2009{
2010    NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
2011}
2012
2013void VBOXCALL   supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2014{
2015    NOREF(pDevExt); NOREF(pImage);
2016}
2017
2018int  VBOXCALL   supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
2019{
2020    NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
2021    return VINF_SUCCESS;
2022}
2023
2024
2025/**
2026 * memcmp + errormsg + log.
2027 *
2028 * @returns Same as memcmp.
2029 * @param   pImage          The image.
2030 * @param   pbImageBits     The image bits ring-3 uploads.
2031 * @param   uRva            The RVA to start comparing at.
2032 * @param   cb              The number of bytes to compare.
2033 * @param   pReq            The load request.
2034 */
2035static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb, PSUPLDRLOAD pReq)
2036{
2037    int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
2038    if (iDiff)
2039    {
2040        uint32_t        cbLeft = cb;
2041        const uint8_t  *pbNativeBits = (const uint8_t *)pImage->pvImage;
2042        for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
2043            if (pbNativeBits[off] != pbImageBits[off])
2044            {
2045                /* Note! We need to copy image bits into a temporary stack buffer here as we'd
2046                         otherwise risk overwriting them while formatting the error message. */
2047                uint8_t abBytes[64];
2048                memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
2049                supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
2050                                   "Mismatch at %#x (%p) of %s loaded at %p:\n"
2051                                   "ntld: %.*Rhxs\n"
2052                                   "iprt: %.*Rhxs",
2053                                   off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
2054                                   RT_MIN(64, cbLeft), &pbNativeBits[off],
2055                                   RT_MIN(64, cbLeft), &abBytes[0]);
2056                SUPR0Printf("VBoxDrv: %s", pReq->u.Out.szError);
2057                break;
2058            }
2059    }
2060    return iDiff;
2061}
2062
2063
2064int  VBOXCALL   supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
2065{
2066    NOREF(pDevExt);
2067    if (pImage->pvNtSectionObj)
2068    {
2069        /*
2070         * Usually, the entire image matches exactly.
2071         */
2072        if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
2073            return VINF_SUCCESS;
2074
2075        /*
2076         * On Windows 10 the ImageBase member of the optional header is sometimes
2077         * updated with the actual load address and sometimes not.  Try compare
2078         *
2079         */
2080        uint32_t const  offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
2081                                  ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
2082                                  : 0;
2083        AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
2084        IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
2085        IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
2086
2087        uint32_t const  offImageBase = offNtHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2088        uint32_t const  cbImageBase  = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2089        if (   pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2090            && (   pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2091                || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage)
2092            && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2093            && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2094            && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
2095            && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
2096                       pbImageBits                      + offImageBase + cbImageBase,
2097                       pImage->cbImageBits              - offImageBase - cbImageBase))
2098            return VINF_SUCCESS;
2099
2100        /*
2101         * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
2102         * up and we typically get a mismatch in the INIT section.
2103         *
2104         * So, lets see if everything matches when excluding the
2105         * OriginalFirstThunk tables and (maybe) the ImageBase member.
2106         * For simplicity the max number of exclusion regions is set to 16.
2107         */
2108        if (    pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2109            &&  pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2110            &&  pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
2111            &&  pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
2112            &&  pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2113            &&  pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
2114            )
2115        {
2116            struct MyRegion
2117            {
2118                uint32_t uRva;
2119                uint32_t cb;
2120            }           aExcludeRgns[16];
2121            unsigned    cExcludeRgns = 0;
2122
2123            /* ImageBase: */
2124            if (   pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2125                && (   pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2126                    || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
2127            {
2128                aExcludeRgns[cExcludeRgns].uRva = offImageBase;
2129                aExcludeRgns[cExcludeRgns].cb   = cbImageBase;
2130                cExcludeRgns++;
2131            }
2132
2133            /* Imports: */
2134            uint32_t    cImpsLeft    = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
2135                                     / sizeof(IMAGE_IMPORT_DESCRIPTOR);
2136            uint32_t    offImps      = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2137            AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
2138            IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
2139            while (   cImpsLeft-- > 0
2140                   && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
2141            {
2142                uint32_t uRvaThunk = pImp->OriginalFirstThunk;
2143                if (    uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
2144                    &&  uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
2145                    &&  uRvaThunk != pImp->FirstThunk)
2146                {
2147                    /* Find the size of the thunk table. */
2148                    IMAGE_THUNK_DATA const *paThunk    = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2149                    uint32_t                cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2150                    uint32_t                cThunks    = 0;
2151                    while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2152                        cThunks++;
2153
2154                    /* Ordered table insert. */
2155                    unsigned i = 0;
2156                    for (; i < cExcludeRgns; i++)
2157                        if (uRvaThunk < aExcludeRgns[i].uRva)
2158                            break;
2159                    if (i != cExcludeRgns)
2160                        memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
2161                    aExcludeRgns[i].uRva = uRvaThunk;
2162                    aExcludeRgns[i].cb   = cThunks * sizeof(IMAGE_THUNK_DATA);
2163                    cExcludeRgns++;
2164                }
2165
2166                /* advance */
2167                pImp++;
2168            }
2169
2170            /*
2171             * Ok, do the comparison.
2172             */
2173            int         iDiff    = 0;
2174            uint32_t    uRvaNext = 0;
2175            for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
2176            {
2177                if (uRvaNext < aExcludeRgns[i].uRva)
2178                    iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext, pReq);
2179                uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
2180            }
2181            if (!iDiff && uRvaNext < pImage->cbImageBits)
2182                iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2183            if (!iDiff)
2184                return VINF_SUCCESS;
2185        }
2186        else
2187            supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2188        return VERR_LDR_MISMATCH_NATIVE;
2189    }
2190    return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2191}
2192
2193
2194void VBOXCALL   supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2195{
2196    if (pImage->pvNtSectionObj)
2197    {
2198        if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2199        {
2200            RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2201            pImage->hMemLock = NIL_RTR0MEMOBJ;
2202        }
2203
2204        NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2205                                               &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2206        if (rcNt != STATUS_SUCCESS)
2207            SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2208        pImage->pvNtSectionObj = NULL;
2209    }
2210    NOREF(pDevExt);
2211}
2212
2213
2214#ifdef SUPDRV_WITH_MSR_PROBER
2215
2216#if 1
2217/** @todo make this selectable. */
2218# define AMD_MSR_PASSCODE 0x9c5a203a
2219#else
2220# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2221# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2222#endif
2223
2224
2225/**
2226 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2227 */
2228typedef struct SUPDRVNTMSPROBERARGS
2229{
2230    uint32_t    uMsr;
2231    uint64_t    uValue;
2232    bool        fGp;
2233} SUPDRVNTMSPROBERARGS;
2234
2235/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2236static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2237{
2238    /*
2239     * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2240     * (At least on 32-bit XP.)
2241     */
2242    SUPDRVNTMSPROBERARGS   *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2243    RTCCUINTREG             fOldFlags = ASMIntDisableFlags();
2244    __try
2245    {
2246        pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2247        pArgs->fGp    = false;
2248    }
2249    __except(EXCEPTION_EXECUTE_HANDLER)
2250    {
2251        pArgs->fGp    = true;
2252        pArgs->uValue = 0;
2253    }
2254    ASMSetFlags(fOldFlags);
2255}
2256
2257
2258int VBOXCALL    supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2259{
2260    SUPDRVNTMSPROBERARGS Args;
2261    Args.uMsr   = uMsr;
2262    Args.uValue = 0;
2263    Args.fGp    = true;
2264
2265    if (idCpu == NIL_RTCPUID)
2266        supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2267    else
2268    {
2269        int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2270        if (RT_FAILURE(rc))
2271            return rc;
2272    }
2273
2274    if (Args.fGp)
2275        return VERR_ACCESS_DENIED;
2276    *puValue = Args.uValue;
2277    return VINF_SUCCESS;
2278}
2279
2280
2281/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2282static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2283{
2284    /*
2285     * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2286     * (At least on 32-bit XP.)
2287     */
2288    SUPDRVNTMSPROBERARGS   *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2289    RTCCUINTREG             fOldFlags = ASMIntDisableFlags();
2290    __try
2291    {
2292        ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2293        pArgs->fGp = false;
2294    }
2295    __except(EXCEPTION_EXECUTE_HANDLER)
2296    {
2297        pArgs->fGp = true;
2298    }
2299    ASMSetFlags(fOldFlags);
2300}
2301
2302int VBOXCALL    supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2303{
2304    SUPDRVNTMSPROBERARGS Args;
2305    Args.uMsr   = uMsr;
2306    Args.uValue = uValue;
2307    Args.fGp    = true;
2308
2309    if (idCpu == NIL_RTCPUID)
2310        supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2311    else
2312    {
2313        int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2314        if (RT_FAILURE(rc))
2315            return rc;
2316    }
2317
2318    if (Args.fGp)
2319        return VERR_ACCESS_DENIED;
2320    return VINF_SUCCESS;
2321}
2322
2323/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2324static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2325{
2326    PSUPMSRPROBER       pReq        = (PSUPMSRPROBER)pvUser1;
2327    register uint32_t   uMsr        = pReq->u.In.uMsr;
2328    bool const          fFaster     = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2329    uint64_t            uBefore     = 0;
2330    uint64_t            uWritten    = 0;
2331    uint64_t            uAfter      = 0;
2332    bool                fBeforeGp   = true;
2333    bool                fModifyGp   = true;
2334    bool                fAfterGp    = true;
2335    bool                fRestoreGp  = true;
2336    RTCCUINTREG         fOldFlags;
2337    RT_NOREF2(idCpu, pvUser2);
2338
2339    /*
2340     * Do the job.
2341     */
2342    fOldFlags = ASMIntDisableFlags();
2343    ASMCompilerBarrier(); /* paranoia */
2344    if (!fFaster)
2345        ASMWriteBackAndInvalidateCaches();
2346
2347    __try
2348    {
2349        uBefore   = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2350        fBeforeGp = false;
2351    }
2352    __except(EXCEPTION_EXECUTE_HANDLER)
2353    {
2354        fBeforeGp = true;
2355    }
2356    if (!fBeforeGp)
2357    {
2358        register uint64_t uRestore = uBefore;
2359
2360        /* Modify. */
2361        uWritten  = uRestore;
2362        uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2363        uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2364        __try
2365        {
2366            ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2367            fModifyGp = false;
2368        }
2369        __except(EXCEPTION_EXECUTE_HANDLER)
2370        {
2371            fModifyGp = true;
2372        }
2373
2374        /* Read modified value. */
2375        __try
2376        {
2377            uAfter   = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2378            fAfterGp = false;
2379        }
2380        __except(EXCEPTION_EXECUTE_HANDLER)
2381        {
2382            fAfterGp = true;
2383        }
2384
2385        /* Restore original value. */
2386        __try
2387        {
2388            ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2389            fRestoreGp = false;
2390        }
2391        __except(EXCEPTION_EXECUTE_HANDLER)
2392        {
2393            fRestoreGp = true;
2394        }
2395
2396        /* Invalid everything we can. */
2397        if (!fFaster)
2398        {
2399            ASMWriteBackAndInvalidateCaches();
2400            ASMReloadCR3();
2401            ASMNopPause();
2402        }
2403    }
2404
2405    ASMCompilerBarrier(); /* paranoia */
2406    ASMSetFlags(fOldFlags);
2407
2408    /*
2409     * Write out the results.
2410     */
2411    pReq->u.Out.uResults.Modify.uBefore    = uBefore;
2412    pReq->u.Out.uResults.Modify.uWritten   = uWritten;
2413    pReq->u.Out.uResults.Modify.uAfter     = uAfter;
2414    pReq->u.Out.uResults.Modify.fBeforeGp  = fBeforeGp;
2415    pReq->u.Out.uResults.Modify.fModifyGp  = fModifyGp;
2416    pReq->u.Out.uResults.Modify.fAfterGp   = fAfterGp;
2417    pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2418    RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2419}
2420
2421
2422int VBOXCALL    supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2423{
2424    if (idCpu == NIL_RTCPUID)
2425    {
2426        supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2427        return VINF_SUCCESS;
2428    }
2429    return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
2430}
2431
2432#endif /* SUPDRV_WITH_MSR_PROBER */
2433
2434
2435/**
2436 * Converts an IPRT error code to an nt status code.
2437 *
2438 * @returns corresponding nt status code.
2439 * @param   rc      IPRT error status code.
2440 */
2441static NTSTATUS     VBoxDrvNtErr2NtStatus(int rc)
2442{
2443    switch (rc)
2444    {
2445        case VINF_SUCCESS:                  return STATUS_SUCCESS;
2446        case VERR_GENERAL_FAILURE:          return STATUS_NOT_SUPPORTED;
2447        case VERR_INVALID_PARAMETER:        return STATUS_INVALID_PARAMETER;
2448        case VERR_INVALID_MAGIC:            return STATUS_UNKNOWN_REVISION;
2449        case VERR_INVALID_HANDLE:           return STATUS_INVALID_HANDLE;
2450        case VERR_INVALID_POINTER:          return STATUS_INVALID_ADDRESS;
2451        case VERR_LOCK_FAILED:              return STATUS_NOT_LOCKED;
2452        case VERR_ALREADY_LOADED:           return STATUS_IMAGE_ALREADY_LOADED;
2453        case VERR_PERMISSION_DENIED:        return STATUS_ACCESS_DENIED;
2454        case VERR_VERSION_MISMATCH:         return STATUS_REVISION_MISMATCH;
2455    }
2456
2457    if (rc < 0)
2458    {
2459        if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2460            return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2461    }
2462    return STATUS_UNSUCCESSFUL;
2463}
2464
2465
2466/**
2467 * Alternative version of SUPR0Printf for Windows.
2468 *
2469 * @returns 0.
2470 * @param   pszFormat   The format string.
2471 */
2472SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2473{
2474    va_list va;
2475    char    szMsg[384];
2476
2477    va_start(va, pszFormat);
2478    size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2479    szMsg[sizeof(szMsg) - 1] = '\0';
2480    va_end(va);
2481
2482    RTLogWriteDebugger(szMsg, cch);
2483    return 0;
2484}
2485
2486
2487SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2488{
2489    return 0;
2490}
2491
2492
2493#ifdef VBOX_WITH_HARDENING
2494
2495/** @name Identifying Special Processes: CSRSS.EXE
2496 * @{ */
2497
2498
2499/**
2500 * Checks if the process is a system32 process by the given name.
2501 *
2502 * @returns true / false.
2503 * @param   pProcess            The process to check.
2504 * @param   pszName             The lower case process name (no path!).
2505 */
2506static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2507{
2508    Assert(strlen(pszName) < 16); /* see buffer below */
2509
2510    /*
2511     * This test works on XP+.
2512     */
2513    const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2514    if (!pszImageFile)
2515        return false;
2516
2517    if (RTStrICmp(pszImageFile, pszName) != 0)
2518        return false;
2519
2520    /*
2521     * This test requires a Vista+ API.
2522     */
2523    if (g_pfnPsReferenceProcessFilePointer)
2524    {
2525        PFILE_OBJECT pFile = NULL;
2526        NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2527        if (!NT_SUCCESS(rcNt))
2528            return false;
2529
2530        union
2531        {
2532            OBJECT_NAME_INFORMATION Info;
2533            uint8_t        abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2534        } Buf;
2535        ULONG cbIgn;
2536        rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2537        ObDereferenceObject(pFile);
2538        if (!NT_SUCCESS(rcNt))
2539            return false;
2540
2541        /* Terminate the name. */
2542        PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2543        pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2544
2545        /* Match the name against the system32 directory path. */
2546        uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2547        if (Buf.Info.Name.Length < cbSystem32)
2548            return false;
2549        if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2550            return false;
2551        pwszName += cbSystem32 / sizeof(RTUTF16);
2552        if (*pwszName++ != '\\')
2553            return false;
2554
2555        /* Compare the name. */
2556        const char *pszRight = pszName;
2557        for (;;)
2558        {
2559            WCHAR wchLeft = *pwszName++;
2560            char  chRight = *pszRight++;
2561            Assert(chRight == RT_C_TO_LOWER(chRight));
2562
2563            if (   wchLeft != chRight
2564                && RT_C_TO_LOWER(wchLeft) != chRight)
2565                return false;
2566            if (!chRight)
2567                break;
2568        }
2569    }
2570
2571    return true;
2572}
2573
2574
2575/**
2576 * Checks if the current process is likely to be CSRSS.
2577 *
2578 * @returns true/false.
2579 * @param   pProcess        The process.
2580 */
2581static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2582{
2583    /*
2584     * On Windows 8.1 CSRSS.EXE is a protected process.
2585     */
2586    if (g_pfnPsIsProtectedProcessLight)
2587    {
2588        if (!g_pfnPsIsProtectedProcessLight(pProcess))
2589            return false;
2590    }
2591
2592    /*
2593     * The name tests.
2594     */
2595    if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2596        return false;
2597
2598    /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2599     *        current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2600
2601    return true;
2602}
2603
2604
2605/**
2606 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
2607 *
2608 * @returns true if done, false if not.
2609 * @param   pwszPortNm          The port path.
2610 * @param   ppObjType           The object type return variable, updated when
2611 *                              returning true.
2612 */
2613static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
2614{
2615    bool fDone = false;
2616
2617    UNICODE_STRING UniStrPortNm;
2618    UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
2619    UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
2620    UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
2621
2622    OBJECT_ATTRIBUTES ObjAttr;
2623    InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2624
2625    HANDLE hPort;
2626    NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
2627    if (NT_SUCCESS(rcNt))
2628    {
2629        PVOID pvObject;
2630        rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
2631                                         KernelMode, &pvObject, NULL /*pHandleInfo*/);
2632        if (NT_SUCCESS(rcNt))
2633        {
2634            POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
2635            if (pObjType)
2636            {
2637                SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
2638                *ppObjType = pObjType;
2639                fDone = true;
2640            }
2641            ObDereferenceObject(pvObject);
2642        }
2643        NtClose(hPort);
2644    }
2645    return fDone;
2646}
2647
2648
2649/**
2650 * Attempts to retrieve the ALPC Port object type.
2651 *
2652 * We've had at least three reports that using LpcPortObjectType when trying to
2653 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
2654 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
2655 * exported) so that it differs from the actual ApiPort type, or maybe this
2656 * unknown entity is intercepting our attempt to reference the port and
2657 * tries to mislead us.  The paranoid explanataion is of course that some evil
2658 * root kit like software is messing with the OS, however, it's possible that
2659 * this is valid kernel behavior that 99.8% of our users and 100% of the
2660 * developers are not triggering for some reason.
2661 *
2662 * The code here creates an ALPC port object and gets it's type.  It will cache
2663 * the result in g_pAlpcPortObjectType2 on success.
2664 *
2665 * @returns Object type.
2666 * @param   uSessionId      The session id.
2667 * @param   pszSessionId    The session id formatted as a string.
2668 */
2669static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
2670{
2671    POBJECT_TYPE pObjType = *LpcPortObjectType;
2672
2673    if (   g_pfnZwAlpcCreatePort
2674        && g_pfnObGetObjectType)
2675    {
2676        int     rc;
2677        ssize_t cchTmp; NOREF(cchTmp);
2678        char    szTmp[16];
2679        RTUTF16 wszPortNm[128];
2680        size_t  offRand;
2681
2682        /*
2683         * First attempt is in the session directory.
2684         */
2685        rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2686        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2687        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
2688        cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2689        Assert(cchTmp > 0);
2690        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2691        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2692        offRand = RTUtf16Len(wszPortNm);
2693        cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2694        Assert(cchTmp > 0);
2695        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2696        AssertRCSuccess(rc);
2697
2698        bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2699        if (!fDone)
2700        {
2701            wszPortNm[offRand] = '\0';
2702            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
2703            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2704            AssertRCSuccess(rc);
2705
2706            fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2707        }
2708        if (!fDone)
2709        {
2710            /*
2711             * Try base names.
2712             */
2713            if (uSessionId == 0)
2714                rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2715            else
2716            {
2717                rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2718                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2719                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2720            }
2721            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2722            Assert(cchTmp > 0);
2723            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2724            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2725            offRand = RTUtf16Len(wszPortNm);
2726            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2727            Assert(cchTmp > 0);
2728            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2729            AssertRCSuccess(rc);
2730
2731            bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2732            if (!fDone)
2733            {
2734                wszPortNm[offRand] = '\0';
2735                cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2736                Assert(cchTmp > 0);
2737                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2738                AssertRCSuccess(rc);
2739
2740                fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2741            }
2742        }
2743
2744        /* Cache the result in g_pAlpcPortObjectType2. */
2745        if (   g_pAlpcPortObjectType2 == NULL
2746            && pObjType != g_pAlpcPortObjectType1
2747            && fDone)
2748            g_pAlpcPortObjectType2 = pObjType;
2749
2750    }
2751
2752    return pObjType;
2753}
2754
2755
2756/**
2757 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
2758 * current process.
2759 *
2760 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
2761 * additional access right so we need to make 101% sure we correctly identify
2762 * the CSRSS process a process is associated with.
2763 *
2764 * @returns IPRT status code.
2765 * @param   pNtProtect          The NT protected process structure. The
2766 *                              hCsrssPid member will be updated on success.
2767 */
2768static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
2769{
2770    Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
2771    Assert(pNtProtect->pCsrssProcess == NULL);
2772    Assert(pNtProtect->hCsrssPid == NULL);
2773
2774    /*
2775     * We'll try use the ApiPort LPC object for the session we're in to track
2776     * down the CSRSS process. So, we start by constructing a path to it.
2777     */
2778    int         rc;
2779    uint32_t    uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
2780    char        szSessionId[16];
2781    WCHAR       wszApiPort[48];
2782    if (uSessionId == 0)
2783    {
2784        szSessionId[0] = '0';
2785        szSessionId[1] = '\0';
2786        rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2787    }
2788    else
2789    {
2790        ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
2791        AssertReturn(cchTmp > 0, (int)cchTmp);
2792        rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
2793        if (RT_SUCCESS(rc))
2794            rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
2795        if (RT_SUCCESS(rc))
2796            rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2797    }
2798    AssertRCReturn(rc, rc);
2799
2800    UNICODE_STRING ApiPortStr;
2801    ApiPortStr.Buffer = wszApiPort;
2802    ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
2803    ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
2804
2805    /*
2806     * The object cannot be opened, but we can reference it by name.
2807     */
2808    void *pvApiPortObj = NULL;
2809    NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
2810                                            0,
2811                                            NULL /*pAccessState*/,
2812                                            STANDARD_RIGHTS_READ,
2813                                            g_pAlpcPortObjectType1,
2814                                            KernelMode,
2815                                            NULL /*pvParseContext*/,
2816                                            &pvApiPortObj);
2817    if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
2818        && g_pAlpcPortObjectType2 != NULL)
2819        rcNt = ObReferenceObjectByName(&ApiPortStr,
2820                                       0,
2821                                       NULL /*pAccessState*/,
2822                                       STANDARD_RIGHTS_READ,
2823                                       g_pAlpcPortObjectType2,
2824                                       KernelMode,
2825                                       NULL /*pvParseContext*/,
2826                                       &pvApiPortObj);
2827    if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
2828        && g_pfnObGetObjectType
2829        && g_pfnZwAlpcCreatePort)
2830        rcNt = ObReferenceObjectByName(&ApiPortStr,
2831                                       0,
2832                                       NULL /*pAccessState*/,
2833                                       STANDARD_RIGHTS_READ,
2834                                       supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
2835                                       KernelMode,
2836                                       NULL /*pvParseContext*/,
2837                                       &pvApiPortObj);
2838    if (!NT_SUCCESS(rcNt))
2839    {
2840        SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
2841        return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
2842    }
2843
2844    /*
2845     * Query the processes in the system so we can locate CSRSS.EXE candidates.
2846     * Note! Attempts at using SystemSessionProcessInformation failed with
2847     *       STATUS_ACCESS_VIOLATION.
2848     * Note! The 32 bytes on the size of to counteract the allocation header
2849     *       that rtR0MemAllocEx slaps on everything.
2850     */
2851    ULONG       cbNeeded = _64K - 32;
2852    uint32_t    cbBuf;
2853    uint8_t    *pbBuf = NULL;
2854    do
2855    {
2856        cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
2857        pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
2858        if (!pbBuf)
2859            break;
2860
2861        cbNeeded = 0;
2862#if 0 /* doesn't work. */
2863        SYSTEM_SESSION_PROCESS_INFORMATION Req;
2864        Req.SessionId    = uSessionId;
2865        Req.BufferLength = cbBuf;
2866        Req.Buffer       = pbBuf;
2867        rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
2868#else
2869        rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
2870#endif
2871        if (NT_SUCCESS(rcNt))
2872            break;
2873
2874        RTMemFree(pbBuf);
2875        pbBuf = NULL;
2876    } while (   rcNt == STATUS_INFO_LENGTH_MISMATCH
2877             && cbNeeded > cbBuf
2878             && cbNeeded < 32U*_1M);
2879
2880    if (   pbBuf
2881        && NT_SUCCESS(rcNt)
2882        && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
2883    {
2884        /*
2885         * Walk the returned data and look for the process associated with the
2886         * ApiPort object.  The ApiPort object keeps the EPROCESS address of
2887         * the owner process (i.e. CSRSS) relatively early in the structure. On
2888         * 64-bit windows 8.1 it's at offset 0x18.  So, obtain the EPROCESS
2889         * pointer to likely CSRSS processes and check for a match in the first
2890         * 0x40 bytes of the ApiPort object.
2891         */
2892        rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
2893        for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
2894        {
2895            PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
2896            if (   pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
2897                && pProcInfo->NumberOfThreads > 2   /* Very low guess. */
2898                && pProcInfo->HandleCount     > 32  /* Very low guess, I hope. */
2899                && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
2900                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
2901                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
2902                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
2903                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
2904                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
2905                &&               pProcInfo->ProcessName.Buffer[5]  == '.'
2906                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
2907                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
2908                && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
2909            {
2910
2911                /* Get the process structure and perform some more thorough
2912                   process checks. */
2913                PEPROCESS pProcess;
2914                rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
2915                if (NT_SUCCESS(rcNt))
2916                {
2917                    if (supdrvNtProtectIsCsrssByProcess(pProcess))
2918                    {
2919                        if (PsGetProcessSessionId(pProcess) == uSessionId)
2920                        {
2921                            /* Final test, check the ApiPort.
2922                               Note! The old LPC (pre Vista) objects has the PID
2923                                     much earlier in the structure.  Might be
2924                                     worth looking for it instead. */
2925                            bool fThatsIt = false;
2926                            __try
2927                            {
2928                                PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
2929                                uint32_t   cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
2930                                do
2931                                {
2932                                    fThatsIt = *ppPortProc == pProcess;
2933                                    ppPortProc++;
2934                                } while (!fThatsIt && --cTests > 0);
2935                            }
2936                            __except(EXCEPTION_EXECUTE_HANDLER)
2937                            {
2938                                fThatsIt = false;
2939                            }
2940                            if (fThatsIt)
2941                            {
2942                                /* Ok, we found it!  Keep the process structure
2943                                   reference as well as the PID so we can
2944                                   safely identify it later on.  */
2945                                pNtProtect->hCsrssPid     = pProcInfo->UniqueProcessId;
2946                                pNtProtect->pCsrssProcess = pProcess;
2947                                rc = VINF_SUCCESS;
2948                                break;
2949                            }
2950                        }
2951                    }
2952
2953                    ObDereferenceObject(pProcess);
2954                }
2955            }
2956
2957            /* Advance. */
2958            if (!pProcInfo->NextEntryOffset)
2959                break;
2960            offBuf += pProcInfo->NextEntryOffset;
2961        }
2962    }
2963    else
2964        rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
2965    RTMemFree(pbBuf);
2966    ObDereferenceObject(pvApiPortObj);
2967    return rc;
2968}
2969
2970
2971/**
2972 * Checks that the given process is the CSRSS process associated with protected
2973 * process.
2974 *
2975 * @returns true / false.
2976 * @param   pNtProtect          The NT protection structure.
2977 * @param   pCsrss              The process structure of the alleged CSRSS.EXE
2978 *                              process.
2979 */
2980static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
2981{
2982    if (pNtProtect->pCsrssProcess == pCsrss)
2983    {
2984        if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
2985        {
2986            return true;
2987        }
2988    }
2989    return false;
2990}
2991
2992
2993/**
2994 * Checks if the given process is the stupid themes service.
2995 *
2996 * The caller does some screening of access masks and what not. We do the rest.
2997 *
2998 * @returns true / false.
2999 * @param   pNtProtect          The NT protection structure.
3000 * @param   pAnnoyingProcess    The process structure of an process that might
3001 *                              happen to be the annoying themes process.
3002 */
3003static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3004{
3005    RT_NOREF1(pNtProtect);
3006
3007    /*
3008     * Check the process name.
3009     */
3010    if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3011        return false;
3012
3013    /** @todo Come up with more checks. */
3014
3015    return true;
3016}
3017
3018
3019#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3020/**
3021 * Checks if the given process is one of the whitelisted debuggers.
3022 *
3023 * @returns true / false.
3024 * @param   pProcess            The process to check.
3025 */
3026static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3027{
3028    const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3029    if (!pszImageFile)
3030        return false;
3031
3032    if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3033    {
3034        if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3035            return true;
3036        if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3037            return true;
3038        if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3039            return true;
3040    }
3041    else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3042    {
3043        if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3044            return true;
3045        if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3046            return true;
3047    }
3048
3049    return false;
3050}
3051#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3052
3053
3054/** @} */
3055
3056
3057/** @name Process Creation Callbacks.
3058 * @{ */
3059
3060
3061/**
3062 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3063 *
3064 * @param   hProcessId          The ID of the dead process.
3065 */
3066static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3067{
3068    int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3069    if (RT_SUCCESS(rc))
3070    {
3071        PSUPDRVNTERRORINFO pCur, pNext;
3072        RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3073        {
3074            if (pCur->hProcessId == hProcessId)
3075            {
3076                RTListNodeRemove(&pCur->ListEntry);
3077                RTMemFree(pCur);
3078            }
3079        }
3080        RTSemMutexRelease(g_hErrorInfoLock);
3081    }
3082}
3083
3084
3085/**
3086 * Common worker used by the process creation hooks as well as the process
3087 * handle creation hooks to check if a VM process is being created.
3088 *
3089 * @returns true if likely to be a VM process, false if not.
3090 * @param   pNtStub             The NT protection structure for the possible
3091 *                              stub process.
3092 * @param   hParentPid          The parent pid.
3093 * @param   hChildPid           The child pid.
3094 */
3095static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3096{
3097    bool fRc = false;
3098    if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3099    {
3100        if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3101        {
3102            /* Compare short names. */
3103            PEPROCESS pStubProcess;
3104            NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3105            if (NT_SUCCESS(rcNt))
3106            {
3107                PEPROCESS pChildProcess;
3108                rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3109                if (NT_SUCCESS(rcNt))
3110                {
3111                    const char *pszStub  = (const char *)PsGetProcessImageFileName(pStubProcess);
3112                    const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3113                    fRc = pszStub != NULL
3114                       && pszChild != NULL
3115                       && strcmp(pszStub, pszChild) == 0;
3116
3117                    /** @todo check that the full image names matches. */
3118
3119                    ObDereferenceObject(pChildProcess);
3120                }
3121                ObDereferenceObject(pStubProcess);
3122            }
3123        }
3124    }
3125    return fRc;
3126}
3127
3128
3129/**
3130 * Common code used by the notifies to protect a child process.
3131 *
3132 * @returns VBox status code.
3133 * @param   pNtStub             The NT protect structure for the parent.
3134 * @param   hChildPid           The child pid.
3135 */
3136static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3137{
3138    /*
3139     * Create a child protection struction.
3140     */
3141    PSUPDRVNTPROTECT pNtChild;
3142    int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3143    if (RT_SUCCESS(rc))
3144    {
3145        pNtChild->fFirstProcessCreateHandle = true;
3146        pNtChild->fFirstThreadCreateHandle = true;
3147        pNtChild->fCsrssFirstProcessCreateHandle = true;
3148        pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3149        pNtChild->fThemesFirstProcessCreateHandle = true;
3150        pNtChild->hParentPid = pNtParent->AvlCore.Key;
3151        pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3152        pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3153        if (pNtChild->pCsrssProcess)
3154            ObReferenceObject(pNtChild->pCsrssProcess);
3155
3156        /*
3157         * Take the spinlock, recheck parent conditions and link things.
3158         */
3159        RTSpinlockAcquire(g_hNtProtectLock);
3160        if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3161        {
3162            bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3163            if (fSuccess)
3164            {
3165                pNtChild->fInTree         = true;
3166                pNtParent->u.pChild       = pNtChild; /* Parent keeps the initial reference. */
3167                pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3168                pNtChild->u.pParent       = pNtParent;
3169
3170                RTSpinlockRelease(g_hNtProtectLock);
3171                return VINF_SUCCESS;
3172            }
3173
3174            rc = VERR_INTERNAL_ERROR_2;
3175        }
3176        else
3177            rc = VERR_WRONG_ORDER;
3178        pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3179        RTSpinlockRelease(g_hNtProtectLock);
3180
3181        supdrvNtProtectRelease(pNtChild);
3182    }
3183    return rc;
3184}
3185
3186
3187/**
3188 * Common process termination code.
3189 *
3190 * Transitions protected process to the dead states, protecting against handle
3191 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3192 *
3193 * @param   hDeadPid            The PID of the dead process.
3194 */
3195static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3196{
3197    PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3198    if (pNtProtect)
3199    {
3200        PSUPDRVNTPROTECT pNtChild = NULL;
3201
3202        RTSpinlockAcquire(g_hNtProtectLock);
3203
3204        /*
3205         * If this is an unconfirmed VM process, we must release the reference
3206         * the parent structure holds.
3207         */
3208        if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3209        {
3210            PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
3211            AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
3212            pNtParent->u.pChild   = NULL;
3213            pNtProtect->u.pParent = NULL;
3214            pNtChild = pNtProtect;
3215        }
3216        /*
3217         * If this is a stub exitting before the VM process gets confirmed,
3218         * release the protection of the potential VM process as this is not
3219         * the prescribed behavior.
3220         */
3221        else if (   pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3222                 && pNtProtect->u.pChild)
3223        {
3224            pNtChild = pNtProtect->u.pChild;
3225            pNtProtect->u.pChild = NULL;
3226            pNtChild->u.pParent  = NULL;
3227            pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3228        }
3229
3230        /*
3231         * Transition it to the dead state to prevent it from opening the
3232         * support driver again or be posthumously abused as a vm process parent.
3233         */
3234        if (   pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3235            || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
3236            pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3237        else if (   pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3238                 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
3239                 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3240            pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
3241
3242        RTSpinlockRelease(g_hNtProtectLock);
3243
3244        supdrvNtProtectRelease(pNtProtect);
3245        supdrvNtProtectRelease(pNtChild);
3246
3247        /*
3248         * Do session cleanups.
3249         */
3250        AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3251        if (g_pDevObjSys)
3252        {
3253            PSUPDRVDEVEXT  pDevExt  = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3254            PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3255                                                                 RTR0ProcHandleSelf(), NULL);
3256            if (pSession)
3257            {
3258                supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3259                supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3260            }
3261        }
3262    }
3263}
3264
3265
3266/**
3267 * Common worker for the process creation callback that verifies a new child
3268 * being created by the handle creation callback code.
3269 *
3270 * @param   pNtStub         The parent.
3271 * @param   pNtVm           The child.
3272 * @param   fCallerChecks   The result of any additional tests the caller made.
3273 *                          This is in order to avoid duplicating the failure
3274 *                          path code.
3275 */
3276static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3277{
3278    if (   fCallerChecks
3279        && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3280        && pNtVm->enmProcessKind   == kSupDrvNtProtectKind_VmProcessUnconfirmed
3281        && pNtVm->u.pParent        == pNtStub
3282        && pNtStub->u.pChild       == pNtVm)
3283    {
3284        /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3285        pNtVm->fFirstProcessCreateHandle = true;
3286        return;
3287    }
3288
3289    LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3290    if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3291        supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3292}
3293
3294
3295/**
3296 * Old style callback (since forever).
3297 *
3298 * @param   hParentPid          The parent PID.
3299 * @param   hNewPid             The PID of the new child.
3300 * @param   fCreated            TRUE if it's a creation notification,
3301 *                              FALSE if termination.
3302 * @remarks ASSUMES this arrives before the handle creation callback.
3303 */
3304static VOID __stdcall
3305supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3306{
3307    /*
3308     * Is it a new process that needs protection?
3309     */
3310    if (fCreated)
3311    {
3312        PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3313        if (pNtStub)
3314        {
3315            PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3316            if (!pNtVm)
3317            {
3318                if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3319                    supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3320            }
3321            else
3322            {
3323                supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3324                supdrvNtProtectRelease(pNtVm);
3325            }
3326            supdrvNtProtectRelease(pNtStub);
3327        }
3328    }
3329    /*
3330     * Process termination, do clean ups.
3331     */
3332    else
3333    {
3334        supdrvNtProtectUnprotectDeadProcess(hNewPid);
3335        supdrvNtErrorInfoCleanupProcess(hNewPid);
3336    }
3337}
3338
3339
3340/**
3341 * New style callback (Vista SP1+ / w2k8).
3342 *
3343 * @param   pNewProcess         The new process.
3344 * @param   hNewPid             The PID of the new process.
3345 * @param   pInfo               Process creation details. NULL if process
3346 *                              termination notification.
3347 * @remarks ASSUMES this arrives before the handle creation callback.
3348 */
3349static VOID __stdcall
3350supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3351{
3352    RT_NOREF1(pNewProcess);
3353
3354    /*
3355     * Is it a new process that needs protection?
3356     */
3357    if (pInfo)
3358    {
3359        PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3360
3361        Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3362             PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3363             hNewPid, pInfo->ParentProcessId,
3364             pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3365             pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3366             pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3367
3368        if (pNtStub)
3369        {
3370            PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3371            if (!pNtVm)
3372            {
3373                /* Parent must be creator. */
3374                if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3375                {
3376                    if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3377                        supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3378                }
3379            }
3380            else
3381            {
3382                /* Parent must be creator (as above). */
3383                supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3384                                                        pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3385                supdrvNtProtectRelease(pNtVm);
3386            }
3387            supdrvNtProtectRelease(pNtStub);
3388        }
3389    }
3390    /*
3391     * Process termination, do clean ups.
3392     */
3393    else
3394    {
3395        supdrvNtProtectUnprotectDeadProcess(hNewPid);
3396        supdrvNtErrorInfoCleanupProcess(hNewPid);
3397    }
3398}
3399
3400/** @} */
3401
3402
3403/** @name Process Handle Callbacks.
3404 * @{ */
3405
3406/** Process rights that we allow for handles to stub and VM processes. */
3407# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS  \
3408    (  PROCESS_TERMINATE \
3409     | PROCESS_VM_READ \
3410     | PROCESS_QUERY_INFORMATION \
3411     | PROCESS_QUERY_LIMITED_INFORMATION \
3412     | PROCESS_SUSPEND_RESUME \
3413     | DELETE \
3414     | READ_CONTROL \
3415     | SYNCHRONIZE)
3416
3417/** Evil process rights. */
3418# define SUPDRV_NT_EVIL_PROCESS_RIGHTS  \
3419    (  PROCESS_CREATE_THREAD \
3420     | PROCESS_SET_SESSIONID /*?*/ \
3421     | PROCESS_VM_OPERATION \
3422     | PROCESS_VM_WRITE \
3423     | PROCESS_DUP_HANDLE \
3424     | PROCESS_CREATE_PROCESS /*?*/ \
3425     | PROCESS_SET_QUOTA /*?*/ \
3426     | PROCESS_SET_INFORMATION \
3427     | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3428     | 0)
3429AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3430
3431
3432static OB_PREOP_CALLBACK_STATUS __stdcall
3433supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3434{
3435    Assert(pvUser == NULL); RT_NOREF1(pvUser);
3436    Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3437    Assert(pOpInfo->ObjectType == *PsProcessType);
3438
3439    /*
3440     * Protected?  Kludge required for NtOpenProcess calls comming in before
3441     * the create process hook triggers on Windows 8.1 (possibly others too).
3442     */
3443    HANDLE           hObjPid    = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3444    PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3445    if (!pNtProtect)
3446    {
3447        HANDLE           hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3448        PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3449        if (pNtStub)
3450        {
3451            if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3452            {
3453                supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3454                pNtProtect = supdrvNtProtectLookup(hObjPid);
3455            }
3456            supdrvNtProtectRelease(pNtStub);
3457        }
3458    }
3459    pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3460    if (pNtProtect)
3461    {
3462        /*
3463         * Ok, it's a protected process.  Strip rights as required or possible.
3464         */
3465        static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3466        ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3467
3468        if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3469        {
3470            /* Don't restrict the process accessing itself. */
3471            if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3472            {
3473                pOpInfo->CallContext = NULL; /* don't assert */
3474                pNtProtect->fFirstProcessCreateHandle = false;
3475
3476                Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3477                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3478                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3479                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3480                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3481            }
3482#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3483            /* Allow debuggers full access. */
3484            else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3485            {
3486                pOpInfo->CallContext = NULL; /* don't assert */
3487                pNtProtect->fFirstProcessCreateHandle = false;
3488
3489                Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3490                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3491                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3492                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3493                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3494            }
3495#endif
3496            else
3497            {
3498                ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
3499
3500                /* Special case 1 on Vista, 7 & 8:
3501                   The CreateProcess code passes the handle over to CSRSS.EXE
3502                   and the code inBaseSrvCreateProcess will duplicate the
3503                   handle with 0x1fffff as access mask.  NtDuplicateObject will
3504                   fail this call before it ever gets down here.
3505
3506                   Special case 2 on 8.1:
3507                   The CreateProcess code requires additional rights for
3508                   something, we'll drop these in the stub code. */
3509                if (   pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3510                    && pNtProtect->fFirstProcessCreateHandle
3511                    && pOpInfo->KernelHandle == 0
3512                    && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
3513                    && ExGetPreviousMode() != KernelMode)
3514                {
3515                    if (   !pOpInfo->KernelHandle
3516                        && fDesiredAccess == s_fCsrssStupidDesires)
3517                    {
3518                        if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
3519                            fAllowedRights |= s_fCsrssStupidDesires;
3520                        else
3521                            fAllowedRights = fAllowedRights
3522                                           | PROCESS_VM_OPERATION
3523                                           | PROCESS_VM_WRITE
3524                                           | PROCESS_SET_INFORMATION
3525                                           | PROCESS_SET_LIMITED_INFORMATION
3526                                           | 0;
3527                        pOpInfo->CallContext = NULL; /* don't assert this. */
3528                    }
3529                    pNtProtect->fFirstProcessCreateHandle = false;
3530                }
3531
3532                /* Special case 3 on 8.1:
3533                   The interaction between the CreateProcess code and CSRSS.EXE
3534                   has changed to the better with Windows 8.1.  CSRSS.EXE no
3535                   longer duplicates the process (thread too) handle, but opens
3536                   it, thus allowing us to do our job. */
3537                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3538                    && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3539                    && pNtProtect->fCsrssFirstProcessCreateHandle
3540                    && pOpInfo->KernelHandle == 0
3541                    && ExGetPreviousMode() == UserMode
3542                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3543                {
3544                    pNtProtect->fCsrssFirstProcessCreateHandle = false;
3545                    if (fDesiredAccess == s_fCsrssStupidDesires)
3546                    {
3547                        /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3548                           PROCESS_CREATE_PROCESS */
3549                        fAllowedRights = fAllowedRights
3550                                       | PROCESS_VM_OPERATION
3551                                       | PROCESS_VM_WRITE
3552                                       | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
3553                                       | 0;
3554                        pOpInfo->CallContext = NULL; /* don't assert this. */
3555                    }
3556                }
3557
3558                /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
3559                   The Themes service requires PROCESS_DUP_HANDLE access to our
3560                   process or we won't get any menus and dialogs will be half
3561                   unreadable.  This is _very_ unfortunate and more work will
3562                   go into making this more secure.  */
3563                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
3564                    && g_uNtVerCombined  < SUP_MAKE_NT_VER_SIMPLE(6, 2)
3565                    && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
3566                    && pNtProtect->fThemesFirstProcessCreateHandle
3567                    && pOpInfo->KernelHandle == 0
3568                    && ExGetPreviousMode() == UserMode
3569                    && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
3570                {
3571                    pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
3572                    fAllowedRights |= PROCESS_DUP_HANDLE;
3573                    pOpInfo->CallContext = NULL; /* don't assert this. */
3574                }
3575
3576                /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
3577                   PROCESS_SET_LIMITED_INFORMATION right.  It seems like it need it for
3578                   some myserious and weirdly placed cpu set management of our process.
3579                   I'd love to understand what that's all about...
3580                   Currently playing safe and only grand this right, however limited, to
3581                   audiodg.exe. */
3582                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3583                    && (   fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3584                        || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3585                        || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION)         /* expected fix #2 */
3586                        )
3587                    && pOpInfo->KernelHandle == 0
3588                    && ExGetPreviousMode() == UserMode
3589                    && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3590                {
3591                    fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3592                    pOpInfo->CallContext = NULL; /* don't assert this. */
3593                }
3594
3595                Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3596                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3597                     fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3598                     fAllowedRights, fDesiredAccess & fAllowedRights,
3599                     PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
3600
3601                pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3602            }
3603        }
3604        else
3605        {
3606            /* Don't restrict the process accessing itself. */
3607            if (   (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
3608                && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
3609            {
3610                Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3611                     PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3612                     pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3613                     PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3614                     pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3615                     pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3616                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3617                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3618
3619                pOpInfo->CallContext = NULL; /* don't assert */
3620            }
3621            else
3622            {
3623                ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
3624
3625                /* Special case 5 on Vista, 7 & 8:
3626                   This is the CSRSS.EXE end of special case #1. */
3627                if (   g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3628                    && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3629                    && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
3630                    && pOpInfo->KernelHandle == 0
3631                    && fDesiredAccess == s_fCsrssStupidDesires
3632                    &&    pNtProtect->hParentPid
3633                       == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
3634                    && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3635                    && ExGetPreviousMode() == UserMode
3636                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
3637                {
3638                    if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
3639                    {
3640                        /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3641                           PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
3642                        fAllowedRights = fAllowedRights
3643                                       | PROCESS_VM_OPERATION
3644                                       | PROCESS_VM_WRITE
3645                                       | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
3646                                       | 0;
3647                        pOpInfo->CallContext = NULL; /* don't assert this. */
3648                    }
3649                }
3650
3651                /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
3652                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3653                    && (   fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3654                        || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3655                        || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION)         /* expected fix #2 */
3656                        )
3657                    && pOpInfo->KernelHandle == 0
3658                    && ExGetPreviousMode() == UserMode
3659                    && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3660                {
3661                    fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3662                    pOpInfo->CallContext = NULL; /* don't assert this. */
3663                }
3664
3665                Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3666                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3667                     pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3668                     PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3669                     pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3670                     fDesiredAccess,
3671                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3672                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3673
3674                pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3675            }
3676        }
3677        supdrvNtProtectRelease(pNtProtect);
3678    }
3679
3680    return OB_PREOP_SUCCESS;
3681}
3682
3683
3684static VOID __stdcall
3685supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3686{
3687    Assert(pvUser == NULL); RT_NOREF1(pvUser);
3688    Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3689    Assert(pOpInfo->ObjectType == *PsProcessType);
3690
3691    if (   pOpInfo->CallContext
3692        && NT_SUCCESS(pOpInfo->ReturnStatus))
3693    {
3694        ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
3695                                         ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
3696                                         : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
3697        AssertReleaseMsg(   !(fGrantedAccess & ~(  SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3698                                                 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3699                                                 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
3700                                                 /*| PROCESS_UNKNOWN_8000 */ ) )
3701                         || pOpInfo->KernelHandle,
3702                         ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3703                          fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
3704    }
3705}
3706
3707# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3708
3709/** @} */
3710
3711
3712/** @name Thread Handle Callbacks
3713 * @{ */
3714
3715/* From ntifs.h */
3716extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
3717
3718/** Thread rights that we allow for handles to stub and VM processes. */
3719# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS  \
3720    (  THREAD_TERMINATE \
3721     | THREAD_GET_CONTEXT \
3722     | THREAD_QUERY_INFORMATION \
3723     | THREAD_QUERY_LIMITED_INFORMATION \
3724     | DELETE \
3725     | READ_CONTROL \
3726     | SYNCHRONIZE)
3727/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
3728
3729/** Evil thread rights.
3730 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
3731 *          Windows 8.1, at least for some processes.  We dont' actively
3732 *          allow it though, just tollerate it when forced to. */
3733# define SUPDRV_NT_EVIL_THREAD_RIGHTS  \
3734    (  THREAD_SUSPEND_RESUME \
3735     | THREAD_SET_CONTEXT \
3736     | THREAD_SET_INFORMATION \
3737     | THREAD_SET_LIMITED_INFORMATION /*?*/ \
3738     | THREAD_SET_THREAD_TOKEN /*?*/ \
3739     | THREAD_IMPERSONATE /*?*/ \
3740     | THREAD_DIRECT_IMPERSONATION /*?*/ \
3741     /*| THREAD_RESUME - see remarks. */ \
3742     | 0)
3743AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
3744
3745
3746static OB_PREOP_CALLBACK_STATUS __stdcall
3747supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3748{
3749    Assert(pvUser == NULL); RT_NOREF1(pvUser);
3750    Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3751    Assert(pOpInfo->ObjectType == *PsThreadType);
3752
3753    PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
3754    PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
3755    pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3756    if (pNtProtect)
3757    {
3758        static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3759        ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
3760
3761        if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3762        {
3763            /* Don't restrict the process accessing its own threads. */
3764            if (pProcess == PsGetCurrentProcess())
3765            {
3766                Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
3767                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3768                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3769                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
3770                pOpInfo->CallContext = NULL; /* don't assert */
3771                pNtProtect->fFirstThreadCreateHandle = false;
3772            }
3773#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3774            /* Allow debuggers full access. */
3775            else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3776            {
3777                Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3778                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3779                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3780                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3781                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3782                pOpInfo->CallContext = NULL; /* don't assert */
3783            }
3784#endif
3785            else
3786            {
3787                /* Special case 1 on Vista, 7, 8:
3788                   The CreateProcess code passes the handle over to CSRSS.EXE
3789                   and the code inBaseSrvCreateProcess will duplicate the
3790                   handle with 0x1fffff as access mask.  NtDuplicateObject will
3791                   fail this call before it ever gets down here.  */
3792                if (   g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3793                    && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3794                    && pNtProtect->fFirstThreadCreateHandle
3795                    && pOpInfo->KernelHandle == 0
3796                    && ExGetPreviousMode() == UserMode
3797                    && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
3798                {
3799                    if (   !pOpInfo->KernelHandle
3800                        && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3801                    {
3802                        fAllowedRights |= s_fCsrssStupidDesires;
3803                        pOpInfo->CallContext = NULL; /* don't assert this. */
3804                    }
3805                    pNtProtect->fFirstThreadCreateHandle = false;
3806                }
3807
3808                /* Special case 2 on 8.1, possibly also Vista, 7, 8:
3809                   When creating a process like VBoxTestOGL from the VM process,
3810                   CSRSS.EXE will try talk to the calling thread and, it
3811                   appears, impersonate it.  We unfortunately need to allow
3812                   this or there will be no 3D support.  Typical DbgPrint:
3813                        "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
3814                SUPDRVNTPROTECTKIND enmProcessKind;
3815                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3816                    && (   (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3817                        || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3818                    && pOpInfo->KernelHandle == 0
3819                    && ExGetPreviousMode() == UserMode
3820                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3821                {
3822                    fAllowedRights |= THREAD_IMPERSONATE;
3823                    fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3824                    //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3825                    pOpInfo->CallContext = NULL; /* don't assert this. */
3826                }
3827
3828                Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3829                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3830                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3831                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3832                     pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3833                     PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
3834
3835                pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3836            }
3837        }
3838        else
3839        {
3840            /* Don't restrict the process accessing its own threads. */
3841            if (   pProcess == PsGetCurrentProcess()
3842                && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
3843            {
3844                Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
3845                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3846                     pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3847                     PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3848                     pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3849                     pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3850                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3851                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3852                pOpInfo->CallContext = NULL; /* don't assert */
3853            }
3854            else
3855            {
3856                /* Special case 3 on Vista, 7, 8:
3857                   This is the follow up to special case 1. */
3858                SUPDRVNTPROTECTKIND enmProcessKind;
3859                if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3860                    && (   (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3861                        || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3862                    && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3863                    && pOpInfo->KernelHandle == 0
3864                    && ExGetPreviousMode() == UserMode
3865                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3866                {
3867                    fAllowedRights |= THREAD_IMPERSONATE;
3868                    fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3869                    //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3870                    pOpInfo->CallContext = NULL; /* don't assert this. */
3871                }
3872
3873                Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3874                     pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3875                     pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3876                     PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3877                     pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3878                     pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3879                     pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3880                     pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
3881                     PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3882
3883                pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3884            }
3885        }
3886
3887        supdrvNtProtectRelease(pNtProtect);
3888    }
3889
3890    return OB_PREOP_SUCCESS;
3891}
3892
3893
3894static VOID __stdcall
3895supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3896{
3897    Assert(pvUser == NULL); RT_NOREF1(pvUser);
3898    Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3899    Assert(pOpInfo->ObjectType == *PsThreadType);
3900
3901    if (   pOpInfo->CallContext
3902        && NT_SUCCESS(pOpInfo->ReturnStatus))
3903    {
3904        ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
3905        AssertReleaseMsg(   !(fGrantedAccess & ~(  SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3906                                                 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3907                                                 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
3908                                                 ) )
3909                         || pOpInfo->KernelHandle,
3910                         ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3911                          fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
3912    }
3913}
3914
3915# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3916
3917/** @} */
3918
3919
3920/**
3921 * Creates a new process protection structure.
3922 *
3923 * @returns VBox status code.
3924 * @param   ppNtProtect         Where to return the pointer to the structure
3925 *                              on success.
3926 * @param   hPid                The process ID of the process to protect.
3927 * @param   enmProcessKind      The kind of process we're protecting.
3928 * @param   fLink               Whether to link the structure into the tree.
3929 */
3930static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
3931{
3932    AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
3933
3934    PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
3935    if (!pNtProtect)
3936        return VERR_NO_MEMORY;
3937
3938    pNtProtect->AvlCore.Key                  = hPid;
3939    pNtProtect->u32Magic                     = SUPDRVNTPROTECT_MAGIC;
3940    pNtProtect->cRefs                        = 1;
3941    pNtProtect->enmProcessKind               = enmProcessKind;
3942    pNtProtect->hParentPid                   = NULL;
3943    pNtProtect->hOpenTid                     = NULL;
3944    pNtProtect->hCsrssPid                    = NULL;
3945    pNtProtect->pCsrssProcess                = NULL;
3946
3947    if (fLink)
3948    {
3949        RTSpinlockAcquire(g_hNtProtectLock);
3950        bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
3951        pNtProtect->fInTree = fSuccess;
3952        RTSpinlockRelease(g_hNtProtectLock);
3953
3954        if (!fSuccess)
3955        {
3956            /* Duplicate entry, fail. */
3957            pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
3958            LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
3959            RTMemFree(pNtProtect);
3960            return VERR_DUPLICATE;
3961        }
3962    }
3963
3964    *ppNtProtect = pNtProtect;
3965    return VINF_SUCCESS;
3966}
3967
3968
3969/**
3970 * Releases a reference to a NT protection structure.
3971 *
3972 * @param   pNtProtect          The NT protection structure.
3973 */
3974static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
3975{
3976    if (!pNtProtect)
3977        return;
3978    AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
3979
3980    RTSpinlockAcquire(g_hNtProtectLock);
3981    uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
3982    if (cRefs != 0)
3983        RTSpinlockRelease(g_hNtProtectLock);
3984    else
3985    {
3986        /*
3987         * That was the last reference.  Remove it from the tree, invalidate it
3988         * and free the resources associated with it.  Also, release any
3989         * child/parent references related to this protection structure.
3990         */
3991        ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
3992        if (pNtProtect->fInTree)
3993        {
3994            PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
3995            Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
3996            pNtProtect->fInTree = false;
3997        }
3998
3999        PSUPDRVNTPROTECT pChild = NULL;
4000        if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4001        {
4002            pChild = pNtProtect->u.pChild;
4003            if (pChild)
4004            {
4005                pNtProtect->u.pChild   = NULL;
4006                pChild->u.pParent      = NULL;
4007                pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4008                uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4009                if (!cChildRefs)
4010                {
4011                    Assert(pChild->fInTree);
4012                    if (pChild->fInTree)
4013                    {
4014                        PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4015                        Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4016                        pChild->fInTree = false;
4017                    }
4018                }
4019                else
4020                    pChild = NULL;
4021            }
4022        }
4023        else
4024            AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4025
4026        RTSpinlockRelease(g_hNtProtectLock);
4027
4028        if (pNtProtect->pCsrssProcess)
4029        {
4030            ObDereferenceObject(pNtProtect->pCsrssProcess);
4031            pNtProtect->pCsrssProcess = NULL;
4032        }
4033
4034        RTMemFree(pNtProtect);
4035        if (pChild)
4036            RTMemFree(pChild);
4037    }
4038}
4039
4040
4041/**
4042 * Looks up a PID in the NT protect tree.
4043 *
4044 * @returns Pointer to a NT protection structure (with a referenced) on success,
4045 *          NULL if not found.
4046 * @param   hPid                The process ID.
4047 */
4048static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4049{
4050    RTSpinlockAcquire(g_hNtProtectLock);
4051    PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4052    if (pFound)
4053        ASMAtomicIncU32(&pFound->cRefs);
4054    RTSpinlockRelease(g_hNtProtectLock);
4055    return pFound;
4056}
4057
4058
4059/**
4060 * Validates a few facts about the stub process when the VM process opens
4061 * vboxdrv.
4062 *
4063 * This makes sure the stub process is still around and that it has neither
4064 * debugger nor extra threads in it.
4065 *
4066 * @returns VBox status code.
4067 * @param   pNtProtect          The unconfirmed VM process currently trying to
4068 *                              open vboxdrv.
4069 * @param   pErrInfo            Additional error information.
4070 */
4071static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4072{
4073    /*
4074     * Grab a reference to the parent stub process.
4075     */
4076    SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4077    PSUPDRVNTPROTECT    pNtStub = NULL;
4078    RTSpinlockAcquire(g_hNtProtectLock);
4079    if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4080    {
4081        pNtStub = pNtProtect->u.pParent; /* weak reference. */
4082        if (pNtStub)
4083        {
4084            enmStub = pNtStub->enmProcessKind;
4085            if (enmStub == kSupDrvNtProtectKind_StubParent)
4086            {
4087                uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4088                Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4089            }
4090            else
4091                pNtStub = NULL;
4092        }
4093    }
4094    RTSpinlockRelease(g_hNtProtectLock);
4095
4096    /*
4097     * We require the stub process to be present.
4098     */
4099    if (!pNtStub)
4100        return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4101
4102    /*
4103     * Open the parent process and thread so we can check for debuggers and unwanted threads.
4104     */
4105    int rc;
4106    PEPROCESS pStubProcess;
4107    NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4108    if (NT_SUCCESS(rcNt))
4109    {
4110        HANDLE hStubProcess;
4111        rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4112                                     0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4113        if (NT_SUCCESS(rcNt))
4114        {
4115            PETHREAD pStubThread;
4116            rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4117            if (NT_SUCCESS(rcNt))
4118            {
4119                HANDLE hStubThread;
4120                rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4121                                             0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4122                if (NT_SUCCESS(rcNt))
4123                {
4124                    /*
4125                     * Do some simple sanity checking.
4126                     */
4127                    rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4128                    if (RT_SUCCESS(rc))
4129                        rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4130
4131                    /* Clean up. */
4132                    rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4133                }
4134                else
4135                    rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4136                                       "Error opening stub thread %p (tid %p, pid %p): %#x",
4137                                       pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4138            }
4139            else
4140                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4141                                   "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4142            rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4143        }
4144        else
4145            rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4146                               "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4147        ObDereferenceObject(pStubProcess);
4148    }
4149    else
4150        rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4151                           "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4152
4153    supdrvNtProtectRelease(pNtStub);
4154    return rc;
4155}
4156
4157
4158/**
4159 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
4160 * process and its thread.
4161 *
4162 * @returns VBox status code.
4163 * @param   pNtProtect          The NT protect structure for getting information
4164 *                              about special processes.
4165 * @param   pErrInfo            Where to return additional error details.
4166 */
4167static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4168{
4169    /*
4170     * What to protect.
4171     */
4172    PEPROCESS   pProtectedProcess = PsGetCurrentProcess();
4173    HANDLE      hProtectedPid     = PsGetProcessId(pProtectedProcess);
4174    PETHREAD    pProtectedThread  = PsGetCurrentThread();
4175    AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
4176
4177    /*
4178     * Take a snapshot of all the handles in the system.
4179     * Note! The 32 bytes on the size of to counteract the allocation header
4180     *       that rtR0MemAllocEx slaps on everything.
4181     */
4182    uint32_t    cbBuf    = _256K - 32;
4183    uint8_t    *pbBuf    = (uint8_t *)RTMemAlloc(cbBuf);
4184    ULONG       cbNeeded = cbBuf;
4185    NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4186    if (!NT_SUCCESS(rcNt))
4187    {
4188        while (   rcNt == STATUS_INFO_LENGTH_MISMATCH
4189               && cbNeeded > cbBuf
4190               && cbBuf <= 32U*_1M)
4191        {
4192            cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
4193            RTMemFree(pbBuf);
4194            pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4195            if (!pbBuf)
4196                return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
4197            rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4198        }
4199        if (!NT_SUCCESS(rcNt))
4200        {
4201            RTMemFree(pbBuf);
4202            return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
4203                                 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
4204        }
4205    }
4206
4207    /*
4208     * Walk the information and look for handles to the two objects we're protecting.
4209     */
4210    int rc = VINF_SUCCESS;
4211# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4212    HANDLE   idLastDebugger = (HANDLE)~(uintptr_t)0;
4213# endif
4214
4215    uint32_t cCsrssProcessHandles  = 0;
4216    uint32_t cSystemProcessHandles = 0;
4217    uint32_t cEvilProcessHandles   = 0;
4218    uint32_t cBenignProcessHandles = 0;
4219
4220    uint32_t cCsrssThreadHandles   = 0;
4221    uint32_t cEvilThreadHandles    = 0;
4222    uint32_t cBenignThreadHandles  = 0;
4223
4224    SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
4225    ULONG_PTR i = pInfo->NumberOfHandles;
4226    AssertRelease(RT_OFFSETOF(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
4227    while (i-- > 0)
4228    {
4229        const char *pszType;
4230        SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
4231        if (pHandleInfo->Object == pProtectedProcess)
4232        {
4233            /* Handles within the protected process are fine. */
4234            if (   !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
4235                || pHandleInfo->UniqueProcessId == hProtectedPid)
4236            {
4237                cBenignProcessHandles++;
4238                continue;
4239            }
4240
4241            /* CSRSS is allowed to have one evil process handle.
4242               See the special cases in the hook code. */
4243            if (   cCsrssProcessHandles < 1
4244                && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4245            {
4246                cCsrssProcessHandles++;
4247                continue;
4248            }
4249
4250            /* The system process is allowed having two open process handle in
4251               Windows 8.1 and later, and one in earlier. This is probably a
4252               little overly paranoid as I think we can safely trust the
4253               system process... */
4254            if (   cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
4255                && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
4256            {
4257                cSystemProcessHandles++;
4258                continue;
4259            }
4260
4261            cEvilProcessHandles++;
4262            pszType = "process";
4263        }
4264        else if (pHandleInfo->Object == pProtectedThread)
4265        {
4266            /* Handles within the protected process is fine. */
4267            if (   !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
4268                || pHandleInfo->UniqueProcessId == hProtectedPid)
4269            {
4270                cBenignThreadHandles++;
4271                continue;
4272            }
4273
4274            /* CSRSS is allowed to have one evil handle to the primary thread
4275               for LPC purposes.  See the hook for special case. */
4276            if (   cCsrssThreadHandles < 1
4277                && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4278            {
4279                cCsrssThreadHandles++;
4280                continue;
4281            }
4282
4283            cEvilThreadHandles++;
4284            pszType = "thread";
4285        }
4286        else
4287            continue;
4288
4289# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4290        /* Ignore whitelisted debuggers. */
4291        if (pHandleInfo->UniqueProcessId == idLastDebugger)
4292            continue;
4293        PEPROCESS pDbgProc;
4294        NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4295        if (NT_SUCCESS(rcNt))
4296        {
4297            bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4298            ObDereferenceObject(pDbgProc);
4299            if (fIsDebugger)
4300            {
4301                idLastDebugger = pHandleInfo->UniqueProcessId;
4302                continue;
4303            }
4304        }
4305# endif
4306
4307        /* Found evil handle. Currently ignoring on pre-Vista. */
4308# ifndef VBOX_WITH_VISTA_NO_SP
4309        if (   g_uNtVerCombined >= SUP_NT_VER_VISTA
4310# else
4311        if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4312# endif
4313            || g_pfnObRegisterCallbacks)
4314        {
4315            LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4316                    pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4317                    pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4318            rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4319                               *pErrInfo->pszMsg
4320                               ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4321                               : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4322                               pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4323                               pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4324
4325            /* Try add the process name. */
4326            PEPROCESS pOffendingProcess;
4327            rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4328            if (NT_SUCCESS(rcNt))
4329            {
4330                const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4331                if (pszName && *pszName)
4332                    rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4333
4334                ObDereferenceObject(pOffendingProcess);
4335            }
4336        }
4337    }
4338
4339    RTMemFree(pbBuf);
4340    return rc;
4341}
4342
4343
4344/**
4345 * Checks if the current process checks out as a VM process stub.
4346 *
4347 * @returns VBox status code.
4348 * @param   pNtProtect          The NT protect structure.  This is upgraded to a
4349 *                              final protection kind (state) on success.
4350 */
4351static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4352{
4353    AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4354
4355    /*
4356     * Do the verification.  The handle restriction checks are only preformed
4357     * on VM processes.
4358     */
4359    int rc = VINF_SUCCESS;
4360    PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4361    if (RT_SUCCESS(rc))
4362    {
4363        pErrorInfo->hProcessId = PsGetCurrentProcessId();
4364        pErrorInfo->hThreadId  = PsGetCurrentThreadId();
4365        RTERRINFO ErrInfo;
4366        RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4367
4368        if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4369            rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4370        if (RT_SUCCESS(rc))
4371        {
4372            rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4373                                             NULL /*pcFixes*/, &ErrInfo);
4374            if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4375                rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4376        }
4377    }
4378    else
4379        rc = VERR_NO_MEMORY;
4380
4381    /*
4382     * Upgrade and return.
4383     */
4384    HANDLE hOpenTid = PsGetCurrentThreadId();
4385    RTSpinlockAcquire(g_hNtProtectLock);
4386
4387    /* Stub process verficiation is pretty much straight forward. */
4388    if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4389    {
4390        pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4391        pNtProtect->hOpenTid       = hOpenTid;
4392    }
4393    /* The VM process verification is a little bit more complicated
4394       because we need to drop the parent process reference as well. */
4395    else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4396    {
4397        AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4398        PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4399        AssertRelease(pParent);
4400        AssertRelease(pParent->u.pParent == pNtProtect);
4401        AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4402        pParent->u.pParent = NULL;
4403
4404        pNtProtect->u.pParent = NULL;
4405        ASMAtomicDecU32(&pNtProtect->cRefs);
4406
4407        if (RT_SUCCESS(rc))
4408        {
4409            pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4410            pNtProtect->hOpenTid       = hOpenTid;
4411        }
4412        else
4413            pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4414    }
4415
4416    /* Since the stub and VM processes are only supposed to have one thread,
4417       we're not supposed to be subject to any races from within the processes.
4418
4419       There is a race between VM process verification and the stub process
4420       exiting, though.  We require the stub process to be alive until the new
4421       VM process has made it thru the validation.  So, when the stub
4422       terminates the notification handler will change the state of both stub
4423       and VM process to dead.
4424
4425       Also, I'm not entirely certain where the process
4426       termination notification is triggered from, so that can theorically
4427       create a race in both cases.  */
4428    else
4429    {
4430        AssertReleaseMsg(   pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4431                         || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4432                         ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4433        if (RT_SUCCESS(rc))
4434            rc = VERR_INVALID_STATE; /* There should be no races here. */
4435    }
4436
4437    RTSpinlockRelease(g_hNtProtectLock);
4438
4439    /*
4440     * Free error info on success, keep it on failure.
4441     */
4442    if (RT_SUCCESS(rc))
4443        RTMemFree(pErrorInfo);
4444    else if (pErrorInfo)
4445    {
4446        pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4447        if (!pErrorInfo->cchErrorInfo)
4448            pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4449                                                             "supdrvNtProtectVerifyProcess: rc=%d", rc);
4450        RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4451
4452        int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4453        if (RT_SUCCESS(rc2))
4454        {
4455            pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4456
4457            /* Free old entries. */
4458            PSUPDRVNTERRORINFO pCur;
4459            while (   (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4460                   && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4461            {
4462                RTListNodeRemove(&pCur->ListEntry);
4463                RTMemFree(pCur);
4464            }
4465
4466            /* Insert our new entry. */
4467            RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4468
4469            RTSemMutexRelease(g_hErrorInfoLock);
4470        }
4471        else
4472            RTMemFree(pErrorInfo);
4473    }
4474
4475    return rc;
4476}
4477
4478
4479# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4480
4481/**
4482 * Checks if the current process is being debugged.
4483 * @return @c true if debugged, @c false if not.
4484 */
4485static bool supdrvNtIsDebuggerAttached(void)
4486{
4487    return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4488}
4489
4490# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4491
4492
4493/**
4494 * Terminates the hardening bits.
4495 */
4496static void supdrvNtProtectTerm(void)
4497{
4498    /*
4499     * Stop intercepting process and thread handle creation calls.
4500     */
4501    if (g_pvObCallbacksCookie)
4502    {
4503        g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
4504        g_pvObCallbacksCookie = NULL;
4505    }
4506
4507    /*
4508     * Stop intercepting process creation and termination notifications.
4509     */
4510    NTSTATUS rcNt;
4511    if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4512        rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4513    else
4514        rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4515    AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
4516
4517    Assert(g_NtProtectTree == NULL);
4518
4519    /*
4520     * Clean up globals.
4521     */
4522    RTSpinlockDestroy(g_hNtProtectLock);
4523    g_NtProtectTree = NIL_RTSPINLOCK;
4524
4525    RTSemMutexDestroy(g_hErrorInfoLock);
4526    g_hErrorInfoLock = NIL_RTSEMMUTEX;
4527
4528    PSUPDRVNTERRORINFO pCur;
4529    while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
4530    {
4531        RTListNodeRemove(&pCur->ListEntry);
4532        RTMemFree(pCur);
4533    }
4534
4535    supHardenedWinTermImageVerifier();
4536}
4537
4538# ifdef RT_ARCH_X86
4539DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
4540DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
4541DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
4542DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
4543DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
4544DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
4545DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
4546DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
4547DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
4548DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
4549DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
4550DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
4551DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
4552DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
4553DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
4554DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
4555# elif defined(RT_ARCH_AMD64)
4556DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
4557DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
4558DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
4559DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
4560DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
4561extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
4562# endif
4563
4564
4565/**
4566 * Initalizes the hardening bits.
4567 *
4568 * @returns NT status code.
4569 */
4570static NTSTATUS supdrvNtProtectInit(void)
4571{
4572    /*
4573     * Initialize the globals.
4574     */
4575
4576    /* The NT version. */
4577    ULONG uMajor, uMinor, uBuild;
4578    PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
4579    g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
4580
4581    /* Resolve methods we want but isn't available everywhere. */
4582    UNICODE_STRING RoutineName;
4583
4584    RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
4585    g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
4586
4587    RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
4588    g_pfnObRegisterCallbacks   = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4589
4590    RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
4591    g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4592
4593    RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
4594    g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
4595
4596    RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
4597    g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
4598
4599    RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
4600    g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
4601
4602    RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
4603    g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
4604
4605    RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
4606    g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
4607    if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
4608    {
4609        /* XP & W2K3 doesn't have this function exported, so we've cooked up a
4610           few alternative in the assembly helper file that uses the code in
4611           ZwReadFile with a different eax value.  We figure the syscall number
4612           by inspecting ZwQueryVolumeInformationFile as it's the next number. */
4613# ifdef RT_ARCH_X86
4614        uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
4615        if (*pbCode == 0xb8) /* mov eax, dword */
4616            switch (*(uint32_t const *)&pbCode[1])
4617            {
4618                case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
4619                case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
4620                case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
4621                case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
4622                case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
4623                case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
4624                case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
4625                case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
4626                case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
4627                case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
4628                case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
4629                case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
4630                case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
4631                case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
4632                case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
4633                case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
4634            }
4635# elif defined(RT_ARCH_AMD64)
4636        uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
4637        if (   pbCode[ 0] == 0x48   /* mov rax, rsp */
4638            && pbCode[ 1] == 0x8b
4639            && pbCode[ 2] == 0xc4
4640            && pbCode[ 3] == 0xfa   /* cli */
4641            && pbCode[ 4] == 0x48   /* sub rsp, 10h */
4642            && pbCode[ 5] == 0x83
4643            && pbCode[ 6] == 0xec
4644            && pbCode[ 7] == 0x10
4645            && pbCode[ 8] == 0x50   /* push rax */
4646            && pbCode[ 9] == 0x9c   /* pushfq */
4647            && pbCode[10] == 0x6a   /* push 10 */
4648            && pbCode[11] == 0x10
4649            && pbCode[12] == 0x48   /* lea rax, [nt!KiServiceLinkage] */
4650            && pbCode[13] == 0x8d
4651            && pbCode[14] == 0x05
4652            && pbCode[19] == 0x50   /* push rax */
4653            && pbCode[20] == 0xb8   /* mov eax,1fh <- the syscall no. */
4654            /*&& pbCode[21] == 0x1f*/
4655            && pbCode[22] == 0x00
4656            && pbCode[23] == 0x00
4657            && pbCode[24] == 0x00
4658            && pbCode[25] == 0xe9   /* jmp KiServiceInternal */
4659           )
4660        {
4661            uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
4662            uint8_t const *pbKiServiceLinkage  = &pbCode[19] + *(int32_t const *)&pbCode[15];
4663            if (*pbKiServiceLinkage == 0xc3)
4664            {
4665                g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
4666                g_pfnKiServiceLinkage  = (PFNRT)pbKiServiceLinkage;
4667                switch (pbCode[21])
4668                {
4669                    case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
4670                    case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
4671                    case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
4672                    case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
4673                    case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
4674                }
4675            }
4676        }
4677# endif
4678    }
4679    if (!g_pfnNtQueryVirtualMemory)
4680    {
4681        LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
4682        return STATUS_PROCEDURE_NOT_FOUND;
4683    }
4684
4685# ifdef VBOX_STRICT
4686    if (   g_uNtVerCombined >= SUP_NT_VER_W70
4687        && (   g_pfnObGetObjectType == NULL
4688            || g_pfnZwAlpcCreatePort == NULL) )
4689    {
4690        LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
4691        return STATUS_PROCEDURE_NOT_FOUND;
4692    }
4693# endif
4694
4695    /* LPC object type. */
4696    g_pAlpcPortObjectType1 = *LpcPortObjectType;
4697
4698    /* The spinlock protecting our structures. */
4699    int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
4700    if (RT_FAILURE(rc))
4701        return VBoxDrvNtErr2NtStatus(rc);
4702    g_NtProtectTree = NULL;
4703
4704    NTSTATUS rcNt;
4705
4706    /* The mutex protecting the error information. */
4707    RTListInit(&g_ErrorInfoHead);
4708    rc = RTSemMutexCreate(&g_hErrorInfoLock);
4709    if (RT_SUCCESS(rc))
4710    {
4711        /* Image stuff + certificates. */
4712        rc = supHardenedWinInitImageVerifier(NULL);
4713        if (RT_SUCCESS(rc))
4714        {
4715            /*
4716             * Intercept process creation and termination.
4717             */
4718            if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4719                rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
4720            else
4721                rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
4722            if (NT_SUCCESS(rcNt))
4723            {
4724                /*
4725                 * Intercept process and thread handle creation calls.
4726                 * The preferred method is only available on Vista SP1+.
4727                 */
4728                if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
4729                {
4730                    static OB_OPERATION_REGISTRATION s_aObOperations[] =
4731                    {
4732                        {
4733                            0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
4734                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4735                            supdrvNtProtectCallback_ProcessHandlePre,
4736                            supdrvNtProtectCallback_ProcessHandlePost,
4737                        },
4738                        {
4739                            0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
4740                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4741                            supdrvNtProtectCallback_ThreadHandlePre,
4742                            supdrvNtProtectCallback_ThreadHandlePost,
4743                        },
4744                    };
4745                    s_aObOperations[0].ObjectType = PsProcessType;
4746                    s_aObOperations[1].ObjectType = PsThreadType;
4747
4748                    static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
4749                    {
4750                        /* .Version                     = */ OB_FLT_REGISTRATION_VERSION,
4751                        /* .OperationRegistrationCount  = */ RT_ELEMENTS(s_aObOperations),
4752                        /* .Altitude.Length             = */ 0,
4753                        /* .Altitude.MaximumLength      = */ 0,
4754                        /* .Altitude.Buffer             = */ NULL,
4755                        /* .RegistrationContext         = */ NULL,
4756                        /* .OperationRegistration       = */ &s_aObOperations[0]
4757                    };
4758                    static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
4759                    {
4760                         L"48596.98940",  L"46935.19485",  L"49739.39704",  L"40334.74976",
4761                         L"66667.98940",  L"69888.19485",  L"69889.39704",  L"60364.74976",
4762                         L"85780.98940",  L"88978.19485",  L"89939.39704",  L"80320.74976",
4763                         L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
4764                    };
4765
4766                    rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
4767                    for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
4768                    {
4769                        s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
4770                        s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
4771                        s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
4772
4773                        rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
4774                        if (NT_SUCCESS(rcNt))
4775                        {
4776                            /*
4777                             * Happy ending.
4778                             */
4779                            return STATUS_SUCCESS;
4780                        }
4781                    }
4782                    LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
4783                    g_pvObCallbacksCookie = NULL;
4784                }
4785                else
4786                {
4787                    /*
4788                     * For the time being, we do not implement extra process
4789                     * protection on pre-Vista-SP1 systems as they are lacking
4790                     * necessary KPIs.  XP is end of life, we do not wish to
4791                     * spend more time on it, so we don't put up a fuss there.
4792                     * Vista users without SP1 can install SP1 (or later), darn it,
4793                     * so refuse to load.
4794                     */
4795                    /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
4796                     *        stuff to a couple of object types. */
4797# ifndef VBOX_WITH_VISTA_NO_SP
4798                    if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
4799# else
4800                    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
4801# endif
4802                    {
4803                        DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
4804                        rcNt = STATUS_SXS_VERSION_CONFLICT;
4805                    }
4806                    else
4807                    {
4808                        Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
4809                        return rcNt = STATUS_SUCCESS;
4810                    }
4811                    g_pvObCallbacksCookie = NULL;
4812                }
4813
4814                /*
4815                 * Drop process create/term notifications.
4816                 */
4817                if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4818                    g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4819                else
4820                    PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4821            }
4822            else
4823                LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
4824                        g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
4825            supHardenedWinTermImageVerifier();
4826        }
4827        else
4828            rcNt = VBoxDrvNtErr2NtStatus(rc);
4829
4830        RTSemMutexDestroy(g_hErrorInfoLock);
4831        g_hErrorInfoLock = NIL_RTSEMMUTEX;
4832    }
4833    else
4834        rcNt = VBoxDrvNtErr2NtStatus(rc);
4835
4836    RTSpinlockDestroy(g_hNtProtectLock);
4837    g_NtProtectTree = NIL_RTSPINLOCK;
4838    return rcNt;
4839}
4840
4841#endif /* VBOX_WITH_HARDENING */
4842
Note: See TracBrowser for help on using the repository browser.

www.oracle.com
ContactPrivacy policyTerms of Use