VirtualBox

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

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

SupHardNt: Made RTNtPathExpand8dot3Path() work correctly in kernel context (needs IPRT_NT_MAP_TO_ZW) and expand 8.3 names when comparing the executable image we found in the memory map with what NT returns for the process.

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

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