VirtualBox

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

Last change on this file since 106558 was 106527, checked in by vboxsync, 4 months ago

SUPDrv/win: Added some {} and commented out an unused variable. jiraref:1171

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