VirtualBox

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

Last change on this file since 64255 was 64255, checked in by vboxsync, 8 years ago

SUP,VMM,IPRT: SUPDrv and GIP major version bump! Added processor group info to GIP along with a new RDTSCP-based method for getting the current CPU (for the timesup code).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use