VirtualBox

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

Last change on this file since 76781 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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

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