VirtualBox

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

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

Fix for bugref:9328

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 213.0 KB
Line 
1/* $Id: SUPDrv-win.cpp 76785 2019-01-11 17:35:01Z 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 pMatch = NULL;
1575 PSUPDRVNTERRORINFO pCur;
1576 RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
1577 {
1578 if ( pCur->hProcessId == hCurProcessId
1579 && pCur->hThreadId == hCurThreadId)
1580 {
1581 pMatch = pCur;
1582 break;
1583 }
1584 }
1585
1586 /*
1587 * Did we find error info and is the caller requesting data within it?
1588 * If so, check the destination buffer and copy the data into it.
1589 */
1590 if ( pMatch
1591 && pStack->Parameters.Read.ByteOffset.QuadPart < pMatch->cchErrorInfo
1592 && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
1593 {
1594 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1595 if (pvDstBuf)
1596 {
1597 uint32_t offRead = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
1598 uint32_t cbToRead = pMatch->cchErrorInfo - offRead;
1599 if (cbToRead < pStack->Parameters.Read.Length)
1600 RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
1601 else
1602 cbToRead = pStack->Parameters.Read.Length;
1603 memcpy(pvDstBuf, &pMatch->szErrorInfo[offRead], cbToRead);
1604 pIrp->IoStatus.Information = cbToRead;
1605
1606 rcNt = STATUS_SUCCESS;
1607 }
1608 else
1609 rcNt = STATUS_INVALID_ADDRESS;
1610 }
1611 /*
1612 * End of file. Free the info.
1613 */
1614 else if (pMatch)
1615 {
1616 RTListNodeRemove(&pMatch->ListEntry);
1617 RTMemFree(pMatch);
1618 rcNt = STATUS_END_OF_FILE;
1619 }
1620 /*
1621 * We found no error info. Return EOF.
1622 */
1623 else
1624 rcNt = STATUS_END_OF_FILE;
1625
1626 RTSemMutexRelease(g_hErrorInfoLock);
1627 }
1628 else
1629 rcNt = STATUS_UNSUCCESSFUL;
1630
1631 /* Paranoia: Clear the buffer on failure. */
1632 if (!NT_SUCCESS(rcNt))
1633 {
1634 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1635 if ( pvDstBuf
1636 && pStack->Parameters.Read.Length)
1637 RT_BZERO(pvDstBuf, pStack->Parameters.Read.Length);
1638 }
1639 }
1640 else
1641 rcNt = STATUS_INVALID_PARAMETER;
1642 }
1643 else
1644#endif /* VBOX_WITH_HARDENING */
1645 {
1646 /*
1647 * Stub.
1648 */
1649 rcNt = STATUS_NOT_SUPPORTED;
1650 }
1651
1652 /*
1653 * Complete the request.
1654 */
1655 pIrp->IoStatus.Status = rcNt;
1656 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1657 return rcNt;
1658}
1659
1660
1661/**
1662 * Stub function for functions we don't implemented.
1663 *
1664 * @returns STATUS_NOT_SUPPORTED
1665 * @param pDevObj Device object.
1666 * @param pIrp IRP.
1667 */
1668NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1669{
1670 Log(("VBoxDrvNtNotSupportedStub\n"));
1671 NOREF(pDevObj);
1672
1673 pIrp->IoStatus.Information = 0;
1674 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1675 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1676
1677 return STATUS_NOT_SUPPORTED;
1678}
1679
1680
1681/**
1682 * ExRegisterCallback handler for power events
1683 *
1684 * @param pCallbackContext User supplied parameter (pDevObj)
1685 * @param pvArgument1 First argument
1686 * @param pvArgument2 Second argument
1687 */
1688VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pvArgument1, PVOID pvArgument2)
1689{
1690 /*PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;*/ RT_NOREF1(pCallbackContext);
1691 Log(("VBoxPowerDispatchCallback: %x %x\n", pvArgument1, pvArgument2));
1692
1693 /* Power change imminent? */
1694 if ((uintptr_t)pvArgument1 == PO_CB_SYSTEM_STATE_LOCK)
1695 {
1696 if (pvArgument2 == NULL)
1697 Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
1698 else
1699 Log(("VBoxPowerDispatchCallback: resumed!\n"));
1700
1701 /* Inform any clients that have registered themselves with IPRT. */
1702 RTPowerSignalEvent(pvArgument2 == NULL ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
1703 }
1704}
1705
1706
1707/**
1708 * Called to clean up the session structure before it's freed.
1709 *
1710 * @param pDevExt The device globals.
1711 * @param pSession The session that's being cleaned up.
1712 */
1713void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1714{
1715#ifdef VBOX_WITH_HARDENING
1716 if (pSession->pNtProtect)
1717 {
1718 supdrvNtProtectRelease(pSession->pNtProtect);
1719 pSession->pNtProtect = NULL;
1720 }
1721 RT_NOREF1(pDevExt);
1722#else
1723 RT_NOREF2(pDevExt, pSession);
1724#endif
1725}
1726
1727
1728void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1729{
1730 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1731}
1732
1733
1734void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1735{
1736 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1737}
1738
1739
1740size_t VBOXCALL supdrvOSGipGetGroupTableSize(PSUPDRVDEVEXT pDevExt)
1741{
1742 NOREF(pDevExt);
1743 uint32_t cMaxCpus = RTMpGetCount();
1744 uint32_t cGroups = RTMpGetMaxCpuGroupCount();
1745
1746 return cGroups * RT_UOFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs)
1747 + RT_SIZEOFMEMB(SUPGIPCPUGROUP, aiCpuSetIdxs[0]) * cMaxCpus;
1748}
1749
1750
1751int VBOXCALL supdrvOSInitGipGroupTable(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, size_t cbGipCpuGroups)
1752{
1753 Assert(cbGipCpuGroups > 0); NOREF(cbGipCpuGroups); NOREF(pDevExt);
1754
1755 unsigned const cGroups = RTMpGetMaxCpuGroupCount();
1756 AssertReturn(cGroups > 0 && cGroups < RT_ELEMENTS(pGip->aoffCpuGroup), VERR_INTERNAL_ERROR_2);
1757 pGip->cPossibleCpuGroups = cGroups;
1758
1759 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)&pGip->aCPUs[pGip->cCpus];
1760 for (uint32_t idxGroup = 0; idxGroup < cGroups; idxGroup++)
1761 {
1762 uint32_t cActive = 0;
1763 uint32_t cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1764 uint32_t cbNeeded = RT_UOFFSETOF_DYN(SUPGIPCPUGROUP, aiCpuSetIdxs[cMax]);
1765 AssertReturn(cbNeeded <= cbGipCpuGroups, VERR_INTERNAL_ERROR_3);
1766 AssertReturn(cActive <= cMax, VERR_INTERNAL_ERROR_4);
1767
1768 pGip->aoffCpuGroup[idxGroup] = (uint16_t)((uintptr_t)pGroup - (uintptr_t)pGip);
1769 pGroup->cMembers = cActive;
1770 pGroup->cMaxMembers = cMax;
1771 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1772 {
1773 pGroup->aiCpuSetIdxs[idxMember] = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1774 Assert((unsigned)pGroup->aiCpuSetIdxs[idxMember] < pGip->cPossibleCpus);
1775 }
1776
1777 /* advance. */
1778 cbGipCpuGroups -= cbNeeded;
1779 pGroup = (PSUPGIPCPUGROUP)&pGroup->aiCpuSetIdxs[cMax];
1780 }
1781
1782 return VINF_SUCCESS;
1783}
1784
1785
1786void VBOXCALL supdrvOSGipInitGroupBitsForCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu)
1787{
1788 NOREF(pDevExt);
1789
1790 /*
1791 * Translate the CPU index into a group and member.
1792 */
1793 PROCESSOR_NUMBER ProcNum = { 0, pGipCpu->iCpuSet, 0 };
1794 if (g_pfnKeGetProcessorNumberFromIndex)
1795 {
1796 NTSTATUS rcNt = g_pfnKeGetProcessorNumberFromIndex(pGipCpu->iCpuSet, &ProcNum);
1797 if (NT_SUCCESS(rcNt))
1798 Assert(ProcNum.Group < g_pfnKeQueryMaximumGroupCount());
1799 else
1800 {
1801 AssertFailed();
1802 ProcNum.Group = 0;
1803 ProcNum.Number = pGipCpu->iCpuSet;
1804 }
1805 }
1806 pGipCpu->iCpuGroup = ProcNum.Group;
1807 pGipCpu->iCpuGroupMember = ProcNum.Number;
1808
1809 /*
1810 * Update the group info. Just do this wholesale for now (doesn't scale well).
1811 */
1812 for (uint32_t idxGroup = 0; idxGroup < pGip->cPossibleCpuGroups; idxGroup++)
1813 if (pGip->aoffCpuGroup[idxGroup] != UINT16_MAX)
1814 {
1815 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)((uintptr_t)pGip + pGip->aoffCpuGroup[idxGroup]);
1816
1817 uint32_t cActive = 0;
1818 uint32_t cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1819 AssertStmt(cMax == pGroup->cMaxMembers, cMax = pGroup->cMaxMembers);
1820 AssertStmt(cActive <= cMax, cActive = cMax);
1821 if (pGroup->cMembers != cActive)
1822 pGroup->cMembers = cActive;
1823
1824 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1825 {
1826 int idxCpuSet = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1827 AssertMsg((unsigned)idxCpuSet < pGip->cPossibleCpus,
1828 ("%d vs %d for %u.%u\n", idxCpuSet, pGip->cPossibleCpus, idxGroup, idxMember));
1829
1830 if (pGroup->aiCpuSetIdxs[idxMember] != idxCpuSet)
1831 pGroup->aiCpuSetIdxs[idxMember] = idxCpuSet;
1832 }
1833 }
1834}
1835
1836
1837/**
1838 * Initializes any OS specific object creator fields.
1839 */
1840void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1841{
1842 NOREF(pObj);
1843 NOREF(pSession);
1844}
1845
1846
1847/**
1848 * Checks if the session can access the object.
1849 *
1850 * @returns true if a decision has been made.
1851 * @returns false if the default access policy should be applied.
1852 *
1853 * @param pObj The object in question.
1854 * @param pSession The session wanting to access the object.
1855 * @param pszObjName The object name, can be NULL.
1856 * @param prc Where to store the result when returning true.
1857 */
1858bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1859{
1860 NOREF(pObj);
1861 NOREF(pSession);
1862 NOREF(pszObjName);
1863 NOREF(prc);
1864 return false;
1865}
1866
1867
1868/**
1869 * Force async tsc mode (stub).
1870 */
1871bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1872{
1873 RT_NOREF1(pDevExt);
1874 return g_Options.fOptForceAsyncTsc != 0;
1875}
1876
1877
1878/**
1879 * Whether the host takes CPUs offline during a suspend/resume operation.
1880 */
1881bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
1882{
1883 return false;
1884}
1885
1886
1887/**
1888 * Whether the hardware TSC has been synchronized by the OS.
1889 */
1890bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1891{
1892 /* If IPRT didn't find KeIpiGenericCall we pretend windows(, the firmware,
1893 or whoever) always configures TSCs perfectly. */
1894 return !RTMpOnPairIsConcurrentExecSupported();
1895}
1896
1897
1898/**
1899 * Checks whether we're allowed by Hyper-V to modify CR4.
1900 */
1901int VBOXCALL supdrvOSGetRawModeUsability(void)
1902{
1903 int rc = VINF_SUCCESS;
1904
1905#ifdef RT_ARCH_AMD64
1906 /*
1907 * Broadwell running W10 17083.100:
1908 * CR4: 0x170678
1909 * Evil mask: 0x170638
1910 * X86_CR4_SMEP - evil
1911 * X86_CR4_FSGSBASE - evil
1912 * X86_CR4_PCIDE - evil
1913 * X86_CR4_OSXSAVE - evil
1914 * X86_CR4_OSFXSR - evil
1915 * X86_CR4_OSXMMEEXCPT - evil
1916 * X86_CR4_PSE - evil
1917 * X86_CR4_PAE - evil
1918 * X86_CR4_MCE - okay
1919 * X86_CR4_DE - evil
1920 */
1921 if (ASMHasCpuId())
1922 {
1923 uint32_t cStd = ASMCpuId_EAX(0);
1924 if (ASMIsValidStdRange(cStd))
1925 {
1926 uint32_t uIgn = 0;
1927 uint32_t fEdxFeatures = 0;
1928 uint32_t fEcxFeatures = 0;
1929 ASMCpuIdExSlow(1, 0, 0, 0, &uIgn, &uIgn, &fEcxFeatures, &fEdxFeatures);
1930 if (fEcxFeatures & X86_CPUID_FEATURE_ECX_HVP)
1931 {
1932 RTCCUINTREG const fOldFlags = ASMIntDisableFlags();
1933 RTCCUINTXREG const fCr4 = ASMGetCR4();
1934
1935 RTCCUINTXREG const fSafeToClear = X86_CR4_TSD | X86_CR4_DE | X86_CR4_PGE | X86_CR4_PCE
1936 | X86_CR4_FSGSBASE | X86_CR4_PCIDE | X86_CR4_SMEP | X86_CR4_SMAP
1937 | X86_CR4_OSXSAVE | X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT;
1938 RTCCUINTXREG fLoadCr4 = fCr4 & ~fSafeToClear;
1939 RTCCUINTXREG const fCleared = fCr4 & fSafeToClear;
1940 if (!(fCleared & X86_CR4_TSD) && (fEdxFeatures & X86_CPUID_FEATURE_EDX_TSC))
1941 fLoadCr4 |= X86_CR4_TSD;
1942 if (!(fCleared & X86_CR4_PGE) && (fEdxFeatures & X86_CPUID_FEATURE_EDX_PGE))
1943 fLoadCr4 |= X86_CR4_PGE;
1944 __try
1945 {
1946 ASMSetCR4(fLoadCr4);
1947 }
1948 __except(EXCEPTION_EXECUTE_HANDLER)
1949 {
1950 rc = VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT;
1951 }
1952 if (RT_SUCCESS(rc))
1953 ASMSetCR4(fCr4);
1954 ASMSetFlags(fOldFlags);
1955 }
1956 }
1957 }
1958#endif
1959 return rc;
1960}
1961
1962
1963#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
1964#define MY_SystemUnloadGdiDriverInformation 27
1965
1966typedef struct MYSYSTEMGDIDRIVERINFO
1967{
1968 UNICODE_STRING Name; /**< In: image file name. */
1969 PVOID ImageAddress; /**< Out: the load address. */
1970 PVOID SectionPointer; /**< Out: section object. */
1971 PVOID EntryPointer; /**< Out: entry point address. */
1972 PVOID ExportSectionPointer; /**< Out: export directory/section. */
1973 ULONG ImageLength; /**< Out: SizeOfImage. */
1974} MYSYSTEMGDIDRIVERINFO;
1975
1976extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
1977
1978int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1979{
1980 pImage->pvNtSectionObj = NULL;
1981 pImage->hMemLock = NIL_RTR0MEMOBJ;
1982
1983#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
1984# ifndef RT_ARCH_X86
1985# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
1986# endif
1987 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
1988 return VERR_NOT_SUPPORTED;
1989
1990#else
1991 /*
1992 * Convert the filename from DOS UTF-8 to NT UTF-16.
1993 */
1994 size_t cwcFilename;
1995 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
1996 if (RT_FAILURE(rc))
1997 return rc;
1998
1999 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
2000 if (!pwcsFilename)
2001 return VERR_NO_TMP_MEMORY;
2002
2003 pwcsFilename[0] = '\\';
2004 pwcsFilename[1] = '?';
2005 pwcsFilename[2] = '?';
2006 pwcsFilename[3] = '\\';
2007 PRTUTF16 pwcsTmp = &pwcsFilename[4];
2008 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
2009 if (RT_SUCCESS(rc))
2010 {
2011 /*
2012 * Try load it.
2013 */
2014 MYSYSTEMGDIDRIVERINFO Info;
2015 RtlInitUnicodeString(&Info.Name, pwcsFilename);
2016 Info.ImageAddress = NULL;
2017 Info.SectionPointer = NULL;
2018 Info.EntryPointer = NULL;
2019 Info.ExportSectionPointer = NULL;
2020 Info.ImageLength = 0;
2021
2022 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
2023 if (NT_SUCCESS(rcNt))
2024 {
2025 pImage->pvImage = Info.ImageAddress;
2026 pImage->pvNtSectionObj = Info.SectionPointer;
2027 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
2028 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
2029# ifdef DEBUG_bird
2030 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
2031 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
2032# endif
2033 if (pImage->cbImageBits == Info.ImageLength)
2034 {
2035 /*
2036 * Lock down the entire image, just to be on the safe side.
2037 */
2038 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
2039 if (RT_FAILURE(rc))
2040 {
2041 pImage->hMemLock = NIL_RTR0MEMOBJ;
2042 supdrvOSLdrUnload(pDevExt, pImage);
2043 }
2044 }
2045 else
2046 {
2047 supdrvOSLdrUnload(pDevExt, pImage);
2048 rc = VERR_LDR_MISMATCH_NATIVE;
2049 }
2050 }
2051 else
2052 {
2053 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
2054 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
2055 switch (rcNt)
2056 {
2057 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
2058# ifdef RT_ARCH_AMD64
2059 /* Unwind will crash and BSOD, so no fallback here! */
2060 rc = VERR_NOT_IMPLEMENTED;
2061# else
2062 /*
2063 * Use the old way of loading the modules.
2064 *
2065 * Note! We do *NOT* try class 26 because it will probably
2066 * not work correctly on terminal servers and such.
2067 */
2068 rc = VERR_NOT_SUPPORTED;
2069# endif
2070 break;
2071 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
2072 rc = VERR_MODULE_NOT_FOUND;
2073 break;
2074 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
2075 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
2076 break;
2077 case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
2078 rc = VERR_LDR_IMAGE_HASH;
2079 break;
2080 case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
2081 Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
2082 rc = VERR_ALREADY_LOADED;
2083 break;
2084 default:
2085 rc = VERR_LDR_GENERAL_FAILURE;
2086 break;
2087 }
2088
2089 pImage->pvNtSectionObj = NULL;
2090 }
2091 }
2092
2093 RTMemTmpFree(pwcsFilename);
2094 NOREF(pDevExt);
2095 return rc;
2096#endif
2097}
2098
2099
2100void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
2101{
2102 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
2103}
2104
2105
2106void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2107{
2108 NOREF(pDevExt); NOREF(pImage);
2109}
2110
2111
2112/**
2113 * Common worker for supdrvOSLdrQuerySymbol and supdrvOSLdrValidatePointer.
2114 *
2115 * @note Similar code in rtR0DbgKrnlNtParseModule.
2116 */
2117static int supdrvOSLdrValidatePointerOrQuerySymbol(PSUPDRVLDRIMAGE pImage, void *pv, const char *pszSymbol,
2118 size_t cchSymbol, void **ppvSymbol)
2119{
2120 AssertReturn(pImage->pvNtSectionObj, VERR_INVALID_STATE);
2121 Assert(pszSymbol || !ppvSymbol);
2122
2123 /*
2124 * Locate the export directory in the loaded image.
2125 */
2126 uint8_t const *pbMapping = (uint8_t const *)pImage->pvImage;
2127 uint32_t const cbMapping = pImage->cbImageBits;
2128 uint32_t const uRvaToValidate = (uint32_t)((uintptr_t)pv - (uintptr_t)pbMapping);
2129 AssertReturn(uRvaToValidate < cbMapping || ppvSymbol, VERR_INTERNAL_ERROR_3);
2130
2131 uint32_t const offNtHdrs = *(uint16_t *)pbMapping == IMAGE_DOS_SIGNATURE
2132 ? ((IMAGE_DOS_HEADER const *)pbMapping)->e_lfanew
2133 : 0;
2134 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < cbMapping, VERR_INTERNAL_ERROR_5);
2135
2136 IMAGE_NT_HEADERS const *pNtHdrs = (IMAGE_NT_HEADERS const *)((uintptr_t)pbMapping + offNtHdrs);
2137 AssertLogRelReturn(pNtHdrs->Signature == IMAGE_NT_SIGNATURE, VERR_INVALID_EXE_SIGNATURE);
2138 AssertLogRelReturn(pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC, VERR_BAD_EXE_FORMAT);
2139 AssertLogRelReturn(pNtHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES, VERR_BAD_EXE_FORMAT);
2140
2141 uint32_t const offEndSectHdrs = offNtHdrs
2142 + sizeof(*pNtHdrs)
2143 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
2144 AssertReturn(offEndSectHdrs < cbMapping, VERR_BAD_EXE_FORMAT);
2145
2146 /*
2147 * Find the export directory.
2148 */
2149 IMAGE_DATA_DIRECTORY ExpDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
2150 if (!ExpDir.Size)
2151 {
2152 SUPR0Printf("SUPDrv: No exports in %s!\n", pImage->szName);
2153 return ppvSymbol ? VERR_SYMBOL_NOT_FOUND : VERR_NOT_FOUND;
2154 }
2155 AssertReturn( ExpDir.Size >= sizeof(IMAGE_EXPORT_DIRECTORY)
2156 && ExpDir.VirtualAddress >= offEndSectHdrs
2157 && ExpDir.VirtualAddress < cbMapping
2158 && ExpDir.VirtualAddress + ExpDir.Size <= cbMapping, VERR_BAD_EXE_FORMAT);
2159
2160 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pbMapping[ExpDir.VirtualAddress];
2161
2162 uint32_t const cNamedExports = pExpDir->NumberOfNames;
2163 AssertReturn(cNamedExports < _1M, VERR_BAD_EXE_FORMAT);
2164 AssertReturn(pExpDir->NumberOfFunctions < _1M, VERR_BAD_EXE_FORMAT);
2165 if (pExpDir->NumberOfFunctions == 0 || cNamedExports == 0)
2166 {
2167 SUPR0Printf("SUPDrv: No exports in %s!\n", pImage->szName);
2168 return ppvSymbol ? VERR_SYMBOL_NOT_FOUND : VERR_NOT_FOUND;
2169 }
2170
2171 uint32_t const cExports = RT_MAX(cNamedExports, pExpDir->NumberOfFunctions);
2172
2173 AssertReturn( pExpDir->AddressOfFunctions >= offEndSectHdrs
2174 && pExpDir->AddressOfFunctions < cbMapping
2175 && pExpDir->AddressOfFunctions + cExports * sizeof(uint32_t) <= cbMapping,
2176 VERR_BAD_EXE_FORMAT);
2177 uint32_t const * const paoffExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfFunctions];
2178
2179 AssertReturn( pExpDir->AddressOfNames >= offEndSectHdrs
2180 && pExpDir->AddressOfNames < cbMapping
2181 && pExpDir->AddressOfNames + cNamedExports * sizeof(uint32_t) <= cbMapping,
2182 VERR_BAD_EXE_FORMAT);
2183 uint32_t const * const paoffNamedExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfNames];
2184
2185 AssertReturn( pExpDir->AddressOfNameOrdinals >= offEndSectHdrs
2186 && pExpDir->AddressOfNameOrdinals < cbMapping
2187 && pExpDir->AddressOfNameOrdinals + cNamedExports * sizeof(uint32_t) <= cbMapping,
2188 VERR_BAD_EXE_FORMAT);
2189 uint16_t const * const pau16NameOrdinals = (uint16_t const *)&pbMapping[pExpDir->AddressOfNameOrdinals];
2190
2191 /*
2192 * Validate the entrypoint RVA by scanning the export table.
2193 */
2194 uint32_t iExportOrdinal = UINT32_MAX;
2195 if (!ppvSymbol)
2196 {
2197 for (uint32_t i = 0; i < cExports; i++)
2198 if (paoffExports[i] == uRvaToValidate)
2199 {
2200 iExportOrdinal = i;
2201 break;
2202 }
2203 if (iExportOrdinal == UINT32_MAX)
2204 {
2205 SUPR0Printf("SUPDrv: No export with rva %#x (%s) in %s!\n", uRvaToValidate, pszSymbol, pImage->szName);
2206 return VERR_NOT_FOUND;
2207 }
2208 }
2209
2210 /*
2211 * Can we validate the symbol name too or should we find a name?
2212 * If so, just do a linear search.
2213 */
2214 if (pszSymbol && (RT_C_IS_UPPER(*pszSymbol) || ppvSymbol))
2215 {
2216 for (uint32_t i = 0; i < cNamedExports; i++)
2217 {
2218 uint32_t const offName = paoffNamedExports[i];
2219 AssertReturn(offName < cbMapping, VERR_BAD_EXE_FORMAT);
2220 uint32_t const cchMaxName = cbMapping - offName;
2221 const char * const pszName = (const char *)&pbMapping[offName];
2222 const char * const pszEnd = (const char *)memchr(pszName, '\0', cchMaxName);
2223 AssertReturn(pszEnd, VERR_BAD_EXE_FORMAT);
2224
2225 if ( cchSymbol == (size_t)(pszEnd - pszName)
2226 && memcmp(pszName, pszSymbol, cchSymbol) == 0)
2227 {
2228 if (ppvSymbol)
2229 {
2230 iExportOrdinal = pau16NameOrdinals[i];
2231 if ( iExportOrdinal < cExports
2232 && paoffExports[iExportOrdinal] < cbMapping)
2233 {
2234 *ppvSymbol = (void *)(paoffExports[iExportOrdinal] + pbMapping);
2235 return VINF_SUCCESS;
2236 }
2237 }
2238 else if (pau16NameOrdinals[i] == iExportOrdinal)
2239 return VINF_SUCCESS;
2240 else
2241 SUPR0Printf("SUPDrv: Different exports found for %s and rva %#x in %s: %#x vs %#x\n",
2242 pszSymbol, uRvaToValidate, pImage->szName, pau16NameOrdinals[i], iExportOrdinal);
2243 return VERR_LDR_BAD_FIXUP;
2244 }
2245 }
2246 if (!ppvSymbol)
2247 SUPR0Printf("SUPDrv: No export named %s (%#x) in %s!\n", pszSymbol, uRvaToValidate, pImage->szName);
2248 return VERR_SYMBOL_NOT_FOUND;
2249 }
2250 return VINF_SUCCESS;
2251}
2252
2253
2254int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
2255 const uint8_t *pbImageBits, const char *pszSymbol)
2256{
2257 RT_NOREF(pDevExt, pbImageBits);
2258 return supdrvOSLdrValidatePointerOrQuerySymbol(pImage, pv, pszSymbol, pszSymbol ? strlen(pszSymbol) : 0, NULL);
2259}
2260
2261
2262int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
2263 const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
2264{
2265 RT_NOREF(pDevExt);
2266 AssertReturn(ppvSymbol, VERR_INVALID_PARAMETER);
2267 AssertReturn(pszSymbol, VERR_INVALID_PARAMETER);
2268 return supdrvOSLdrValidatePointerOrQuerySymbol(pImage, NULL, pszSymbol, cchSymbol, ppvSymbol);
2269}
2270
2271
2272/**
2273 * memcmp + errormsg + log.
2274 *
2275 * @returns Same as memcmp.
2276 * @param pImage The image.
2277 * @param pbImageBits The image bits ring-3 uploads.
2278 * @param uRva The RVA to start comparing at.
2279 * @param cb The number of bytes to compare.
2280 * @param pReq The load request.
2281 */
2282static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb, PSUPLDRLOAD pReq)
2283{
2284 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
2285 if (iDiff)
2286 {
2287 uint32_t cbLeft = cb;
2288 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
2289 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
2290 if (pbNativeBits[off] != pbImageBits[off])
2291 {
2292 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
2293 otherwise risk overwriting them while formatting the error message. */
2294 uint8_t abBytes[64];
2295 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
2296 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
2297 "Mismatch at %#x (%p) of %s loaded at %p:\n"
2298 "ntld: %.*Rhxs\n"
2299 "iprt: %.*Rhxs",
2300 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
2301 RT_MIN(64, cbLeft), &pbNativeBits[off],
2302 RT_MIN(64, cbLeft), &abBytes[0]);
2303 SUPR0Printf("VBoxDrv: %s", pReq->u.Out.szError);
2304 break;
2305 }
2306 }
2307 return iDiff;
2308}
2309
2310/** Image compare exclusion regions. */
2311typedef struct SUPDRVNTEXCLREGIONS
2312{
2313 /** Number of regions. */
2314 uint32_t cRegions;
2315 /** The regions. */
2316 struct SUPDRVNTEXCLREGION
2317 {
2318 uint32_t uRva;
2319 uint32_t cb;
2320 } aRegions[16];
2321} SUPDRVNTEXCLREGIONS;
2322
2323/**
2324 * Adds an exclusion region to the collection.
2325 */
2326static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion)
2327{
2328 uint32_t const cRegions = pRegions->cRegions;
2329 AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false);
2330 uint32_t i = 0;
2331 for (; i < cRegions; i++)
2332 if (uRvaRegion < pRegions->aRegions[i].uRva)
2333 break;
2334 if (i != cRegions)
2335 memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0]));
2336 pRegions->aRegions[i].uRva = uRvaRegion;
2337 pRegions->aRegions[i].cb = cbRegion;
2338 pRegions->cRegions++;
2339 return true;
2340}
2341
2342
2343int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
2344{
2345 NOREF(pDevExt);
2346 if (pImage->pvNtSectionObj)
2347 {
2348 /*
2349 * Usually, the entire image matches exactly.
2350 */
2351 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
2352 return VINF_SUCCESS;
2353
2354 /*
2355 * On Windows 10 the ImageBase member of the optional header is sometimes
2356 * updated with the actual load address and sometimes not.
2357 */
2358 uint32_t const offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
2359 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
2360 : 0;
2361 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
2362 IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
2363 IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
2364
2365 uint32_t const offImageBase = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2366 uint32_t const cbImageBase = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2367 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2368 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2369 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage)
2370 && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2371 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2372 && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
2373 && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
2374 pbImageBits + offImageBase + cbImageBase,
2375 pImage->cbImageBits - offImageBase - cbImageBase))
2376 return VINF_SUCCESS;
2377
2378 /*
2379 * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
2380 * up and we typically get a mismatch in the INIT section.
2381 *
2382 * So, lets see if everything matches when excluding the
2383 * OriginalFirstThunk tables and (maybe) the ImageBase member.
2384 * For simplicity the max number of exclusion regions is set to 16.
2385 */
2386 if ( pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2387 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2388 && pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
2389 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
2390 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2391 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
2392 )
2393 {
2394 SUPDRVNTEXCLREGIONS ExcludeRegions;
2395 ExcludeRegions.cRegions = 0;
2396
2397 /* ImageBase: */
2398 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2399 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2400 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
2401 supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase);
2402
2403 /* Imports: */
2404 uint32_t cImpsLeft = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
2405 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
2406 uint32_t offImps = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2407 AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
2408 IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
2409 while ( cImpsLeft-- > 0
2410 && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions))
2411 {
2412 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
2413 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2414 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
2415 && uRvaThunk != pImp->FirstThunk)
2416 {
2417 /* Find the size of the thunk table. */
2418 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2419 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2420 uint32_t cThunks = 0;
2421 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2422 cThunks++;
2423 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2424 }
2425
2426#if 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrvLdr.cpp. */
2427 /* Exclude the other thunk table if ntoskrnl.exe. */
2428 uint32_t uRvaName = pImp->Name;
2429 if ( uRvaName > sizeof(IMAGE_NT_HEADERS)
2430 && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe")
2431 && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0)
2432 {
2433 uRvaThunk = pImp->FirstThunk;
2434 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2435 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA))
2436 {
2437 /* Find the size of the thunk table. */
2438 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2439 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2440 uint32_t cThunks = 0;
2441 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2442 cThunks++;
2443 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2444 }
2445 }
2446#endif
2447
2448 /* advance */
2449 pImp++;
2450 }
2451
2452 /*
2453 * Ok, do the comparison.
2454 */
2455 int iDiff = 0;
2456 uint32_t uRvaNext = 0;
2457 for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
2458 {
2459 if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
2460 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
2461 uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
2462 }
2463 if (!iDiff && uRvaNext < pImage->cbImageBits)
2464 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2465 if (!iDiff)
2466 return VINF_SUCCESS;
2467 }
2468 else
2469 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2470 return VERR_LDR_MISMATCH_NATIVE;
2471 }
2472 return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2473}
2474
2475
2476void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2477{
2478 if (pImage->pvNtSectionObj)
2479 {
2480 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2481 {
2482 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2483 pImage->hMemLock = NIL_RTR0MEMOBJ;
2484 }
2485
2486 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2487 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2488 if (rcNt != STATUS_SUCCESS)
2489 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2490 pImage->pvNtSectionObj = NULL;
2491 }
2492 NOREF(pDevExt);
2493}
2494
2495
2496#ifdef SUPDRV_WITH_MSR_PROBER
2497
2498#if 1
2499/** @todo make this selectable. */
2500# define AMD_MSR_PASSCODE 0x9c5a203a
2501#else
2502# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2503# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2504#endif
2505
2506
2507/**
2508 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2509 */
2510typedef struct SUPDRVNTMSPROBERARGS
2511{
2512 uint32_t uMsr;
2513 uint64_t uValue;
2514 bool fGp;
2515} SUPDRVNTMSPROBERARGS;
2516
2517/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2518static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2519{
2520 /*
2521 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2522 * (At least on 32-bit XP.)
2523 */
2524 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2525 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2526 __try
2527 {
2528 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2529 pArgs->fGp = false;
2530 }
2531 __except(EXCEPTION_EXECUTE_HANDLER)
2532 {
2533 pArgs->fGp = true;
2534 pArgs->uValue = 0;
2535 }
2536 ASMSetFlags(fOldFlags);
2537}
2538
2539
2540int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2541{
2542 SUPDRVNTMSPROBERARGS Args;
2543 Args.uMsr = uMsr;
2544 Args.uValue = 0;
2545 Args.fGp = true;
2546
2547 if (idCpu == NIL_RTCPUID)
2548 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2549 else
2550 {
2551 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2552 if (RT_FAILURE(rc))
2553 return rc;
2554 }
2555
2556 if (Args.fGp)
2557 return VERR_ACCESS_DENIED;
2558 *puValue = Args.uValue;
2559 return VINF_SUCCESS;
2560}
2561
2562
2563/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2564static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2565{
2566 /*
2567 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2568 * (At least on 32-bit XP.)
2569 */
2570 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2571 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2572 __try
2573 {
2574 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2575 pArgs->fGp = false;
2576 }
2577 __except(EXCEPTION_EXECUTE_HANDLER)
2578 {
2579 pArgs->fGp = true;
2580 }
2581 ASMSetFlags(fOldFlags);
2582}
2583
2584int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2585{
2586 SUPDRVNTMSPROBERARGS Args;
2587 Args.uMsr = uMsr;
2588 Args.uValue = uValue;
2589 Args.fGp = true;
2590
2591 if (idCpu == NIL_RTCPUID)
2592 supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2593 else
2594 {
2595 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2596 if (RT_FAILURE(rc))
2597 return rc;
2598 }
2599
2600 if (Args.fGp)
2601 return VERR_ACCESS_DENIED;
2602 return VINF_SUCCESS;
2603}
2604
2605/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2606static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2607{
2608 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
2609 register uint32_t uMsr = pReq->u.In.uMsr;
2610 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2611 uint64_t uBefore = 0;
2612 uint64_t uWritten = 0;
2613 uint64_t uAfter = 0;
2614 bool fBeforeGp = true;
2615 bool fModifyGp = true;
2616 bool fAfterGp = true;
2617 bool fRestoreGp = true;
2618 RTCCUINTREG fOldFlags;
2619 RT_NOREF2(idCpu, pvUser2);
2620
2621 /*
2622 * Do the job.
2623 */
2624 fOldFlags = ASMIntDisableFlags();
2625 ASMCompilerBarrier(); /* paranoia */
2626 if (!fFaster)
2627 ASMWriteBackAndInvalidateCaches();
2628
2629 __try
2630 {
2631 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2632 fBeforeGp = false;
2633 }
2634 __except(EXCEPTION_EXECUTE_HANDLER)
2635 {
2636 fBeforeGp = true;
2637 }
2638 if (!fBeforeGp)
2639 {
2640 register uint64_t uRestore = uBefore;
2641
2642 /* Modify. */
2643 uWritten = uRestore;
2644 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2645 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2646 __try
2647 {
2648 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2649 fModifyGp = false;
2650 }
2651 __except(EXCEPTION_EXECUTE_HANDLER)
2652 {
2653 fModifyGp = true;
2654 }
2655
2656 /* Read modified value. */
2657 __try
2658 {
2659 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2660 fAfterGp = false;
2661 }
2662 __except(EXCEPTION_EXECUTE_HANDLER)
2663 {
2664 fAfterGp = true;
2665 }
2666
2667 /* Restore original value. */
2668 __try
2669 {
2670 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2671 fRestoreGp = false;
2672 }
2673 __except(EXCEPTION_EXECUTE_HANDLER)
2674 {
2675 fRestoreGp = true;
2676 }
2677
2678 /* Invalid everything we can. */
2679 if (!fFaster)
2680 {
2681 ASMWriteBackAndInvalidateCaches();
2682 ASMReloadCR3();
2683 ASMNopPause();
2684 }
2685 }
2686
2687 ASMCompilerBarrier(); /* paranoia */
2688 ASMSetFlags(fOldFlags);
2689
2690 /*
2691 * Write out the results.
2692 */
2693 pReq->u.Out.uResults.Modify.uBefore = uBefore;
2694 pReq->u.Out.uResults.Modify.uWritten = uWritten;
2695 pReq->u.Out.uResults.Modify.uAfter = uAfter;
2696 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
2697 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
2698 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
2699 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2700 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2701}
2702
2703
2704int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2705{
2706 if (idCpu == NIL_RTCPUID)
2707 {
2708 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2709 return VINF_SUCCESS;
2710 }
2711 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
2712}
2713
2714#endif /* SUPDRV_WITH_MSR_PROBER */
2715
2716
2717/**
2718 * Converts an IPRT error code to an nt status code.
2719 *
2720 * @returns corresponding nt status code.
2721 * @param rc IPRT error status code.
2722 */
2723static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
2724{
2725 switch (rc)
2726 {
2727 case VINF_SUCCESS: return STATUS_SUCCESS;
2728 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
2729 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
2730 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
2731 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
2732 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
2733 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
2734 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
2735 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
2736 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
2737 }
2738
2739 if (rc < 0)
2740 {
2741 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2742 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2743 }
2744 return STATUS_UNSUCCESSFUL;
2745}
2746
2747
2748/**
2749 * Alternative version of SUPR0Printf for Windows.
2750 *
2751 * @returns 0.
2752 * @param pszFormat The format string.
2753 */
2754SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2755{
2756 va_list va;
2757 char szMsg[384];
2758
2759 va_start(va, pszFormat);
2760 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2761 szMsg[sizeof(szMsg) - 1] = '\0';
2762 va_end(va);
2763
2764 RTLogWriteDebugger(szMsg, cch);
2765 return 0;
2766}
2767
2768
2769SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2770{
2771 return 0;
2772}
2773
2774
2775SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
2776{
2777 /*
2778 * Validate input.
2779 */
2780 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
2781 *ppCtx = NULL;
2782 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2783 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2784
2785 /*
2786 * Turn the partition handle into a file object and related device object
2787 * so that we can issue direct I/O control calls to the pair later.
2788 */
2789 PFILE_OBJECT pFileObject = NULL;
2790 OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
2791 NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
2792 UserMode, (void **)&pFileObject, &HandleInfo);
2793 if (!NT_SUCCESS(rcNt))
2794 return RTErrConvertFromNtStatus(rcNt);
2795 AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
2796
2797 PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
2798 AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
2799 ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
2800
2801 /*
2802 * Allocate a context structure and fill it in.
2803 */
2804 PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
2805 if (pCtx)
2806 {
2807 pCtx->u32Magic = SUPR0IOCTLCTX_MAGIC;
2808 pCtx->cRefs = 1;
2809 pCtx->pFileObject = pFileObject;
2810 pCtx->pDeviceObject = pDevObject;
2811
2812 PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
2813 if ( RT_VALID_PTR(pDrvObject->FastIoDispatch)
2814 && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
2815 pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
2816 else
2817 pCtx->pfnFastIoDeviceControl = NULL;
2818 *ppCtx = pCtx;
2819 return VINF_SUCCESS;
2820 }
2821
2822 ObDereferenceObject(pFileObject);
2823 return VERR_NO_MEMORY;
2824}
2825
2826
2827/**
2828 * I/O control destructor for NT.
2829 *
2830 * @param pCtx The context to destroy.
2831 */
2832static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
2833{
2834 PFILE_OBJECT pFileObject = pCtx->pFileObject;
2835 pCtx->pfnFastIoDeviceControl = NULL;
2836 pCtx->pFileObject = NULL;
2837 pCtx->pDeviceObject = NULL;
2838 ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
2839
2840 if (RT_VALID_PTR(pFileObject))
2841 ObDereferenceObject(pFileObject);
2842 RTMemFree(pCtx);
2843}
2844
2845
2846SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
2847{
2848 if (pCtx != NULL)
2849 {
2850 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2851 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
2852
2853 uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2854 Assert(cRefs < _4K);
2855 if (cRefs == 0)
2856 supdrvNtIoCtlContextDestroy(pCtx);
2857 }
2858 return VINF_SUCCESS;
2859}
2860
2861
2862SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
2863 void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
2864 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
2865 int32_t *piNativeRc)
2866{
2867 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2868 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
2869
2870 /* Reference the context. */
2871 uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
2872 Assert(cRefs > 1 && cRefs < _4K);
2873
2874 /*
2875 * Try fast I/O control path first.
2876 */
2877 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
2878 if (pCtx->pfnFastIoDeviceControl)
2879 {
2880 /* Must pass user addresses here as that's what's being expected. */
2881 BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
2882 TRUE /*Wait*/,
2883 (void *)pvInputUser, (ULONG)cbInput,
2884 (void *)pvOutputUser, (ULONG)cbOutput,
2885 uFunction,
2886 &Ios,
2887 pCtx->pDeviceObject);
2888 if (fHandled)
2889 {
2890 /* Relase the context. */
2891 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2892 Assert(cRefs < _4K);
2893 if (cRefs == 0)
2894 supdrvNtIoCtlContextDestroy(pCtx);
2895
2896 /* Set/convert status and return. */
2897 if (piNativeRc)
2898 {
2899 *piNativeRc = Ios.Status;
2900 return VINF_SUCCESS;
2901 }
2902 if (NT_SUCCESS(Ios.Status))
2903 return VINF_SUCCESS;
2904 return RTErrConvertFromNtStatus(Ios.Status);
2905 }
2906
2907 /*
2908 * Fall back on IRP if not handled.
2909 *
2910 * Note! Perhaps we should rather fail, because VID.SYS will crash getting
2911 * the partition ID with the code below. It tries to zero the output
2912 * buffer as if it were as system buffer...
2913 */
2914 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
2915 }
2916
2917 /*
2918 * For directly accessed buffers we must supply user mode addresses or
2919 * we'll fail ProbeForWrite validation.
2920 */
2921 switch (uFunction & 3)
2922 {
2923 case METHOD_BUFFERED:
2924 /* For buffered accesses, we can supply kernel buffers. */
2925 break;
2926
2927 case METHOD_IN_DIRECT:
2928 pvInput = (void *)pvInputUser;
2929 break;
2930
2931 case METHOD_NEITHER:
2932 pvInput = (void *)pvInputUser;
2933 RT_FALL_THRU();
2934
2935 case METHOD_OUT_DIRECT:
2936 pvOutput = (void *)pvOutputUser;
2937 break;
2938 }
2939
2940 /*
2941 * Build the request.
2942 */
2943 int rc;
2944 KEVENT Event;
2945 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2946
2947 PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
2948 pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
2949 FALSE /* InternalDeviceControl */, &Event, &Ios);
2950 if (pIrp)
2951 {
2952 IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
2953
2954 /*
2955 * Make the call.
2956 */
2957 NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
2958 if (rcNt == STATUS_PENDING)
2959 {
2960 rcNt = KeWaitForSingleObject(&Event, /* Object */
2961 Executive, /* WaitReason */
2962 KernelMode, /* WaitMode */
2963 FALSE, /* Alertable */
2964 NULL); /* TimeOut */
2965 AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
2966 rcNt = Ios.Status;
2967 }
2968 else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
2969 rcNt = Ios.Status;
2970
2971 /* Set/convert return code. */
2972 if (piNativeRc)
2973 {
2974 *piNativeRc = rcNt;
2975 rc = VINF_SUCCESS;
2976 }
2977 else if (NT_SUCCESS(rcNt))
2978 rc = VINF_SUCCESS;
2979 else
2980 rc = RTErrConvertFromNtStatus(rcNt);
2981 }
2982 else
2983 {
2984 if (piNativeRc)
2985 *piNativeRc = STATUS_NO_MEMORY;
2986 rc = VERR_NO_MEMORY;
2987 }
2988
2989 /* Relase the context. */
2990 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2991 Assert(cRefs < _4K);
2992 if (cRefs == 0)
2993 supdrvNtIoCtlContextDestroy(pCtx);
2994
2995 return rc;
2996}
2997
2998
2999#ifdef VBOX_WITH_HARDENING
3000
3001/** @name Identifying Special Processes: CSRSS.EXE
3002 * @{ */
3003
3004
3005/**
3006 * Checks if the process is a system32 process by the given name.
3007 *
3008 * @returns true / false.
3009 * @param pProcess The process to check.
3010 * @param pszName The lower case process name (no path!).
3011 */
3012static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
3013{
3014 Assert(strlen(pszName) < 16); /* see buffer below */
3015
3016 /*
3017 * This test works on XP+.
3018 */
3019 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3020 if (!pszImageFile)
3021 return false;
3022
3023 if (RTStrICmp(pszImageFile, pszName) != 0)
3024 return false;
3025
3026 /*
3027 * This test requires a Vista+ API.
3028 */
3029 if (g_pfnPsReferenceProcessFilePointer)
3030 {
3031 PFILE_OBJECT pFile = NULL;
3032 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
3033 if (!NT_SUCCESS(rcNt))
3034 return false;
3035
3036 union
3037 {
3038 OBJECT_NAME_INFORMATION Info;
3039 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
3040 } Buf;
3041 ULONG cbIgn;
3042 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
3043 ObDereferenceObject(pFile);
3044 if (!NT_SUCCESS(rcNt))
3045 return false;
3046
3047 /* Terminate the name. */
3048 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
3049 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
3050
3051 /* Match the name against the system32 directory path. */
3052 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
3053 if (Buf.Info.Name.Length < cbSystem32)
3054 return false;
3055 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
3056 return false;
3057 pwszName += cbSystem32 / sizeof(RTUTF16);
3058 if (*pwszName++ != '\\')
3059 return false;
3060
3061 /* Compare the name. */
3062 const char *pszRight = pszName;
3063 for (;;)
3064 {
3065 WCHAR wchLeft = *pwszName++;
3066 char chRight = *pszRight++;
3067 Assert(chRight == RT_C_TO_LOWER(chRight));
3068
3069 if ( wchLeft != chRight
3070 && RT_C_TO_LOWER(wchLeft) != chRight)
3071 return false;
3072 if (!chRight)
3073 break;
3074 }
3075 }
3076
3077 return true;
3078}
3079
3080
3081/**
3082 * Checks if the current process is likely to be CSRSS.
3083 *
3084 * @returns true/false.
3085 * @param pProcess The process.
3086 */
3087static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
3088{
3089 /*
3090 * On Windows 8.1 CSRSS.EXE is a protected process.
3091 */
3092 if (g_pfnPsIsProtectedProcessLight)
3093 {
3094 if (!g_pfnPsIsProtectedProcessLight(pProcess))
3095 return false;
3096 }
3097
3098 /*
3099 * The name tests.
3100 */
3101 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
3102 return false;
3103
3104 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
3105 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
3106
3107 return true;
3108}
3109
3110
3111/**
3112 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
3113 *
3114 * @returns true if done, false if not.
3115 * @param pwszPortNm The port path.
3116 * @param ppObjType The object type return variable, updated when
3117 * returning true.
3118 */
3119static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
3120{
3121 bool fDone = false;
3122
3123 UNICODE_STRING UniStrPortNm;
3124 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
3125 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
3126 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
3127
3128 OBJECT_ATTRIBUTES ObjAttr;
3129 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
3130
3131 HANDLE hPort;
3132 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
3133 if (NT_SUCCESS(rcNt))
3134 {
3135 PVOID pvObject;
3136 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
3137 KernelMode, &pvObject, NULL /*pHandleInfo*/);
3138 if (NT_SUCCESS(rcNt))
3139 {
3140 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
3141 if (pObjType)
3142 {
3143 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
3144 *ppObjType = pObjType;
3145 fDone = true;
3146 }
3147 ObDereferenceObject(pvObject);
3148 }
3149 NtClose(hPort);
3150 }
3151 return fDone;
3152}
3153
3154
3155/**
3156 * Attempts to retrieve the ALPC Port object type.
3157 *
3158 * We've had at least three reports that using LpcPortObjectType when trying to
3159 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
3160 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
3161 * exported) so that it differs from the actual ApiPort type, or maybe this
3162 * unknown entity is intercepting our attempt to reference the port and
3163 * tries to mislead us. The paranoid explanataion is of course that some evil
3164 * root kit like software is messing with the OS, however, it's possible that
3165 * this is valid kernel behavior that 99.8% of our users and 100% of the
3166 * developers are not triggering for some reason.
3167 *
3168 * The code here creates an ALPC port object and gets it's type. It will cache
3169 * the result in g_pAlpcPortObjectType2 on success.
3170 *
3171 * @returns Object type.
3172 * @param uSessionId The session id.
3173 * @param pszSessionId The session id formatted as a string.
3174 */
3175static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
3176{
3177 POBJECT_TYPE pObjType = *LpcPortObjectType;
3178
3179 if ( g_pfnZwAlpcCreatePort
3180 && g_pfnObGetObjectType)
3181 {
3182 int rc;
3183 ssize_t cchTmp; NOREF(cchTmp);
3184 char szTmp[16];
3185 RTUTF16 wszPortNm[128];
3186 size_t offRand;
3187
3188 /*
3189 * First attempt is in the session directory.
3190 */
3191 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3192 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3193 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
3194 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3195 Assert(cchTmp > 0);
3196 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3197 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3198 offRand = RTUtf16Len(wszPortNm);
3199 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3200 Assert(cchTmp > 0);
3201 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3202 AssertRCSuccess(rc);
3203
3204 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3205 if (!fDone)
3206 {
3207 wszPortNm[offRand] = '\0';
3208 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
3209 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3210 AssertRCSuccess(rc);
3211
3212 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3213 }
3214 if (!fDone)
3215 {
3216 /*
3217 * Try base names.
3218 */
3219 if (uSessionId == 0)
3220 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3221 else
3222 {
3223 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3224 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3225 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3226 }
3227 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3228 Assert(cchTmp > 0);
3229 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3230 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3231 offRand = RTUtf16Len(wszPortNm);
3232 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3233 Assert(cchTmp > 0);
3234 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3235 AssertRCSuccess(rc);
3236
3237 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3238 if (!fDone)
3239 {
3240 wszPortNm[offRand] = '\0';
3241 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3242 Assert(cchTmp > 0);
3243 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3244 AssertRCSuccess(rc);
3245
3246 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3247 }
3248 }
3249
3250 /* Cache the result in g_pAlpcPortObjectType2. */
3251 if ( g_pAlpcPortObjectType2 == NULL
3252 && pObjType != g_pAlpcPortObjectType1
3253 && fDone)
3254 g_pAlpcPortObjectType2 = pObjType;
3255
3256 }
3257
3258 return pObjType;
3259}
3260
3261
3262/**
3263 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
3264 * current process.
3265 *
3266 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
3267 * additional access right so we need to make 101% sure we correctly identify
3268 * the CSRSS process a process is associated with.
3269 *
3270 * @returns IPRT status code.
3271 * @param pNtProtect The NT protected process structure. The
3272 * hCsrssPid member will be updated on success.
3273 */
3274static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
3275{
3276 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
3277 Assert(pNtProtect->pCsrssProcess == NULL);
3278 Assert(pNtProtect->hCsrssPid == NULL);
3279
3280 /*
3281 * We'll try use the ApiPort LPC object for the session we're in to track
3282 * down the CSRSS process. So, we start by constructing a path to it.
3283 */
3284 int rc;
3285 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
3286 char szSessionId[16];
3287 WCHAR wszApiPort[48];
3288 if (uSessionId == 0)
3289 {
3290 szSessionId[0] = '0';
3291 szSessionId[1] = '\0';
3292 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3293 }
3294 else
3295 {
3296 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
3297 AssertReturn(cchTmp > 0, (int)cchTmp);
3298 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
3299 if (RT_SUCCESS(rc))
3300 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
3301 if (RT_SUCCESS(rc))
3302 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3303 }
3304 AssertRCReturn(rc, rc);
3305
3306 UNICODE_STRING ApiPortStr;
3307 ApiPortStr.Buffer = wszApiPort;
3308 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
3309 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
3310
3311 /*
3312 * The object cannot be opened, but we can reference it by name.
3313 */
3314 void *pvApiPortObj = NULL;
3315 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
3316 0,
3317 NULL /*pAccessState*/,
3318 STANDARD_RIGHTS_READ,
3319 g_pAlpcPortObjectType1,
3320 KernelMode,
3321 NULL /*pvParseContext*/,
3322 &pvApiPortObj);
3323 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3324 && g_pAlpcPortObjectType2 != NULL)
3325 rcNt = ObReferenceObjectByName(&ApiPortStr,
3326 0,
3327 NULL /*pAccessState*/,
3328 STANDARD_RIGHTS_READ,
3329 g_pAlpcPortObjectType2,
3330 KernelMode,
3331 NULL /*pvParseContext*/,
3332 &pvApiPortObj);
3333 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3334 && g_pfnObGetObjectType
3335 && g_pfnZwAlpcCreatePort)
3336 rcNt = ObReferenceObjectByName(&ApiPortStr,
3337 0,
3338 NULL /*pAccessState*/,
3339 STANDARD_RIGHTS_READ,
3340 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
3341 KernelMode,
3342 NULL /*pvParseContext*/,
3343 &pvApiPortObj);
3344 if (!NT_SUCCESS(rcNt))
3345 {
3346 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
3347 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
3348 }
3349
3350 /*
3351 * Query the processes in the system so we can locate CSRSS.EXE candidates.
3352 * Note! Attempts at using SystemSessionProcessInformation failed with
3353 * STATUS_ACCESS_VIOLATION.
3354 * Note! The 32 bytes on the size of to counteract the allocation header
3355 * that rtR0MemAllocEx slaps on everything.
3356 */
3357 ULONG cbNeeded = _64K - 32;
3358 uint32_t cbBuf;
3359 uint8_t *pbBuf = NULL;
3360 do
3361 {
3362 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
3363 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3364 if (!pbBuf)
3365 break;
3366
3367 cbNeeded = 0;
3368#if 0 /* doesn't work. */
3369 SYSTEM_SESSION_PROCESS_INFORMATION Req;
3370 Req.SessionId = uSessionId;
3371 Req.BufferLength = cbBuf;
3372 Req.Buffer = pbBuf;
3373 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
3374#else
3375 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
3376#endif
3377 if (NT_SUCCESS(rcNt))
3378 break;
3379
3380 RTMemFree(pbBuf);
3381 pbBuf = NULL;
3382 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3383 && cbNeeded > cbBuf
3384 && cbNeeded < 32U*_1M);
3385
3386 if ( pbBuf
3387 && NT_SUCCESS(rcNt)
3388 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
3389 {
3390 /*
3391 * Walk the returned data and look for the process associated with the
3392 * ApiPort object. The ApiPort object keeps the EPROCESS address of
3393 * the owner process (i.e. CSRSS) relatively early in the structure. On
3394 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
3395 * pointer to likely CSRSS processes and check for a match in the first
3396 * 0x40 bytes of the ApiPort object.
3397 */
3398 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
3399 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
3400 {
3401 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
3402 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
3403 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
3404 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
3405 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
3406 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
3407 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
3408 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
3409 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
3410 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
3411 && pProcInfo->ProcessName.Buffer[5] == '.'
3412 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
3413 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
3414 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
3415 {
3416
3417 /* Get the process structure and perform some more thorough
3418 process checks. */
3419 PEPROCESS pProcess;
3420 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
3421 if (NT_SUCCESS(rcNt))
3422 {
3423 if (supdrvNtProtectIsCsrssByProcess(pProcess))
3424 {
3425 if (PsGetProcessSessionId(pProcess) == uSessionId)
3426 {
3427 /* Final test, check the ApiPort.
3428 Note! The old LPC (pre Vista) objects has the PID
3429 much earlier in the structure. Might be
3430 worth looking for it instead. */
3431 bool fThatsIt = false;
3432 __try
3433 {
3434 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
3435 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
3436 do
3437 {
3438 fThatsIt = *ppPortProc == pProcess;
3439 ppPortProc++;
3440 } while (!fThatsIt && --cTests > 0);
3441 }
3442 __except(EXCEPTION_EXECUTE_HANDLER)
3443 {
3444 fThatsIt = false;
3445 }
3446 if (fThatsIt)
3447 {
3448 /* Ok, we found it! Keep the process structure
3449 reference as well as the PID so we can
3450 safely identify it later on. */
3451 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
3452 pNtProtect->pCsrssProcess = pProcess;
3453 rc = VINF_SUCCESS;
3454 break;
3455 }
3456 }
3457 }
3458
3459 ObDereferenceObject(pProcess);
3460 }
3461 }
3462
3463 /* Advance. */
3464 if (!pProcInfo->NextEntryOffset)
3465 break;
3466 offBuf += pProcInfo->NextEntryOffset;
3467 }
3468 }
3469 else
3470 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
3471 RTMemFree(pbBuf);
3472 ObDereferenceObject(pvApiPortObj);
3473 return rc;
3474}
3475
3476
3477/**
3478 * Checks that the given process is the CSRSS process associated with protected
3479 * process.
3480 *
3481 * @returns true / false.
3482 * @param pNtProtect The NT protection structure.
3483 * @param pCsrss The process structure of the alleged CSRSS.EXE
3484 * process.
3485 */
3486static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
3487{
3488 if (pNtProtect->pCsrssProcess == pCsrss)
3489 {
3490 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
3491 {
3492 return true;
3493 }
3494 }
3495 return false;
3496}
3497
3498
3499/**
3500 * Checks if the given process is the stupid themes service.
3501 *
3502 * The caller does some screening of access masks and what not. We do the rest.
3503 *
3504 * @returns true / false.
3505 * @param pNtProtect The NT protection structure.
3506 * @param pAnnoyingProcess The process structure of an process that might
3507 * happen to be the annoying themes process.
3508 */
3509static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3510{
3511 RT_NOREF1(pNtProtect);
3512
3513 /*
3514 * Check the process name.
3515 */
3516 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3517 return false;
3518
3519 /** @todo Come up with more checks. */
3520
3521 return true;
3522}
3523
3524
3525#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3526/**
3527 * Checks if the given process is one of the whitelisted debuggers.
3528 *
3529 * @returns true / false.
3530 * @param pProcess The process to check.
3531 */
3532static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3533{
3534 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3535 if (!pszImageFile)
3536 return false;
3537
3538 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3539 {
3540 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3541 return true;
3542 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3543 return true;
3544 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3545 return true;
3546 }
3547 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3548 {
3549 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3550 return true;
3551 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3552 return true;
3553 }
3554
3555 return false;
3556}
3557#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3558
3559
3560/** @} */
3561
3562
3563/** @name Process Creation Callbacks.
3564 * @{ */
3565
3566
3567/**
3568 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3569 *
3570 * @param hProcessId The ID of the dead process.
3571 */
3572static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3573{
3574 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3575 if (RT_SUCCESS(rc))
3576 {
3577 PSUPDRVNTERRORINFO pCur, pNext;
3578 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3579 {
3580 if (pCur->hProcessId == hProcessId)
3581 {
3582 RTListNodeRemove(&pCur->ListEntry);
3583 RTMemFree(pCur);
3584 }
3585 }
3586 RTSemMutexRelease(g_hErrorInfoLock);
3587 }
3588}
3589
3590
3591/**
3592 * Common worker used by the process creation hooks as well as the process
3593 * handle creation hooks to check if a VM process is being created.
3594 *
3595 * @returns true if likely to be a VM process, false if not.
3596 * @param pNtStub The NT protection structure for the possible
3597 * stub process.
3598 * @param hParentPid The parent pid.
3599 * @param hChildPid The child pid.
3600 */
3601static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3602{
3603 bool fRc = false;
3604 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3605 {
3606 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3607 {
3608 /* Compare short names. */
3609 PEPROCESS pStubProcess;
3610 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3611 if (NT_SUCCESS(rcNt))
3612 {
3613 PEPROCESS pChildProcess;
3614 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3615 if (NT_SUCCESS(rcNt))
3616 {
3617 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
3618 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3619 fRc = pszStub != NULL
3620 && pszChild != NULL
3621 && strcmp(pszStub, pszChild) == 0;
3622
3623 /** @todo check that the full image names matches. */
3624
3625 ObDereferenceObject(pChildProcess);
3626 }
3627 ObDereferenceObject(pStubProcess);
3628 }
3629 }
3630 }
3631 return fRc;
3632}
3633
3634
3635/**
3636 * Common code used by the notifies to protect a child process.
3637 *
3638 * @returns VBox status code.
3639 * @param pNtStub The NT protect structure for the parent.
3640 * @param hChildPid The child pid.
3641 */
3642static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3643{
3644 /*
3645 * Create a child protection struction.
3646 */
3647 PSUPDRVNTPROTECT pNtChild;
3648 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3649 if (RT_SUCCESS(rc))
3650 {
3651 pNtChild->fFirstProcessCreateHandle = true;
3652 pNtChild->fFirstThreadCreateHandle = true;
3653 pNtChild->fCsrssFirstProcessCreateHandle = true;
3654 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3655 pNtChild->fThemesFirstProcessCreateHandle = true;
3656 pNtChild->hParentPid = pNtParent->AvlCore.Key;
3657 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3658 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3659 if (pNtChild->pCsrssProcess)
3660 ObReferenceObject(pNtChild->pCsrssProcess);
3661
3662 /*
3663 * Take the spinlock, recheck parent conditions and link things.
3664 */
3665 RTSpinlockAcquire(g_hNtProtectLock);
3666 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3667 {
3668 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3669 if (fSuccess)
3670 {
3671 pNtChild->fInTree = true;
3672 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
3673 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3674 pNtChild->u.pParent = pNtParent;
3675
3676 RTSpinlockRelease(g_hNtProtectLock);
3677 return VINF_SUCCESS;
3678 }
3679
3680 rc = VERR_INTERNAL_ERROR_2;
3681 }
3682 else
3683 rc = VERR_WRONG_ORDER;
3684 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3685 RTSpinlockRelease(g_hNtProtectLock);
3686
3687 supdrvNtProtectRelease(pNtChild);
3688 }
3689 return rc;
3690}
3691
3692
3693/**
3694 * Common process termination code.
3695 *
3696 * Transitions protected process to the dead states, protecting against handle
3697 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3698 *
3699 * @param hDeadPid The PID of the dead process.
3700 */
3701static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3702{
3703 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3704 if (pNtProtect)
3705 {
3706 PSUPDRVNTPROTECT pNtChild = NULL;
3707
3708 RTSpinlockAcquire(g_hNtProtectLock);
3709
3710 /*
3711 * If this is an unconfirmed VM process, we must release the reference
3712 * the parent structure holds.
3713 */
3714 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3715 {
3716 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
3717 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
3718 pNtParent->u.pChild = NULL;
3719 pNtProtect->u.pParent = NULL;
3720 pNtChild = pNtProtect;
3721 }
3722 /*
3723 * If this is a stub exitting before the VM process gets confirmed,
3724 * release the protection of the potential VM process as this is not
3725 * the prescribed behavior.
3726 */
3727 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3728 && pNtProtect->u.pChild)
3729 {
3730 pNtChild = pNtProtect->u.pChild;
3731 pNtProtect->u.pChild = NULL;
3732 pNtChild->u.pParent = NULL;
3733 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3734 }
3735
3736 /*
3737 * Transition it to the dead state to prevent it from opening the
3738 * support driver again or be posthumously abused as a vm process parent.
3739 */
3740 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3741 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
3742 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3743 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3744 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
3745 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3746 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
3747
3748 RTSpinlockRelease(g_hNtProtectLock);
3749
3750 supdrvNtProtectRelease(pNtProtect);
3751 supdrvNtProtectRelease(pNtChild);
3752
3753 /*
3754 * Do session cleanups.
3755 */
3756 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3757 if (g_pDevObjSys)
3758 {
3759 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3760 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3761 RTR0ProcHandleSelf(), NULL);
3762 if (pSession)
3763 {
3764 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3765 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3766 }
3767 }
3768 }
3769}
3770
3771
3772/**
3773 * Common worker for the process creation callback that verifies a new child
3774 * being created by the handle creation callback code.
3775 *
3776 * @param pNtStub The parent.
3777 * @param pNtVm The child.
3778 * @param fCallerChecks The result of any additional tests the caller made.
3779 * This is in order to avoid duplicating the failure
3780 * path code.
3781 */
3782static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3783{
3784 if ( fCallerChecks
3785 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3786 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3787 && pNtVm->u.pParent == pNtStub
3788 && pNtStub->u.pChild == pNtVm)
3789 {
3790 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3791 pNtVm->fFirstProcessCreateHandle = true;
3792 return;
3793 }
3794
3795 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3796 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3797 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3798}
3799
3800
3801/**
3802 * Old style callback (since forever).
3803 *
3804 * @param hParentPid The parent PID.
3805 * @param hNewPid The PID of the new child.
3806 * @param fCreated TRUE if it's a creation notification,
3807 * FALSE if termination.
3808 * @remarks ASSUMES this arrives before the handle creation callback.
3809 */
3810static VOID __stdcall
3811supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3812{
3813 /*
3814 * Is it a new process that needs protection?
3815 */
3816 if (fCreated)
3817 {
3818 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3819 if (pNtStub)
3820 {
3821 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3822 if (!pNtVm)
3823 {
3824 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3825 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3826 }
3827 else
3828 {
3829 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3830 supdrvNtProtectRelease(pNtVm);
3831 }
3832 supdrvNtProtectRelease(pNtStub);
3833 }
3834 }
3835 /*
3836 * Process termination, do clean ups.
3837 */
3838 else
3839 {
3840 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3841 supdrvNtErrorInfoCleanupProcess(hNewPid);
3842 }
3843}
3844
3845
3846/**
3847 * New style callback (Vista SP1+ / w2k8).
3848 *
3849 * @param pNewProcess The new process.
3850 * @param hNewPid The PID of the new process.
3851 * @param pInfo Process creation details. NULL if process
3852 * termination notification.
3853 * @remarks ASSUMES this arrives before the handle creation callback.
3854 */
3855static VOID __stdcall
3856supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3857{
3858 RT_NOREF1(pNewProcess);
3859
3860 /*
3861 * Is it a new process that needs protection?
3862 */
3863 if (pInfo)
3864 {
3865 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3866
3867 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3868 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3869 hNewPid, pInfo->ParentProcessId,
3870 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3871 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3872 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3873
3874 if (pNtStub)
3875 {
3876 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3877 if (!pNtVm)
3878 {
3879 /* Parent must be creator. */
3880 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3881 {
3882 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3883 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3884 }
3885 }
3886 else
3887 {
3888 /* Parent must be creator (as above). */
3889 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3890 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3891 supdrvNtProtectRelease(pNtVm);
3892 }
3893 supdrvNtProtectRelease(pNtStub);
3894 }
3895 }
3896 /*
3897 * Process termination, do clean ups.
3898 */
3899 else
3900 {
3901 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3902 supdrvNtErrorInfoCleanupProcess(hNewPid);
3903 }
3904}
3905
3906/** @} */
3907
3908
3909/** @name Process Handle Callbacks.
3910 * @{ */
3911
3912/** Process rights that we allow for handles to stub and VM processes. */
3913# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
3914 ( PROCESS_TERMINATE \
3915 | PROCESS_VM_READ \
3916 | PROCESS_QUERY_INFORMATION \
3917 | PROCESS_QUERY_LIMITED_INFORMATION \
3918 | PROCESS_SUSPEND_RESUME \
3919 | DELETE \
3920 | READ_CONTROL \
3921 | SYNCHRONIZE)
3922
3923/** Evil process rights. */
3924# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
3925 ( PROCESS_CREATE_THREAD \
3926 | PROCESS_SET_SESSIONID /*?*/ \
3927 | PROCESS_VM_OPERATION \
3928 | PROCESS_VM_WRITE \
3929 | PROCESS_DUP_HANDLE \
3930 | PROCESS_CREATE_PROCESS /*?*/ \
3931 | PROCESS_SET_QUOTA /*?*/ \
3932 | PROCESS_SET_INFORMATION \
3933 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3934 | 0)
3935AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3936
3937
3938static OB_PREOP_CALLBACK_STATUS __stdcall
3939supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3940{
3941 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3942 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3943 Assert(pOpInfo->ObjectType == *PsProcessType);
3944
3945 /*
3946 * Protected? Kludge required for NtOpenProcess calls comming in before
3947 * the create process hook triggers on Windows 8.1 (possibly others too).
3948 */
3949 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3950 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3951 if (!pNtProtect)
3952 {
3953 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3954 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3955 if (pNtStub)
3956 {
3957 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3958 {
3959 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3960 pNtProtect = supdrvNtProtectLookup(hObjPid);
3961 }
3962 supdrvNtProtectRelease(pNtStub);
3963 }
3964 }
3965 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3966 if (pNtProtect)
3967 {
3968 /*
3969 * Ok, it's a protected process. Strip rights as required or possible.
3970 */
3971 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3972 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3973
3974 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3975 {
3976 /* Don't restrict the process accessing itself. */
3977 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3978 {
3979 pOpInfo->CallContext = NULL; /* don't assert */
3980 pNtProtect->fFirstProcessCreateHandle = false;
3981
3982 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3983 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3984 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3985 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3986 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3987 }
3988#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3989 /* Allow debuggers full access. */
3990 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3991 {
3992 pOpInfo->CallContext = NULL; /* don't assert */
3993 pNtProtect->fFirstProcessCreateHandle = false;
3994
3995 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3996 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3997 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3998 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3999 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4000 }
4001#endif
4002 else
4003 {
4004 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
4005
4006 /* Special case 1 on Vista, 7 & 8:
4007 The CreateProcess code passes the handle over to CSRSS.EXE
4008 and the code inBaseSrvCreateProcess will duplicate the
4009 handle with 0x1fffff as access mask. NtDuplicateObject will
4010 fail this call before it ever gets down here.
4011
4012 Special case 2 on 8.1:
4013 The CreateProcess code requires additional rights for
4014 something, we'll drop these in the stub code. */
4015 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4016 && pNtProtect->fFirstProcessCreateHandle
4017 && pOpInfo->KernelHandle == 0
4018 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
4019 && ExGetPreviousMode() != KernelMode)
4020 {
4021 if ( !pOpInfo->KernelHandle
4022 && fDesiredAccess == s_fCsrssStupidDesires)
4023 {
4024 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
4025 fAllowedRights |= s_fCsrssStupidDesires;
4026 else
4027 fAllowedRights = fAllowedRights
4028 | PROCESS_VM_OPERATION
4029 | PROCESS_VM_WRITE
4030 | PROCESS_SET_INFORMATION
4031 | PROCESS_SET_LIMITED_INFORMATION
4032 | 0;
4033 pOpInfo->CallContext = NULL; /* don't assert this. */
4034 }
4035 pNtProtect->fFirstProcessCreateHandle = false;
4036 }
4037
4038 /* Special case 3 on 8.1:
4039 The interaction between the CreateProcess code and CSRSS.EXE
4040 has changed to the better with Windows 8.1. CSRSS.EXE no
4041 longer duplicates the process (thread too) handle, but opens
4042 it, thus allowing us to do our job. */
4043 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
4044 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4045 && pNtProtect->fCsrssFirstProcessCreateHandle
4046 && pOpInfo->KernelHandle == 0
4047 && ExGetPreviousMode() == UserMode
4048 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4049 {
4050 pNtProtect->fCsrssFirstProcessCreateHandle = false;
4051 if (fDesiredAccess == s_fCsrssStupidDesires)
4052 {
4053 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4054 PROCESS_CREATE_PROCESS */
4055 fAllowedRights = fAllowedRights
4056 | PROCESS_VM_OPERATION
4057 | PROCESS_VM_WRITE
4058 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
4059 | 0;
4060 pOpInfo->CallContext = NULL; /* don't assert this. */
4061 }
4062 }
4063
4064 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
4065 The Themes service requires PROCESS_DUP_HANDLE access to our
4066 process or we won't get any menus and dialogs will be half
4067 unreadable. This is _very_ unfortunate and more work will
4068 go into making this more secure. */
4069 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
4070 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
4071 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
4072 && pNtProtect->fThemesFirstProcessCreateHandle
4073 && pOpInfo->KernelHandle == 0
4074 && ExGetPreviousMode() == UserMode
4075 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
4076 {
4077 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
4078 fAllowedRights |= PROCESS_DUP_HANDLE;
4079 pOpInfo->CallContext = NULL; /* don't assert this. */
4080 }
4081
4082 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
4083 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
4084 some myserious and weirdly placed cpu set management of our process.
4085 I'd love to understand what that's all about...
4086 Currently playing safe and only grand this right, however limited, to
4087 audiodg.exe. */
4088 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4089 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4090 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4091 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4092 )
4093 && pOpInfo->KernelHandle == 0
4094 && ExGetPreviousMode() == UserMode
4095 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4096 {
4097 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4098 pOpInfo->CallContext = NULL; /* don't assert this. */
4099 }
4100
4101 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4102 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4103 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4104 fAllowedRights, fDesiredAccess & fAllowedRights,
4105 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
4106
4107 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4108 }
4109 }
4110 else
4111 {
4112 /* Don't restrict the process accessing itself. */
4113 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
4114 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
4115 {
4116 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4117 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4118 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4119 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4120 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4121 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4122 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4123 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4124
4125 pOpInfo->CallContext = NULL; /* don't assert */
4126 }
4127 else
4128 {
4129 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
4130
4131 /* Special case 5 on Vista, 7 & 8:
4132 This is the CSRSS.EXE end of special case #1. */
4133 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4134 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4135 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
4136 && pOpInfo->KernelHandle == 0
4137 && fDesiredAccess == s_fCsrssStupidDesires
4138 && pNtProtect->hParentPid
4139 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
4140 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4141 && ExGetPreviousMode() == UserMode
4142 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
4143 {
4144 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
4145 {
4146 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4147 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
4148 fAllowedRights = fAllowedRights
4149 | PROCESS_VM_OPERATION
4150 | PROCESS_VM_WRITE
4151 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
4152 | 0;
4153 pOpInfo->CallContext = NULL; /* don't assert this. */
4154 }
4155 }
4156
4157 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
4158 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4159 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4160 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4161 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4162 )
4163 && pOpInfo->KernelHandle == 0
4164 && ExGetPreviousMode() == UserMode
4165 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4166 {
4167 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4168 pOpInfo->CallContext = NULL; /* don't assert this. */
4169 }
4170
4171 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4172 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4173 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4174 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4175 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4176 fDesiredAccess,
4177 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4178 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4179
4180 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4181 }
4182 }
4183 supdrvNtProtectRelease(pNtProtect);
4184 }
4185
4186 return OB_PREOP_SUCCESS;
4187}
4188
4189
4190static VOID __stdcall
4191supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4192{
4193 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4194 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4195 Assert(pOpInfo->ObjectType == *PsProcessType);
4196
4197 if ( pOpInfo->CallContext
4198 && NT_SUCCESS(pOpInfo->ReturnStatus))
4199 {
4200 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
4201 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
4202 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
4203 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4204 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4205 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
4206 /*| PROCESS_UNKNOWN_8000 */ ) )
4207 || pOpInfo->KernelHandle,
4208 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4209 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
4210 }
4211}
4212
4213# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4214
4215/** @} */
4216
4217
4218/** @name Thread Handle Callbacks
4219 * @{ */
4220
4221/* From ntifs.h */
4222extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
4223
4224/** Thread rights that we allow for handles to stub and VM processes. */
4225# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
4226 ( THREAD_TERMINATE \
4227 | THREAD_GET_CONTEXT \
4228 | THREAD_QUERY_INFORMATION \
4229 | THREAD_QUERY_LIMITED_INFORMATION \
4230 | DELETE \
4231 | READ_CONTROL \
4232 | SYNCHRONIZE)
4233/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
4234
4235/** Evil thread rights.
4236 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
4237 * Windows 8.1, at least for some processes. We dont' actively
4238 * allow it though, just tollerate it when forced to. */
4239# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
4240 ( THREAD_SUSPEND_RESUME \
4241 | THREAD_SET_CONTEXT \
4242 | THREAD_SET_INFORMATION \
4243 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
4244 | THREAD_SET_THREAD_TOKEN /*?*/ \
4245 | THREAD_IMPERSONATE /*?*/ \
4246 | THREAD_DIRECT_IMPERSONATION /*?*/ \
4247 /*| THREAD_RESUME - see remarks. */ \
4248 | 0)
4249AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
4250
4251
4252static OB_PREOP_CALLBACK_STATUS __stdcall
4253supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4254{
4255 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4256 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4257 Assert(pOpInfo->ObjectType == *PsThreadType);
4258
4259 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
4260 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
4261 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4262 if (pNtProtect)
4263 {
4264 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4265 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
4266
4267 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4268 {
4269 /* Don't restrict the process accessing its own threads. */
4270 if (pProcess == PsGetCurrentProcess())
4271 {
4272 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
4273 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4274 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4275 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
4276 pOpInfo->CallContext = NULL; /* don't assert */
4277 pNtProtect->fFirstThreadCreateHandle = false;
4278 }
4279#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4280 /* Allow debuggers full access. */
4281 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4282 {
4283 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4284 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4285 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4286 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4287 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4288 pOpInfo->CallContext = NULL; /* don't assert */
4289 }
4290#endif
4291 else
4292 {
4293 /* Special case 1 on Vista, 7, 8:
4294 The CreateProcess code passes the handle over to CSRSS.EXE
4295 and the code inBaseSrvCreateProcess will duplicate the
4296 handle with 0x1fffff as access mask. NtDuplicateObject will
4297 fail this call before it ever gets down here. */
4298 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4299 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4300 && pNtProtect->fFirstThreadCreateHandle
4301 && pOpInfo->KernelHandle == 0
4302 && ExGetPreviousMode() == UserMode
4303 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
4304 {
4305 if ( !pOpInfo->KernelHandle
4306 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
4307 {
4308 fAllowedRights |= s_fCsrssStupidDesires;
4309 pOpInfo->CallContext = NULL; /* don't assert this. */
4310 }
4311 pNtProtect->fFirstThreadCreateHandle = false;
4312 }
4313
4314 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
4315 When creating a process like VBoxTestOGL from the VM process,
4316 CSRSS.EXE will try talk to the calling thread and, it
4317 appears, impersonate it. We unfortunately need to allow
4318 this or there will be no 3D support. Typical DbgPrint:
4319 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
4320 SUPDRVNTPROTECTKIND enmProcessKind;
4321 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4322 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4323 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4324 && pOpInfo->KernelHandle == 0
4325 && ExGetPreviousMode() == UserMode
4326 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4327 {
4328 fAllowedRights |= THREAD_IMPERSONATE;
4329 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4330 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4331 pOpInfo->CallContext = NULL; /* don't assert this. */
4332 }
4333
4334 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4335 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4336 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4337 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4338 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
4339 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
4340
4341 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4342 }
4343 }
4344 else
4345 {
4346 /* Don't restrict the process accessing its own threads. */
4347 if ( pProcess == PsGetCurrentProcess()
4348 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
4349 {
4350 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
4351 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4352 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4353 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4354 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4355 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4356 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4357 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4358 pOpInfo->CallContext = NULL; /* don't assert */
4359 }
4360 else
4361 {
4362 /* Special case 3 on Vista, 7, 8:
4363 This is the follow up to special case 1. */
4364 SUPDRVNTPROTECTKIND enmProcessKind;
4365 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4366 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4367 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4368 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4369 && pOpInfo->KernelHandle == 0
4370 && ExGetPreviousMode() == UserMode
4371 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4372 {
4373 fAllowedRights |= THREAD_IMPERSONATE;
4374 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4375 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4376 pOpInfo->CallContext = NULL; /* don't assert this. */
4377 }
4378
4379 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
4380 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4381 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4382 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4383 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4384 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4385 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4386 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
4387 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4388
4389 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4390 }
4391 }
4392
4393 supdrvNtProtectRelease(pNtProtect);
4394 }
4395
4396 return OB_PREOP_SUCCESS;
4397}
4398
4399
4400static VOID __stdcall
4401supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4402{
4403 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4404 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4405 Assert(pOpInfo->ObjectType == *PsThreadType);
4406
4407 if ( pOpInfo->CallContext
4408 && NT_SUCCESS(pOpInfo->ReturnStatus))
4409 {
4410 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
4411 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4412 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4413 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
4414 ) )
4415 || pOpInfo->KernelHandle,
4416 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4417 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
4418 }
4419}
4420
4421# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4422
4423/** @} */
4424
4425
4426/**
4427 * Creates a new process protection structure.
4428 *
4429 * @returns VBox status code.
4430 * @param ppNtProtect Where to return the pointer to the structure
4431 * on success.
4432 * @param hPid The process ID of the process to protect.
4433 * @param enmProcessKind The kind of process we're protecting.
4434 * @param fLink Whether to link the structure into the tree.
4435 */
4436static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
4437{
4438 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
4439
4440 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
4441 if (!pNtProtect)
4442 return VERR_NO_MEMORY;
4443
4444 pNtProtect->AvlCore.Key = hPid;
4445 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
4446 pNtProtect->cRefs = 1;
4447 pNtProtect->enmProcessKind = enmProcessKind;
4448 pNtProtect->hParentPid = NULL;
4449 pNtProtect->hOpenTid = NULL;
4450 pNtProtect->hCsrssPid = NULL;
4451 pNtProtect->pCsrssProcess = NULL;
4452
4453 if (fLink)
4454 {
4455 RTSpinlockAcquire(g_hNtProtectLock);
4456 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
4457 pNtProtect->fInTree = fSuccess;
4458 RTSpinlockRelease(g_hNtProtectLock);
4459
4460 if (!fSuccess)
4461 {
4462 /* Duplicate entry, fail. */
4463 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
4464 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
4465 RTMemFree(pNtProtect);
4466 return VERR_DUPLICATE;
4467 }
4468 }
4469
4470 *ppNtProtect = pNtProtect;
4471 return VINF_SUCCESS;
4472}
4473
4474
4475/**
4476 * Releases a reference to a NT protection structure.
4477 *
4478 * @param pNtProtect The NT protection structure.
4479 */
4480static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
4481{
4482 if (!pNtProtect)
4483 return;
4484 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
4485
4486 RTSpinlockAcquire(g_hNtProtectLock);
4487 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
4488 if (cRefs != 0)
4489 RTSpinlockRelease(g_hNtProtectLock);
4490 else
4491 {
4492 /*
4493 * That was the last reference. Remove it from the tree, invalidate it
4494 * and free the resources associated with it. Also, release any
4495 * child/parent references related to this protection structure.
4496 */
4497 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
4498 if (pNtProtect->fInTree)
4499 {
4500 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
4501 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
4502 pNtProtect->fInTree = false;
4503 }
4504
4505 PSUPDRVNTPROTECT pChild = NULL;
4506 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4507 {
4508 pChild = pNtProtect->u.pChild;
4509 if (pChild)
4510 {
4511 pNtProtect->u.pChild = NULL;
4512 pChild->u.pParent = NULL;
4513 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4514 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4515 if (!cChildRefs)
4516 {
4517 Assert(pChild->fInTree);
4518 if (pChild->fInTree)
4519 {
4520 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4521 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4522 pChild->fInTree = false;
4523 }
4524 }
4525 else
4526 pChild = NULL;
4527 }
4528 }
4529 else
4530 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4531
4532 RTSpinlockRelease(g_hNtProtectLock);
4533
4534 if (pNtProtect->pCsrssProcess)
4535 {
4536 ObDereferenceObject(pNtProtect->pCsrssProcess);
4537 pNtProtect->pCsrssProcess = NULL;
4538 }
4539
4540 RTMemFree(pNtProtect);
4541 if (pChild)
4542 RTMemFree(pChild);
4543 }
4544}
4545
4546
4547/**
4548 * Looks up a PID in the NT protect tree.
4549 *
4550 * @returns Pointer to a NT protection structure (with a referenced) on success,
4551 * NULL if not found.
4552 * @param hPid The process ID.
4553 */
4554static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4555{
4556 RTSpinlockAcquire(g_hNtProtectLock);
4557 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4558 if (pFound)
4559 ASMAtomicIncU32(&pFound->cRefs);
4560 RTSpinlockRelease(g_hNtProtectLock);
4561 return pFound;
4562}
4563
4564
4565/**
4566 * Validates a few facts about the stub process when the VM process opens
4567 * vboxdrv.
4568 *
4569 * This makes sure the stub process is still around and that it has neither
4570 * debugger nor extra threads in it.
4571 *
4572 * @returns VBox status code.
4573 * @param pNtProtect The unconfirmed VM process currently trying to
4574 * open vboxdrv.
4575 * @param pErrInfo Additional error information.
4576 */
4577static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4578{
4579 /*
4580 * Grab a reference to the parent stub process.
4581 */
4582 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4583 PSUPDRVNTPROTECT pNtStub = NULL;
4584 RTSpinlockAcquire(g_hNtProtectLock);
4585 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4586 {
4587 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4588 if (pNtStub)
4589 {
4590 enmStub = pNtStub->enmProcessKind;
4591 if (enmStub == kSupDrvNtProtectKind_StubParent)
4592 {
4593 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4594 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4595 }
4596 else
4597 pNtStub = NULL;
4598 }
4599 }
4600 RTSpinlockRelease(g_hNtProtectLock);
4601
4602 /*
4603 * We require the stub process to be present.
4604 */
4605 if (!pNtStub)
4606 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4607
4608 /*
4609 * Open the parent process and thread so we can check for debuggers and unwanted threads.
4610 */
4611 int rc;
4612 PEPROCESS pStubProcess;
4613 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4614 if (NT_SUCCESS(rcNt))
4615 {
4616 HANDLE hStubProcess;
4617 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4618 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4619 if (NT_SUCCESS(rcNt))
4620 {
4621 PETHREAD pStubThread;
4622 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4623 if (NT_SUCCESS(rcNt))
4624 {
4625 HANDLE hStubThread;
4626 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4627 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4628 if (NT_SUCCESS(rcNt))
4629 {
4630 /*
4631 * Do some simple sanity checking.
4632 */
4633 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4634 if (RT_SUCCESS(rc))
4635 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4636
4637 /* Clean up. */
4638 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4639 }
4640 else
4641 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4642 "Error opening stub thread %p (tid %p, pid %p): %#x",
4643 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4644 }
4645 else
4646 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4647 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4648 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4649 }
4650 else
4651 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4652 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4653 ObDereferenceObject(pStubProcess);
4654 }
4655 else
4656 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4657 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4658
4659 supdrvNtProtectRelease(pNtStub);
4660 return rc;
4661}
4662
4663
4664/**
4665 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
4666 * process and its thread.
4667 *
4668 * @returns VBox status code.
4669 * @param pNtProtect The NT protect structure for getting information
4670 * about special processes.
4671 * @param pErrInfo Where to return additional error details.
4672 */
4673static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4674{
4675 /*
4676 * What to protect.
4677 */
4678 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
4679 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
4680 PETHREAD pProtectedThread = PsGetCurrentThread();
4681 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
4682
4683 /*
4684 * Take a snapshot of all the handles in the system.
4685 * Note! The 32 bytes on the size of to counteract the allocation header
4686 * that rtR0MemAllocEx slaps on everything.
4687 */
4688 uint32_t cbBuf = _256K - 32;
4689 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4690 ULONG cbNeeded = cbBuf;
4691 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4692 if (!NT_SUCCESS(rcNt))
4693 {
4694 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
4695 && cbNeeded > cbBuf
4696 && cbBuf <= 32U*_1M)
4697 {
4698 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
4699 RTMemFree(pbBuf);
4700 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4701 if (!pbBuf)
4702 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
4703 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4704 }
4705 if (!NT_SUCCESS(rcNt))
4706 {
4707 RTMemFree(pbBuf);
4708 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
4709 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
4710 }
4711 }
4712
4713 /*
4714 * Walk the information and look for handles to the two objects we're protecting.
4715 */
4716 int rc = VINF_SUCCESS;
4717# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4718 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
4719# endif
4720
4721 uint32_t cCsrssProcessHandles = 0;
4722 uint32_t cSystemProcessHandles = 0;
4723 uint32_t cEvilProcessHandles = 0;
4724 uint32_t cBenignProcessHandles = 0;
4725
4726 uint32_t cCsrssThreadHandles = 0;
4727 uint32_t cEvilThreadHandles = 0;
4728 uint32_t cBenignThreadHandles = 0;
4729
4730 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
4731 ULONG_PTR i = pInfo->NumberOfHandles;
4732 AssertRelease(RT_UOFFSETOF_DYN(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
4733 while (i-- > 0)
4734 {
4735 const char *pszType;
4736 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
4737 if (pHandleInfo->Object == pProtectedProcess)
4738 {
4739 /* Handles within the protected process are fine. */
4740 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
4741 || pHandleInfo->UniqueProcessId == hProtectedPid)
4742 {
4743 cBenignProcessHandles++;
4744 continue;
4745 }
4746
4747 /* CSRSS is allowed to have one evil process handle.
4748 See the special cases in the hook code. */
4749 if ( cCsrssProcessHandles < 1
4750 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4751 {
4752 cCsrssProcessHandles++;
4753 continue;
4754 }
4755
4756 /* The system process is allowed having two open process handle in
4757 Windows 8.1 and later, and one in earlier. This is probably a
4758 little overly paranoid as I think we can safely trust the
4759 system process... */
4760 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
4761 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
4762 {
4763 cSystemProcessHandles++;
4764 continue;
4765 }
4766
4767 cEvilProcessHandles++;
4768 pszType = "process";
4769 }
4770 else if (pHandleInfo->Object == pProtectedThread)
4771 {
4772 /* Handles within the protected process is fine. */
4773 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
4774 || pHandleInfo->UniqueProcessId == hProtectedPid)
4775 {
4776 cBenignThreadHandles++;
4777 continue;
4778 }
4779
4780 /* CSRSS is allowed to have one evil handle to the primary thread
4781 for LPC purposes. See the hook for special case. */
4782 if ( cCsrssThreadHandles < 1
4783 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4784 {
4785 cCsrssThreadHandles++;
4786 continue;
4787 }
4788
4789 cEvilThreadHandles++;
4790 pszType = "thread";
4791 }
4792 else
4793 continue;
4794
4795# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4796 /* Ignore whitelisted debuggers. */
4797 if (pHandleInfo->UniqueProcessId == idLastDebugger)
4798 continue;
4799 PEPROCESS pDbgProc;
4800 NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4801 if (NT_SUCCESS(rcNt))
4802 {
4803 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4804 ObDereferenceObject(pDbgProc);
4805 if (fIsDebugger)
4806 {
4807 idLastDebugger = pHandleInfo->UniqueProcessId;
4808 continue;
4809 }
4810 }
4811# endif
4812
4813 /* Found evil handle. Currently ignoring on pre-Vista. */
4814# ifndef VBOX_WITH_VISTA_NO_SP
4815 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
4816# else
4817 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4818# endif
4819 || g_pfnObRegisterCallbacks)
4820 {
4821 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4822 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4823 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4824 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4825 *pErrInfo->pszMsg
4826 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4827 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4828 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4829 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4830
4831 /* Try add the process name. */
4832 PEPROCESS pOffendingProcess;
4833 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4834 if (NT_SUCCESS(rcNt))
4835 {
4836 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4837 if (pszName && *pszName)
4838 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4839
4840 ObDereferenceObject(pOffendingProcess);
4841 }
4842 }
4843 }
4844
4845 RTMemFree(pbBuf);
4846 return rc;
4847}
4848
4849
4850/**
4851 * Checks if the current process checks out as a VM process stub.
4852 *
4853 * @returns VBox status code.
4854 * @param pNtProtect The NT protect structure. This is upgraded to a
4855 * final protection kind (state) on success.
4856 */
4857static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4858{
4859 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4860
4861 /*
4862 * Do the verification. The handle restriction checks are only preformed
4863 * on VM processes.
4864 */
4865 int rc = VINF_SUCCESS;
4866 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4867 if (RT_SUCCESS(rc))
4868 {
4869 pErrorInfo->hProcessId = PsGetCurrentProcessId();
4870 pErrorInfo->hThreadId = PsGetCurrentThreadId();
4871 RTERRINFO ErrInfo;
4872 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4873
4874 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4875 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4876 if (RT_SUCCESS(rc))
4877 {
4878 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4879 NULL /*pcFixes*/, &ErrInfo);
4880 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4881 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4882 }
4883 }
4884 else
4885 rc = VERR_NO_MEMORY;
4886
4887 /*
4888 * Upgrade and return.
4889 */
4890 HANDLE hOpenTid = PsGetCurrentThreadId();
4891 RTSpinlockAcquire(g_hNtProtectLock);
4892
4893 /* Stub process verficiation is pretty much straight forward. */
4894 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4895 {
4896 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4897 pNtProtect->hOpenTid = hOpenTid;
4898 }
4899 /* The VM process verification is a little bit more complicated
4900 because we need to drop the parent process reference as well. */
4901 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4902 {
4903 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4904 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4905 AssertRelease(pParent);
4906 AssertRelease(pParent->u.pParent == pNtProtect);
4907 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4908 pParent->u.pParent = NULL;
4909
4910 pNtProtect->u.pParent = NULL;
4911 ASMAtomicDecU32(&pNtProtect->cRefs);
4912
4913 if (RT_SUCCESS(rc))
4914 {
4915 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4916 pNtProtect->hOpenTid = hOpenTid;
4917 }
4918 else
4919 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4920 }
4921
4922 /* Since the stub and VM processes are only supposed to have one thread,
4923 we're not supposed to be subject to any races from within the processes.
4924
4925 There is a race between VM process verification and the stub process
4926 exiting, though. We require the stub process to be alive until the new
4927 VM process has made it thru the validation. So, when the stub
4928 terminates the notification handler will change the state of both stub
4929 and VM process to dead.
4930
4931 Also, I'm not entirely certain where the process
4932 termination notification is triggered from, so that can theorically
4933 create a race in both cases. */
4934 else
4935 {
4936 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4937 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4938 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4939 if (RT_SUCCESS(rc))
4940 rc = VERR_INVALID_STATE; /* There should be no races here. */
4941 }
4942
4943 RTSpinlockRelease(g_hNtProtectLock);
4944
4945 /*
4946 * Free error info on success, keep it on failure.
4947 */
4948 if (RT_SUCCESS(rc))
4949 RTMemFree(pErrorInfo);
4950 else if (pErrorInfo)
4951 {
4952 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4953 if (!pErrorInfo->cchErrorInfo)
4954 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4955 "supdrvNtProtectVerifyProcess: rc=%d", rc);
4956 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4957
4958 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4959 if (RT_SUCCESS(rc2))
4960 {
4961 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4962
4963 /* Free old entries. */
4964 PSUPDRVNTERRORINFO pCur;
4965 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4966 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4967 {
4968 RTListNodeRemove(&pCur->ListEntry);
4969 RTMemFree(pCur);
4970 }
4971
4972 /* Insert our new entry. */
4973 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4974
4975 RTSemMutexRelease(g_hErrorInfoLock);
4976 }
4977 else
4978 RTMemFree(pErrorInfo);
4979 }
4980
4981 return rc;
4982}
4983
4984
4985# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4986
4987/**
4988 * Checks if the current process is being debugged.
4989 * @return @c true if debugged, @c false if not.
4990 */
4991static bool supdrvNtIsDebuggerAttached(void)
4992{
4993 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4994}
4995
4996# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4997
4998
4999/**
5000 * Terminates the hardening bits.
5001 */
5002static void supdrvNtProtectTerm(void)
5003{
5004 /*
5005 * Stop intercepting process and thread handle creation calls.
5006 */
5007 if (g_pvObCallbacksCookie)
5008 {
5009 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
5010 g_pvObCallbacksCookie = NULL;
5011 }
5012
5013 /*
5014 * Stop intercepting process creation and termination notifications.
5015 */
5016 NTSTATUS rcNt;
5017 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5018 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5019 else
5020 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5021 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
5022
5023 Assert(g_NtProtectTree == NULL);
5024
5025 /*
5026 * Clean up globals.
5027 */
5028 RTSpinlockDestroy(g_hNtProtectLock);
5029 g_NtProtectTree = NIL_RTSPINLOCK;
5030
5031 RTSemMutexDestroy(g_hErrorInfoLock);
5032 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5033
5034 PSUPDRVNTERRORINFO pCur;
5035 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
5036 {
5037 RTListNodeRemove(&pCur->ListEntry);
5038 RTMemFree(pCur);
5039 }
5040
5041 supHardenedWinTermImageVerifier();
5042}
5043
5044# ifdef RT_ARCH_X86
5045DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
5046DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
5047DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
5048DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
5049DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
5050DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
5051DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
5052DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
5053DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
5054DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
5055DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
5056DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
5057DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
5058DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
5059DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
5060DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
5061# elif defined(RT_ARCH_AMD64)
5062DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
5063DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
5064DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
5065DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
5066DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
5067extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
5068# endif
5069
5070
5071/**
5072 * Initalizes the hardening bits.
5073 *
5074 * @returns NT status code.
5075 */
5076static NTSTATUS supdrvNtProtectInit(void)
5077{
5078 /*
5079 * Initialize the globals.
5080 */
5081
5082 /* The NT version. */
5083 ULONG uMajor, uMinor, uBuild;
5084 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
5085 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
5086
5087 /* Resolve methods we want but isn't available everywhere. */
5088 UNICODE_STRING RoutineName;
5089
5090 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
5091 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
5092
5093 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
5094 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5095
5096 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
5097 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5098
5099 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
5100 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
5101
5102 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
5103 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
5104
5105 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
5106 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
5107
5108 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
5109 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
5110
5111 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
5112 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
5113 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
5114 {
5115 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
5116 few alternative in the assembly helper file that uses the code in
5117 ZwReadFile with a different eax value. We figure the syscall number
5118 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
5119# ifdef RT_ARCH_X86
5120 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
5121 if (*pbCode == 0xb8) /* mov eax, dword */
5122 switch (*(uint32_t const *)&pbCode[1])
5123 {
5124 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
5125 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
5126 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
5127 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
5128 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
5129 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
5130 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
5131 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
5132 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
5133 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
5134 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
5135 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
5136 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
5137 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
5138 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
5139 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
5140 }
5141# elif defined(RT_ARCH_AMD64)
5142 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
5143 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
5144 && pbCode[ 1] == 0x8b
5145 && pbCode[ 2] == 0xc4
5146 && pbCode[ 3] == 0xfa /* cli */
5147 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
5148 && pbCode[ 5] == 0x83
5149 && pbCode[ 6] == 0xec
5150 && pbCode[ 7] == 0x10
5151 && pbCode[ 8] == 0x50 /* push rax */
5152 && pbCode[ 9] == 0x9c /* pushfq */
5153 && pbCode[10] == 0x6a /* push 10 */
5154 && pbCode[11] == 0x10
5155 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
5156 && pbCode[13] == 0x8d
5157 && pbCode[14] == 0x05
5158 && pbCode[19] == 0x50 /* push rax */
5159 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
5160 /*&& pbCode[21] == 0x1f*/
5161 && pbCode[22] == 0x00
5162 && pbCode[23] == 0x00
5163 && pbCode[24] == 0x00
5164 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
5165 )
5166 {
5167 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
5168 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
5169 if (*pbKiServiceLinkage == 0xc3)
5170 {
5171 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
5172 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
5173 switch (pbCode[21])
5174 {
5175 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
5176 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
5177 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
5178 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
5179 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
5180 }
5181 }
5182 }
5183# endif
5184 }
5185 if (!g_pfnNtQueryVirtualMemory)
5186 {
5187 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
5188 return STATUS_PROCEDURE_NOT_FOUND;
5189 }
5190
5191# ifdef VBOX_STRICT
5192 if ( g_uNtVerCombined >= SUP_NT_VER_W70
5193 && ( g_pfnObGetObjectType == NULL
5194 || g_pfnZwAlpcCreatePort == NULL) )
5195 {
5196 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
5197 return STATUS_PROCEDURE_NOT_FOUND;
5198 }
5199# endif
5200
5201 /* LPC object type. */
5202 g_pAlpcPortObjectType1 = *LpcPortObjectType;
5203
5204 /* The spinlock protecting our structures. */
5205 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
5206 if (RT_FAILURE(rc))
5207 return VBoxDrvNtErr2NtStatus(rc);
5208 g_NtProtectTree = NULL;
5209
5210 NTSTATUS rcNt;
5211
5212 /* The mutex protecting the error information. */
5213 RTListInit(&g_ErrorInfoHead);
5214 rc = RTSemMutexCreate(&g_hErrorInfoLock);
5215 if (RT_SUCCESS(rc))
5216 {
5217 /* Image stuff + certificates. */
5218 rc = supHardenedWinInitImageVerifier(NULL);
5219 if (RT_SUCCESS(rc))
5220 {
5221 /*
5222 * Intercept process creation and termination.
5223 */
5224 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5225 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
5226 else
5227 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
5228 if (NT_SUCCESS(rcNt))
5229 {
5230 /*
5231 * Intercept process and thread handle creation calls.
5232 * The preferred method is only available on Vista SP1+.
5233 */
5234 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
5235 {
5236 static OB_OPERATION_REGISTRATION s_aObOperations[] =
5237 {
5238 {
5239 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
5240 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5241 supdrvNtProtectCallback_ProcessHandlePre,
5242 supdrvNtProtectCallback_ProcessHandlePost,
5243 },
5244 {
5245 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
5246 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5247 supdrvNtProtectCallback_ThreadHandlePre,
5248 supdrvNtProtectCallback_ThreadHandlePost,
5249 },
5250 };
5251 s_aObOperations[0].ObjectType = PsProcessType;
5252 s_aObOperations[1].ObjectType = PsThreadType;
5253
5254 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
5255 {
5256 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
5257 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
5258 /* .Altitude.Length = */ 0,
5259 /* .Altitude.MaximumLength = */ 0,
5260 /* .Altitude.Buffer = */ NULL,
5261 /* .RegistrationContext = */ NULL,
5262 /* .OperationRegistration = */ &s_aObOperations[0]
5263 };
5264 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
5265 {
5266 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
5267 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
5268 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
5269 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
5270 };
5271
5272 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
5273 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
5274 {
5275 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
5276 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
5277 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
5278
5279 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
5280 if (NT_SUCCESS(rcNt))
5281 {
5282 /*
5283 * Happy ending.
5284 */
5285 return STATUS_SUCCESS;
5286 }
5287 }
5288 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
5289 g_pvObCallbacksCookie = NULL;
5290 }
5291 else
5292 {
5293 /*
5294 * For the time being, we do not implement extra process
5295 * protection on pre-Vista-SP1 systems as they are lacking
5296 * necessary KPIs. XP is end of life, we do not wish to
5297 * spend more time on it, so we don't put up a fuss there.
5298 * Vista users without SP1 can install SP1 (or later), darn it,
5299 * so refuse to load.
5300 */
5301 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
5302 * stuff to a couple of object types. */
5303# ifndef VBOX_WITH_VISTA_NO_SP
5304 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
5305# else
5306 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
5307# endif
5308 {
5309 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
5310 rcNt = STATUS_SXS_VERSION_CONFLICT;
5311 }
5312 else
5313 {
5314 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
5315 return rcNt = STATUS_SUCCESS;
5316 }
5317 g_pvObCallbacksCookie = NULL;
5318 }
5319
5320 /*
5321 * Drop process create/term notifications.
5322 */
5323 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5324 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5325 else
5326 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5327 }
5328 else
5329 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
5330 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
5331 supHardenedWinTermImageVerifier();
5332 }
5333 else
5334 rcNt = VBoxDrvNtErr2NtStatus(rc);
5335
5336 RTSemMutexDestroy(g_hErrorInfoLock);
5337 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5338 }
5339 else
5340 rcNt = VBoxDrvNtErr2NtStatus(rc);
5341
5342 RTSpinlockDestroy(g_hNtProtectLock);
5343 g_NtProtectTree = NIL_RTSPINLOCK;
5344 return rcNt;
5345}
5346
5347#endif /* VBOX_WITH_HARDENING */
5348
Note: See TracBrowser for help on using the repository browser.

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