VirtualBox

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

Last change on this file since 63549 was 62677, checked in by vboxsync, 8 years ago

SUPHardNt: -Wall warnings.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette