VirtualBox

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

Last change on this file was 99828, checked in by vboxsync, 12 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use