VirtualBox

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

Last change on this file since 92270 was 92203, checked in by vboxsync, 3 years ago

SUPDrv-win.cpp: Debugged and enabled the VBOXDRV_WITH_SID_TO_UID_MAPPING code. bugref:10093

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