VirtualBox

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

Last change on this file since 87593 was 84497, checked in by vboxsync, 5 years ago

SUPDrv-win.cpp: Relax the ImageBase check when comparing NT loaded and IPRT loaded image bits. This broke on older windows versions after we updated the compiler to 14.2. Perhaps some linker version check there. Saw addresses like 0x000007fef3c20000 and 0x000007fddf250000 rather than the linker base address or actual kernel load address. Weird. bugref:8489

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