VirtualBox

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

Last change on this file since 104428 was 104428, checked in by vboxsync, 7 months ago

SUPDrv: More logging for bugref:10657

  • 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 104428 2024-04-25 10:07:44Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie)
2690 && pCfg->SecurityCookie != NULL)
2691 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->SecurityCookie - (uintptr_t)pImage->pvImage, sizeof(void *));
2692
2693 /* Also exclude the GuardCFCheckFunctionPointer and GuardCFDispatchFunctionPointer pointer variables. */
2694 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardCFCheckFunctionPointer)
2695 && pCfg->GuardCFCheckFunctionPointer != NULL)
2696 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardCFCheckFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2697 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardCFDispatchFunctionPointer)
2698 && pCfg->GuardCFDispatchFunctionPointer != NULL)
2699 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardCFDispatchFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2700
2701 /* Ditto for the XFG variants: */
2702 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardXFGCheckFunctionPointer)
2703 && pCfg->GuardXFGCheckFunctionPointer != NULL)
2704 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardXFGCheckFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2705 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardXFGDispatchFunctionPointer)
2706 && pCfg->GuardXFGDispatchFunctionPointer != NULL)
2707 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardXFGDispatchFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2708
2709 /** @todo What about GuardRFVerifyStackPointerFunctionPointer and
2710 * GuardRFFailureRoutineFunctionPointer? Ignore for now as the compiler we're
2711 * using (19.26.28805) sets them to zero from what I can tell. */
2712
2713 /*
2714 * Ok, do the comparison.
2715 */
2716 int iDiff = 0;
2717 uint32_t uRvaNext = 0;
2718 for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
2719 {
2720 if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
2721 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
2722 uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
2723 }
2724 if (!iDiff && uRvaNext < pImage->cbImageBits)
2725 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2726 if (!iDiff)
2727 {
2728 /*
2729 * If there is a cookie init export, call it.
2730 *
2731 * This typically just does:
2732 * __security_cookie = (rdtsc ^ &__security_cookie) & 0xffffffffffff;
2733 * __security_cookie_complement = ~__security_cookie;
2734 */
2735 PFNRT pfnModuleInitSecurityCookie = NULL;
2736 int rcSym = supdrvOSLdrQuerySymbol(pDevExt, pImage, RT_STR_TUPLE("ModuleInitSecurityCookie"),
2737 (void **)&pfnModuleInitSecurityCookie);
2738 if (RT_SUCCESS(rcSym) && pfnModuleInitSecurityCookie)
2739 pfnModuleInitSecurityCookie();
2740
2741 return VINF_SUCCESS;
2742 }
2743 }
2744 else
2745 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2746 return VERR_LDR_MISMATCH_NATIVE;
2747 }
2748 return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2749}
2750
2751
2752void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2753{
2754 if (pImage->pvNtSectionObj)
2755 {
2756 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2757 {
2758 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2759 pImage->hMemLock = NIL_RTR0MEMOBJ;
2760 }
2761
2762 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2763 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2764 if (rcNt != STATUS_SUCCESS)
2765 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2766 pImage->pvNtSectionObj = NULL;
2767 }
2768 NOREF(pDevExt);
2769}
2770
2771
2772void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2773{
2774 RT_NOREF(pDevExt, pImage);
2775 AssertFailed();
2776}
2777
2778
2779void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2780{
2781 RT_NOREF(pDevExt, pImage);
2782 AssertFailed();
2783}
2784
2785
2786#ifdef SUPDRV_WITH_MSR_PROBER
2787
2788#if 1
2789/** @todo make this selectable. */
2790# define AMD_MSR_PASSCODE 0x9c5a203a
2791#else
2792# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2793# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2794#endif
2795
2796
2797/**
2798 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2799 */
2800typedef struct SUPDRVNTMSPROBERARGS
2801{
2802 uint32_t uMsr;
2803 uint64_t uValue;
2804 bool fGp;
2805} SUPDRVNTMSPROBERARGS;
2806
2807/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2808static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2809{
2810 /*
2811 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2812 * (At least on 32-bit XP.)
2813 */
2814 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2815 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2816 __try
2817 {
2818 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2819 pArgs->fGp = false;
2820 }
2821 __except(EXCEPTION_EXECUTE_HANDLER)
2822 {
2823 pArgs->fGp = true;
2824 pArgs->uValue = 0;
2825 }
2826 ASMSetFlags(fOldFlags);
2827}
2828
2829
2830int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2831{
2832 SUPDRVNTMSPROBERARGS Args;
2833 Args.uMsr = uMsr;
2834 Args.uValue = 0;
2835 Args.fGp = true;
2836
2837 if (idCpu == NIL_RTCPUID)
2838 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2839 else
2840 {
2841 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2842 if (RT_FAILURE(rc))
2843 return rc;
2844 }
2845
2846 if (Args.fGp)
2847 return VERR_ACCESS_DENIED;
2848 *puValue = Args.uValue;
2849 return VINF_SUCCESS;
2850}
2851
2852
2853/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2854static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2855{
2856 /*
2857 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2858 * (At least on 32-bit XP.)
2859 */
2860 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2861 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2862 __try
2863 {
2864 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2865 pArgs->fGp = false;
2866 }
2867 __except(EXCEPTION_EXECUTE_HANDLER)
2868 {
2869 pArgs->fGp = true;
2870 }
2871 ASMSetFlags(fOldFlags);
2872}
2873
2874int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2875{
2876 SUPDRVNTMSPROBERARGS Args;
2877 Args.uMsr = uMsr;
2878 Args.uValue = uValue;
2879 Args.fGp = true;
2880
2881 if (idCpu == NIL_RTCPUID)
2882 supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2883 else
2884 {
2885 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2886 if (RT_FAILURE(rc))
2887 return rc;
2888 }
2889
2890 if (Args.fGp)
2891 return VERR_ACCESS_DENIED;
2892 return VINF_SUCCESS;
2893}
2894
2895/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2896static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2897{
2898 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
2899 register uint32_t uMsr = pReq->u.In.uMsr;
2900 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2901 uint64_t uBefore = 0;
2902 uint64_t uWritten = 0;
2903 uint64_t uAfter = 0;
2904 bool fBeforeGp = true;
2905 bool fModifyGp = true;
2906 bool fAfterGp = true;
2907 bool fRestoreGp = true;
2908 RTCCUINTREG fOldFlags;
2909 RT_NOREF2(idCpu, pvUser2);
2910
2911 /*
2912 * Do the job.
2913 */
2914 fOldFlags = ASMIntDisableFlags();
2915 ASMCompilerBarrier(); /* paranoia */
2916 if (!fFaster)
2917 ASMWriteBackAndInvalidateCaches();
2918
2919 __try
2920 {
2921 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2922 fBeforeGp = false;
2923 }
2924 __except(EXCEPTION_EXECUTE_HANDLER)
2925 {
2926 fBeforeGp = true;
2927 }
2928 if (!fBeforeGp)
2929 {
2930 register uint64_t uRestore = uBefore;
2931
2932 /* Modify. */
2933 uWritten = uRestore;
2934 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2935 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2936 __try
2937 {
2938 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2939 fModifyGp = false;
2940 }
2941 __except(EXCEPTION_EXECUTE_HANDLER)
2942 {
2943 fModifyGp = true;
2944 }
2945
2946 /* Read modified value. */
2947 __try
2948 {
2949 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2950 fAfterGp = false;
2951 }
2952 __except(EXCEPTION_EXECUTE_HANDLER)
2953 {
2954 fAfterGp = true;
2955 }
2956
2957 /* Restore original value. */
2958 __try
2959 {
2960 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2961 fRestoreGp = false;
2962 }
2963 __except(EXCEPTION_EXECUTE_HANDLER)
2964 {
2965 fRestoreGp = true;
2966 }
2967
2968 /* Invalid everything we can. */
2969 if (!fFaster)
2970 {
2971 ASMWriteBackAndInvalidateCaches();
2972 ASMReloadCR3();
2973 ASMNopPause();
2974 }
2975 }
2976
2977 ASMCompilerBarrier(); /* paranoia */
2978 ASMSetFlags(fOldFlags);
2979
2980 /*
2981 * Write out the results.
2982 */
2983 pReq->u.Out.uResults.Modify.uBefore = uBefore;
2984 pReq->u.Out.uResults.Modify.uWritten = uWritten;
2985 pReq->u.Out.uResults.Modify.uAfter = uAfter;
2986 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
2987 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
2988 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
2989 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2990 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2991}
2992
2993
2994int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2995{
2996 if (idCpu == NIL_RTCPUID)
2997 {
2998 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2999 return VINF_SUCCESS;
3000 }
3001 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
3002}
3003
3004#endif /* SUPDRV_WITH_MSR_PROBER */
3005
3006
3007/**
3008 * Converts an IPRT error code to an nt status code.
3009 *
3010 * @returns corresponding nt status code.
3011 * @param rc IPRT error status code.
3012 */
3013static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
3014{
3015 switch (rc)
3016 {
3017 case VINF_SUCCESS: return STATUS_SUCCESS;
3018 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
3019 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
3020 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
3021 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
3022 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
3023 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
3024 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
3025 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
3026 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
3027 }
3028
3029 if (rc < 0)
3030 {
3031 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
3032 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
3033 }
3034 return STATUS_UNSUCCESSFUL;
3035}
3036
3037
3038SUPR0DECL(int) SUPR0PrintfV(const char *pszFormat, va_list va)
3039{
3040 char szMsg[384];
3041 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
3042 szMsg[sizeof(szMsg) - 1] = '\0';
3043
3044 RTLogWriteDebugger(szMsg, cch);
3045 return 0;
3046}
3047
3048
3049SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
3050{
3051 return 0;
3052}
3053
3054
3055SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook)
3056{
3057 RT_NOREF(fCtxHook);
3058 return false;
3059}
3060
3061
3062SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook)
3063{
3064 RT_NOREF(fCtxHook);
3065}
3066
3067
3068SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
3069{
3070 /*
3071 * Validate input.
3072 */
3073 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
3074 *ppCtx = NULL;
3075 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3076 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
3077
3078 /*
3079 * Turn the partition handle into a file object and related device object
3080 * so that we can issue direct I/O control calls to the pair later.
3081 */
3082 PFILE_OBJECT pFileObject = NULL;
3083 OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
3084 NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
3085 UserMode, (void **)&pFileObject, &HandleInfo);
3086 if (!NT_SUCCESS(rcNt))
3087 return RTErrConvertFromNtStatus(rcNt);
3088 AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
3089
3090 PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
3091 AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
3092 ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
3093
3094 /*
3095 * Allocate a context structure and fill it in.
3096 */
3097 PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
3098 if (pCtx)
3099 {
3100 pCtx->u32Magic = SUPR0IOCTLCTX_MAGIC;
3101 pCtx->cRefs = 1;
3102 pCtx->pFileObject = pFileObject;
3103 pCtx->pDeviceObject = pDevObject;
3104
3105 PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
3106 if ( RT_VALID_PTR(pDrvObject->FastIoDispatch)
3107 && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
3108 pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
3109 else
3110 pCtx->pfnFastIoDeviceControl = NULL;
3111 *ppCtx = pCtx;
3112 return VINF_SUCCESS;
3113 }
3114
3115 ObDereferenceObject(pFileObject);
3116 return VERR_NO_MEMORY;
3117}
3118
3119
3120/**
3121 * I/O control destructor for NT.
3122 *
3123 * @param pCtx The context to destroy.
3124 */
3125static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
3126{
3127 PFILE_OBJECT pFileObject = pCtx->pFileObject;
3128 pCtx->pfnFastIoDeviceControl = NULL;
3129 pCtx->pFileObject = NULL;
3130 pCtx->pDeviceObject = NULL;
3131 ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
3132
3133 if (RT_VALID_PTR(pFileObject))
3134 ObDereferenceObject(pFileObject);
3135 RTMemFree(pCtx);
3136}
3137
3138
3139SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
3140{
3141 if (pCtx != NULL)
3142 {
3143 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
3144 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
3145
3146 uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3147 Assert(cRefs < _4K);
3148 if (cRefs == 0)
3149 supdrvNtIoCtlContextDestroy(pCtx);
3150 }
3151 return VINF_SUCCESS;
3152}
3153
3154
3155SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
3156 void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
3157 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
3158 int32_t *piNativeRc)
3159{
3160 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
3161 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
3162
3163 /* Reference the context. */
3164 uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
3165 Assert(cRefs > 1 && cRefs < _4K);
3166
3167 /*
3168 * Try fast I/O control path first.
3169 */
3170 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
3171 if (pCtx->pfnFastIoDeviceControl)
3172 {
3173 /* Must pass user addresses here as that's what's being expected. */
3174 BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
3175 TRUE /*Wait*/,
3176 (void *)pvInputUser, (ULONG)cbInput,
3177 (void *)pvOutputUser, (ULONG)cbOutput,
3178 uFunction,
3179 &Ios,
3180 pCtx->pDeviceObject);
3181 if (fHandled)
3182 {
3183 /* Relase the context. */
3184 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3185 Assert(cRefs < _4K);
3186 if (cRefs == 0)
3187 supdrvNtIoCtlContextDestroy(pCtx);
3188
3189 /* Set/convert status and return. */
3190 if (piNativeRc)
3191 {
3192 *piNativeRc = Ios.Status;
3193 return VINF_SUCCESS;
3194 }
3195 if (NT_SUCCESS(Ios.Status))
3196 return VINF_SUCCESS;
3197 return RTErrConvertFromNtStatus(Ios.Status);
3198 }
3199
3200 /*
3201 * Fall back on IRP if not handled.
3202 *
3203 * Note! Perhaps we should rather fail, because VID.SYS will crash getting
3204 * the partition ID with the code below. It tries to zero the output
3205 * buffer as if it were as system buffer...
3206 */
3207 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
3208 }
3209
3210 /*
3211 * For directly accessed buffers we must supply user mode addresses or
3212 * we'll fail ProbeForWrite validation.
3213 */
3214 switch (uFunction & 3)
3215 {
3216 case METHOD_BUFFERED:
3217 /* For buffered accesses, we can supply kernel buffers. */
3218 break;
3219
3220 case METHOD_IN_DIRECT:
3221 pvInput = (void *)pvInputUser;
3222 break;
3223
3224 case METHOD_NEITHER:
3225 pvInput = (void *)pvInputUser;
3226 RT_FALL_THRU();
3227
3228 case METHOD_OUT_DIRECT:
3229 pvOutput = (void *)pvOutputUser;
3230 break;
3231 }
3232
3233 /*
3234 * Build the request.
3235 */
3236 int rc;
3237 KEVENT Event;
3238 KeInitializeEvent(&Event, NotificationEvent, FALSE);
3239
3240 PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
3241 pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
3242 FALSE /* InternalDeviceControl */, &Event, &Ios);
3243 if (pIrp)
3244 {
3245 IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
3246
3247 /*
3248 * Make the call.
3249 */
3250 NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
3251 if (rcNt == STATUS_PENDING)
3252 {
3253 rcNt = KeWaitForSingleObject(&Event, /* Object */
3254 Executive, /* WaitReason */
3255 KernelMode, /* WaitMode */
3256 FALSE, /* Alertable */
3257 NULL); /* TimeOut */
3258 AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
3259 rcNt = Ios.Status;
3260 }
3261 else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
3262 rcNt = Ios.Status;
3263
3264 /* Set/convert return code. */
3265 if (piNativeRc)
3266 {
3267 *piNativeRc = rcNt;
3268 rc = VINF_SUCCESS;
3269 }
3270 else if (NT_SUCCESS(rcNt))
3271 rc = VINF_SUCCESS;
3272 else
3273 rc = RTErrConvertFromNtStatus(rcNt);
3274 }
3275 else
3276 {
3277 if (piNativeRc)
3278 *piNativeRc = STATUS_NO_MEMORY;
3279 rc = VERR_NO_MEMORY;
3280 }
3281
3282 /* Relase the context. */
3283 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3284 Assert(cRefs < _4K);
3285 if (cRefs == 0)
3286 supdrvNtIoCtlContextDestroy(pCtx);
3287
3288 return rc;
3289}
3290
3291
3292#ifdef VBOX_WITH_HARDENING
3293
3294/** @name Identifying Special Processes: CSRSS.EXE
3295 * @{ */
3296
3297
3298/**
3299 * Checks if the process is a system32 process by the given name.
3300 *
3301 * @returns true / false.
3302 * @param pProcess The process to check.
3303 * @param pszName The lower case process name (no path!).
3304 */
3305static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
3306{
3307 Assert(strlen(pszName) < 16); /* see buffer below */
3308
3309 /*
3310 * This test works on XP+.
3311 */
3312 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3313 if (!pszImageFile)
3314 return false;
3315
3316 if (RTStrICmp(pszImageFile, pszName) != 0)
3317 return false;
3318
3319 /*
3320 * This test requires a Vista+ API.
3321 */
3322 if (g_pfnPsReferenceProcessFilePointer)
3323 {
3324 PFILE_OBJECT pFile = NULL;
3325 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
3326 if (!NT_SUCCESS(rcNt))
3327 return false;
3328
3329 union
3330 {
3331 OBJECT_NAME_INFORMATION Info;
3332 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
3333 } Buf;
3334 ULONG cbIgn;
3335 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
3336 ObDereferenceObject(pFile);
3337 if (!NT_SUCCESS(rcNt))
3338 return false;
3339
3340 /* Terminate the name. */
3341 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
3342 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
3343
3344 /* Match the name against the system32 directory path. */
3345 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
3346 if (Buf.Info.Name.Length < cbSystem32)
3347 return false;
3348 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
3349 return false;
3350 pwszName += cbSystem32 / sizeof(RTUTF16);
3351 if (*pwszName++ != '\\')
3352 return false;
3353
3354 /* Compare the name. */
3355 const char *pszRight = pszName;
3356 for (;;)
3357 {
3358 WCHAR wchLeft = *pwszName++;
3359 char chRight = *pszRight++;
3360 Assert(chRight == RT_C_TO_LOWER(chRight));
3361
3362 if ( wchLeft != chRight
3363 && RT_C_TO_LOWER(wchLeft) != chRight)
3364 return false;
3365 if (!chRight)
3366 break;
3367 }
3368 }
3369
3370 return true;
3371}
3372
3373
3374/**
3375 * Checks if the current process is likely to be CSRSS.
3376 *
3377 * @returns true/false.
3378 * @param pProcess The process.
3379 */
3380static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
3381{
3382 /*
3383 * On Windows 8.1 CSRSS.EXE is a protected process.
3384 */
3385 if (g_pfnPsIsProtectedProcessLight)
3386 {
3387 if (!g_pfnPsIsProtectedProcessLight(pProcess))
3388 return false;
3389 }
3390
3391 /*
3392 * The name tests.
3393 */
3394 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
3395 return false;
3396
3397 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
3398 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
3399
3400 return true;
3401}
3402
3403
3404/**
3405 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
3406 *
3407 * @returns true if done, false if not.
3408 * @param pwszPortNm The port path.
3409 * @param ppObjType The object type return variable, updated when
3410 * returning true.
3411 */
3412static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
3413{
3414 bool fDone = false;
3415
3416 UNICODE_STRING UniStrPortNm;
3417 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
3418 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
3419 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
3420
3421 OBJECT_ATTRIBUTES ObjAttr;
3422 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
3423
3424 HANDLE hPort;
3425 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
3426 if (NT_SUCCESS(rcNt))
3427 {
3428 PVOID pvObject;
3429 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
3430 KernelMode, &pvObject, NULL /*pHandleInfo*/);
3431 if (NT_SUCCESS(rcNt))
3432 {
3433 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
3434 if (pObjType)
3435 {
3436 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
3437 *ppObjType = pObjType;
3438 fDone = true;
3439 }
3440 ObDereferenceObject(pvObject);
3441 }
3442 NtClose(hPort);
3443 }
3444 return fDone;
3445}
3446
3447
3448/**
3449 * Attempts to retrieve the ALPC Port object type.
3450 *
3451 * We've had at least three reports that using LpcPortObjectType when trying to
3452 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
3453 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
3454 * exported) so that it differs from the actual ApiPort type, or maybe this
3455 * unknown entity is intercepting our attempt to reference the port and
3456 * tries to mislead us. The paranoid explanataion is of course that some evil
3457 * root kit like software is messing with the OS, however, it's possible that
3458 * this is valid kernel behavior that 99.8% of our users and 100% of the
3459 * developers are not triggering for some reason.
3460 *
3461 * The code here creates an ALPC port object and gets it's type. It will cache
3462 * the result in g_pAlpcPortObjectType2 on success.
3463 *
3464 * @returns Object type.
3465 * @param uSessionId The session id.
3466 * @param pszSessionId The session id formatted as a string.
3467 */
3468static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
3469{
3470 POBJECT_TYPE pObjType = *LpcPortObjectType;
3471
3472 if ( g_pfnZwAlpcCreatePort
3473 && g_pfnObGetObjectType)
3474 {
3475 int rc;
3476 ssize_t cchTmp; NOREF(cchTmp);
3477 char szTmp[16];
3478 RTUTF16 wszPortNm[128];
3479 size_t offRand;
3480
3481 /*
3482 * First attempt is in the session directory.
3483 */
3484 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3485 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3486 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
3487 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3488 Assert(cchTmp > 0);
3489 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3490 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3491 offRand = RTUtf16Len(wszPortNm);
3492 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3493 Assert(cchTmp > 0);
3494 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3495 AssertRCSuccess(rc);
3496
3497 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3498 if (!fDone)
3499 {
3500 wszPortNm[offRand] = '\0';
3501 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
3502 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3503 AssertRCSuccess(rc);
3504
3505 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3506 }
3507 if (!fDone)
3508 {
3509 /*
3510 * Try base names.
3511 */
3512 if (uSessionId == 0)
3513 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3514 else
3515 {
3516 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3517 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3518 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3519 }
3520 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3521 Assert(cchTmp > 0);
3522 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3523 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3524 offRand = RTUtf16Len(wszPortNm);
3525 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3526 Assert(cchTmp > 0);
3527 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3528 AssertRCSuccess(rc);
3529
3530 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3531 if (!fDone)
3532 {
3533 wszPortNm[offRand] = '\0';
3534 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3535 Assert(cchTmp > 0);
3536 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3537 AssertRCSuccess(rc);
3538
3539 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3540 }
3541 }
3542
3543 /* Cache the result in g_pAlpcPortObjectType2. */
3544 if ( g_pAlpcPortObjectType2 == NULL
3545 && pObjType != g_pAlpcPortObjectType1
3546 && fDone)
3547 g_pAlpcPortObjectType2 = pObjType;
3548
3549 }
3550
3551 return pObjType;
3552}
3553
3554
3555/**
3556 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
3557 * current process.
3558 *
3559 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
3560 * additional access right so we need to make 101% sure we correctly identify
3561 * the CSRSS process a process is associated with.
3562 *
3563 * @returns IPRT status code.
3564 * @param pNtProtect The NT protected process structure. The
3565 * hCsrssPid member will be updated on success.
3566 */
3567static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
3568{
3569 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
3570 Assert(pNtProtect->pCsrssProcess == NULL);
3571 Assert(pNtProtect->hCsrssPid == NULL);
3572
3573 /*
3574 * We'll try use the ApiPort LPC object for the session we're in to track
3575 * down the CSRSS process. So, we start by constructing a path to it.
3576 */
3577 int rc;
3578 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
3579 char szSessionId[16];
3580 WCHAR wszApiPort[48];
3581 if (uSessionId == 0)
3582 {
3583 szSessionId[0] = '0';
3584 szSessionId[1] = '\0';
3585 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3586 }
3587 else
3588 {
3589 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
3590 AssertReturn(cchTmp > 0, (int)cchTmp);
3591 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
3592 if (RT_SUCCESS(rc))
3593 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
3594 if (RT_SUCCESS(rc))
3595 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3596 }
3597 AssertRCReturn(rc, rc);
3598
3599 UNICODE_STRING ApiPortStr;
3600 ApiPortStr.Buffer = wszApiPort;
3601 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
3602 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
3603
3604 /*
3605 * The object cannot be opened, but we can reference it by name.
3606 */
3607 void *pvApiPortObj = NULL;
3608 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
3609 0,
3610 NULL /*pAccessState*/,
3611 STANDARD_RIGHTS_READ,
3612 g_pAlpcPortObjectType1,
3613 KernelMode,
3614 NULL /*pvParseContext*/,
3615 &pvApiPortObj);
3616 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3617 && g_pAlpcPortObjectType2 != NULL)
3618 rcNt = ObReferenceObjectByName(&ApiPortStr,
3619 0,
3620 NULL /*pAccessState*/,
3621 STANDARD_RIGHTS_READ,
3622 g_pAlpcPortObjectType2,
3623 KernelMode,
3624 NULL /*pvParseContext*/,
3625 &pvApiPortObj);
3626 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3627 && g_pfnObGetObjectType
3628 && g_pfnZwAlpcCreatePort)
3629 rcNt = ObReferenceObjectByName(&ApiPortStr,
3630 0,
3631 NULL /*pAccessState*/,
3632 STANDARD_RIGHTS_READ,
3633 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
3634 KernelMode,
3635 NULL /*pvParseContext*/,
3636 &pvApiPortObj);
3637 if (!NT_SUCCESS(rcNt))
3638 {
3639 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
3640 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
3641 }
3642
3643 /*
3644 * Query the processes in the system so we can locate CSRSS.EXE candidates.
3645 * Note! Attempts at using SystemSessionProcessInformation failed with
3646 * STATUS_ACCESS_VIOLATION.
3647 * Note! The 32 bytes on the size of to counteract the allocation header
3648 * that rtR0MemAllocEx slaps on everything.
3649 */
3650 ULONG cbNeeded = _64K - 32;
3651 uint32_t cbBuf;
3652 uint8_t *pbBuf = NULL;
3653 do
3654 {
3655 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
3656 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3657 if (!pbBuf)
3658 break;
3659
3660 cbNeeded = 0;
3661#if 0 /* doesn't work. */
3662 SYSTEM_SESSION_PROCESS_INFORMATION Req;
3663 Req.SessionId = uSessionId;
3664 Req.BufferLength = cbBuf;
3665 Req.Buffer = pbBuf;
3666 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
3667#else
3668 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
3669#endif
3670 if (NT_SUCCESS(rcNt))
3671 break;
3672
3673 RTMemFree(pbBuf);
3674 pbBuf = NULL;
3675 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3676 && cbNeeded > cbBuf
3677 && cbNeeded < 32U*_1M);
3678
3679 if ( pbBuf
3680 && NT_SUCCESS(rcNt)
3681 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
3682 {
3683 /*
3684 * Walk the returned data and look for the process associated with the
3685 * ApiPort object. The ApiPort object keeps the EPROCESS address of
3686 * the owner process (i.e. CSRSS) relatively early in the structure. On
3687 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
3688 * pointer to likely CSRSS processes and check for a match in the first
3689 * 0x40 bytes of the ApiPort object.
3690 */
3691 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
3692 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
3693 {
3694 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
3695 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
3696 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
3697 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
3698 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
3699 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
3700 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
3701 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
3702 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
3703 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
3704 && pProcInfo->ProcessName.Buffer[5] == '.'
3705 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
3706 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
3707 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
3708 {
3709
3710 /* Get the process structure and perform some more thorough
3711 process checks. */
3712 PEPROCESS pProcess;
3713 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
3714 if (NT_SUCCESS(rcNt))
3715 {
3716 if (supdrvNtProtectIsCsrssByProcess(pProcess))
3717 {
3718 if (PsGetProcessSessionId(pProcess) == uSessionId)
3719 {
3720 /* Final test, check the ApiPort.
3721 Note! The old LPC (pre Vista) objects has the PID
3722 much earlier in the structure. Might be
3723 worth looking for it instead. */
3724 bool fThatsIt = false;
3725 __try
3726 {
3727 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
3728 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
3729 do
3730 {
3731 fThatsIt = *ppPortProc == pProcess;
3732 ppPortProc++;
3733 } while (!fThatsIt && --cTests > 0);
3734 }
3735 __except(EXCEPTION_EXECUTE_HANDLER)
3736 {
3737 fThatsIt = false;
3738 }
3739 if (fThatsIt)
3740 {
3741 /* Ok, we found it! Keep the process structure
3742 reference as well as the PID so we can
3743 safely identify it later on. */
3744 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
3745 pNtProtect->pCsrssProcess = pProcess;
3746 rc = VINF_SUCCESS;
3747 break;
3748 }
3749 }
3750 }
3751
3752 ObDereferenceObject(pProcess);
3753 }
3754 }
3755
3756 /* Advance. */
3757 if (!pProcInfo->NextEntryOffset)
3758 break;
3759 offBuf += pProcInfo->NextEntryOffset;
3760 }
3761 }
3762 else
3763 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
3764 RTMemFree(pbBuf);
3765 ObDereferenceObject(pvApiPortObj);
3766 return rc;
3767}
3768
3769
3770/**
3771 * Checks that the given process is the CSRSS process associated with protected
3772 * process.
3773 *
3774 * @returns true / false.
3775 * @param pNtProtect The NT protection structure.
3776 * @param pCsrss The process structure of the alleged CSRSS.EXE
3777 * process.
3778 */
3779static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
3780{
3781 if (pNtProtect->pCsrssProcess == pCsrss)
3782 {
3783 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
3784 {
3785 return true;
3786 }
3787 }
3788 return false;
3789}
3790
3791
3792/**
3793 * Checks if the given process is the stupid themes service.
3794 *
3795 * The caller does some screening of access masks and what not. We do the rest.
3796 *
3797 * @returns true / false.
3798 * @param pNtProtect The NT protection structure.
3799 * @param pAnnoyingProcess The process structure of an process that might
3800 * happen to be the annoying themes process.
3801 */
3802static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3803{
3804 RT_NOREF1(pNtProtect);
3805
3806 /*
3807 * Check the process name.
3808 */
3809 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3810 return false;
3811
3812 /** @todo Come up with more checks. */
3813
3814 return true;
3815}
3816
3817
3818#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3819/**
3820 * Checks if the given process is one of the whitelisted debuggers.
3821 *
3822 * @returns true / false.
3823 * @param pProcess The process to check.
3824 */
3825static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3826{
3827 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3828 if (!pszImageFile)
3829 return false;
3830
3831 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3832 {
3833 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3834 return true;
3835 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3836 return true;
3837 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3838 return true;
3839 }
3840 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3841 {
3842 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3843 return true;
3844 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3845 return true;
3846 }
3847
3848 return false;
3849}
3850#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3851
3852
3853/** @} */
3854
3855
3856/** @name Process Creation Callbacks.
3857 * @{ */
3858
3859
3860/**
3861 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3862 *
3863 * @param hProcessId The ID of the dead process.
3864 */
3865static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3866{
3867 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3868 if (RT_SUCCESS(rc))
3869 {
3870 PSUPDRVNTERRORINFO pCur, pNext;
3871 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3872 {
3873 if (pCur->hProcessId == hProcessId)
3874 {
3875 RTListNodeRemove(&pCur->ListEntry);
3876 RTMemFree(pCur);
3877 }
3878 }
3879 RTSemMutexRelease(g_hErrorInfoLock);
3880 }
3881}
3882
3883
3884/**
3885 * Common worker used by the process creation hooks as well as the process
3886 * handle creation hooks to check if a VM process is being created.
3887 *
3888 * @returns true if likely to be a VM process, false if not.
3889 * @param pNtStub The NT protection structure for the possible
3890 * stub process.
3891 * @param hParentPid The parent pid.
3892 * @param hChildPid The child pid.
3893 */
3894static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3895{
3896 bool fRc = false;
3897 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3898 {
3899 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3900 {
3901 /* Compare short names. */
3902 PEPROCESS pStubProcess;
3903 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3904 if (NT_SUCCESS(rcNt))
3905 {
3906 PEPROCESS pChildProcess;
3907 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3908 if (NT_SUCCESS(rcNt))
3909 {
3910 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
3911 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3912 fRc = pszStub != NULL
3913 && pszChild != NULL
3914 && strcmp(pszStub, pszChild) == 0;
3915
3916 /** @todo check that the full image names matches. */
3917
3918 ObDereferenceObject(pChildProcess);
3919 }
3920 ObDereferenceObject(pStubProcess);
3921 }
3922 }
3923 }
3924 return fRc;
3925}
3926
3927
3928/**
3929 * Common code used by the notifies to protect a child process.
3930 *
3931 * @returns VBox status code.
3932 * @param pNtStub The NT protect structure for the parent.
3933 * @param hChildPid The child pid.
3934 */
3935static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3936{
3937 /*
3938 * Create a child protection struction.
3939 */
3940 PSUPDRVNTPROTECT pNtChild;
3941 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3942 if (RT_SUCCESS(rc))
3943 {
3944 pNtChild->fFirstProcessCreateHandle = true;
3945 pNtChild->fFirstThreadCreateHandle = true;
3946 pNtChild->fCsrssFirstProcessCreateHandle = true;
3947 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3948 pNtChild->fThemesFirstProcessCreateHandle = true;
3949 pNtChild->hParentPid = pNtParent->AvlCore.Key;
3950 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3951 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3952 if (pNtChild->pCsrssProcess)
3953 ObReferenceObject(pNtChild->pCsrssProcess);
3954
3955 /*
3956 * Take the spinlock, recheck parent conditions and link things.
3957 */
3958 RTSpinlockAcquire(g_hNtProtectLock);
3959 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3960 {
3961 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3962 if (fSuccess)
3963 {
3964 pNtChild->fInTree = true;
3965 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
3966 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3967 pNtChild->u.pParent = pNtParent;
3968
3969 RTSpinlockRelease(g_hNtProtectLock);
3970 return VINF_SUCCESS;
3971 }
3972
3973 rc = VERR_INTERNAL_ERROR_2;
3974 }
3975 else
3976 rc = VERR_WRONG_ORDER;
3977 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3978 RTSpinlockRelease(g_hNtProtectLock);
3979
3980 supdrvNtProtectRelease(pNtChild);
3981 }
3982 return rc;
3983}
3984
3985
3986/**
3987 * Common process termination code.
3988 *
3989 * Transitions protected process to the dead states, protecting against handle
3990 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3991 *
3992 * @param hDeadPid The PID of the dead process.
3993 */
3994static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3995{
3996 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3997 if (pNtProtect)
3998 {
3999 PSUPDRVNTPROTECT pNtChild = NULL;
4000
4001 RTSpinlockAcquire(g_hNtProtectLock);
4002
4003 /*
4004 * If this is an unconfirmed VM process, we must release the reference
4005 * the parent structure holds.
4006 */
4007 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4008 {
4009 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
4010 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
4011 pNtParent->u.pChild = NULL;
4012 pNtProtect->u.pParent = NULL;
4013 pNtChild = pNtProtect;
4014 }
4015 /*
4016 * If this is a stub exitting before the VM process gets confirmed,
4017 * release the protection of the potential VM process as this is not
4018 * the prescribed behavior.
4019 */
4020 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
4021 && pNtProtect->u.pChild)
4022 {
4023 pNtChild = pNtProtect->u.pChild;
4024 pNtProtect->u.pChild = NULL;
4025 pNtChild->u.pParent = NULL;
4026 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4027 }
4028
4029 /*
4030 * Transition it to the dead state to prevent it from opening the
4031 * support driver again or be posthumously abused as a vm process parent.
4032 */
4033 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4034 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
4035 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4036 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
4037 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
4038 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4039 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
4040
4041 RTSpinlockRelease(g_hNtProtectLock);
4042
4043 supdrvNtProtectRelease(pNtProtect);
4044 supdrvNtProtectRelease(pNtChild);
4045
4046 /*
4047 * Do session cleanups.
4048 */
4049 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
4050 if (g_pDevObjSys)
4051 {
4052 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
4053 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
4054 RTR0ProcHandleSelf(), NULL);
4055 if (pSession)
4056 {
4057 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
4058 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
4059 }
4060 }
4061 }
4062}
4063
4064
4065/**
4066 * Common worker for the process creation callback that verifies a new child
4067 * being created by the handle creation callback code.
4068 *
4069 * @param pNtStub The parent.
4070 * @param pNtVm The child.
4071 * @param fCallerChecks The result of any additional tests the caller made.
4072 * This is in order to avoid duplicating the failure
4073 * path code.
4074 */
4075static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
4076{
4077 if ( fCallerChecks
4078 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
4079 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4080 && pNtVm->u.pParent == pNtStub
4081 && pNtStub->u.pChild == pNtVm)
4082 {
4083 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
4084 pNtVm->fFirstProcessCreateHandle = true;
4085 return;
4086 }
4087
4088 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
4089 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
4090 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
4091}
4092
4093
4094/**
4095 * Old style callback (since forever).
4096 *
4097 * @param hParentPid The parent PID.
4098 * @param hNewPid The PID of the new child.
4099 * @param fCreated TRUE if it's a creation notification,
4100 * FALSE if termination.
4101 * @remarks ASSUMES this arrives before the handle creation callback.
4102 */
4103static VOID __stdcall
4104supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
4105{
4106 /*
4107 * Is it a new process that needs protection?
4108 */
4109 if (fCreated)
4110 {
4111 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
4112 if (pNtStub)
4113 {
4114 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
4115 if (!pNtVm)
4116 {
4117 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
4118 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
4119 }
4120 else
4121 {
4122 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
4123 supdrvNtProtectRelease(pNtVm);
4124 }
4125 supdrvNtProtectRelease(pNtStub);
4126 }
4127 }
4128 /*
4129 * Process termination, do clean ups.
4130 */
4131 else
4132 {
4133 supdrvNtProtectUnprotectDeadProcess(hNewPid);
4134 supdrvNtErrorInfoCleanupProcess(hNewPid);
4135 }
4136}
4137
4138
4139/**
4140 * New style callback (Vista SP1+ / w2k8).
4141 *
4142 * @param pNewProcess The new process.
4143 * @param hNewPid The PID of the new process.
4144 * @param pInfo Process creation details. NULL if process
4145 * termination notification.
4146 * @remarks ASSUMES this arrives before the handle creation callback.
4147 */
4148static VOID __stdcall
4149supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
4150{
4151 RT_NOREF1(pNewProcess);
4152
4153 /*
4154 * Is it a new process that needs protection?
4155 */
4156 if (pInfo)
4157 {
4158 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
4159
4160 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
4161 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4162 hNewPid, pInfo->ParentProcessId,
4163 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
4164 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
4165 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
4166
4167 if (pNtStub)
4168 {
4169 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
4170 if (!pNtVm)
4171 {
4172 /* Parent must be creator. */
4173 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
4174 {
4175 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
4176 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
4177 }
4178 }
4179 else
4180 {
4181 /* Parent must be creator (as above). */
4182 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
4183 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
4184 supdrvNtProtectRelease(pNtVm);
4185 }
4186 supdrvNtProtectRelease(pNtStub);
4187 }
4188 }
4189 /*
4190 * Process termination, do clean ups.
4191 */
4192 else
4193 {
4194 supdrvNtProtectUnprotectDeadProcess(hNewPid);
4195 supdrvNtErrorInfoCleanupProcess(hNewPid);
4196 }
4197}
4198
4199/** @} */
4200
4201
4202/** @name Process Handle Callbacks.
4203 * @{ */
4204
4205/** Process rights that we allow for handles to stub and VM processes. */
4206# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
4207 ( PROCESS_TERMINATE \
4208 | PROCESS_VM_READ \
4209 | PROCESS_QUERY_INFORMATION \
4210 | PROCESS_QUERY_LIMITED_INFORMATION \
4211 | PROCESS_SUSPEND_RESUME \
4212 | DELETE \
4213 | READ_CONTROL \
4214 | SYNCHRONIZE)
4215
4216/** Evil process rights. */
4217# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
4218 ( PROCESS_CREATE_THREAD \
4219 | PROCESS_SET_SESSIONID /*?*/ \
4220 | PROCESS_VM_OPERATION \
4221 | PROCESS_VM_WRITE \
4222 | PROCESS_DUP_HANDLE \
4223 | PROCESS_CREATE_PROCESS /*?*/ \
4224 | PROCESS_SET_QUOTA /*?*/ \
4225 | PROCESS_SET_INFORMATION \
4226 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
4227 | 0)
4228AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
4229
4230
4231static OB_PREOP_CALLBACK_STATUS __stdcall
4232supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4233{
4234 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4235 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4236 Assert(pOpInfo->ObjectType == *PsProcessType);
4237
4238 /*
4239 * Protected? Kludge required for NtOpenProcess calls comming in before
4240 * the create process hook triggers on Windows 8.1 (possibly others too).
4241 */
4242 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
4243 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
4244 if (!pNtProtect)
4245 {
4246 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
4247 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
4248 if (pNtStub)
4249 {
4250 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
4251 {
4252 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
4253 pNtProtect = supdrvNtProtectLookup(hObjPid);
4254 }
4255 supdrvNtProtectRelease(pNtStub);
4256 }
4257 }
4258 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4259 if (pNtProtect)
4260 {
4261 /*
4262 * Ok, it's a protected process. Strip rights as required or possible.
4263 */
4264 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4265 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
4266
4267 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4268 {
4269 /* Don't restrict the process accessing itself. */
4270 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
4271 {
4272 pOpInfo->CallContext = NULL; /* don't assert */
4273 pNtProtect->fFirstProcessCreateHandle = false;
4274
4275 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
4276 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4277 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4278 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4279 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4280 }
4281#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4282 /* Allow debuggers full access. */
4283 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4284 {
4285 pOpInfo->CallContext = NULL; /* don't assert */
4286 pNtProtect->fFirstProcessCreateHandle = false;
4287
4288 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4289 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4290 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4291 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4292 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4293 }
4294#endif
4295 else
4296 {
4297 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
4298
4299 /* Special case 1 on Vista, 7 & 8:
4300 The CreateProcess code passes the handle over to CSRSS.EXE
4301 and the code inBaseSrvCreateProcess will duplicate the
4302 handle with 0x1fffff as access mask. NtDuplicateObject will
4303 fail this call before it ever gets down here.
4304
4305 Special case 2 on 8.1:
4306 The CreateProcess code requires additional rights for
4307 something, we'll drop these in the stub code. */
4308 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4309 && pNtProtect->fFirstProcessCreateHandle
4310 && pOpInfo->KernelHandle == 0
4311 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
4312 && ExGetPreviousMode() != KernelMode)
4313 {
4314 if ( !pOpInfo->KernelHandle
4315 && fDesiredAccess == s_fCsrssStupidDesires)
4316 {
4317 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
4318 fAllowedRights |= s_fCsrssStupidDesires;
4319 else
4320 fAllowedRights = fAllowedRights
4321 | PROCESS_VM_OPERATION
4322 | PROCESS_VM_WRITE
4323 | PROCESS_SET_INFORMATION
4324 | PROCESS_SET_LIMITED_INFORMATION
4325 | 0;
4326 pOpInfo->CallContext = NULL; /* don't assert this. */
4327 }
4328 pNtProtect->fFirstProcessCreateHandle = false;
4329 }
4330
4331 /* Special case 3 on 8.1:
4332 The interaction between the CreateProcess code and CSRSS.EXE
4333 has changed to the better with Windows 8.1. CSRSS.EXE no
4334 longer duplicates the process (thread too) handle, but opens
4335 it, thus allowing us to do our job. */
4336 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
4337 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4338 && pNtProtect->fCsrssFirstProcessCreateHandle
4339 && pOpInfo->KernelHandle == 0
4340 && ExGetPreviousMode() == UserMode
4341 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4342 {
4343 pNtProtect->fCsrssFirstProcessCreateHandle = false;
4344 if (fDesiredAccess == s_fCsrssStupidDesires)
4345 {
4346 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4347 PROCESS_CREATE_PROCESS */
4348 fAllowedRights = fAllowedRights
4349 | PROCESS_VM_OPERATION
4350 | PROCESS_VM_WRITE
4351 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
4352 | 0;
4353 pOpInfo->CallContext = NULL; /* don't assert this. */
4354 }
4355 }
4356
4357 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
4358 The Themes service requires PROCESS_DUP_HANDLE access to our
4359 process or we won't get any menus and dialogs will be half
4360 unreadable. This is _very_ unfortunate and more work will
4361 go into making this more secure. */
4362 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
4363 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
4364 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
4365 && pNtProtect->fThemesFirstProcessCreateHandle
4366 && pOpInfo->KernelHandle == 0
4367 && ExGetPreviousMode() == UserMode
4368 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
4369 {
4370 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
4371 fAllowedRights |= PROCESS_DUP_HANDLE;
4372 pOpInfo->CallContext = NULL; /* don't assert this. */
4373 }
4374
4375 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
4376 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
4377 some myserious and weirdly placed cpu set management of our process.
4378 I'd love to understand what that's all about...
4379 Currently playing safe and only grand this right, however limited, to
4380 audiodg.exe. */
4381 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4382 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4383 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4384 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4385 )
4386 && pOpInfo->KernelHandle == 0
4387 && ExGetPreviousMode() == UserMode
4388 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4389 {
4390 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4391 pOpInfo->CallContext = NULL; /* don't assert this. */
4392 }
4393
4394 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4395 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4396 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4397 fAllowedRights, fDesiredAccess & fAllowedRights,
4398 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
4399
4400 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4401 }
4402 }
4403 else
4404 {
4405 /* Don't restrict the process accessing itself. */
4406 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
4407 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
4408 {
4409 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4410 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4411 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4412 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4413 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4414 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4415 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4416 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4417
4418 pOpInfo->CallContext = NULL; /* don't assert */
4419 }
4420 else
4421 {
4422 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
4423
4424 /* Special case 5 on Vista, 7 & 8:
4425 This is the CSRSS.EXE end of special case #1. */
4426 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4427 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4428 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
4429 && pOpInfo->KernelHandle == 0
4430 && fDesiredAccess == s_fCsrssStupidDesires
4431 && pNtProtect->hParentPid
4432 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
4433 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4434 && ExGetPreviousMode() == UserMode
4435 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
4436 {
4437 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
4438 {
4439 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4440 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
4441 fAllowedRights = fAllowedRights
4442 | PROCESS_VM_OPERATION
4443 | PROCESS_VM_WRITE
4444 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
4445 | 0;
4446 pOpInfo->CallContext = NULL; /* don't assert this. */
4447 }
4448 }
4449
4450 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
4451 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4452 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4453 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4454 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4455 )
4456 && pOpInfo->KernelHandle == 0
4457 && ExGetPreviousMode() == UserMode
4458 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4459 {
4460 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4461 pOpInfo->CallContext = NULL; /* don't assert this. */
4462 }
4463
4464 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4465 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4466 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4467 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4468 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4469 fDesiredAccess,
4470 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4471 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4472
4473 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4474 }
4475 }
4476 supdrvNtProtectRelease(pNtProtect);
4477 }
4478
4479 return OB_PREOP_SUCCESS;
4480}
4481
4482
4483static VOID __stdcall
4484supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4485{
4486 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4487 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4488 Assert(pOpInfo->ObjectType == *PsProcessType);
4489
4490 if ( pOpInfo->CallContext
4491 && NT_SUCCESS(pOpInfo->ReturnStatus))
4492 {
4493 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
4494 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
4495 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
4496 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4497 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4498 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
4499 /*| PROCESS_UNKNOWN_8000 */ ) )
4500 || pOpInfo->KernelHandle,
4501 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4502 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
4503 }
4504}
4505
4506# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4507
4508/** @} */
4509
4510
4511/** @name Thread Handle Callbacks
4512 * @{ */
4513
4514/* From ntifs.h */
4515extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
4516
4517/** Thread rights that we allow for handles to stub and VM processes. */
4518# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
4519 ( THREAD_TERMINATE \
4520 | THREAD_GET_CONTEXT \
4521 | THREAD_QUERY_INFORMATION \
4522 | THREAD_QUERY_LIMITED_INFORMATION \
4523 | DELETE \
4524 | READ_CONTROL \
4525 | SYNCHRONIZE)
4526/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
4527
4528/** Evil thread rights.
4529 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
4530 * Windows 8.1, at least for some processes. We dont' actively
4531 * allow it though, just tollerate it when forced to. */
4532# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
4533 ( THREAD_SUSPEND_RESUME \
4534 | THREAD_SET_CONTEXT \
4535 | THREAD_SET_INFORMATION \
4536 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
4537 | THREAD_SET_THREAD_TOKEN /*?*/ \
4538 | THREAD_IMPERSONATE /*?*/ \
4539 | THREAD_DIRECT_IMPERSONATION /*?*/ \
4540 /*| THREAD_RESUME - see remarks. */ \
4541 | 0)
4542AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
4543
4544
4545static OB_PREOP_CALLBACK_STATUS __stdcall
4546supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4547{
4548 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4549 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4550 Assert(pOpInfo->ObjectType == *PsThreadType);
4551
4552 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
4553 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
4554 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4555 if (pNtProtect)
4556 {
4557 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4558 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
4559
4560 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4561 {
4562 /* Don't restrict the process accessing its own threads. */
4563 if (pProcess == PsGetCurrentProcess())
4564 {
4565 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
4566 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4567 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4568 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
4569 pOpInfo->CallContext = NULL; /* don't assert */
4570 pNtProtect->fFirstThreadCreateHandle = false;
4571 }
4572#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4573 /* Allow debuggers full access. */
4574 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4575 {
4576 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4577 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4578 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4579 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4580 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4581 pOpInfo->CallContext = NULL; /* don't assert */
4582 }
4583#endif
4584 else
4585 {
4586 /* Special case 1 on Vista, 7, 8:
4587 The CreateProcess code passes the handle over to CSRSS.EXE
4588 and the code inBaseSrvCreateProcess will duplicate the
4589 handle with 0x1fffff as access mask. NtDuplicateObject will
4590 fail this call before it ever gets down here. */
4591 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4592 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4593 && pNtProtect->fFirstThreadCreateHandle
4594 && pOpInfo->KernelHandle == 0
4595 && ExGetPreviousMode() == UserMode
4596 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
4597 {
4598 if ( !pOpInfo->KernelHandle
4599 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
4600 {
4601 fAllowedRights |= s_fCsrssStupidDesires;
4602 pOpInfo->CallContext = NULL; /* don't assert this. */
4603 }
4604 pNtProtect->fFirstThreadCreateHandle = false;
4605 }
4606
4607 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
4608 When creating a process like VBoxTestOGL from the VM process,
4609 CSRSS.EXE will try talk to the calling thread and, it
4610 appears, impersonate it. We unfortunately need to allow
4611 this or there will be no 3D support. Typical DbgPrint:
4612 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
4613 SUPDRVNTPROTECTKIND enmProcessKind;
4614 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4615 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4616 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4617 && pOpInfo->KernelHandle == 0
4618 && ExGetPreviousMode() == UserMode
4619 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4620 {
4621 fAllowedRights |= THREAD_IMPERSONATE;
4622 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4623 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4624 pOpInfo->CallContext = NULL; /* don't assert this. */
4625 }
4626
4627 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4628 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4629 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4630 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4631 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
4632 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
4633
4634 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4635 }
4636 }
4637 else
4638 {
4639 /* Don't restrict the process accessing its own threads. */
4640 if ( pProcess == PsGetCurrentProcess()
4641 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
4642 {
4643 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
4644 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4645 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4646 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4647 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4648 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4649 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4650 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4651 pOpInfo->CallContext = NULL; /* don't assert */
4652 }
4653 else
4654 {
4655 /* Special case 3 on Vista, 7, 8:
4656 This is the follow up to special case 1. */
4657 SUPDRVNTPROTECTKIND enmProcessKind;
4658 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4659 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4660 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4661 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4662 && pOpInfo->KernelHandle == 0
4663 && ExGetPreviousMode() == UserMode
4664 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4665 {
4666 fAllowedRights |= THREAD_IMPERSONATE;
4667 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4668 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4669 pOpInfo->CallContext = NULL; /* don't assert this. */
4670 }
4671
4672 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
4673 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4674 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4675 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4676 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4677 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4678 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4679 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
4680 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4681
4682 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4683 }
4684 }
4685
4686 supdrvNtProtectRelease(pNtProtect);
4687 }
4688
4689 return OB_PREOP_SUCCESS;
4690}
4691
4692
4693static VOID __stdcall
4694supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4695{
4696 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4697 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4698 Assert(pOpInfo->ObjectType == *PsThreadType);
4699
4700 if ( pOpInfo->CallContext
4701 && NT_SUCCESS(pOpInfo->ReturnStatus))
4702 {
4703 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
4704 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4705 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4706 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
4707 ) )
4708 || pOpInfo->KernelHandle,
4709 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4710 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
4711 }
4712}
4713
4714# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4715
4716/** @} */
4717
4718
4719/**
4720 * Creates a new process protection structure.
4721 *
4722 * @returns VBox status code.
4723 * @param ppNtProtect Where to return the pointer to the structure
4724 * on success.
4725 * @param hPid The process ID of the process to protect.
4726 * @param enmProcessKind The kind of process we're protecting.
4727 * @param fLink Whether to link the structure into the tree.
4728 */
4729static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
4730{
4731 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
4732
4733 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
4734 if (!pNtProtect)
4735 return VERR_NO_MEMORY;
4736
4737 pNtProtect->AvlCore.Key = hPid;
4738 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
4739 pNtProtect->cRefs = 1;
4740 pNtProtect->enmProcessKind = enmProcessKind;
4741 pNtProtect->hParentPid = NULL;
4742 pNtProtect->hOpenTid = NULL;
4743 pNtProtect->hCsrssPid = NULL;
4744 pNtProtect->pCsrssProcess = NULL;
4745
4746 if (fLink)
4747 {
4748 RTSpinlockAcquire(g_hNtProtectLock);
4749 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
4750 pNtProtect->fInTree = fSuccess;
4751 RTSpinlockRelease(g_hNtProtectLock);
4752
4753 if (!fSuccess)
4754 {
4755 /* Duplicate entry, fail. */
4756 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
4757 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
4758 RTMemFree(pNtProtect);
4759 return VERR_DUPLICATE;
4760 }
4761 }
4762
4763 *ppNtProtect = pNtProtect;
4764 return VINF_SUCCESS;
4765}
4766
4767
4768/**
4769 * Releases a reference to a NT protection structure.
4770 *
4771 * @param pNtProtect The NT protection structure.
4772 */
4773static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
4774{
4775 if (!pNtProtect)
4776 return;
4777 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
4778
4779 RTSpinlockAcquire(g_hNtProtectLock);
4780 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
4781 if (cRefs != 0)
4782 RTSpinlockRelease(g_hNtProtectLock);
4783 else
4784 {
4785 /*
4786 * That was the last reference. Remove it from the tree, invalidate it
4787 * and free the resources associated with it. Also, release any
4788 * child/parent references related to this protection structure.
4789 */
4790 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
4791 if (pNtProtect->fInTree)
4792 {
4793 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
4794 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
4795 pNtProtect->fInTree = false;
4796 }
4797
4798 PSUPDRVNTPROTECT pChild = NULL;
4799 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4800 {
4801 pChild = pNtProtect->u.pChild;
4802 if (pChild)
4803 {
4804 pNtProtect->u.pChild = NULL;
4805 pChild->u.pParent = NULL;
4806 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4807 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4808 if (!cChildRefs)
4809 {
4810 Assert(pChild->fInTree);
4811 if (pChild->fInTree)
4812 {
4813 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4814 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4815 pChild->fInTree = false;
4816 }
4817 }
4818 else
4819 pChild = NULL;
4820 }
4821 }
4822 else
4823 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4824
4825 RTSpinlockRelease(g_hNtProtectLock);
4826
4827 if (pNtProtect->pCsrssProcess)
4828 {
4829 ObDereferenceObject(pNtProtect->pCsrssProcess);
4830 pNtProtect->pCsrssProcess = NULL;
4831 }
4832
4833 RTMemFree(pNtProtect);
4834 if (pChild)
4835 RTMemFree(pChild);
4836 }
4837}
4838
4839
4840/**
4841 * Looks up a PID in the NT protect tree.
4842 *
4843 * @returns Pointer to a NT protection structure (with a referenced) on success,
4844 * NULL if not found.
4845 * @param hPid The process ID.
4846 */
4847static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4848{
4849 RTSpinlockAcquire(g_hNtProtectLock);
4850 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4851 if (pFound)
4852 ASMAtomicIncU32(&pFound->cRefs);
4853 RTSpinlockRelease(g_hNtProtectLock);
4854 return pFound;
4855}
4856
4857
4858/**
4859 * Validates a few facts about the stub process when the VM process opens
4860 * vboxdrv.
4861 *
4862 * This makes sure the stub process is still around and that it has neither
4863 * debugger nor extra threads in it.
4864 *
4865 * @returns VBox status code.
4866 * @param pNtProtect The unconfirmed VM process currently trying to
4867 * open vboxdrv.
4868 * @param pErrInfo Additional error information.
4869 */
4870static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4871{
4872 /*
4873 * Grab a reference to the parent stub process.
4874 */
4875 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4876 PSUPDRVNTPROTECT pNtStub = NULL;
4877 RTSpinlockAcquire(g_hNtProtectLock);
4878 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4879 {
4880 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4881 if (pNtStub)
4882 {
4883 enmStub = pNtStub->enmProcessKind;
4884 if (enmStub == kSupDrvNtProtectKind_StubParent)
4885 {
4886 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4887 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4888 }
4889 else
4890 pNtStub = NULL;
4891 }
4892 }
4893 RTSpinlockRelease(g_hNtProtectLock);
4894
4895 /*
4896 * We require the stub process to be present.
4897 */
4898 if (!pNtStub)
4899 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4900
4901 /*
4902 * Open the parent process and thread so we can check for debuggers and unwanted threads.
4903 */
4904 int rc;
4905 PEPROCESS pStubProcess;
4906 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4907 if (NT_SUCCESS(rcNt))
4908 {
4909 HANDLE hStubProcess;
4910 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4911 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4912 if (NT_SUCCESS(rcNt))
4913 {
4914 PETHREAD pStubThread;
4915 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4916 if (NT_SUCCESS(rcNt))
4917 {
4918 HANDLE hStubThread;
4919 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4920 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4921 if (NT_SUCCESS(rcNt))
4922 {
4923 /*
4924 * Do some simple sanity checking.
4925 */
4926 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4927 if (RT_SUCCESS(rc))
4928 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4929
4930 /* Clean up. */
4931 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4932 }
4933 else
4934 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4935 "Error opening stub thread %p (tid %p, pid %p): %#x",
4936 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4937 }
4938 else
4939 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4940 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4941 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4942 }
4943 else
4944 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4945 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4946 ObDereferenceObject(pStubProcess);
4947 }
4948 else
4949 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4950 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4951
4952 supdrvNtProtectRelease(pNtStub);
4953 return rc;
4954}
4955
4956
4957static const char *supdrvNtProtectHandleTypeIndexToName(ULONG idxType, char *pszName, size_t cbName)
4958{
4959 /*
4960 * Query the object types.
4961 */
4962 uint32_t cbBuf = _8K;
4963 uint8_t *pbBuf = (uint8_t *)RTMemAllocZ(_8K);
4964 ULONG cbNeeded = cbBuf;
4965 NTSTATUS rcNt = NtQueryObject(NULL, ObjectTypesInformation, pbBuf, cbBuf, &cbNeeded);
4966 while (rcNt == STATUS_INFO_LENGTH_MISMATCH)
4967 {
4968 cbBuf = RT_ALIGN_32(cbNeeded + 256, _64K);
4969 RTMemFree(pbBuf);
4970 pbBuf = (uint8_t *)RTMemAllocZ(cbBuf);
4971 if (pbBuf)
4972 rcNt = NtQueryObject(NULL, ObjectTypesInformation, pbBuf, cbBuf, &cbNeeded);
4973 else
4974 break;
4975 }
4976 if (NT_SUCCESS(rcNt))
4977 {
4978 Assert(cbNeeded <= cbBuf);
4979
4980 POBJECT_TYPES_INFORMATION pObjTypes = (OBJECT_TYPES_INFORMATION *)pbBuf;
4981 POBJECT_TYPE_INFORMATION pCurType = &pObjTypes->FirstType;
4982 ULONG cLeft = pObjTypes->NumberOfTypes;
4983 while (cLeft-- > 0 && (uintptr_t)&pCurType[1] - (uintptr_t)pbBuf < cbNeeded)
4984 {
4985 if (pCurType->TypeIndex == idxType)
4986 {
4987 PCRTUTF16 const pwszSrc = pCurType->TypeName.Buffer;
4988 AssertBreak(pwszSrc);
4989 size_t idxName = pCurType->TypeName.Length / sizeof(RTUTF16);
4990 AssertBreak(idxName > 0);
4991 AssertBreak(idxName < 128);
4992 if (idxName >= cbName)
4993 idxName = cbName - 1;
4994 pszName[idxName] = '\0';
4995 while (idxName-- > 0)
4996 pszName[idxName] = (char )pwszSrc[idxName];
4997 RTMemFree(pbBuf);
4998 return pszName;
4999 }
5000
5001 /* next */
5002 pCurType = (POBJECT_TYPE_INFORMATION)( (uintptr_t)pCurType->TypeName.Buffer
5003 + RT_ALIGN_32(pCurType->TypeName.MaximumLength, sizeof(uintptr_t)));
5004 }
5005 }
5006
5007 RTMemFree(pbBuf);
5008 return "unknown";
5009}
5010
5011
5012/**
5013 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
5014 * process and its thread.
5015 *
5016 * @returns VBox status code.
5017 * @param pNtProtect The NT protect structure for getting information
5018 * about special processes.
5019 * @param pErrInfo Where to return additional error details.
5020 */
5021static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
5022{
5023 /*
5024 * What to protect.
5025 */
5026 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
5027 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
5028 PETHREAD pProtectedThread = PsGetCurrentThread();
5029 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
5030
5031 /*
5032 * Take a snapshot of all the handles in the system.
5033 * Note! The 32 bytes on the size of to counteract the allocation header
5034 * that rtR0MemAllocEx slaps on everything.
5035 */
5036 uint32_t cbBuf = _256K - 32;
5037 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
5038 ULONG cbNeeded = cbBuf;
5039 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
5040 if (!NT_SUCCESS(rcNt))
5041 {
5042 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
5043 && cbNeeded > cbBuf
5044 && cbBuf <= 32U*_1M)
5045 {
5046 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
5047 RTMemFree(pbBuf);
5048 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
5049 if (!pbBuf)
5050 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
5051 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
5052 }
5053 if (!NT_SUCCESS(rcNt))
5054 {
5055 RTMemFree(pbBuf);
5056 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
5057 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
5058 }
5059 }
5060
5061 /*
5062 * Walk the information and look for handles to the two objects we're protecting.
5063 */
5064 int rc = VINF_SUCCESS;
5065# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
5066 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
5067# endif
5068
5069 uint32_t cCsrssProcessHandles = 0;
5070 uint32_t cSystemProcessHandles = 0;
5071 uint32_t cEvilProcessHandles = 0;
5072 uint32_t cBenignProcessHandles = 0;
5073
5074 uint32_t cCsrssThreadHandles = 0;
5075 uint32_t cEvilThreadHandles = 0;
5076 uint32_t cBenignThreadHandles = 0;
5077
5078 uint32_t cEvilInheritableHandles = 0;
5079 uint32_t cBenignInheritableHandles = 0;
5080 char szTmpName[32];
5081
5082 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
5083 ULONG_PTR i = pInfo->NumberOfHandles;
5084 AssertRelease(RT_UOFFSETOF_DYN(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
5085 while (i-- > 0)
5086 {
5087 const char *pszType;
5088 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
5089 if (pHandleInfo->Object == pProtectedProcess)
5090 {
5091 /* Handles within the protected process are fine. */
5092 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
5093 || pHandleInfo->UniqueProcessId == hProtectedPid)
5094 {
5095 cBenignProcessHandles++;
5096 continue;
5097 }
5098
5099 /* CSRSS is allowed to have one evil process handle.
5100 See the special cases in the hook code. */
5101 if ( cCsrssProcessHandles < 1
5102 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
5103 {
5104 cCsrssProcessHandles++;
5105 continue;
5106 }
5107
5108 /* The system process is allowed having two open process handle in
5109 Windows 8.1 and later, and one in earlier. This is probably a
5110 little overly paranoid as I think we can safely trust the
5111 system process... */
5112 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
5113 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
5114 {
5115 cSystemProcessHandles++;
5116 continue;
5117 }
5118
5119 cEvilProcessHandles++;
5120 pszType = "process";
5121 }
5122 else if (pHandleInfo->Object == pProtectedThread)
5123 {
5124 /* Handles within the protected process is fine. */
5125 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
5126 || pHandleInfo->UniqueProcessId == hProtectedPid)
5127 {
5128 cBenignThreadHandles++;
5129 continue;
5130 }
5131
5132 /* CSRSS is allowed to have one evil handle to the primary thread
5133 for LPC purposes. See the hook for special case. */
5134 if ( cCsrssThreadHandles < 1
5135 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
5136 {
5137 cCsrssThreadHandles++;
5138 continue;
5139 }
5140
5141 cEvilThreadHandles++;
5142 pszType = "thread";
5143 }
5144 else if ( (pHandleInfo->HandleAttributes & OBJ_INHERIT)
5145 && pHandleInfo->UniqueProcessId == hProtectedPid)
5146 {
5147 /* No handles should be marked inheritable, except files and two events.
5148 Handles to NT 'directory' objects are especially evil, because of
5149 KnownDlls faking. See bugref{10294} for details.
5150
5151 Correlating the ObjectTypeIndex to a type is complicated, so instead
5152 we try referecing the handle and check the type that way. So, only
5153 file and events objects are allowed to be marked inheritable at the
5154 moment. Add more in whitelist fashion if needed. */
5155 void *pvObject = NULL;
5156 rcNt = ObReferenceObjectByHandle(pHandleInfo->HandleValue, 0, *IoFileObjectType, KernelMode, &pvObject, NULL);
5157 if (rcNt == STATUS_OBJECT_TYPE_MISMATCH)
5158 rcNt = ObReferenceObjectByHandle(pHandleInfo->HandleValue, 0, *ExEventObjectType, KernelMode, &pvObject, NULL);
5159 if (NT_SUCCESS(rcNt))
5160 {
5161 ObDereferenceObject(pvObject);
5162 cBenignInheritableHandles++;
5163 continue;
5164 }
5165
5166 if (rcNt != STATUS_OBJECT_TYPE_MISMATCH)
5167 {
5168 cBenignInheritableHandles++;
5169 continue;
5170 }
5171
5172 cEvilInheritableHandles++;
5173 pszType = supdrvNtProtectHandleTypeIndexToName(pHandleInfo->ObjectTypeIndex, szTmpName, sizeof(szTmpName));
5174 }
5175 else
5176 continue;
5177
5178# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
5179 /* Ignore whitelisted debuggers. */
5180 if (pHandleInfo->UniqueProcessId == idLastDebugger)
5181 continue;
5182 PEPROCESS pDbgProc;
5183 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
5184 if (NT_SUCCESS(rcNt))
5185 {
5186 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
5187 ObDereferenceObject(pDbgProc);
5188 if (fIsDebugger)
5189 {
5190 idLastDebugger = pHandleInfo->UniqueProcessId;
5191 continue;
5192 }
5193 }
5194# endif
5195
5196 /* Found evil handle. Currently ignoring on pre-Vista. */
5197# ifndef VBOX_WITH_VISTA_NO_SP
5198 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
5199# else
5200 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
5201# endif
5202 || g_pfnObRegisterCallbacks)
5203 {
5204 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)\n",
5205 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
5206 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType, pHandleInfo->ObjectTypeIndex));
5207 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
5208 *pErrInfo->pszMsg
5209 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)"
5210 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)",
5211 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
5212 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType, pHandleInfo->ObjectTypeIndex);
5213
5214 /* Try add the process name. */
5215 PEPROCESS pOffendingProcess;
5216 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
5217 if (NT_SUCCESS(rcNt))
5218 {
5219 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
5220 if (pszName && *pszName)
5221 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
5222
5223 ObDereferenceObject(pOffendingProcess);
5224 }
5225 }
5226 }
5227
5228 RTMemFree(pbBuf);
5229 return rc;
5230}
5231
5232
5233/**
5234 * Checks if the current process checks out as a VM process stub.
5235 *
5236 * @returns VBox status code.
5237 * @param pNtProtect The NT protect structure. This is upgraded to a
5238 * final protection kind (state) on success.
5239 */
5240static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
5241{
5242 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
5243
5244 /*
5245 * Do the verification. The handle restriction checks are only preformed
5246 * on VM processes.
5247 */
5248 int rc = VINF_SUCCESS;
5249 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
5250 if (RT_SUCCESS(rc))
5251 {
5252 pErrorInfo->hProcessId = PsGetCurrentProcessId();
5253 pErrorInfo->hThreadId = PsGetCurrentThreadId();
5254 RTERRINFO ErrInfo;
5255 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
5256
5257 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
5258 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
5259 if (RT_SUCCESS(rc))
5260 {
5261 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
5262 NULL /*pcFixes*/, &ErrInfo);
5263 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
5264 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
5265 }
5266 }
5267 else
5268 rc = VERR_NO_MEMORY;
5269
5270 /*
5271 * Upgrade and return.
5272 */
5273 HANDLE hOpenTid = PsGetCurrentThreadId();
5274 RTSpinlockAcquire(g_hNtProtectLock);
5275
5276 /* Stub process verficiation is pretty much straight forward. */
5277 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
5278 {
5279 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
5280 pNtProtect->hOpenTid = hOpenTid;
5281 }
5282 /* The VM process verification is a little bit more complicated
5283 because we need to drop the parent process reference as well. */
5284 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
5285 {
5286 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
5287 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
5288 AssertRelease(pParent);
5289 AssertRelease(pParent->u.pParent == pNtProtect);
5290 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
5291 pParent->u.pParent = NULL;
5292
5293 pNtProtect->u.pParent = NULL;
5294 ASMAtomicDecU32(&pNtProtect->cRefs);
5295
5296 if (RT_SUCCESS(rc))
5297 {
5298 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
5299 pNtProtect->hOpenTid = hOpenTid;
5300 }
5301 else
5302 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
5303 }
5304
5305 /* Since the stub and VM processes are only supposed to have one thread,
5306 we're not supposed to be subject to any races from within the processes.
5307
5308 There is a race between VM process verification and the stub process
5309 exiting, though. We require the stub process to be alive until the new
5310 VM process has made it thru the validation. So, when the stub
5311 terminates the notification handler will change the state of both stub
5312 and VM process to dead.
5313
5314 Also, I'm not entirely certain where the process
5315 termination notification is triggered from, so that can theorically
5316 create a race in both cases. */
5317 else
5318 {
5319 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
5320 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
5321 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
5322 if (RT_SUCCESS(rc))
5323 rc = VERR_INVALID_STATE; /* There should be no races here. */
5324 }
5325
5326 RTSpinlockRelease(g_hNtProtectLock);
5327
5328 /*
5329 * Free error info on success, keep it on failure.
5330 */
5331 if (RT_SUCCESS(rc))
5332 RTMemFree(pErrorInfo);
5333 else if (pErrorInfo)
5334 {
5335 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
5336 if (!pErrorInfo->cchErrorInfo)
5337 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
5338 "supdrvNtProtectVerifyProcess: rc=%d", rc);
5339 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
5340
5341 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
5342 if (RT_SUCCESS(rc2))
5343 {
5344 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
5345
5346 /* Free old entries. */
5347 PSUPDRVNTERRORINFO pCur;
5348 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
5349 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
5350 {
5351 RTListNodeRemove(&pCur->ListEntry);
5352 RTMemFree(pCur);
5353 }
5354
5355 /* Insert our new entry. */
5356 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
5357
5358 RTSemMutexRelease(g_hErrorInfoLock);
5359 }
5360 else
5361 RTMemFree(pErrorInfo);
5362 }
5363
5364 return rc;
5365}
5366
5367
5368# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
5369
5370/**
5371 * Checks if the current process is being debugged.
5372 * @return @c true if debugged, @c false if not.
5373 */
5374static bool supdrvNtIsDebuggerAttached(void)
5375{
5376 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
5377}
5378
5379# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
5380
5381
5382/**
5383 * Terminates the hardening bits.
5384 */
5385static void supdrvNtProtectTerm(void)
5386{
5387 /*
5388 * Stop intercepting process and thread handle creation calls.
5389 */
5390 if (g_pvObCallbacksCookie)
5391 {
5392 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
5393 g_pvObCallbacksCookie = NULL;
5394 }
5395
5396 /*
5397 * Stop intercepting process creation and termination notifications.
5398 */
5399 NTSTATUS rcNt;
5400 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5401 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5402 else
5403 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5404 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
5405
5406 Assert(g_NtProtectTree == NULL);
5407
5408 /*
5409 * Clean up globals.
5410 */
5411 RTSpinlockDestroy(g_hNtProtectLock);
5412 g_NtProtectTree = NIL_RTSPINLOCK;
5413
5414 RTSemMutexDestroy(g_hErrorInfoLock);
5415 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5416
5417 PSUPDRVNTERRORINFO pCur;
5418 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
5419 {
5420 RTListNodeRemove(&pCur->ListEntry);
5421 RTMemFree(pCur);
5422 }
5423
5424 supHardenedWinTermImageVerifier();
5425}
5426
5427# ifdef RT_ARCH_X86
5428DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
5429DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
5430DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
5431DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
5432DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
5433DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
5434DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
5435DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
5436DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
5437DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
5438DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
5439DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
5440DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
5441DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
5442DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
5443DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
5444# elif defined(RT_ARCH_AMD64)
5445DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
5446DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
5447DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
5448DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
5449DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
5450extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
5451# endif
5452
5453
5454/**
5455 * Initalizes the hardening bits.
5456 *
5457 * @returns NT status code.
5458 */
5459static NTSTATUS supdrvNtProtectInit(void)
5460{
5461 /*
5462 * Initialize the globals.
5463 */
5464
5465 /* The NT version. */
5466 ULONG uMajor, uMinor, uBuild;
5467 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
5468 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
5469
5470 /* Resolve methods we want but isn't available everywhere. */
5471 UNICODE_STRING RoutineName;
5472
5473 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
5474 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
5475
5476 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
5477 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5478
5479 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
5480 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5481
5482 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
5483 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
5484
5485 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
5486 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
5487
5488 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
5489 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
5490
5491 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
5492 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
5493
5494 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
5495 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
5496 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
5497 {
5498 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
5499 few alternative in the assembly helper file that uses the code in
5500 ZwReadFile with a different eax value. We figure the syscall number
5501 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
5502# ifdef RT_ARCH_X86
5503 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
5504 if (*pbCode == 0xb8) /* mov eax, dword */
5505 switch (*(uint32_t const *)&pbCode[1])
5506 {
5507 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
5508 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
5509 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
5510 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
5511 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
5512 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
5513 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
5514 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
5515 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
5516 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
5517 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
5518 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
5519 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
5520 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
5521 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
5522 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
5523 }
5524# elif defined(RT_ARCH_AMD64)
5525 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
5526 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
5527 && pbCode[ 1] == 0x8b
5528 && pbCode[ 2] == 0xc4
5529 && pbCode[ 3] == 0xfa /* cli */
5530 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
5531 && pbCode[ 5] == 0x83
5532 && pbCode[ 6] == 0xec
5533 && pbCode[ 7] == 0x10
5534 && pbCode[ 8] == 0x50 /* push rax */
5535 && pbCode[ 9] == 0x9c /* pushfq */
5536 && pbCode[10] == 0x6a /* push 10 */
5537 && pbCode[11] == 0x10
5538 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
5539 && pbCode[13] == 0x8d
5540 && pbCode[14] == 0x05
5541 && pbCode[19] == 0x50 /* push rax */
5542 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
5543 /*&& pbCode[21] == 0x1f*/
5544 && pbCode[22] == 0x00
5545 && pbCode[23] == 0x00
5546 && pbCode[24] == 0x00
5547 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
5548 )
5549 {
5550 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
5551 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
5552 if (*pbKiServiceLinkage == 0xc3)
5553 {
5554 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
5555 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
5556 switch (pbCode[21])
5557 {
5558 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
5559 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
5560 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
5561 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
5562 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
5563 }
5564 }
5565 }
5566# endif
5567 }
5568 if (!g_pfnNtQueryVirtualMemory)
5569 {
5570 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
5571 return STATUS_PROCEDURE_NOT_FOUND;
5572 }
5573
5574# ifdef VBOX_STRICT
5575 if ( g_uNtVerCombined >= SUP_NT_VER_W70
5576 && ( g_pfnObGetObjectType == NULL
5577 || g_pfnZwAlpcCreatePort == NULL) )
5578 {
5579 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
5580 return STATUS_PROCEDURE_NOT_FOUND;
5581 }
5582# endif
5583
5584 /* LPC object type. */
5585 g_pAlpcPortObjectType1 = *LpcPortObjectType;
5586
5587 /* The spinlock protecting our structures. */
5588 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
5589 if (RT_FAILURE(rc))
5590 return VBoxDrvNtErr2NtStatus(rc);
5591 g_NtProtectTree = NULL;
5592
5593 NTSTATUS rcNt;
5594
5595 /* The mutex protecting the error information. */
5596 RTListInit(&g_ErrorInfoHead);
5597 rc = RTSemMutexCreate(&g_hErrorInfoLock);
5598 if (RT_SUCCESS(rc))
5599 {
5600 /* Image stuff + certificates. */
5601 rc = supHardenedWinInitImageVerifier(NULL);
5602 if (RT_SUCCESS(rc))
5603 {
5604 /*
5605 * Intercept process creation and termination.
5606 */
5607 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5608 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
5609 else
5610 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
5611 if (NT_SUCCESS(rcNt))
5612 {
5613 /*
5614 * Intercept process and thread handle creation calls.
5615 * The preferred method is only available on Vista SP1+.
5616 */
5617 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
5618 {
5619 static OB_OPERATION_REGISTRATION s_aObOperations[] =
5620 {
5621 {
5622 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
5623 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5624 supdrvNtProtectCallback_ProcessHandlePre,
5625 supdrvNtProtectCallback_ProcessHandlePost,
5626 },
5627 {
5628 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
5629 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5630 supdrvNtProtectCallback_ThreadHandlePre,
5631 supdrvNtProtectCallback_ThreadHandlePost,
5632 },
5633 };
5634 s_aObOperations[0].ObjectType = PsProcessType;
5635 s_aObOperations[1].ObjectType = PsThreadType;
5636
5637 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
5638 {
5639 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
5640 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
5641 /* .Altitude.Length = */ { 0,
5642 /* .Altitude.MaximumLength = */ 0,
5643 /* .Altitude.Buffer = */ NULL },
5644 /* .RegistrationContext = */ NULL,
5645 /* .OperationRegistration = */ &s_aObOperations[0]
5646 };
5647 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
5648 {
5649 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
5650 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
5651 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
5652 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
5653 };
5654
5655 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
5656 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
5657 {
5658 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
5659 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
5660 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
5661
5662 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
5663 if (NT_SUCCESS(rcNt))
5664 {
5665 /*
5666 * Happy ending.
5667 */
5668 return STATUS_SUCCESS;
5669 }
5670 }
5671 DbgPrint("VBoxSup: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt); /* temp for @bugref{10657} */
5672 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
5673
5674 g_pvObCallbacksCookie = NULL;
5675 }
5676 else
5677 {
5678 /*
5679 * For the time being, we do not implement extra process
5680 * protection on pre-Vista-SP1 systems as they are lacking
5681 * necessary KPIs. XP is end of life, we do not wish to
5682 * spend more time on it, so we don't put up a fuss there.
5683 * Vista users without SP1 can install SP1 (or later), darn it,
5684 * so refuse to load.
5685 */
5686 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
5687 * stuff to a couple of object types. */
5688# ifndef VBOX_WITH_VISTA_NO_SP
5689 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
5690# else
5691 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
5692# endif
5693 {
5694 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
5695 rcNt = STATUS_SXS_VERSION_CONFLICT;
5696 }
5697 else
5698 {
5699 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
5700 return rcNt = STATUS_SUCCESS;
5701 }
5702 g_pvObCallbacksCookie = NULL;
5703 }
5704
5705 /*
5706 * Drop process create/term notifications.
5707 */
5708 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5709 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5710 else
5711 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5712 }
5713 else
5714 {
5715 DbgPrint("VBoxSup: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x!\n",
5716 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt); /* temp for @bugref{10657} */
5717 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
5718 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
5719 }
5720 supHardenedWinTermImageVerifier();
5721 }
5722 else
5723 rcNt = VBoxDrvNtErr2NtStatus(rc);
5724
5725 RTSemMutexDestroy(g_hErrorInfoLock);
5726 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5727 }
5728 else
5729 rcNt = VBoxDrvNtErr2NtStatus(rc);
5730
5731 RTSpinlockDestroy(g_hNtProtectLock);
5732 g_NtProtectTree = NIL_RTSPINLOCK;
5733 return rcNt;
5734}
5735
5736#endif /* VBOX_WITH_HARDENING */
5737
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