VirtualBox

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

Last change on this file since 91136 was 90780, checked in by vboxsync, 4 years ago

SUP: VALID_PTR -> RT_VALID_PTR.

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