VirtualBox

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

Last change on this file since 82592 was 81369, checked in by vboxsync, 5 years ago

*: doxygen fixes

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

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