[Pkg-virtualbox-commits] [virtualbox] 01/03: Imported Upstream version 4.3.18-dfsg
Gianfranco Costamagna
locutusofborg-guest at moszumanska.debian.org
Tue Oct 14 13:59:54 UTC 2014
This is an automated email from the git hooks/post-receive script.
locutusofborg-guest pushed a commit to branch master
in repository virtualbox.
commit f10ef2ab0f5a37acbc7a6685c6d1bb39dc2b6222
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Tue Oct 14 15:43:23 2014 +0200
Imported Upstream version 4.3.18-dfsg
---
.dir-locals.el | 7 +
Config.kmk | 15 +-
Makefile.kmk | 162 +-
doc/manual/en_US/SDKRef.xml | 2 +-
doc/manual/en_US/user_AdvancedTopics.xml | 20 +
doc/manual/en_US/user_Security.xml | 7 +
doc/manual/user_ChangeLogImpl.xml | 150 +-
include/VBox/err.h | 23 +
include/VBox/ostypes.h | 2 +
include/VBox/vd-ifs.h | 134 +-
include/iprt/asm.h | 2 +-
include/iprt/asn1.h | 3 +
include/iprt/mangling.h | 4 +
include/iprt/nt/nt.h | 398 +-
include/iprt/path.h | 26 +
include/iprt/string.h | 46 +
.../Additions/common/VBoxGuest/VBoxGuest-win.cpp | 11 +
.../Additions/common/VBoxGuest/VBoxGuest-win.h | 1 +
src/VBox/Additions/linux/Makefile.kmk | 2 +-
src/VBox/Additions/x11/vboxvideo/vboxvideo.c | 5 +-
src/VBox/Debugger/DBGPlugInSolaris.cpp | 4 +-
src/VBox/Devices/Bus/DevPCI.cpp | 1 -
src/VBox/Devices/EFI/DevSmc.cpp | 2 +
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd | Bin 1048576 -> 1048576 bytes
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd | Bin 1048576 -> 1048576 bytes
src/VBox/Devices/Graphics/DevVGA_VBVA.cpp | 3 +
src/VBox/Devices/Makefile.kmk | 22 +-
src/VBox/Devices/Network/DrvNAT.cpp | 12 +-
src/VBox/Devices/Network/slirp/slirp_dns.c | 7 -
src/VBox/Devices/PC/BIOS/ahci.c | 2 +-
src/VBox/Devices/PC/BIOS/ata.c | 4 +-
src/VBox/Devices/PC/BIOS/scsi.c | 2 +-
src/VBox/Devices/PC/DevACPI.cpp | 237 +-
src/VBox/Devices/PC/DevSMC.cpp | 630 ---
src/VBox/Devices/Storage/DevAHCI.cpp | 42 +-
src/VBox/Devices/Storage/DrvDiskIntegrity.cpp | 10 +
src/VBox/Devices/USB/DevOHCI.cpp | 43 +-
src/VBox/Devices/USB/DrvVUSBRootHub.cpp | 6 +-
src/VBox/Devices/USB/VUSBDevice.cpp | 135 +-
src/VBox/Devices/USB/VUSBInternal.h | 59 +-
src/VBox/Devices/USB/VUSBUrb.cpp | 4 +-
.../Devices/USB/linux/USBProxyDevice-linux.cpp | 24 +-
src/VBox/Devices/build/VBoxDD.cpp | 2 -
src/VBox/Devices/build/VBoxDD2.cpp | 5 -
src/VBox/Devices/build/VBoxDD2.h | 3 -
src/VBox/Devices/testcase/tstDeviceStructSize.cpp | 2 +-
.../Devices/testcase/tstDeviceStructSizeRC.cpp | 23 +-
.../Frontends/VBoxManage/VBoxManageGuestCtrl.cpp | 30 +-
src/VBox/Frontends/VirtualBox/Makefile.kmk | 3 +-
.../Frontends/VirtualBox/src/VBoxFBOverlay.cpp | 2 +-
.../VirtualBox/src/extensions/QIFileDialog.cpp | 12 +-
.../Frontends/VirtualBox/src/globals/UIDefs.cpp | 3 +
src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h | 6 +-
.../VirtualBox/src/globals/VBoxGlobal.cpp | 136 +-
.../Frontends/VirtualBox/src/globals/VBoxGlobal.h | 5 +-
.../src/platform/darwin/VBoxUtils-darwin-cocoa.mm | 6 +
.../src/platform/darwin/VBoxUtils-darwin.cpp | 5 +
.../src/platform/darwin/VBoxUtils-darwin.h | 2 +
.../VirtualBox/src/runtime/UIMachineLogic.cpp | 7 +-
.../VirtualBox/src/runtime/UIMachineLogic.h | 4 +-
.../VirtualBox/src/runtime/UIMachineView.h | 4 +-
.../VirtualBox/src/runtime/UIMachineWindow.cpp | 7 +
.../VirtualBox/src/runtime/UIMachineWindow.h | 5 +-
.../Frontends/VirtualBox/src/runtime/UISession.cpp | 4 +-
.../fullscreen/UIMachineLogicFullscreen.cpp | 129 +-
.../runtime/fullscreen/UIMachineLogicFullscreen.h | 13 +-
.../runtime/fullscreen/UIMachineViewFullscreen.cpp | 7 +-
.../runtime/fullscreen/UIMachineViewFullscreen.h | 4 +-
.../fullscreen/UIMachineWindowFullscreen.cpp | 70 +-
.../runtime/fullscreen/UIMachineWindowFullscreen.h | 5 +
.../src/runtime/normal/UIMachineViewNormal.cpp | 9 +-
.../src/runtime/normal/UIMachineViewNormal.h | 4 +-
.../src/runtime/normal/UIMachineWindowNormal.cpp | 15 +
.../runtime/seamless/UIMachineLogicSeamless.cpp | 15 +-
.../src/runtime/seamless/UIMachineLogicSeamless.h | 4 +-
.../src/runtime/seamless/UIMachineViewSeamless.cpp | 9 +-
.../src/runtime/seamless/UIMachineViewSeamless.h | 4 +-
.../runtime/seamless/UIMachineWindowSeamless.cpp | 103 +-
.../src/runtime/seamless/UIMachineWindowSeamless.h | 24 +-
.../src/widgets/UIApplianceEditorWidget.h | 2 +-
.../VirtualBox/src/widgets/UIMiniToolBar.cpp | 52 +-
.../VirtualBox/src/widgets/UIMiniToolBar.h | 12 +
.../wizards/exportappliance/UIWizardExportApp.cpp | 2 +-
src/VBox/HostDrivers/Support/Makefile.kmk | 7 +
src/VBox/HostDrivers/Support/SUPDrvIOC.h | 17 +-
src/VBox/HostDrivers/Support/SUPLib.cpp | 5 +-
src/VBox/HostDrivers/Support/SUPLibInternal.h | 33 +-
src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp | 270 +-
.../HostDrivers/Support/SUPR3HardenedVerify.cpp | 17 +-
.../HostDrivers/Support/darwin/SUPLib-darwin.cpp | 2 +-
.../HostDrivers/Support/freebsd/SUPLib-freebsd.cpp | 2 +-
.../HostDrivers/Support/linux/SUPLib-linux.cpp | 2 +-
src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp | 2 +-
.../HostDrivers/Support/solaris/SUPLib-solaris.cpp | 2 +-
...NtCreateSection-template-amd64-syscall-type-1.h | 78 -
.../NtCreateSection-template-x86-syscall-type-1.h | 286 --
src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp | 954 ++++-
.../Support/win/SUPHardenedVerify-win.h | 54 +-
.../Support/win/SUPHardenedVerifyImage-win.cpp | 354 +-
.../Support/win/SUPHardenedVerifyProcess-win.cpp | 233 +-
src/VBox/HostDrivers/Support/win/SUPLib-win.cpp | 137 +-
.../Support/win/SUPR3HardenedMain-win.cpp | 4060 +++++++++++++-------
.../Support/win/SUPR3HardenedMainA-win.asm | 117 +-
.../Support/win/SUPR3HardenedMainImports-win.cpp | 326 +-
.../Support/win/SUPR3HardenedNoCrt-win.cpp | 294 +-
.../HostDrivers/Support/win/VBoxSupLib-win.cpp | 2 +-
.../Support/win/import-template-kernel32.h | 12 +-
.../Support/win/import-template-ntdll.h | 46 +-
.../SharedOpenGL/crserverlib/server_getshaders.c | 2 +-
src/VBox/Installer/win/Makefile.kmk | 53 +-
src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi | 8 +-
src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c | 4 +-
src/VBox/Main/cbinding/VBoxCAPIGlue.c | 4 +-
src/VBox/Main/cbinding/capiidl.xsl | 10 +-
src/VBox/Main/cbinding/tstCAPIGlue.c | 4 +-
src/VBox/Main/include/ConsoleEvents.h | 154 -
src/VBox/Main/include/KeyboardImpl.h | 4 -
src/VBox/Main/include/MachineImpl.h | 2 +-
src/VBox/Main/include/MouseImpl.h | 1 -
src/VBox/Main/src-client/GuestCtrlPrivate.cpp | 5 +
src/VBox/Main/src-server/ApplianceImplExport.cpp | 22 +-
src/VBox/Main/src-server/ApplianceImplImport.cpp | 9 +-
src/VBox/Main/src-server/MachineImpl.cpp | 12 +-
src/VBox/Main/src-server/MediumImpl.cpp | 3 +-
src/VBox/Main/xml/Settings.cpp | 6 +-
src/VBox/NetworkServices/NAT/proxy.c | 2 +-
.../NetLib/VBoxNetPortForwardString.cpp | 6 +-
src/VBox/Runtime/Makefile.kmk | 15 +
.../Runtime/common/asn1/asn1-efence-allocator.cpp | 85 +
src/VBox/Runtime/common/asn1/asn1-ut-string.cpp | 6 +-
src/VBox/Runtime/common/crypto/store-inmem.cpp | 6 +-
src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp | 1 +
src/VBox/Runtime/common/ldr/ldrMemory.cpp | 2 +-
src/VBox/Runtime/common/ldr/ldrPE.cpp | 2 +-
src/VBox/Runtime/common/string/strformat.cpp | 2 +-
src/VBox/Runtime/common/string/utf-16.cpp | 14 +
src/VBox/Runtime/common/time/time.cpp | 2 +-
src/VBox/Runtime/generic/RTPathAbs-generic.cpp | 358 ++
.../generic/RTPathGetCurrentDrive-generic.cpp | 106 +
.../generic/RTPathGetCurrentOnDrive-generic.cpp | 84 +
src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c | 9 +-
src/VBox/Runtime/r3/memsafer-r3.cpp | 10 +
src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp | 10 +-
src/VBox/Runtime/r3/nt/fs-nt.cpp | 24 +-
src/VBox/Runtime/r3/nt/internal-r3-nt.h | 78 +-
src/VBox/Runtime/r3/nt/pathint-nt.cpp | 237 +-
src/VBox/Runtime/r3/posix/path-posix.cpp | 218 --
.../Runtime/r3/win/RTSystemQueryOSInfo-win.cpp | 1 +
src/VBox/Runtime/r3/win/init-win.cpp | 3 +
src/VBox/Runtime/r3/win/internal-r3-win.h | 1 +
src/VBox/Runtime/r3/win/ntdll-mini-implib.def | 27 +-
src/VBox/Runtime/r3/win/path-win.cpp | 22 +-
src/VBox/Runtime/testcase/tstRTPath.cpp | 2 +-
src/VBox/Storage/VHD.cpp | 2 +-
src/VBox/Storage/testcase/BuiltinTests.h | 41 +
src/VBox/Storage/testcase/Makefile.kmk | 80 +-
src/VBox/Storage/testcase/VDMemDisk.cpp | 1 +
src/VBox/Storage/testcase/VDScript.cpp | 393 +-
src/VBox/Storage/testcase/VDScript.h | 69 +
src/VBox/Storage/testcase/VDScriptAst.cpp | 18 +-
src/VBox/Storage/testcase/VDScriptAst.h | 129 +
src/VBox/Storage/testcase/tstVDCompact.vd | 30 +-
src/VBox/Storage/testcase/tstVDCopy.vd | 18 +-
src/VBox/Storage/testcase/tstVDDiscard.vd | 8 +-
src/VBox/Storage/testcase/tstVDIo.cpp | 233 +-
src/VBox/Storage/testcase/tstVDIo.vd | 16 +-
src/VBox/Storage/testcase/tstVDMultBackends.vd | 60 +
src/VBox/Storage/testcase/tstVDResize.vd | 21 +-
src/VBox/Storage/testcase/tstVDShareable.vd | 9 +-
src/VBox/VMM/VMMAll/IOMAllMMIO.cpp | 2 +-
src/VBox/VMM/VMMR0/HMSVMR0.cpp | 17 +-
src/VBox/VMM/VMMR0/HMVMXR0.cpp | 22 +-
src/VBox/VMM/VMMR3/MMPagePool.cpp | 2 +-
src/VBox/VMM/VMMR3/PGMPhys.cpp | 2 +-
src/VBox/VMM/VMMR3/PGMPool.cpp | 4 +-
src/VBox/VMM/VMMR3/PGMSavedState.cpp | 6 +-
src/VBox/VMM/VMMR3/STAM.cpp | 3 +-
src/VBox/VMM/testcase/tstAnimate.cpp | 2 +-
src/bldprogs/VBoxCPP.cpp | 4 +-
src/bldprogs/scmdiff.cpp | 2 +-
180 files changed, 8641 insertions(+), 4529 deletions(-)
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..08dca97
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,7 @@
+;;; Directory Local Variables
+;;; See Info node `(emacs) Directory Variables' for more information.
+
+((c++-mode
+ (indent-tabs-mode))
+ (c-mode
+ (indent-tabs-mode)))
diff --git a/Config.kmk b/Config.kmk
index 26405c1..67b8f87 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -208,7 +208,7 @@ VBOX_VERSION_MINOR = 3
# This is the current build number. It should be increased every time we publish a
# new build. The define is available in every source file. Only even build numbers
# will be published, odd numbers are set during development.
-VBOX_VERSION_BUILD = 16
+VBOX_VERSION_BUILD = 18
# The raw version string. This *must not* contain any other information/fields than
# major, minor and build revision (as it is now) -- also will be used for host/guest version
# comparison.
@@ -641,6 +641,10 @@ endif
ifeq ($(KBUILD_TARGET),win)
VBOX_WITH_MMR = 1
endif
+# Enables use of merge modules in the windows installer. This will increase
+# the overall installer size significantly because merge modules are not able
+# to use a common .cab file to reduce their size.
+#VBOX_WITH_MSM_INSTALL = 1
## @}
@@ -2597,7 +2601,11 @@ ifdef VBOX_SIGNING_MODE
else if1of ($(VBOX_SIGNING_MODE), release development)
VBOX_CERTIFICATE_SUBJECT_NAME ?= Oracle Corporation
VBOX_CERTIFICATE_SUBJECT_NAME_ARGS ?= /n "$(VBOX_CERTIFICATE_SUBJECT_NAME)" /a
- VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/MSCV-VSClass3.cer
+ if defined(VBOX_ONLY_ADDITIONS) || defined(VBOX_ONLY_EXTPACKS)
+ VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/VeriSign Class 3 Public Primary Certification Authority - G5.cer
+ else
+ VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/MSCV-VSClass3.cer
+ endif
VBOX_CROSS_CERTIFICATE_FILE_ARGS ?= /ac "$(VBOX_CROSS_CERTIFICATE_FILE)"
VBOX_TSA_URL ?= http://timestamp.verisign.com/scripts/timestamp.dll
VBOX_TSA_URL_ARGS ?= /t "$(VBOX_TSA_URL)"
@@ -5690,7 +5698,7 @@ endif
SVN ?= svn$(HOSTSUFF_EXE)
VBOX_SVN_REV_KMK = $(PATH_OUT)/revision.kmk
ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 95972 $ )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 96516 $ )
VBOX_SVN_DEP := $(firstword $(wildcard $(PATH_ROOT)/.svn/wc.db $(abspath $(PATH_ROOT)/../.svn/wc.db) $(abspath $(PATH_ROOT)/../../.svn/wc.db) $(PATH_ROOT)/.svn/entries))
ifeq ($(which $(SVN)),)
VBOX_SVN_DEP :=
@@ -5842,3 +5850,4 @@ st stat status:
quick:
$(MAKE) VBOX_QUICK=1
+
diff --git a/Makefile.kmk b/Makefile.kmk
index 4f326b4..b39df14 100644
--- a/Makefile.kmk
+++ b/Makefile.kmk
@@ -174,6 +174,11 @@ else
qt4-bin_SOURCES = \
$(foreach qtmod,$(VBOX_QT4_MOD_NAMES),$(call VBOX_RE_SIGN_DLL_FN,qt4-bin,$(VBOX_PATH_QT4_LIB)/$(qtmod)4$(SUFF_DLL))) \
$(call VBOX_RE_SIGN_DLL_FN,qt4-bin,$(VBOX_PATH_QT4)/plugins/accessible/qtaccessiblewidgets4$(SUFF_DLL))=>accessible/qtaccessiblewidgets4$(SUFF_DLL)
+ ifdef VBOX_WITH_QT_PDBS
+ qt4-bin_SOURCES += \
+ $(foreach qtmod,$(VBOX_QT4_MOD_NAMES),$(VBOX_PATH_QT4_LIB)/$(qtmod)4.pdb) \
+ $(VBOX_PATH_QT4)/plugins/accessible/qtaccessiblewidgets4.pdb=>accessible/qtaccessiblewidgets4.pdb
+ endif
else
INSTALLS += qt4-bin
qt4-bin_MODE = 755
@@ -804,9 +809,9 @@ VBOX_RSYNC_IN_FN = rsync -a -v --delete --delete-excluded --prune-empty-dirs \
#
# VM IP addresses.
#
-VBOX_BLD_VM_LNX_X86_IP := 192.168.27.2
+VBOX_BLD_VM_LNX_IP := 192.168.27.2
+VBOX_BLD_VM_LNX_X86_IP := 192.168.27.11
VBOX_BLD_VM_LNX_AMD64_IP := 192.168.27.12
-VBOX_BLD_VM_LNX_NEW_X86_IP := 192.168.27.11
VBOX_BLD_VM_OS2_IP := 192.168.27.3
VBOX_BLD_VM_SOLARIS_IP := 192.168.27.4
VBOX_BLD_VM_DARWIN_X86_IP := 192.168.27.5
@@ -825,7 +830,7 @@ if 0
VBOX_BLD_VM_MSG_BEGIN = $(call MSG_L1,Building $1.)
VBOX_BLD_VM_MSG_END__ =
else
- VBOX_BLD_VM_MSG_BEGIN = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Building $1.
+ VBOX_BLD_VM_MSG_BEGIN = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Start building $1.
VBOX_BLD_VM_MSG_END__ = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Done building $1.
endif
@@ -861,13 +866,14 @@ additions-build: \
additions-build-solaris.amd64 \
additions-build-solaris.x86 \
additions-build-os2.x86 \
- additions-build-linux.x86.combined
+ additions-build-linux
additions-build-rsync-into-vms: \
additions-build-solaris.rsync-into-vm \
- additions-build-os2.rsync-into-vm
+ additions-build-os2.rsync-into-vm \
+ additions-build-linux.rsync-into-vm
$(call MSG_L1,Rsynced the sources + tools into the VMs.)
-#.NOTPARALLEL: additions-build-rsync-into-vms
+.NOTPARALLEL: additions-build-rsync-into-vms
VBOX_ADDITIONS_BUILD.amd64 = VBOX_ONLY_ADDITIONS=1 VBOX_WITHOUT_ADDITIONS_ISO=1 \
@@ -898,9 +904,9 @@ ifeq ($(KBUILD_TARGET),win)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) packing
else
- $(call VBOX_BLD_VM_MSG_BEGIN,Windows/amd64 additions)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Windows/amd64 additions build+pack)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_WIN_AMD64_IP) " echo $@ && cd e:/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing "
- $(call VBOX_BLD_VM_MSG_END__,Windows/amd64 additions)
+ $(call VBOX_BLD_VM_MSG_END__,Windows/amd64 additions build+pack)
endif
additions-build-win.x86:
@@ -908,9 +914,9 @@ ifeq ($(KBUILD_TARGET),win)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing
else
- $(call VBOX_BLD_VM_MSG_BEGIN,Windows/x86 additions)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Windows/x86 additions build.pack)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_WIN_X86_IP) " echo $@ && cd e:/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh kmk $(VBOX_ADDITIONS_BUILD.x86) all packing"
- $(call VBOX_BLD_VM_MSG_END__,Windows/x86 additions)
+ $(call VBOX_BLD_VM_MSG_END__,Windows/x86 additions build+pack)
endif
# ASSUMES the 64-bit edition are built first. This also serializes VM access.
@@ -933,18 +939,18 @@ additions-build-solaris.rsync-into-vm:
. $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
additions-build-solaris.build-it: additions-build-solaris.rsync-into-vm
- $(call VBOX_BLD_VM_MSG_BEGIN,Solaris/amd64 additions)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Solaris/amd64 additions build+pack)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/amd64 && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing"
- $(call VBOX_BLD_VM_MSG_END__,Solaris/amd64 additions)
- $(call VBOX_BLD_VM_MSG_BEGIN,Solaris/x86 additions)
+ $(call VBOX_BLD_VM_MSG_END__,Solaris/amd64 additions build+pack)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Solaris/x86 additions build+pack)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/x86 && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_SOLARIS_GUEST_PACKAGE=1"
- $(call VBOX_BLD_VM_MSG_END__,Solaris/x86 additions)
+ $(call VBOX_BLD_VM_MSG_END__,Solaris/x86 additions build+pack)
additions-build-solaris.rsync-out-of-vm: additions-build-solaris.build-it
$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/solaris.x86 out/
$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/solaris.amd64 out/
-#.NOTPARALLEL: additions-build-solaris.rsync-into-vm
+.NOTPARALLEL: additions-build-solaris.rsync-into-vm
.PHONY: additions-build-solaris.rsync-into-vm additions-build-solaris.rsync-out-of-vm additions-build-solaris.build-it
additions-build-solaris.amd64: additions-build-solaris.rsync-out-of-vm
@@ -968,14 +974,14 @@ additions-build-os2.rsync-into-vm:
. rsync://vbox@$(VBOX_BLD_VM_OS2_IP)/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
additions-build-os2.build-it: additions-build-os2.rsync-into-vm
- $(call VBOX_BLD_VM_MSG_BEGIN,OS/2 additions)
+ $(call VBOX_BLD_VM_MSG_BEGIN,OS/2 additions build+pack)
$(VBOX_KMK_TIME) rsh -l vbox $(VBOX_BLD_VM_OS2_IP) "cd e:\\tinderbox\\$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && e: && kbuild\\bin\\os2.x86\\kmk_ash tools\\env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing"
- $(call VBOX_BLD_VM_MSG_END__,OS/2 additions)
+ $(call VBOX_BLD_VM_MSG_END__,OS/2 additions build+pack)
additions-build-os2.rsync-out-of-vm: additions-build-os2.build-it
$(VBOX_KMK_TIME) rsync -v -a --delete rsync://vbox@$(VBOX_BLD_VM_OS2_IP)/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/os2.x86 ./out
-#.NOTPARALLEL: additions-build-os2.rsync-into-vm
+.NOTPARALLEL: additions-build-os2.rsync-into-vm
.PHONY: additions-build-os2.rsync-into-vm additions-build-os2.rsync-out-of-vm additions-build-os2.build-it
additions-build-os2.x86: additions-build-os2.rsync-out-of-vm
@@ -986,48 +992,56 @@ additions-build-os2.x86:
# Dummy
endif
-additions-build-linux.amd64: $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
+ifeq ($(KBUILD_TARGET),linux)
+additions-build-linux.amd64:
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
+
+additions-build-linux.x86:
+ + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+ + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
+
+additions-build-linux: additions-build-linux.x86 additions-build-linux.amd64
+ + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+ + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1
else
+additions-build-linux.rsync-into-vm:
+ $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,linux,*) \
+ '--exclude=src/VBox/Additions/WINNT/**' \
+ '--exclude=src/VBox/Frontends/**' \
+ '--exclude=src/VBox/VMM/**' \
+ . $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
+
+additions-build-linux.build-it: additions-build-linux.rsync-into-vm
ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING
$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions/greeter)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) "echo $@ && dchroot -c ubuntu-11.10-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux2.amd64/$(KBUILD_TYPE) VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && dchroot -c ubuntu-11.10-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.amd64/$(KBUILD_TYPE)/greeter VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions/greeter)
endif
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions)
- $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)"
- $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions)
-endif
-
-additions-build-linux.x86: $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
- + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
- + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
-else
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions build+pack)
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
+ $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions build+pack)
ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING
$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions/greeter)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) "echo $@ && dchroot -c ubuntu-11.10-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && BUILD_PLATFORM_ARCH=x86 tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux2.x86/$(KBUILD_TYPE) VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c ubuntu-11.10-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && BUILD_PLATFORM_ARCH=x86 tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.x86/$(KBUILD_TYPE)/greeter VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions/greeter)
endif
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
- $(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions)
-endif
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions build+pack)
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
+ $(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions build+pack)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions combine)
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1\""'
+ $(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions combine)
-# Combined Linux Additions .run package. This depends on the archives
-# created during packing by the architecture-specific builds.
-additions-build-linux.x86.combined: $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST) additions-build-linux.x86 additions-build-linux.amd64
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
- + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
- + $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1
-else
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1\""'
- $(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions)
-endif
+additions-build-linux.rsync-out-of-vm: additions-build-linux.build-it
+ $(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.x86 out/
+ $(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.amd64 out/
+
+.NOTPARALLEL: additions-build-linux.rsync-into-vm
+.PHONY: additions-build-linux.rsync-into-vm additions-build-linux.rsync-out-of-vm additions-build-linux.build-it
+additions-build-linux: additions-build-linux.rsync-out-of-vm
+endif
additions-packing:
+ $(KMK) VBOX_ONLY_ADDITIONS=1 \
@@ -1051,6 +1065,7 @@ additions-packing:
additions-build-solaris.amd64 \
additions-build-solaris.x86 \
additions-build-os2.x86 \
+ additions-build-linux \
additions-build-linux.amd64 \
additions-build-linux.x86 \
additions-build-linux.x86.combined \
@@ -1084,8 +1099,7 @@ extpacks-build: \
extpacks-build-win.x86 \
extpacks-build-solaris.amd64 \
extpacks-build-os2.x86 \
- extpacks-build-linux.amd64 \
- extpacks-build-linux.x86 \
+ extpacks-build-linux \
extpacks-build-darwin.amd64 \
extpacks-build-darwin.x86 \
extpacks-build-freebsd.amd64 \
@@ -1161,22 +1175,35 @@ extpacks-build-os2.x86:
# $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_OS2_IP) " cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) "
#endif
+ifeq ($(KBUILD_TARGET),linux)
extpacks-build-linux.amd64: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_EXTPACKS_BUILD.amd64) all $(VBOX_EXTPACKS_HOST_BUILD_TWEAK)
-else
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 extension packs)
- $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
- $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 extension packs)
-endif
extpacks-build-linux.x86: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_EXTPACKS_BUILD.x86) all $(VBOX_EXTPACKS_HOST_BUILD_TWEAK)
+
+extpacks-build-linux: extpacks-build-linux.x86 extpacks-build-linux.amd64
else
+# Serialize 32-bit and 64-bit ASSUMING the same VM builds both.
+extpacks-build-linux.rsync-into-vm: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
+ $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,linux,*) . $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+
+extpacks-build-linux.build-it: extpacks-build-linux.rsync-into-vm
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 extension packs)
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all\""'
+ $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 extension packs)
$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 extension packs)
- $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all"
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@ && linux32 dchroot -c debian-4.0-i386 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all\""'
$(call VBOX_BLD_VM_MSG_END__,Linux/x86 extension packs)
+
+extpacks-build-linux.rsync-out-of-vm: extpacks-build-linux.build-it
+ $(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/linux.x86 out/
+ $(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/linux.amd64 out/
+
+#.NOTPARALLEL: extpacks-build-linux.rsync-into-vm
+.PHONY: extpacks-build-linux.rsync-out-of-vm extpacks-build-linux.rsync-into-vm extpacks-build-linux.build-it
+
+extpacks-build-linux: extpacks-build-linux.rsync-out-of-vm
endif
extpacks-build-freebsd.amd64: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
@@ -1231,6 +1258,7 @@ extpacks-packing:
extpacks-build-win.amd64 \
extpacks-build-solaris.amd64 \
extpacks-build-os2.x86 \
+ extpacks-build-linux \
extpacks-build-linux.amd64 \
extpacks-build-linux.x86 \
extpacks-build-freebsd.amd64 \
@@ -1384,18 +1412,20 @@ testsuite-build-linux.amd64: $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.amd64) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
else
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 testsuite)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 Validation Kit)
+ #$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all\""'
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all"
- $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 testsuite)
+ $(call VBOX_BLD_VM_MSG_END__,Linux/amd64 Validation Kit)
endif
testsuite-build-linux.x86: $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.x86) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
else
- $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 testsuite)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
- $(call VBOX_BLD_VM_MSG_END__,Linux/x86 testsuite)
+ $(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 Validation Kit)
+ #$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_X86_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
+ $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
+ $(call VBOX_BLD_VM_MSG_END__,Linux/x86 Validation Kit)
endif
testsuite-build-freebsd.amd64: $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
@@ -1421,9 +1451,9 @@ ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),darwin.amd64)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.amd64) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
else
$(call VBOX_BLD_VM_MSG_BEGIN,Darwin/amd64 testsuite)
- $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,amd64) . $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+ $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,amd64) . $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_DARWIN_AMD64_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all"
- $(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/darwin.amd64 out/
+ $(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)/out/darwin.amd64 out/
$(call VBOX_BLD_VM_MSG_END__,Darwin/amd64 testsuite)
endif
@@ -1432,9 +1462,9 @@ ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),darwin.x86)
+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.x86) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
else
$(call VBOX_BLD_VM_MSG_BEGIN,Darwin/x86 testsuite)
- $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,x86) . $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+ $(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,x86) . $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)
$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_DARWIN_X86_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all"
- $(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/darwin.x86 out/
+ $(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)/out/darwin.x86 out/
$(call VBOX_BLD_VM_MSG_END__,Darwin/x86 testsuite)
endif
diff --git a/doc/manual/en_US/SDKRef.xml b/doc/manual/en_US/SDKRef.xml
index 8f773c5..d95c475 100644
--- a/doc/manual/en_US/SDKRef.xml
+++ b/doc/manual/en_US/SDKRef.xml
@@ -1975,7 +1975,7 @@ g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para>
their other functionality:<screen>SAFEARRAY *psa = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc();
ULONG *pData;
ULONG cElements;
-IArrayDemo_ReturnArray(pThis, ComSafeArrayAsOutParam(psa));
+IArrayDemo_ReturnArray(pThis, ComSafeArrayAsOutTypeParam(psa, ULONG));
g_pVBoxFuncs->pfnSafeArrayCopyOutParamHelper((void **)&pData, &cElements, VT_I4, psa);
g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para>
diff --git a/doc/manual/en_US/user_AdvancedTopics.xml b/doc/manual/en_US/user_AdvancedTopics.xml
index 92dd179..6b81646 100644
--- a/doc/manual/en_US/user_AdvancedTopics.xml
+++ b/doc/manual/en_US/user_AdvancedTopics.xml
@@ -2889,6 +2889,26 @@ VBoxManage setextradata "VM name" VBoxInternal2/CoreDumpLive 1</screen>At
</sect2>
+ <sect2 id="legacy-fullscreen-mode">
+ <title>Requesting legacy full-screen mode</title>
+
+ <para>
+ As of version 4.3.16, VirtualBox uses special window manager facilities to switch
+ a multi-screen machine to full-screen on a multi-monitor host system. However,
+ not all window managers provide these facilities correctly, so VirtualBox can be
+ told to use the old method of switching to full-screen mode instead using the command:
+ </para>
+ <para><screen>VBoxManage setextradata global GUI/Fullscreen/LegacyMode true</screen></para>
+
+ <para>
+ You can go back to the new method using the command:
+ </para>
+ <para><screen>VBoxManage setextradata global GUI/Fullscreen/LegacyMode</screen></para>
+
+ <para>This is a global setting.</para>
+
+ </sect2>
+
</sect1>
<sect1 id="vboxwebsrv-daemon">
diff --git a/doc/manual/en_US/user_Security.xml b/doc/manual/en_US/user_Security.xml
index 9eab619..61f0c60 100644
--- a/doc/manual/en_US/user_Security.xml
+++ b/doc/manual/en_US/user_Security.xml
@@ -352,6 +352,13 @@
IPsec), or use encrypted protocols in the guest network (such as
SSH). The security properties are similar to bridged Ethernet.</para>
</listitem>
+
+ <listitem>
+ <para>Because of shortcomings in older Windows versions, using
+ VirtualBox on Windows versions older than Vista with Service Pack 1
+ is not recommended.</para>
+ </listitem>
+
</itemizedlist></para>
</sect2>
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index 3f2b5c6..8fa1c7b 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -1,6 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<sect1>
+ <title>Version 4.3.18 (2014-10-10)</title>
+
+ <para>This is a maintenance release. The following items were fixed and/or
+ added:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>VMM: fixed a potential misbehavior after restoring the A20 state
+ from a saved state</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: fixed full-screen mode mini-toolbar related regressions
+ for different platforms and window managers (bug #13369)</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: X11: fixed full-screen mode Unity panels quirk caused by
+ mini-toolbar code changes in last release (bug #13365)</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: X11: added possibility to use legacy full-screen mode
+ as the new one can cause multi-screen issues under Unity, see
+ <xref linkend="legacy-fullscreen-mode" xreflabel="here"/> (bug #13365)</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: Mac OS X: fixed full-screen mode artifact causing black screen
+ when 3D acceleration was enabled on 10.10 Yosemite hosts (bug #13448)</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: Mac OS X: fixed regression in user-space swiping from/to
+ VBox in full-screen mode</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: Mac OS X: fixed issue with switching to VBox in full-screen
+ mode through Alt+Tab and Mission Control</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: fixed data corruption when resizing huge VHD images under
+ certain circumstances (bug #11960)</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: fixed a rare hang during startup when the BIOS enumerates the
+ storage devices attached to the SATA controller</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: follow the spec with AHCI interrupt acknowledge (bug #13474)</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: fixed broken iSCSI authentication (4.3.14 regression, bugs #13386,
+ #13435)</para>
+ </listitem>
+
+ <listitem>
+ <para>NAT Network: properly parse port forwarding rules to allow UDP
+ rules</para>
+ </listitem>
+
+ <listitem>
+ <para>USB: fixed a crash on Linux hosts with older Linux kernels (bug #13400) and
+ several other fixes</para>
+ </listitem>
+
+ <listitem>
+ <para>ACPI: fixed ACPI timer anomalies (bug #12076)</para>
+ </listitem>
+
+ <listitem>
+ <para>Guest Control: fixed a memory leak (bug #13434)</para>
+ </listitem>
+
+ <listitem>
+ <para>Main: when removing a VM, do also remove the VBoxStartup.log file
+ which might exist on Windows hosts (bug #13478)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows hosts: fixed more startup problems on certain Windows hosts due
+ to conflicts with anti-virus software; better error reporting
+ (4.3.14 regression; bug #13187)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows hosts: propagate the process startup information to the child
+ process (4.3.14 regression; bug #13243)</para>
+ </listitem>
+
+ <listitem>
+ <para>Mac OS X hosts: don't force using the discrete GPU (bug #11111)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows Additions: some Windows 10 tweaks</para>
+ </listitem>
+
+ <listitem>
+ <para>X11 guests: fix a bug handling video driver display properties
+ which prevented GNOME Shell on Fedora 21 from starting</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts / guests: fixed a few remaining warnings in the kernel
+ log if memory allocation fails (bug #11171)</para>
+ </listitem>
+
+ </itemizedlist>
+ </sect1>
+
+ <sect1>
<title>Version 4.3.16 (2014-09-09)</title>
<para>This is a maintenance release. The following items were fixed and/or
@@ -136,7 +254,7 @@
<listitem>
<para>Windows hosts: fixed startup problems on certain Windows hosts due
- to conflicts with anti-virus software (4.3.14 regression, bug #13187)</para>
+ to conflicts with anti-virus software (4.3.14 regression; bug #13187)</para>
</listitem>
<listitem>
@@ -420,7 +538,7 @@
<listitem>
<para>GUI: fixed crash under rare conditions on entering/exiting
- fullscreen/seamless mode</para>
+ full-screen/seamless mode</para>
</listitem>
<listitem>
@@ -920,7 +1038,7 @@
</listitem>
<listitem>
- <para>GUI: fixed deleting of inaccessible VMs (4.3 regression, bug
+ <para>GUI: fixed deleting of inaccessible VMs (4.3 regression; bug
#12205)</para>
</listitem>
@@ -976,7 +1094,7 @@
<listitem>
<para>Solaris hosts: fixed accessing the host driver from non-global zones
- (4.3 regression, bug #12271)</para>
+ (4.3 regression; bug #12271)</para>
</listitem>
</itemizedlist>
@@ -1801,7 +1919,7 @@
<listitem>
<para>Snapshots: fixed a bug which could result in lost medium attachments
- (4.2.18 regression, bug #11750)</para>
+ (4.2.18 regression; bug #11750)</para>
</listitem>
<listitem>
@@ -2553,7 +2671,7 @@
<listitem>
<para>Storage: fixed non working online merging of snapshots
- (4.2.6 regression, bug #11359)</para>
+ (4.2.6 regression; bug #11359)</para>
</listitem>
<listitem>
@@ -2872,7 +2990,7 @@
<listitem>
<para>GUI: fixed validation warning on global settings / proxy page
- (4.2.2 regression, bug #11089)</para>
+ (4.2.2 regression; bug #11089)</para>
</listitem>
<listitem>
@@ -3165,7 +3283,7 @@
<listitem>
<para>VMM: fixed a potential host crash triggered by shutting down a VM
when another VM was running (only affected 32-bit hosts and 64-bit OS X hosts,
- 4.1 regression, bug #9897)</para>
+ 4.1 regression; bug #9897)</para>
</listitem>
<listitem>
@@ -3492,7 +3610,7 @@
<listitem>
<para>Windows Additions: fixed guest driver crash of VBoxSF in certain
- cases (4.1.10 regression, bug #10408)</para>
+ cases (4.1.10 regression; bug #10408)</para>
</listitem>
<listitem>
@@ -7981,7 +8099,7 @@
<listitem>
<para>Linux Additions: make the mouse driver work on Debian 5.0.3 guests
- again (3.1.2 regression, bug #5832)</para>
+ again (3.1.2 regression; bug #5832)</para>
</listitem>
<listitem>
@@ -8999,7 +9117,7 @@
<listitem>
<para>BIOS: fixed a bug that caused the OS/2 boot manager to fail
- (2.1.0 regression, bug #3911)</para>
+ (2.1.0 regression; bug #3911)</para>
</listitem>
<listitem>
@@ -9202,7 +9320,7 @@
<listitem>
<para>USB: fixed a bug that may have rendered USB device filter settings
- inactive (3.0.2 regression, bug #4668)</para>
+ inactive (3.0.2 regression; bug #4668)</para>
</listitem>
<listitem>
@@ -9880,7 +9998,7 @@
<listitem>
<para>Windows Additions: fixed mouse pointer integration of some
- Windows guests (2.2.0 regression, bug #3734)</para>
+ Windows guests (2.2.0 regression; bug #3734)</para>
</listitem>
<listitem>
@@ -9924,7 +10042,7 @@
</listitem>
<listitem>
- <para>GUI: HostKey could not be changed (2.2.0 regression,
+ <para>GUI: HostKey could not be changed (2.2.0 regression;
bug #3689)</para>
</listitem>
@@ -9961,7 +10079,7 @@
<listitem>
<para>Networking: fixed a deadlock caused by the PCnet network device
- emulation (2.2.0 regression, bug #3676)</para>
+ emulation (2.2.0 regression; bug #3676)</para>
</listitem>
<listitem>
@@ -10668,7 +10786,7 @@
<listitem>
<para>SATA: raw disk partitions were not recognized
- (2.1.0 regression, Windows host only, bug #2778)</para>
+ (2.1.0 regression; Windows host only, bug #2778)</para>
</listitem>
<listitem>
diff --git a/include/VBox/err.h b/include/VBox/err.h
index d15b2a8..5bd8993 100644
--- a/include/VBox/err.h
+++ b/include/VBox/err.h
@@ -1762,6 +1762,8 @@
/** The CSRSS instance associated with the client process could not be
* located. */
#define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741)
+/** Type error opening the ApiPort LPC object. */
+#define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742)
/** @} */
@@ -2495,6 +2497,27 @@
#define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER (-5667)
/** The image is outside the expected range. */
#define VERR_SUP_VP_IMAGE_TOO_BIG (-5668)
+/** Stub process not found so it cannot be revalidated when vboxdrv is opened
+ * by the VM process. */
+#define VERR_SUP_VP_STUB_NOT_FOUND (-5669)
+/** Error openeing the stub process for revalidation when vboxdrv is opened by
+ * the VM process. */
+#define VERR_SUP_VP_STUB_OPEN_ERROR (-5670)
+/** Stub process thread not found during revalidation upon vboxdrv opening by
+ * the VM process. */
+#define VERR_SUP_VP_STUB_THREAD_NOT_FOUND (-5671)
+/** Error opening the stub process thread for revalidation when vboxdrv is
+ * opened by the VM process. */
+#define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR (-5672)
+/** Process Purification Failure: NtAllocateVirtualMemory failed to get us
+ * suitable replacement memory for a chunk of executable memory that
+ * shouldn't be present in our process. (You will only see this message if you
+ * got potentially fatally buggy anti-virus software installed.) */
+#define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED (-5673)
+/** Error getting the file mode. */
+#define VERR_SUP_VP_FILE_MODE_ERROR (-5674)
+/** Error creating an event semaphore for used with asynchronous reads. */
+#define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED (-5675)
/** @} */
diff --git a/include/VBox/ostypes.h b/include/VBox/ostypes.h
index 890c2be..c197fe3 100644
--- a/include/VBox/ostypes.h
+++ b/include/VBox/ostypes.h
@@ -69,6 +69,8 @@ typedef enum VBOXOSTYPE
VBOXOSTYPE_Win2k12_x64 = 0x39100,
VBOXOSTYPE_Win81 = 0x3A000,
VBOXOSTYPE_Win81_x64 = 0x3A100,
+ VBOXOSTYPE_Win10 = 0x3B000,
+ VBOXOSTYPE_Win10_x64 = 0x3B100,
VBOXOSTYPE_OS2 = 0x40000,
VBOXOSTYPE_OS2Warp3 = 0x41000,
VBOXOSTYPE_OS2Warp4 = 0x42000,
diff --git a/include/VBox/vd-ifs.h b/include/VBox/vd-ifs.h
index 80cdf54..6d80e92 100644
--- a/include/VBox/vd-ifs.h
+++ b/include/VBox/vd-ifs.h
@@ -973,7 +973,10 @@ DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf,
if (RT_SUCCESS(rc))
{
*ppvData = pbData;
+ /* Exclude terminator if the byte data was obtained using the string query callback. */
*pcbData = cb;
+ if (!pCfgIf->pfnQueryBytes)
+ (*pcbData)--;
}
else
RTMemFree(pbData);
@@ -984,137 +987,6 @@ DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf,
return rc;
}
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
- * character value - the memory is locked to prevent paging to disk,
- * useful for memory which holds keys, passwords, etc.
- *
- * @return VBox status code.
- * @param pCfgIf Pointer to configuration callback table.
- * @param pszName Name of an zero terminated character value
- * @param ppszString Where to store the string pointer. Not set on failure.
- * Free this using RTMemFree().
- */
-DECLINLINE(int) VDCFGQueryStringAllocLocked(PVDINTERFACECONFIG pCfgIf,
- const char *pszName, char **ppszString)
-{
- size_t cb;
- int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
- if (RT_SUCCESS(rc))
- {
- char *pszString = (char *)RTMemLockedAlloc(cb);
- if (pszString)
- {
- rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb);
- if (RT_SUCCESS(rc))
- *ppszString = pszString;
- else
- RTMemFree(pszString);
- }
- else
- rc = VERR_NO_MEMORY;
- }
- return rc;
-}
-
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
- * character value with default - the memory is locked to prevent paging to disk,
- * useful for memory which holds keys, passwords, etc.
- *
- * @return VBox status code.
- * @param pCfgIf Pointer to configuration callback table.
- * @param pszName Name of an zero terminated character value
- * @param ppszString Where to store the string pointer. Not set on failure.
- * Free this using RTMemFree().
- * @param pszDef The default value.
- */
-DECLINLINE(int) VDCFGQueryStringAllocLockedDef(PVDINTERFACECONFIG pCfgIf,
- const char *pszName,
- char **ppszString,
- const char *pszDef)
-{
- size_t cb;
- int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
- if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
- {
- cb = strlen(pszDef) + 1;
- rc = VINF_SUCCESS;
- }
- if (RT_SUCCESS(rc))
- {
- char *pszString = (char *)RTMemLockedAlloc(cb);
- if (pszString)
- {
- rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb);
- if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
- {
- memcpy(pszString, pszDef, cb);
- rc = VINF_SUCCESS;
- }
- if (RT_SUCCESS(rc))
- *ppszString = pszString;
- else
- RTMemFree(pszString);
- }
- else
- rc = VERR_NO_MEMORY;
- }
- return rc;
-}
-
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) byte string value -
- * the memory is locked to prevent paging to disk, useful for memory which holds
- * keys, passwords, etc..
- *
- * @return VBox status code.
- * @param pCfgIf Pointer to configuration callback table.
- * @param pszName Name of an zero terminated character value
- * @param ppvData Where to store the byte string pointer. Not set on failure.
- * Free this using RTMemFree().
- * @param pcbData Where to store the byte string length.
- */
-DECLINLINE(int) VDCFGQueryBytesAllocLocked(PVDINTERFACECONFIG pCfgIf,
- const char *pszName, void **ppvData, size_t *pcbData)
-{
- size_t cb;
- int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
- if (RT_SUCCESS(rc))
- {
- char *pbData;
- Assert(cb);
-
- pbData = (char *)RTMemLockedAlloc(cb);
- if (pbData)
- {
- if(pCfgIf->pfnQueryBytes)
- rc = pCfgIf->pfnQueryBytes(pCfgIf->Core.pvUser, pszName, pbData, cb);
- else
- rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pbData, cb);
-
- if (RT_SUCCESS(rc))
- {
- *ppvData = pbData;
- *pcbData = cb;
- }
- else
- RTMemFree(pbData);
- }
- else
- rc = VERR_NO_MEMORY;
- }
- return rc;
-}
-
-/**
- * Frees memory allocated using one of the VDCFGQuery*AllocLocked methods.
- */
-DECLINLINE(void) VDCFGMemLockedFree(void *pvData)
-{
- RTMemLockedFree(pvData);
-}
-
/** Forward declaration of a VD socket. */
typedef struct VDSOCKETINT *VDSOCKET;
/** Pointer to a VD socket. */
diff --git a/include/iprt/asm.h b/include/iprt/asm.h
index f4eb1ba..11c61af 100644
--- a/include/iprt/asm.h
+++ b/include/iprt/asm.h
@@ -2269,7 +2269,7 @@ DECLINLINE(void) ASMAtomicWritePtrVoid(void * volatile *ppv, const void *pv)
# define ASMAtomicWriteNullPtr(ppv) \
do \
{ \
- __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \
+ __typeof__(*(ppv)) * const ppvTypeChecked = (ppv); \
AssertCompile(sizeof(*ppv) == sizeof(void *)); \
Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \
ASMAtomicWritePtrVoid((void * volatile *)(ppvTypeChecked), NULL); \
diff --git a/include/iprt/asn1.h b/include/iprt/asn1.h
index f5e9b27..987e3a2 100644
--- a/include/iprt/asn1.h
+++ b/include/iprt/asn1.h
@@ -109,6 +109,9 @@ typedef RTASN1ALLOCATORVTABLE const *PCRTASN1ALLOCATORVTABLE;
/** The default ASN.1 allocator. */
extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1DefaultAllocator;
+/** The Electric Fence ASN.1 allocator. */
+extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator;
+
/**
* Allocation information.
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
index 8c28a85..4f1b59c 100644
--- a/include/iprt/mangling.h
+++ b/include/iprt/mangling.h
@@ -1017,6 +1017,8 @@
# define RTPathFilename RT_MANGLER(RTPathFilename)
# define RTPathFilenameEx RT_MANGLER(RTPathFilenameEx)
# define RTPathGetCurrent RT_MANGLER(RTPathGetCurrent)
+# define RTPathGetCurrentDrive RT_MANGLER(RTPathGetCurrentDrive)
+# define RTPathGetCurrentOnDrive RT_MANGLER(RTPathGetCurrentOnDrive)
# define RTPathGetMode RT_MANGLER(RTPathGetMode)
# define RTPathHasExt RT_MANGLER(RTPathHasExt)
# define RTPathHasPath RT_MANGLER(RTPathHasPath)
@@ -1797,6 +1799,7 @@
# define RTUriPath RT_MANGLER(RTUriPath)
# define RTUriQuery RT_MANGLER(RTUriQuery)
# define RTUriScheme RT_MANGLER(RTUriScheme)
+# define RTUtf16AllocTag RT_MANGLER(RTUtf16AllocTag)
# define RTUtf16CalcLatin1Len RT_MANGLER(RTUtf16CalcLatin1Len)
# define RTUtf16CalcLatin1LenEx RT_MANGLER(RTUtf16CalcLatin1LenEx)
# define RTUtf16CalcUtf8Len RT_MANGLER(RTUtf16CalcUtf8Len)
@@ -2913,6 +2916,7 @@
# define g_RTAsn1Boolean_Vtable RT_MANGLER(g_RTAsn1Boolean_Vtable)
# define g_RTAsn1BitString_Vtable RT_MANGLER(g_RTAsn1BitString_Vtable)
# define g_RTAsn1DefaultAllocator RT_MANGLER(g_RTAsn1DefaultAllocator)
+# define g_RTAsn1EFenceAllocator RT_MANGLER(g_RTAsn1EFenceAllocator)
#if 0 /* Disabled for now as I'm not sure the assmbler supports mangling yet. */
# define g_abRTZeroPage RT_MANGLER(g_abRTZeroPage)
# define g_abRTZero4K RT_MANGLER(g_abRTZero4K)
diff --git a/include/iprt/nt/nt.h b/include/iprt/nt/nt.h
index 4c16a55..2051214 100644
--- a/include/iprt/nt/nt.h
+++ b/include/iprt/nt/nt.h
@@ -237,6 +237,31 @@ RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULO
ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
RTDECL(int) RTNtPathClose(HANDLE hHandle);
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name. Free using
+ * RTNtPathFree.
+ * @param phRootDir Where to return the root handle, if applicable.
+ * @param pwszPath The UTF-16 windows-style path.
+ * @param cwcPath The max length of the windows-style path in
+ * RTUTF16 units. Use RTSTR_MAX if unknown and @a
+ * pwszPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszPath, size_t cwcPath);
+
+/**
+ * Frees the native path and root handle.
+ *
+ * @param pNtName The NT path after a successful
+ * RTNtPathFromWinUtf16Ex call.
+ * @param phRootDir The root handle variable after a successfull
+ * RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir);
+
+
RT_C_DECLS_END
/** @} */
@@ -365,6 +390,178 @@ typedef struct _CLIENT_ID
typedef CLIENT_ID *PCLIENT_ID;
#endif
+/** @name User Shared Data
+ * @{ */
+
+#ifdef IPRT_NT_USE_WINTERNL
+typedef struct _KSYSTEM_TIME
+{
+ ULONG LowPart;
+ LONG High1Time;
+ LONG High2Time;
+} KSYSTEM_TIME;
+typedef KSYSTEM_TIME *PKSYSTEM_TIME;
+
+typedef enum _NT_PRODUCT_TYPE
+{
+ NtProductWinNt = 1,
+ NtProductLanManNt,
+ NtProductServer
+} NT_PRODUCT_TYPE;
+
+#define PROCESSOR_FEATURE_MAX 64
+
+typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
+{
+ StandardDesign = 0,
+ NEC98x86,
+ EndAlternatives
+} ALTERNATIVE_ARCHITECTURE_TYPE;
+
+# if 0
+typedef struct _XSTATE_FEATURE
+{
+ ULONG Offset;
+ ULONG Size;
+} XSTATE_FEATURE;
+typedef XSTATE_FEATURE *PXSTATE_FEATURE;
+
+#define MAXIMUM_XSTATE_FEATURES 64
+
+typedef struct _XSTATE_CONFIGURATION
+{
+ ULONG64 EnabledFeatures;
+ ULONG Size;
+ ULONG OptimizedSave : 1;
+ XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES];
+} XSTATE_CONFIGURATION;
+typedef XSTATE_CONFIGURATION *PXSTATE_CONFIGURATION;
+# endif
+
+typedef struct _KUSER_SHARED_DATA
+{
+ ULONG TickCountLowDeprecated;
+ ULONG TickCountMultiplier;
+ KSYSTEM_TIME volatile InterruptTime;
+ KSYSTEM_TIME volatile SystemTime;
+ KSYSTEM_TIME volatile TimeZoneBias;
+ USHORT ImageNumberLow;
+ USHORT ImageNumberHigh;
+ WCHAR NtSystemRoot[260];
+ ULONG MaxStackTraceDepth;
+ ULONG CryptoExponent;
+ ULONG TimeZoneId;
+ ULONG LargePageMinimum;
+ ULONG AitSamplingValue;
+ ULONG AppCompatFlag;
+ ULONGLONG RNGSeedVersion;
+ ULONG GlobalValidationRunlevel;
+ LONG volatile TimeZoneBiasStamp;
+ ULONG Reserved2;
+ NT_PRODUCT_TYPE NtProductType;
+ BOOLEAN ProductTypeIsValid;
+ BOOLEAN Reserved0[1];
+ USHORT NativeProcessorArchitecture;
+ ULONG NtMajorVersion;
+ ULONG NtMinorVersion;
+ BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
+ ULONG Reserved1;
+ ULONG Reserved3;
+ ULONG volatile TimeSlip;
+ ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
+ ULONG AltArchitecturePad[1];
+ LARGE_INTEGER SystemExpirationDate;
+ ULONG SuiteMask;
+ BOOLEAN KdDebuggerEnabled;
+ union
+ {
+ UCHAR MitigationPolicies;
+ struct
+ {
+ UCHAR NXSupportPolicy : 2;
+ UCHAR SEHValidationPolicy : 2;
+ UCHAR CurDirDevicesSkippedForDlls : 2;
+ UCHAR Reserved : 2;
+ };
+ };
+ UCHAR Reserved6[2];
+ ULONG volatile ActiveConsoleId;
+ ULONG volatile DismountCount;
+ ULONG ComPlusPackage;
+ ULONG LastSystemRITEventTickCount;
+ ULONG NumberOfPhysicalPages;
+ BOOLEAN SafeBootMode;
+ UCHAR Reserved12[3];
+ union
+ {
+ ULONG SharedDataFlags;
+ struct
+ {
+ ULONG DbgErrorPortPresent : 1;
+ ULONG DbgElevationEnabled : 1;
+ ULONG DbgVirtEnabled : 1;
+ ULONG DbgInstallerDetectEnabled : 1;
+ ULONG DbgLkgEnabled : 1;
+ ULONG DbgDynProcessorEnabled : 1;
+ ULONG DbgConsoleBrokerEnabled : 1;
+ ULONG DbgSecureBootEnabled : 1;
+ ULONG SpareBits : 24;
+ };
+ };
+ ULONG DataFlagsPad[1];
+ ULONGLONG TestRetInstruction;
+ LONGLONG QpcFrequency;
+ ULONGLONG SystemCallPad[3];
+ union
+ {
+ ULONG64 volatile TickCountQuad;
+ KSYSTEM_TIME volatile TickCount;
+ struct
+ {
+ ULONG ReservedTickCountOverlay[3];
+ ULONG TickCountPad[1];
+ };
+ };
+ ULONG Cookie;
+ ULONG CookiePad[1];
+ LONGLONG ConsoleSessionForegroundProcessId;
+ ULONGLONG TimeUpdateLock;
+ ULONGLONG BaselineSystemTimeQpc;
+ ULONGLONG BaselineInterruptTimeQpc;
+ ULONGLONG QpcSystemTimeIncrement;
+ ULONGLONG QpcInterruptTimeIncrement;
+ ULONG QpcSystemTimeIncrement32;
+ ULONG QpcInterruptTimeIncrement32;
+ UCHAR QpcSystemTimeIncrementShift;
+ UCHAR QpcInterruptTimeIncrementShift;
+ UCHAR Reserved8[14];
+ USHORT UserModeGlobalLogger[16];
+ ULONG ImageFileExecutionOptions;
+ ULONG LangGenerationCount;
+ ULONGLONG Reserved4;
+ ULONGLONG volatile InterruptTimeBias;
+ ULONGLONG volatile QpcBias;
+ ULONG volatile ActiveProcessorCount;
+ UCHAR volatile ActiveGroupCount;
+ UCHAR Reserved9;
+ union
+ {
+ USHORT QpcData;
+ struct
+ {
+ BOOLEAN volatile QpcBypassEnabled;
+ UCHAR QpcShift;
+ };
+ };
+ LARGE_INTEGER TimeZoneBiasEffectiveStart;
+ LARGE_INTEGER TimeZoneBiasEffectiveEnd;
+ XSTATE_CONFIGURATION XState;
+} KUSER_SHARED_DATA;
+typedef KUSER_SHARED_DATA *PKUSER_SHARED_DATA;
+#endif /* IPRT_NT_USE_WINTERNL */
+/** @} */
+
+
/** @name Process And Thread Environment Blocks
* @{ */
@@ -1104,7 +1301,10 @@ typedef PPEB_COMMON PPEB;
typedef TEB_COMMON TEB;
typedef PTEB_COMMON PTEB;
-#define NtCurrentPeb() (((PTEB)NtCurrentTeb())->ProcessEnvironmentBlock)
+#define RTNtCurrentTeb() ((PTEB)NtCurrentTeb())
+#define RTNtCurrentPeb() (RTNtCurrentTeb()->ProcessEnvironmentBlock)
+#define NtCurrentPeb() RTNtCurrentPeb()
+#define RTNtCurrentThreadId() ((uint32_t)(uintptr_t)RTNtCurrentTeb()->ClientId.UniqueThread)
/** @} */
@@ -1172,6 +1372,15 @@ typedef struct _FILE_BOTH_DIR_INFORMATION
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION;
typedef FILE_BOTH_DIR_INFORMATION *PFILE_BOTH_DIR_INFORMATION;
+typedef struct _FILE_BASIC_INFORMATION
+{
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ ULONG FileAttributes;
+} FILE_BASIC_INFORMATION;
+typedef FILE_BASIC_INFORMATION *PFILE_BASIC_INFORMATION;
typedef struct _FILE_STANDARD_INFORMATION
{
LARGE_INTEGER AllocationSize;
@@ -1481,6 +1690,16 @@ typedef enum _SECTION_INFORMATION_CLASS
} SECTION_INFORMATION_CLASS;
NTSYSAPI NTSTATUS NTAPI NtQuerySection(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
+NTSYSAPI NTSTATUS NTAPI NtCreateSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING pTarget);
+NTSYSAPI NTSTATUS NTAPI NtOpenSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+NTSYSAPI NTSTATUS NTAPI NtQuerySymbolicLinkObject(HANDLE, PUNICODE_STRING, PULONG);
+#ifndef SYMBOLIC_LINK_QUERY
+# define SYMBOLIC_LINK_QUERY UINT32_C(0x00000001)
+#endif
+#ifndef SYMBOLIC_LINK_ALL_ACCESS
+# define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYMBOLIC_LINK_QUERY)
+#endif
+
NTSYSAPI NTSTATUS NTAPI NtQueryInformationThread(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
NTSYSAPI NTSTATUS NTAPI NtResumeThread(HANDLE, PULONG);
NTSYSAPI NTSTATUS NTAPI NtSuspendThread(HANDLE, PULONG);
@@ -1599,6 +1818,38 @@ typedef enum _SYSTEM_INFORMATION_CLASS
SystemInformation_Unknown_62,
SystemInformation_Unknown_63,
SystemExtendedHandleInformation, /* 64 */
+ SystemInformation_Unknown_65,
+ SystemInformation_Unknown_66,
+ SystemInformation_Unknown_67,
+ SystemInformation_Unknown_68,
+ SystemInformation_HotPatchInfo, /* 69 */
+ SystemInformation_Unknown_70,
+ SystemInformation_Unknown_71,
+ SystemInformation_Unknown_72,
+ SystemInformation_Unknown_73,
+ SystemInformation_Unknown_74,
+ SystemInformation_Unknown_75,
+ SystemInformation_Unknown_76,
+ SystemInformation_Unknown_77,
+ SystemInformation_Unknown_78,
+ SystemInformation_Unknown_79,
+ SystemInformation_Unknown_80,
+ SystemInformation_Unknown_81,
+ SystemInformation_Unknown_82,
+ SystemInformation_Unknown_83,
+ SystemInformation_Unknown_84,
+ SystemInformation_Unknown_85,
+ SystemInformation_Unknown_86,
+ SystemInformation_Unknown_87,
+ SystemInformation_Unknown_88,
+ SystemInformation_Unknown_89,
+ SystemInformation_Unknown_90,
+ SystemInformation_Unknown_91,
+ SystemInformation_Unknown_92,
+ SystemInformation_Unknown_93,
+ SystemInformation_Unknown_94,
+ SystemInformation_Unknown_95,
+ SystemInformation_KiOpPrefetchPatchCount,
/** @todo fill gap. they've added a whole bunch of things */
SystemPolicyInformation = 134,
@@ -1722,11 +1973,40 @@ NTSYSAPI NTSTATUS NTAPI NtYieldExecution(void);
#ifndef IPRT_NT_USE_WINTERNL
NTSYSAPI NTSTATUS NTAPI NtWaitForSingleObject(HANDLE, BOOLEAN PLARGE_INTEGER);
#endif
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTWAITFORSINGLEOBJECT)(HANDLE, BOOLEAN, PLARGE_INTEGER);
typedef enum _OBJECT_WAIT_TYPE { WaitAllObjects = 0, WaitAnyObject = 1, ObjectWaitTypeHack = 0x7fffffff } OBJECT_WAIT_TYPE;
NTSYSAPI NTSTATUS NTAPI NtWaitForMultipleObjects(ULONG, PHANDLE, OBJECT_WAIT_TYPE, BOOLEAN, PLARGE_INTEGER);
NTSYSAPI NTSTATUS NTAPI NtQuerySecurityObject(HANDLE, ULONG, PSECURITY_DESCRIPTOR, ULONG, PULONG);
+#ifdef IPRT_NT_USE_WINTERNL
+typedef enum _EVENT_TYPE
+{
+ /* Manual reset event. */
+ NotificationEvent = 0,
+ /* Automaitc reset event. */
+ SynchronizationEvent
+} EVENT_TYPE;
+#endif
+NTSYSAPI NTSTATUS NTAPI NtCreateEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
+NTSYSAPI NTSTATUS NTAPI NtOpenEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTCLEAREVENT)(HANDLE);
+NTSYSAPI NTSTATUS NTAPI NtClearEvent(HANDLE);
+NTSYSAPI NTSTATUS NTAPI NtResetEvent(HANDLE, PULONG);
+NTSYSAPI NTSTATUS NTAPI NtSetEvent(HANDLE, PULONG);
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTSETEVENT)(HANDLE, PULONG);
+typedef enum _EVENT_INFORMATION_CLASS
+{
+ EventBasicInformation = 0
+} EVENT_INFORMATION_CLASS;
+/** Data returned by NtQueryEvent + EventBasicInformation. */
+typedef struct EVENT_BASIC_INFORMATION
+{
+ EVENT_TYPE EventType;
+ ULONG EventState;
+} EVENT_BASIC_INFORMATION;
+typedef EVENT_BASIC_INFORMATION *PEVENT_BASIC_INFORMATION;
+NTSYSAPI NTSTATUS NTAPI NtQueryEvent(HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
#ifdef IPRT_NT_USE_WINTERNL
/** For NtQueryValueKey. */
@@ -1879,8 +2159,41 @@ typedef struct CSR_MSG_DATA_CREATED_PROCESS
#define CSR_MSG_NO_CREATED_THREAD UINT32_C(0x10001)
NTSYSAPI NTSTATUS NTAPI CsrClientCallServer(PVOID, PVOID, ULONG, SIZE_T);
#endif
+
NTSYSAPI VOID NTAPI LdrInitializeThunk(PVOID, PVOID, PVOID);
+
+typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA
+{
+ ULONG Flags;
+ PCUNICODE_STRING FullDllName;
+ PCUNICODE_STRING BaseDllName;
+ PVOID DllBase;
+ ULONG SizeOfImage;
+} LDR_DLL_LOADED_NOTIFICATION_DATA, LDR_DLL_UNLOADED_NOTIFICATION_DATA;
+typedef LDR_DLL_LOADED_NOTIFICATION_DATA *PLDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
+typedef LDR_DLL_LOADED_NOTIFICATION_DATA const *PCLDR_DLL_LOADED_NOTIFICATION_DATA, *PCLDR_DLL_UNLOADED_NOTIFICATION_DATA;
+
+typedef union _LDR_DLL_NOTIFICATION_DATA
+{
+ LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
+ LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
+} LDR_DLL_NOTIFICATION_DATA;
+typedef LDR_DLL_NOTIFICATION_DATA *PLDR_DLL_NOTIFICATION_DATA;
+typedef LDR_DLL_NOTIFICATION_DATA const *PCLDR_DLL_NOTIFICATION_DATA;
+
+typedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser);
+
+#define LDR_DLL_NOTIFICATION_REASON_LOADED UINT32_C(1)
+#define LDR_DLL_NOTIFICATION_REASON_UNLOADED UINT32_C(2)
+NTSYSAPI NTSTATUS NTAPI LdrRegisterDllNotification(ULONG fFlags, PLDR_DLL_NOTIFICATION_FUNCTION pfnCallback, PVOID pvUser,
+ PVOID *pvCookie);
+typedef NTSTATUS (NTAPI *PFNLDRREGISTERDLLNOTIFICATION)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, PVOID, PVOID *);
+NTSYSAPI NTSTATUS NTAPI LdrUnregisterDllNotification(PVOID pvCookie);
+typedef NTSTATUS (NTAPI *PFNLDRUNREGISTERDLLNOTIFICATION)(PVOID);
+
NTSYSAPI NTSTATUS NTAPI RtlExpandEnvironmentStrings_U(PVOID, PUNICODE_STRING, PUNICODE_STRING, PULONG);
+NTSYSAPI VOID NTAPI RtlExitUserProcess(NTSTATUS rcExitCode); /**< Vista and later. */
+NTSYSAPI VOID NTAPI RtlExitUserThread(NTSTATUS rcExitCode);
NTSYSAPI NTSTATUS NTAPI RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags,
IN PCUNICODE_STRING pOrgName,
IN PUNICODE_STRING pDefaultSuffix,
@@ -1890,7 +2203,90 @@ NTSYSAPI NTSTATUS NTAPI RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags
IN PULONG pfNewFlags OPTIONAL,
IN PSIZE_T pcbFilename OPTIONAL,
IN PSIZE_T pcbNeeded OPTIONAL);
+
+# ifdef IPRT_NT_USE_WINTERNL
+typedef NTSTATUS NTAPI RTL_HEAP_COMMIT_ROUTINE(PVOID, PVOID *, PSIZE_T);
+typedef RTL_HEAP_COMMIT_ROUTINE *PRTL_HEAP_COMMIT_ROUTINE;
+typedef struct _RTL_HEAP_PARAMETERS
+{
+ ULONG Length;
+ SIZE_T SegmentReserve;
+ SIZE_T SegmentCommit;
+ SIZE_T DeCommitFreeBlockThreshold;
+ SIZE_T DeCommitTotalFreeThreshold;
+ SIZE_T MaximumAllocationSize;
+ SIZE_T VirtualMemoryThreshold;
+ SIZE_T InitialCommit;
+ SIZE_T InitialReserve;
+ PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
+ SIZE_T Reserved[2];
+} RTL_HEAP_PARAMETERS;
+typedef RTL_HEAP_PARAMETERS *PRTL_HEAP_PARAMETERS;
+NTSYSAPI PVOID NTAPI RtlCreateHeap(ULONG fFlags, PVOID pvHeapBase, SIZE_T cbReserve, SIZE_T cbCommit, PVOID pvLock,
+ PRTL_HEAP_PARAMETERS pParameters);
+/** @name Heap flags (for RtlCreateHeap).
+ * @{ */
+/*# define HEAP_NO_SERIALIZE UINT32_C(0x00000001)
+# define HEAP_GROWABLE UINT32_C(0x00000002)
+# define HEAP_GENERATE_EXCEPTIONS UINT32_C(0x00000004)
+# define HEAP_ZERO_MEMORY UINT32_C(0x00000008)
+# define HEAP_REALLOC_IN_PLACE_ONLY UINT32_C(0x00000010)
+# define HEAP_TAIL_CHECKING_ENABLED UINT32_C(0x00000020)
+# define HEAP_FREE_CHECKING_ENABLED UINT32_C(0x00000040)
+# define HEAP_DISABLE_COALESCE_ON_FREE UINT32_C(0x00000080)*/
+# define HEAP_SETTABLE_USER_VALUE UINT32_C(0x00000100)
+# define HEAP_SETTABLE_USER_FLAG1 UINT32_C(0x00000200)
+# define HEAP_SETTABLE_USER_FLAG2 UINT32_C(0x00000400)
+# define HEAP_SETTABLE_USER_FLAG3 UINT32_C(0x00000800)
+# define HEAP_SETTABLE_USER_FLAGS UINT32_C(0x00000e00)
+# define HEAP_CLASS_0 UINT32_C(0x00000000)
+# define HEAP_CLASS_1 UINT32_C(0x00001000)
+# define HEAP_CLASS_2 UINT32_C(0x00002000)
+# define HEAP_CLASS_3 UINT32_C(0x00003000)
+# define HEAP_CLASS_4 UINT32_C(0x00004000)
+# define HEAP_CLASS_5 UINT32_C(0x00005000)
+# define HEAP_CLASS_6 UINT32_C(0x00006000)
+# define HEAP_CLASS_7 UINT32_C(0x00007000)
+# define HEAP_CLASS_8 UINT32_C(0x00008000)
+# define HEAP_CLASS_MASK UINT32_C(0x0000f000)
+# endif
+# define HEAP_CLASS_PROCESS HEAP_CLASS_0
+# define HEAP_CLASS_PRIVATE HEAP_CLASS_1
+# define HEAP_CLASS_KERNEL HEAP_CLASS_2
+# define HEAP_CLASS_GDI HEAP_CLASS_3
+# define HEAP_CLASS_USER HEAP_CLASS_4
+# define HEAP_CLASS_CONSOLE HEAP_CLASS_5
+# define HEAP_CLASS_USER_DESKTOP HEAP_CLASS_6
+# define HEAP_CLASS_CSRSS_SHARED HEAP_CLASS_7
+# define HEAP_CLASS_CSRSS_PORT HEAP_CLASS_8
+# ifdef IPRT_NT_USE_WINTERNL
+/*# define HEAP_CREATE_ALIGN_16 UINT32_C(0x00010000)
+# define HEAP_CREATE_ENABLE_TRACING UINT32_C(0x00020000)
+# define HEAP_CREATE_ENABLE_EXECUTE UINT32_C(0x00040000)*/
+# define HEAP_CREATE_VALID_MASK UINT32_C(0x0007f0ff)
+# endif /* IPRT_NT_USE_WINTERNL */
+/** @} */
+# ifdef IPRT_NT_USE_WINTERNL
+/** @name Heap tagging constants
+ * @{ */
+# define HEAP_GLOBAL_TAG UINT32_C(0x00000800)
+/*# define HEAP_MAXIMUM_TAG UINT32_C(0x00000fff)
+# define HEAP_PSEUDO_TAG_FLAG UINT32_C(0x00008000)
+# define HEAP_TAG_SHIFT 18 */
+# define HEAP_TAG_MASK (HEAP_MAXIMUM_TAG << HEAP_TAG_SHIFT)
+/** @} */
+NTSYSAPI PVOID NTAPI RtlAllocateHeap(HANDLE hHeap, ULONG fFlags, SIZE_T cb);
+NTSYSAPI PVOID NTAPI RtlReAllocateHeap(HANDLE hHeap, ULONG fFlags, PVOID pvOld, SIZE_T cbNew);
+NTSYSAPI BOOLEAN NTAPI RtlFreeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem);
+# endif /* IPRT_NT_USE_WINTERNL */
+NTSYSAPI SIZE_T NTAPI RtlCompactHeap(HANDLE hHeap, ULONG fFlags);
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING);
+NTSYSAPI SIZE_T NTAPI RtlSizeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem);
+NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus(VOID);
+NTSYSAPI ULONG NTAPI RtlGetLastWin32Error(VOID);
+NTSYSAPI VOID NTAPI RtlSetLastWin32Error(ULONG uError);
+NTSYSAPI VOID NTAPI RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS rcNt);
+NTSYSAPI VOID NTAPI RtlRestoreLastWin32Error(ULONG uError);
RT_C_DECLS_END
/** @} */
diff --git a/include/iprt/path.h b/include/iprt/path.h
index 7067a1b..d147d95 100644
--- a/include/iprt/path.h
+++ b/include/iprt/path.h
@@ -239,6 +239,32 @@ RTDECL(int) RTPathSetCurrent(const char *pszPath);
RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath);
/**
+ * Gets the current working directory on the specified drive.
+ *
+ * On systems without drive letters, the root slash will be returned.
+ *
+ * @returns IPRT status code.
+ * @param chDrive The drive we're querying the driver letter on.
+ * @param pszPath Where to store the working directroy path.
+ * @param cbPath The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath);
+
+/**
+ * Gets the current working drive of the process.
+ *
+ * Normally drive letter and colon will be returned, never trailing a root
+ * slash. If the current directory is on a UNC share, the root of the share
+ * will be returned. On systems without drive letters, an empty string is
+ * returned for consistency.
+ *
+ * @returns IPRT status code.
+ * @param pszPath Where to store the working drive or UNC root.
+ * @param cbPath The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath);
+
+/**
* Get the real path (no symlinks, no . or .. components), must exist.
*
* @returns iprt status code.
diff --git a/include/iprt/string.h b/include/iprt/string.h
index 22a4097..60d2346 100644
--- a/include/iprt/string.h
+++ b/include/iprt/string.h
@@ -3219,6 +3219,52 @@ RTDECL(uint32_t) RTStrHash1ExNV(size_t cPairs, va_list va);
*/
/**
+ * Allocates memory for UTF-16 string storage (default tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string. The first wide char is
+ * always set to the string terminator char, the contents of the
+ * remainder of the memory is undefined. The string must be freed by
+ * calling RTUtf16Free.
+ *
+ * NULL is returned if the allocation failed. Please translate this to
+ * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider
+ * RTUtf16AllocEx if an IPRT status code is required.
+ *
+ * @param cb How many bytes to allocate, will be rounded up
+ * to a multiple of two. If this is zero, we will
+ * allocate a terminator wide char anyway.
+ */
+#define RTUtf16Alloc(cb) RTUtf16AllocTag((cb), RTSTR_TAG)
+
+/**
+ * Allocates memory for UTF-16 string storage (custom tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string. The first wide char is
+ * always set to the string terminator char, the contents of the
+ * remainder of the memory is undefined. The string must be freed by
+ * calling RTUtf16Free.
+ *
+ * NULL is returned if the allocation failed. Please translate this to
+ * VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY. Also consider
+ * RTUtf16AllocExTag if an IPRT status code is required.
+ *
+ * @param cb How many bytes to allocate, will be rounded up
+ * to a multiple of two. If this is zero, we will
+ * allocate a terminator wide char anyway.
+ * @param pszTag Allocation tag used for statistics and such.
+ */
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag);
+
+
+/**
* Free a UTF-16 string allocated by RTStrToUtf16(), RTStrToUtf16Ex(),
* RTLatin1ToUtf16(), RTLatin1ToUtf16Ex(), RTUtf16Dup() or RTUtf16DupEx().
*
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
index c3ae0ec..5a8a459 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
@@ -130,6 +130,9 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
case 3:
g_enmVbgdNtVer = VBGDNTVER_WIN81;
break;
+ case 4:
+ g_enmVbgdNtVer = VBGDNTVER_WIN10;
+ break;
default:
Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n", ulMajorVer, ulMinorVer));
rc = STATUS_DRIVER_UNABLE_TO_LOAD;
@@ -1304,6 +1307,14 @@ VBOXOSTYPE vbgdNtVersionToOSType(VBGDNTVER enmNtVer)
#endif
break;
+ case VBGDNTVER_WIN10:
+#if ARCH_BITS == 64
+ enmOsType = VBOXOSTYPE_Win10_x64;
+#else
+ enmOsType = VBOXOSTYPE_Win10;
+#endif
+ break;
+
default:
/* We don't know, therefore NT family. */
enmOsType = VBOXOSTYPE_WinNT;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
index aee6367..8491a20 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
@@ -136,6 +136,7 @@ typedef enum VBGDNTVER
VBGDNTVER_WIN7,
VBGDNTVER_WIN8,
VBGDNTVER_WIN81,
+ VBGDNTVER_WIN10
} VBGDNTVER;
extern VBGDNTVER g_enmVbgdNtVer;
diff --git a/src/VBox/Additions/linux/Makefile.kmk b/src/VBox/Additions/linux/Makefile.kmk
index 4ac2c75..26f2da7 100644
--- a/src/VBox/Additions/linux/Makefile.kmk
+++ b/src/VBox/Additions/linux/Makefile.kmk
@@ -252,7 +252,7 @@ $(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),\
# pattern rule for stripping and copying vbox-greeter to the installation directory
$(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),vbox-greeter): \
- $(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(subst linux,linux2,$(PATH_STAGE_BIN))/additions/% \
+ $(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(subst linux.amd64/release,linux.amd64/release/greeter,$(subst linux.x86/release,linux.x86/release/greeter,$(PATH_STAGE_BIN)))/additions/% \
| $$(dir $$@)
$(call MSG_INST_FILE,$<,$@)
$(QUIET)$(INSTALL) -m 0755 $< $@
diff --git a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
index 726e207..d6dab14 100644
--- a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
+++ b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
@@ -537,11 +537,8 @@ vbox_output_set_property(xf86OutputPtr output, Atom property,
return FALSE;
pVBox->aPreferredSize[cDisplay].cx = w;
pVBox->aPreferredSize[cDisplay].cy = h;
- return TRUE;
}
- if (property == vboxAtomEDID())
- return TRUE;
- return FALSE;
+ return TRUE;
}
#endif
diff --git a/src/VBox/Debugger/DBGPlugInSolaris.cpp b/src/VBox/Debugger/DBGPlugInSolaris.cpp
index 4c7f017..c8fa67f 100644
--- a/src/VBox/Debugger/DBGPlugInSolaris.cpp
+++ b/src/VBox/Debugger/DBGPlugInSolaris.cpp
@@ -516,7 +516,7 @@ static void dbgDiggerSolarisProcessModCtl32(PUVM pUVM, PDBGDIGGERSOLARIS pThis,
return;
/* Ignore modules without symbols. */
- if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symspace)
+ if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symsize)
return;
/* Check that the symtbl and strings points inside the symspace. */
@@ -662,7 +662,7 @@ static void dbgDiggerSolarisProcessModCtl64(PUVM pUVM, PDBGDIGGERSOLARIS pThis,
return;
/* Ignore modules without symbols. */
- if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symspace)
+ if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symsize)
return;
/* Check that the symtbl and strings points inside the symspace. */
diff --git a/src/VBox/Devices/Bus/DevPCI.cpp b/src/VBox/Devices/Bus/DevPCI.cpp
index c454d8b..5b16ec1 100644
--- a/src/VBox/Devices/Bus/DevPCI.cpp
+++ b/src/VBox/Devices/Bus/DevPCI.cpp
@@ -804,7 +804,6 @@ static void pciR3Piix3Reset(PIIX3State *d)
pci_conf[0x80] = 0x00;
pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
pci_conf[0xa0] = 0x08;
- pci_conf[0xa0] = 0x08;
pci_conf[0xa2] = 0x00;
pci_conf[0xa3] = 0x00;
pci_conf[0xa4] = 0x00;
diff --git a/src/VBox/Devices/EFI/DevSmc.cpp b/src/VBox/Devices/EFI/DevSmc.cpp
index fc7cf37..1de17a4 100644
--- a/src/VBox/Devices/EFI/DevSmc.cpp
+++ b/src/VBox/Devices/EFI/DevSmc.cpp
@@ -243,6 +243,7 @@ AssertCompileMembersAtSameOffset(DEVSMC, u.abRegsRW[SMC_REG_STATUS_CODE], DEVSMC
/** Pointer to the SMC state. */
typedef DEVSMC *PDEVSMC;
+#ifndef VBOX_DEVICE_STRUCT_TESTCASE
/**
@@ -1428,3 +1429,4 @@ const PDMDEVREG g_DeviceSmc =
};
#endif /* IN_RING3 */
+#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd
index e726413..de413bd 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd differ
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd
index d22e9ce..043d1d8 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd differ
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
index 28ab4a8..ca12aab 100644
--- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
@@ -522,6 +522,9 @@ static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCt
pCtx->aViews[uScreenId].pVBVA = pVBVA;
pCtx->aViews[uScreenId].u32VBVAOffset = u32Offset;
+
+ /* VBVA is working so disable the pause. */
+ pCtx->fPaused = false;
}
return rc;
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index 9bfbffa..1d033db 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -18,9 +18,6 @@
SUB_DEPTH = ../../..
include $(KBUILD_PATH)/subheader.kmk
-# Enable the new SMC code.
-VBOX_WITH_SMC_NEW = 1
-
# Make sure our Config.kmk is included.
ifndef VBOX_DEVICES_CONFIG_KMK_INCLUDED
include $(PATH_SUB_CURRENT)/Config.kmk
@@ -121,8 +118,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
VBOX_WITH_HGCM \
$(if $(VBOX_BIOS_DMI_FALLBACK),VBOX_BIOS_DMI_FALLBACK,) \
VBOX_WITH_DMI_CHASSIS \
- VBOX_WITH_DMI_OEMSTRINGS \
- $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ VBOX_WITH_DMI_OEMSTRINGS
VBoxDD_DEFS.win = _WIN32_WINNT=0x0510
ifeq ($(KBUILD_TARGET_ARCH),x86)
VBoxDD_DEFS.darwin = VBOX_WITH_2X_4GB_ADDR_SPACE
@@ -139,7 +135,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Bus/DevPciIch9.cpp \
Bus/MsiCommon.cpp \
Bus/MsixCommon.cpp \
- $(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+ EFI/DevSmc.cpp \
Graphics/DevVGA.cpp \
Storage/DevATA.cpp \
PC/DevPit-i8254.cpp \
@@ -802,7 +798,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Bus/DevPciIch9.cpp \
Bus/MsiCommon.cpp \
Bus/MsixCommon.cpp \
- $(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+ EFI/DevSmc.cpp \
Graphics/DevVGA.cpp \
Input/DevPS2.cpp \
Input/PS2K.cpp \
@@ -912,7 +908,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
# VBoxDD2 (shared object)
#
VBoxDD2_TEMPLATE = VBoxR3DllWarnNoPic
- VBoxDD2_DEFS = IN_VBOXDD2 $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ VBoxDD2_DEFS = IN_VBOXDD2
VBoxDD2_INCS := \
build \
$(PATH_SUB_CURRENT)
@@ -920,7 +916,6 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
build/VBoxDD2.cpp \
PC/DevAPIC.cpp \
PC/DevIoApic.cpp \
- $(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp) \
PC/DevLPC.cpp
VBoxDD2_LIBS = \
$(PATH_STAGE_LIB)/PcBiosBin$(VBOX_SUFF_LIB) \
@@ -956,7 +951,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Bus/DevPciIch9.cpp \
Bus/MsiCommon.cpp \
Bus/MsixCommon.cpp \
- $(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+ EFI/DevSmc.cpp \
Graphics/DevVGA.cpp \
Input/DevPS2.cpp \
Input/PS2K.cpp \
@@ -1085,12 +1080,10 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
# VBoxDD2GC (LGPL sysmod)
#
VBoxDD2GC_TEMPLATE = VBoxRc
- VBoxDD2GC_DEFS = $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
VBoxDD2GC_INCS = build
VBoxDD2GC_SOURCES = \
PC/DevAPIC.cpp \
- PC/DevIoApic.cpp \
- $(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp)
+ PC/DevIoApic.cpp
if1of ($(VBOX_LDR_FMT32), pe lx)
VBoxDD2GC_LIBS = \
$(PATH_STAGE_LIB)/VMMRCBuiltin$(VBOX_SUFF_LIB) \
@@ -1103,13 +1096,12 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
# VBoxDD2R0 (LGPL sysmod)
#
VBoxDD2R0_TEMPLATE = VBoxR0
- VBoxDD2R0_DEFS = IN_RT_R0 $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ VBoxDD2R0_DEFS = IN_RT_R0
VBoxDD2R0_INCS = build
VBoxDD2R0_SOURCES = \
build/VBoxDD2R0.cpp \
PC/DevAPIC.cpp \
PC/DevIoApic.cpp \
- $(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp)
if1of ($(VBOX_LDR_FMT), pe lx)
VBoxDD2R0_LIBS = \
diff --git a/src/VBox/Devices/Network/DrvNAT.cpp b/src/VBox/Devices/Network/DrvNAT.cpp
index 12dbb94..0980633 100644
--- a/src/VBox/Devices/Network/DrvNAT.cpp
+++ b/src/VBox/Devices/Network/DrvNAT.cpp
@@ -971,7 +971,7 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
{
PDRVNAT pThis = (PDRVNAT)pvUser;
- LogRel(("NAT: System configuration has changed\n"));
+ Log2(("NAT: System configuration has changed\n"));
/* Check if any of parameters we are interested in were actually changed. If the size
* of hChangedKeys is 0, it means that SCDynamicStore has been restarted. */
@@ -983,14 +983,13 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
if (CFArrayContainsValue(hChangedKeys, CFRangeMake(0, CFArrayGetCount(hChangedKeys)), pDNSKey))
{
LogRel(("NAT: DNS servers changed, triggering reconnect\n"));
-
+#if 0
CFDictionaryRef hDnsDict = (CFDictionaryRef)SCDynamicStoreCopyValue(hDynStor, pDNSKey);
if (hDnsDict)
{
CFArrayRef hArrAddresses = (CFArrayRef)CFDictionaryGetValue(hDnsDict, kSCPropNetDNSServerAddresses);
if (hArrAddresses && CFArrayGetCount(hArrAddresses) > 0)
{
-#if 1
/* Dump DNS servers list. */
for (int i = 0; i < CFArrayGetCount(hArrAddresses); i++)
{
@@ -998,7 +997,6 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
const char *pszDNSAddr = pDNSAddrStr ? CFStringGetCStringPtr(pDNSAddrStr, CFStringGetSystemEncoding()) : NULL;
LogRel(("NAT: New DNS server#%d: %s\n", i, pszDNSAddr ? pszDNSAddr : "None"));
}
-#endif
}
else
LogRel(("NAT: DNS server list is empty (1)\n"));
@@ -1007,14 +1005,14 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
}
else
LogRel(("NAT: DNS server list is empty (2)\n"));
-
+#endif
drvNATHostNetworkConfigurationChangeEventStrategySelector(pThis, /* RT_OS_DARWIN */ true);
}
else
- LogRel(("NAT: No DNS changes detected\n"));
+ Log2(("NAT: No DNS changes detected\n"));
}
else
- LogRel(("NAT: SCDynamicStore has been restarted\n"));
+ Log2(("NAT: SCDynamicStore has been restarted\n"));
}
#endif
diff --git a/src/VBox/Devices/Network/slirp/slirp_dns.c b/src/VBox/Devices/Network/slirp/slirp_dns.c
index 4f56304..9ff44c1 100644
--- a/src/VBox/Devices/Network/slirp/slirp_dns.c
+++ b/src/VBox/Devices/Network/slirp/slirp_dns.c
@@ -247,16 +247,9 @@ static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
*ppszDomain = NULL;
Log(("NAT: DNS Servers:\n"));
-#ifdef RT_OS_DARWIN
- LogRel(("NAT: /etc/resolv.conf dump:\n"));
- int cLine = 0;
-#endif
while ( RT_SUCCESS(rc = RTFileGets(ResolvConfFile, buff, sizeof(buff), &bytes))
&& rc != VERR_EOF)
{
-#ifdef RT_OS_DARWIN
- LogRel(("NAT: resolv.conf:%d: %s\n", ++cLine, buff));
-#endif
struct dns_entry *pDns = NULL;
if ( cNameserversFound == 4
&& !fWarnTooManyDnsServers
diff --git a/src/VBox/Devices/PC/BIOS/ahci.c b/src/VBox/Devices/PC/BIOS/ahci.c
index d91a8e9..cb1ccf4 100644
--- a/src/VBox/Devices/PC/BIOS/ahci.c
+++ b/src/VBox/Devices/PC/BIOS/ahci.c
@@ -728,7 +728,7 @@ void ahci_port_detect_device(ahci_t __far *ahci, uint8_t u8Port)
else
set_geom_lba(&lgeo, sectors); /* Default EDD-style translated LBA geometry. */
- BX_INFO("AHCI %d-P#%d: PCHS=%u/%d/%d LCHS=%u/%u/%u %ld sectors\n", devcount_ahci,
+ BX_INFO("AHCI %d-P#%d: PCHS=%u/%u/%u LCHS=%u/%u/%u %lu sectors\n", devcount_ahci,
u8Port, cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt, sectors);
bios_dsk->devices[hd_index].lchs = lgeo;
diff --git a/src/VBox/Devices/PC/BIOS/ata.c b/src/VBox/Devices/PC/BIOS/ata.c
index 921433d..84a17f7 100644
--- a/src/VBox/Devices/PC/BIOS/ata.c
+++ b/src/VBox/Devices/PC/BIOS/ata.c
@@ -512,8 +512,8 @@ void BIOSCALL ata_detect(void)
else
set_geom_lba(&lgeo, sectors); /* Default EDD-style translated LBA geometry. */
- BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave,
- cylinders,heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt);
+ BX_INFO("ata%d-%d: PCHS=%u/%u/%u LCHS=%u/%u/%u\n", channel, slave,
+ cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt);
bios_dsk->devices[device].device = DSK_DEVICE_HD;
bios_dsk->devices[device].removable = removable;
diff --git a/src/VBox/Devices/PC/BIOS/scsi.c b/src/VBox/Devices/PC/BIOS/scsi.c
index b40255e..236a4db 100644
--- a/src/VBox/Devices/PC/BIOS/scsi.c
+++ b/src/VBox/Devices/PC/BIOS/scsi.c
@@ -511,7 +511,7 @@ void scsi_enumerate_attached_devices(uint16_t io_base)
else
bios_dsk->devices[hd_index].lchs.cylinders = (uint16_t)cylinders;
- BX_INFO("SCSI %d-ID#%d: LCHS=%u/%u/%u %ld sectors\n", devcount_scsi,
+ BX_INFO("SCSI %d-ID#%d: LCHS=%u/%u/%u %lu sectors\n", devcount_scsi,
i, (uint16_t)cylinders, heads, sectors_per_track, sectors);
/* Write PCHS values. */
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index d2a3add..e5fee2b 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -65,7 +65,7 @@
#define PM_TMR_FREQ 3579545
/* Default base for PM PIIX4 device */
#define PM_PORT_BASE 0x4000
-/* Port offsets in PM device */
+/* Port offsets in PM device */
enum
{
PM1a_EVT_OFFSET = 0x00,
@@ -78,6 +78,9 @@ enum
GPE1_OFFSET = -1 /**< not supported */
};
+/* Undef this to enable 24 bit PM timer (mostly for debugging purposes) */
+#define PM_TMR_32BIT
+
#define BAT_INDEX 0x00004040
#define BAT_DATA 0x00004044
#define SYSI_INDEX 0x00004048
@@ -218,6 +221,10 @@ typedef struct ACPIState
PTMTIMERR0 pPmTimerR0;
PTMTIMERRC pPmTimerRC;
+ /* PM Timer last calculated value */
+ uint32_t uPmTimerVal;
+ uint32_t Alignment0;
+
uint32_t gpe0_en;
uint32_t gpe0_sts;
@@ -309,7 +316,11 @@ typedef struct ACPIState
/** ACPI port interface. */
PDMIACPIPORT IACPIPort;
/** Pointer to the device instance. */
- PPDMDEVINSR3 pDevIns;
+ PPDMDEVINSR3 pDevInsR3;
+ PPDMDEVINSR0 pDevInsR0;
+ PPDMDEVINSRC pDevInsRC;
+
+ uint32_t Alignment1;
/** Pointer to the driver base interface. */
R3PTRTYPE(PPDMIBASE) pDrvBase;
/** Pointer to the driver connector interface. */
@@ -332,7 +343,7 @@ typedef struct ACPIState
uint8_t au8OemTabId[8];
/** ACPI custom OEM Rev */
uint32_t u32OemRevision;
- uint32_t Alignment0;
+ uint32_t Alignment2;
/** The custom table binary data. */
R3PTRTYPE(uint8_t *) pu8CustBin;
@@ -484,6 +495,17 @@ struct ACPITBLFADT
#define FADT_FL_FORCE_APIC_CLUSTER_MODEL RT_BIT(18)
#define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
+/* PM Timer mask and msb */
+#ifndef PM_TMR_32BIT
+#define TMR_VAL_MSB 0x800000
+#define TMR_VAL_MASK 0xffffff
+#undef FADT_FL_TMR_VAL_EXT
+#define FADT_FL_TMR_VAL_EXT 0
+#else
+#define TMR_VAL_MSB 0x80000000
+#define TMR_VAL_MASK 0xffffffff
+#endif
+
/** Start of the ACPI 2.0 extension. */
ACPIGENADDR ResetReg; /**< ext addr of reset register */
uint8_t u8ResetVal; /**< ResetReg value to reset the system */
@@ -619,13 +641,11 @@ RT_C_DECLS_END
static int acpiR3PlantTables(ACPIState *pThis);
#endif
-#ifdef IN_RING3
-
/* SCI IRQ */
-DECLINLINE(void) acpiR3SetIrq(ACPIState *pThis, int level)
+DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
{
if (pThis->pm1a_ctl & SCI_EN)
- PDMDevHlpPCISetIrq(pThis->pDevIns, 0, level);
+ PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, level);
}
DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
@@ -650,16 +670,17 @@ DECLINLINE(bool) gpe0_level(ACPIState *pThis)
/**
* Used by acpiR3PM1aStsWrite, acpiR3PM1aEnWrite, acpiR3PmTimer,
- * acpiR3Port_PowerBuffonPress and acpiR3Port_SleepButtonPress to
- * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
+ * acpiR3Port_PowerBuffonPress, acpiR3Port_SleepButtonPress
+ * and acpiPmTmrRead to update the PM1a.STS and PM1a.EN
+ * registers and trigger IRQs.
*
* Caller must hold the state lock.
*
* @param pThis The ACPI instance.
- * @param sts The new GPE0.STS value.
- * @param en The new GPE0.EN value.
+ * @param sts The new PM1a.STS value.
+ * @param en The new PM1a.EN value.
*/
-static void apicR3UpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
+static void apicUpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
{
Assert(PDMCritSectIsOwner(&pThis->CritSect));
@@ -669,15 +690,17 @@ static void apicR3UpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
int const old_level = pm1a_level(pThis);
int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
- Log(("apicR3UpdatePm1a() old=%x new=%x\n", old_level, new_level));
+ Log(("apicUpdatePm1a() old=%x new=%x\n", old_level, new_level));
pThis->pm1a_en = en;
pThis->pm1a_sts = sts;
if (new_level != old_level)
- acpiR3SetIrq(pThis, new_level);
+ acpiSetIrq(pThis, new_level);
}
+#ifdef IN_RING3
+
/**
* Used by acpiR3Gpe0StsWrite, acpiR3Gpe0EnWrite, acpiAttach and acpiDetach to
* update the GPE0.STS and GPE0.EN registers and trigger IRQs.
@@ -695,14 +718,14 @@ static void apicR3UpdateGpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
if (pm1a_level(pThis))
return;
- int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
+ int const old_level = gpe0_level(pThis);
int const new_level = (en & sts) != 0;
pThis->gpe0_en = en;
pThis->gpe0_sts = sts;
if (new_level != old_level)
- acpiR3SetIrq(pThis, new_level);
+ acpiSetIrq(pThis, new_level);
}
/**
@@ -713,7 +736,7 @@ static void apicR3UpdateGpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
*/
static int acpiR3DoPowerOff(ACPIState *pThis)
{
- int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
+ int rc = PDMDevHlpVMPowerOff(pThis->pDevInsR3);
if (RT_FAILURE(rc))
AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
return rc;
@@ -734,19 +757,19 @@ static int acpiR3DoSleep(ACPIState *pThis)
pThis->fSetWakeupOnResume = true;
if (pThis->fSuspendToSavedState)
{
- rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
+ rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevInsR3);
if (rc != VERR_NOT_SUPPORTED)
AssertRC(rc);
else
{
LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
- rc = PDMDevHlpVMSuspend(pThis->pDevIns);
+ rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
AssertRC(rc);
}
}
else
{
- rc = PDMDevHlpVMSuspend(pThis->pDevIns);
+ rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
AssertRC(rc);
}
return rc;
@@ -763,7 +786,7 @@ static DECLCALLBACK(int) acpiR3Port_PowerButtonPress(PPDMIACPIPORT pInterface)
Log(("acpiR3Port_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
pThis->fPowerButtonHandled = false;
- apicR3UpdatePm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
+ apicUpdatePm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
@@ -823,7 +846,7 @@ static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
DEVACPI_LOCK_R3(pThis);
- apicR3UpdatePm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
+ apicUpdatePm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
@@ -841,11 +864,40 @@ static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
static void acpiR3PmTimerReset(ACPIState *pThis, uint64_t uNow)
{
uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
- uint64_t uInterval = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
- TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
+ uint32_t uPmTmrCyclesToRollover = TMR_VAL_MSB - (pThis->uPmTimerVal & (TMR_VAL_MSB - 1));
+ uint64_t uInterval = ASMMultU64ByU32DivByU32(uPmTmrCyclesToRollover, uTimerFreq, PM_TMR_FREQ);
+ TMTimerSet(pThis->pPmTimerR3, uNow + uInterval + 1);
Log(("acpi: uInterval = %RU64\n", uInterval));
}
+#endif
+
+/**
+ * Used by acpiR3PMTimer & acpiPmTmrRead to update TMR_VAL and update TMR_STS
+ *
+ * The caller is expected to either hold the clock lock or to have made sure
+ * the VM is resetting or loading state.
+ *
+ * @param pThis The ACPI instance
+ * @param uNow The current time
+ */
+
+static void acpiPmTimerUpdate(ACPIState *pThis, uint64_t u64Now)
+{
+ uint32_t msb = pThis->uPmTimerVal & TMR_VAL_MSB;
+ uint64_t u64Elapsed = u64Now - pThis->u64PmTimerInitial;
+ Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPmTimer)));
+
+ pThis->uPmTimerVal = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer))) & TMR_VAL_MASK;
+
+ if ( (pThis->uPmTimerVal & TMR_VAL_MSB) != msb)
+ {
+ apicUpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
+ }
+}
+
+#ifdef IN_RING3
+
/**
* @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
*/
@@ -859,10 +911,11 @@ static DECLCALLBACK(void) acpiR3PmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, voi
Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
- apicR3UpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
+ uint64_t u64Now = TMTimerGet(pTimer);
+ acpiPmTimerUpdate(pThis, u64Now);
DEVACPI_UNLOCK(pThis);
- acpiR3PmTimerReset(pThis, TMTimerGet(pTimer));
+ acpiR3PmTimerReset(pThis, u64Now);
}
/**
@@ -1342,7 +1395,7 @@ PDMBOTHCBDECL(int) acpiR3PM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT
Log(("acpiR3PM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
u32 &= ~(RSR_EN | IGN_EN);
u32 &= 0xffff;
- apicR3UpdatePm1a(pThis, pThis->pm1a_sts, u32);
+ apicUpdatePm1a(pThis, pThis->pm1a_sts, u32);
DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
@@ -1385,7 +1438,7 @@ PDMBOTHCBDECL(int) acpiR3PM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT
if (u32 & PWRBTN_STS)
pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
- apicR3UpdatePm1a(pThis, u32, pThis->pm1a_en);
+ apicUpdatePm1a(pThis, u32, pThis->pm1a_en);
DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
@@ -1489,24 +1542,31 @@ PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port
/*
* We use the clock lock to serialize access to u64PmTimerInitial and to
- * make sure we get a reliable time from the clock.
+ * make sure we get a reliable time from the clock
+ * as well as and to prevent uPmTimerVal from being updated during read.
*/
+
int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
- if (rc == VINF_SUCCESS)
+ if (rc != VINF_SUCCESS)
+ return rc;
+
+ rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
+ if (rc != VINF_SUCCESS)
{
- uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
- uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
- TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
-
- /*
- * Calculate the return value.
- */
- DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
- uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
- *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
- Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
+ TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
+ return rc;
}
+ uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
+ acpiPmTimerUpdate(pThis, u64Now);
+ *pu32 = pThis->uPmTimerVal;
+
+ DEVACPI_UNLOCK(pThis);
+ TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
+
+ DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
+ Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
+
NOREF(pvUser); NOREF(Port);
return rc;
}
@@ -1711,7 +1771,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
#define R(offset, cnt, writer, reader, description) \
do { \
- rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
+ rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
NULL, NULL, description); \
if (RT_FAILURE(rc)) \
return rc; \
@@ -1730,7 +1790,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
/* register RC stuff */
if (pThis->fGCEnabled)
{
- rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
+ rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
1, 0, NULL, "acpiPMTmrRead",
NULL, NULL, "ACPI PM Timer");
AssertRCReturn(rc, rc);
@@ -1739,7 +1799,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
/* register R0 stuff */
if (pThis->fR0Enabled)
{
- rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
+ rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
1, 0, NULL, "acpiPMTmrRead",
NULL, NULL, "ACPI PM Timer");
AssertRCReturn(rc, rc);
@@ -1759,7 +1819,7 @@ static int acpiR3UnregisterPmHandlers(ACPIState *pThis)
{
#define U(offset, cnt) \
do { \
- int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiR3CalcPmPort(pThis, offset), cnt); \
+ int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt); \
AssertRCReturn(rc, rc); \
} while (0)
#define L (GPE0_BLK_LEN / 2)
@@ -1870,6 +1930,26 @@ static const SSMFIELD g_AcpiSavedStateFields6[] =
SSMFIELD_ENTRY_TERM()
};
+/**
+ * Saved state structure description, version 7.
+ */
+static const SSMFIELD g_AcpiSavedStateFields7[] =
+{
+ SSMFIELD_ENTRY(ACPIState, pm1a_en),
+ SSMFIELD_ENTRY(ACPIState, pm1a_sts),
+ SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
+ SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
+ SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
+ SSMFIELD_ENTRY(ACPIState, gpe0_en),
+ SSMFIELD_ENTRY(ACPIState, gpe0_sts),
+ SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
+ SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
+ SSMFIELD_ENTRY(ACPIState, uSleepState),
+ SSMFIELD_ENTRY(ACPIState, u8IndexShift),
+ SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
+ SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
+ SSMFIELD_ENTRY_TERM()
+};
/**
* @callback_method_impl{FNSSMDEVSAVEEXEC}
@@ -1877,7 +1957,7 @@ static const SSMFIELD g_AcpiSavedStateFields6[] =
static DECLCALLBACK(int) acpiR3SaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
{
ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
- return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
+ return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
}
/**
@@ -1907,6 +1987,9 @@ static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHand
case 6:
rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
break;
+ case 7:
+ rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
+ break;
default:
rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
break;
@@ -1923,7 +2006,14 @@ static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHand
if (RT_FAILURE(rc))
return rc;
TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
- acpiR3PmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
+ DEVACPI_LOCK_R3(pThis);
+ uint64_t u64Now = TMTimerGet(pThis->pPmTimerR3);
+ /* The interrupt may be incorrectly re-generated
+ * if the state is restored from versions < 7
+ */
+ acpiPmTimerUpdate(pThis, u64Now);
+ acpiR3PmTimerReset(pThis, u64Now);
+ DEVACPI_UNLOCK(pThis);
TMTimerUnlock(pThis->pPmTimerR3);
}
return rc;
@@ -1995,7 +2085,7 @@ static void acpiR3WriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
*/
DECLINLINE(void) acpiR3PhysCopy(ACPIState *pThis, RTGCPHYS32 GCPhys32Dst, const void *pvSrc, size_t cbToCopy)
{
- PDMDevHlpPhysWrite(pThis->pDevIns, GCPhys32Dst, pvSrc, cbToCopy);
+ PDMDevHlpPhysWrite(pThis->pDevInsR3, GCPhys32Dst, pvSrc, cbToCopy);
}
/**
@@ -2129,7 +2219,7 @@ static int acpiR3SetupRsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_en
rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
if (!rsdt)
- return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
+ return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
acpiR3PrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
for (unsigned int i = 0; i < nb_entries; ++i)
@@ -2513,15 +2603,15 @@ static int acpiR3PlantTables(ACPIState *pThis)
cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
- rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
+ rc = CFGMR3QueryU64(pThis->pDevInsR3->pCfg, "RamSize", &pThis->u64RamSize);
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
N_("Configuration error: Querying \"RamSize\" as integer failed"));
uint32_t cbRamHole;
- rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
+ rc = CFGMR3QueryU32Def(pThis->pDevInsR3->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
/*
@@ -2578,7 +2668,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
void *pvSsdtCode = NULL;
size_t cbSsdt = 0;
- rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdt);
+ rc = acpiPrepareSsdt(pThis->pDevInsR3, &pvSsdtCode, &cbSsdt);
if (RT_FAILURE(rc))
return rc;
@@ -2589,14 +2679,14 @@ static int acpiR3PlantTables(ACPIState *pThis)
void *pvDsdtCode = NULL;
size_t cbDsdt = 0;
- rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdt);
+ rc = acpiPrepareDsdt(pThis->pDevInsR3, &pvDsdtCode, &cbDsdt);
if (RT_FAILURE(rc))
return rc;
GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdt, 16);
if (GCPhysCur > 0x10000)
- return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
+ return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_TOO_MUCH_DATA,
N_("Error: ACPI tables bigger than 64KB"));
Log(("RSDP 0x%08X\n", apicR3FindRsdpSpace()));
@@ -2617,7 +2707,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
acpiR3SetupRsdp(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
acpiR3SetupDsdt(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdt);
- acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
+ acpiCleanupDsdt(pThis->pDevInsR3, pvDsdtCode);
acpiR3SetupFacs(pThis, GCPhysFacs + addend);
acpiR3SetupFadt(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
@@ -2649,7 +2739,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
}
acpiR3SetupSsdt(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdt);
- acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
+ acpiCleanupSsdt(pThis->pDevInsR3, pvSsdtCode);
aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
@@ -2826,6 +2916,7 @@ static DECLCALLBACK(void) acpiR3Reset(PPDMDEVINS pDevIns)
pThis->pm1a_sts = 0;
pThis->pm1a_ctl = 0;
pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
+ pThis->uPmTimerVal = 0;
acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
pThis->uBatteryIndex = 0;
pThis->uSystemInfoIndex = 0;
@@ -2875,7 +2966,9 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
*/
/** @todo move more of the code up! */
- pThis->pDevIns = pDevIns;
+ pThis->pDevInsR3 = pDevIns;
+ pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
+ pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
VMCPUSET_EMPTY(&pThis->CpuSetAttached);
VMCPUSET_EMPTY(&pThis->CpuSetLocked);
pThis->idCpuLockCheck = UINT32_C(0xffffffff);
@@ -3106,34 +3199,34 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
}
char *pszOemId = NULL;
- rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiOemId", &pszOemId, "VBOX ");
+ rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiOemId", &pszOemId, "VBOX ");
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
size_t cbOemId = strlen(pszOemId);
if (cbOemId > 6)
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
memcpy(pThis->au8OemId, pszOemId, cbOemId);
MMR3HeapFree(pszOemId);
char *pszCreatorId = NULL;
- rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
+ rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
size_t cbCreatorId = strlen(pszCreatorId);
if (cbCreatorId > 4)
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
MMR3HeapFree(pszCreatorId);
- rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
+ rc = CFGMR3QueryU32Def(pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
pThis->u32OemRevision = RT_H2LE_U32(0x1);
@@ -3141,16 +3234,16 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
* Get the custom table binary file name.
*/
char *pszCustBinFile;
- rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "CustomTable", &pszCustBinFile);
+ rc = CFGMR3QueryStringAlloc(pCfg, "CustomTable", &pszCustBinFile);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "SLICTable", &pszCustBinFile);
+ rc = CFGMR3QueryStringAlloc(pCfg, "SLICTable", &pszCustBinFile);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
pszCustBinFile = NULL;
rc = VINF_SUCCESS;
}
else if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"CustomTable\" as a string failed"));
else if (!*pszCustBinFile)
{
@@ -3179,7 +3272,7 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
/*
* Allocate buffer for the custom table binary data.
*/
- pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, pThis->cbCustBin);
+ pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbCustBin);
if (pThis->pu8CustBin)
{
rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
@@ -3327,7 +3420,7 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
/*
* Register the saved state.
*/
- rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
+ rc = PDMDevHlpSSMRegister(pDevIns, 7, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
if (RT_FAILURE(rc))
return rc;
diff --git a/src/VBox/Devices/PC/DevSMC.cpp b/src/VBox/Devices/PC/DevSMC.cpp
deleted file mode 100644
index 8844fe9..0000000
--- a/src/VBox/Devices/PC/DevSMC.cpp
+++ /dev/null
@@ -1,630 +0,0 @@
-/* $Id: DevSMC.cpp $ */
-/** @file
- * DevSMC - SMC device emulation.
- *
- * @todo Rainy day: Rewrite from scratch!!
- */
-
-/*
- * Copyright (C) 2006-2012 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on:
- *
- * Apple SMC controller
- *
- * Copyright (c) 2007 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * *****************************************************************
- *
- * In all Intel-based Apple hardware there is an SMC chip to control the
- * backlight, fans and several other generic device parameters. It also
- * contains the magic keys used to dongle Mac OS X to the device.
- *
- * This driver was mostly created by looking at the Linux AppleSMC driver
- * implementation and does not support IRQ.
- *
- */
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_SMC
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/log.h>
-#include <VBox/vmm/stam.h>
-#include <iprt/assert.h>
-#include <iprt/string.h>
-#ifdef IN_RING0
-# include <iprt/asm-amd64-x86.h>
-# include <iprt/once.h>
-# include <iprt/thread.h>
-#endif
-
-#include "VBoxDD2.h"
-
-
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
-/* data port used by Apple SMC */
-#define APPLESMC_DATA_PORT 0x300
-/* command/status port used by Apple SMC */
-#define APPLESMC_CMD_PORT 0x304
-#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
-#define APPLESMC_MAX_DATA_LENGTH 32
-
-#define APPLESMC_READ_CMD 0x10
-#define APPLESMC_WRITE_CMD 0x11
-#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
-#define APPLESMC_GET_KEY_TYPE_CMD 0x13
-
-/** The version of the saved state. */
-#define SMC_SAVED_STATE_VERSION 1
-
-/** The ring-0 operation number that attempts to get OSK0 and OSK1 from the real
- * SMC. */
-#define SMC_CALLR0_READ_OSK 1
-
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-typedef struct AppleSMCData
-{
- uint8_t len;
- const char *key;
- const char *data;
-} AppleSMCData;
-
-
-typedef struct
-{
- PPDMDEVINSR3 pDevIns;
-
- uint8_t cmd;
- uint8_t status;
- uint8_t key[4];
- uint8_t read_pos;
- uint8_t data_len;
- uint8_t data_pos;
- uint8_t data[255];
-
- /** The OSK0 value. This is currently only used in the constructor. */
- uint8_t abOsk0[32];
- /** The OSK1 value. This is currently only used in the constructor */
- uint8_t abOsk1[32];
-} SMCState;
-
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
-#ifdef IN_RING3
-static char osk[64];
-
-/* See http://www.mactel-linux.org/wiki/AppleSMC */
-static struct AppleSMCData data[] =
-{
- {6, "REV ", "\0x01\0x13\0x0f\0x00\0x00\0x03"},
- {32,"OSK0", osk },
- {32,"OSK1", osk+32 },
- {1, "NATJ", "\0" },
- {1, "MSSP", "\0" },
- {1, "MSSD", "\0x3" },
- {1, "NTOK", "\0"},
- {0, NULL, NULL }
-};
-#endif /* IN_RING3 */
-#ifdef IN_RING0
-/** Do once for the SMC ring-0 static data (g_abOsk0, g_abOsk1, g_fHaveOsk). */
-static RTONCE g_SmcR0Once = RTONCE_INITIALIZER;
-/** Indicates whether we've successfully queried the OSK* keys. */
-static bool g_fHaveOsk = false;
-/** The OSK0 value. */
-static uint8_t g_abOsk0[32];
-/** The OSK1 value. */
-static uint8_t g_abOsk1[32];
-#endif /* IN_RING0 */
-
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-
-#ifdef IN_RING0
-
-/**
- * Waits for the specified status on the host SMC.
- *
- * @returns success indicator.
- * @param bStatus The desired status.
- * @param pszWhat What we're currently doing. For the log.
- */
-static bool devR0SmcWaitHostStatus(uint8_t bStatus, const char *pszWhat)
-{
- uint8_t bCurStatus;
- for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1)
- {
- RTThreadSleep(cMsSleep);
- bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
- if ((bCurStatus & 0xf) == bStatus)
- return true;
- }
-
- LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", pszWhat, bCurStatus, bStatus));
- return false;
-}
-
-/**
- * Reads a key by name from the host SMC.
- *
- * @returns success indicator.
- * @param pszName The key name, must be exactly 4 chars long.
- * @param pbBuf The output buffer.
- * @param cbBuf The buffer size. Max 32 bytes.
- */
-static bool devR0SmcQueryHostKey(const char *pszName, uint8_t *pbBuf, size_t cbBuf)
-{
- Assert(strlen(pszName) == 4);
- Assert(cbBuf <= 32);
- Assert(cbBuf > 0);
-
- /*
- * Issue the READ command.
- */
- uint32_t cMsSleep = 1;
- for (;;)
- {
- ASMOutU8(APPLESMC_CMD_PORT, APPLESMC_READ_CMD);
- RTThreadSleep(cMsSleep);
- uint8_t bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
- if ((bCurStatus & 0xf) == 0xc)
- break;
- cMsSleep <<= 1;
- if (cMsSleep > 64)
- {
- LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", "cmd", bCurStatus, 0xc));
- return false;
- }
- }
-
- /*
- * Send it the key.
- */
- for (unsigned off = 0; off < 4; off++)
- {
- ASMOutU8(APPLESMC_DATA_PORT, pszName[off]);
- if (!devR0SmcWaitHostStatus(4, "key"))
- return false;
- }
-
- /*
- * The desired amount of output.
- */
- ASMOutU8(APPLESMC_DATA_PORT, (uint8_t)cbBuf);
-
- /*
- * Read the output.
- */
- for (size_t off = 0; off < cbBuf; off++)
- {
- if (!devR0SmcWaitHostStatus(5, off ? "data" : "len"))
- return false;
- pbBuf[off] = ASMInU8(APPLESMC_DATA_PORT);
- }
-
- return true;
-}
-
-/**
- * RTOnce callback that initializes g_fHaveOsk, g_abOsk0 and g_abOsk1.
- *
- * @returns VINF_SUCCESS.
- * @param pvUserIgnored Ignored.
- */
-static DECLCALLBACK(int) devR0SmcInitOnce(void *pvUserIgnored)
-{
- g_fHaveOsk = devR0SmcQueryHostKey("OSK0", &g_abOsk0[0], sizeof(g_abOsk0))
- && devR0SmcQueryHostKey("OSK1", &g_abOsk1[0], sizeof(g_abOsk1));
-
- NOREF(pvUserIgnored);
- return VINF_SUCCESS;
-}
-
-/**
- * @interface_method_impl{FNPDMDEVREQHANDLERR0}
- */
-PDMBOTHCBDECL(int) devR0SmcReqHandler(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
- int rc = VERR_INVALID_FUNCTION;
-
- if (uOperation == SMC_CALLR0_READ_OSK)
- {
- rc = RTOnce(&g_SmcR0Once, devR0SmcInitOnce, NULL);
- if ( RT_SUCCESS(rc)
- && g_fHaveOsk)
- {
- AssertCompile(sizeof(g_abOsk0) == sizeof(pThis->abOsk0));
- AssertCompile(sizeof(g_abOsk1) == sizeof(pThis->abOsk1));
- memcpy(pThis->abOsk0, g_abOsk0, sizeof(pThis->abOsk0));
- memcpy(pThis->abOsk1, g_abOsk1, sizeof(pThis->abOsk1));
- }
- }
- return rc;
-}
-
-#endif /* IN_RING0 */
-#ifdef IN_RING3
-
-/**
- * Saves a state of the SMC device.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pSSMHandle The handle to save the state to.
- */
-static DECLCALLBACK(int) smcSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-
- /** @todo: implement serialization */
- return VINF_SUCCESS;
-}
-
-
-/**
- * Loads a SMC device state.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pSSMHandle The handle to the saved state.
- * @param uVersion The data unit version number.
- * @param uPass The data pass.
- */
-static DECLCALLBACK(int) smcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-
- if (uVersion != SMC_SAVED_STATE_VERSION)
- return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
- Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
-
- /** @todo: implement serialization */
- return VINF_SUCCESS;
-}
-
-/**
- * Reset notification.
- *
- * @returns VBox status.
- * @param pDevIns The device instance data.
- */
-static DECLCALLBACK(void) smcReset(PPDMDEVINS pDevIns)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
- LogFlow(("smcReset: \n"));
-}
-
-
-/**
- * Info handler, device version.
- *
- * @param pDevIns Device instance which registered the info.
- * @param pHlp Callback functions for doing output.
- * @param pszArgs Argument string. Optional and specific to the handler.
- */
-static DECLCALLBACK(void) smcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-}
-
-
-static void applesmc_fill_data(SMCState *s)
-{
- struct AppleSMCData *d;
- for (d=data; d->len; d++)
- {
- uint32_t key_data = *((uint32_t*)d->key);
- uint32_t key_current = *((uint32_t*)s->key);
- if (key_data == key_current)
- {
- Log(("APPLESMC: Key matched (%s Len=%d Data=%s)\n", d->key, d->len, d->data));
- memcpy(s->data, d->data, d->len);
- return;
- }
- }
-}
-
-/**
- * Port I/O Handler for IN operations.
- *
- * @returns VBox status code.
- *
- * @param pDevIns The device instance.
- * @param pvUser User argument - ignored.
- * @param uPort Port number used for the IN operation.
- * @param pu32 Where to store the result.
- * @param cb Number of bytes read.
- */
-PDMBOTHCBDECL(int) smcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
-{
- SMCState * s = PDMINS_2_DATA(pDevIns, SMCState *);
- uint8_t retval = 0;
-
- NOREF(pvUser);
- Log(("SMC port read: %x (%d)\n", Port, cb));
-
- /** @todo: status code? */
- if (cb != 1)
- return VERR_IOM_IOPORT_UNUSED;
-
- switch (Port)
- {
- case APPLESMC_CMD_PORT:
- {
- retval = s->status;
- break;
- }
- case APPLESMC_DATA_PORT:
- {
- switch (s->cmd) {
- case APPLESMC_READ_CMD:
- if(s->data_pos < s->data_len)
- {
- retval = s->data[s->data_pos];
- Log(("APPLESMC: READ_DATA[%d] = %#hhx\n", s->data_pos, retval));
- s->data_pos++;
- if(s->data_pos == s->data_len)
- {
- s->status = 0x00;
- Log(("APPLESMC: EOF\n"));
- }
- else
- s->status = 0x05;
- }
- }
- break;
- }
- }
-
- *pu32 = retval;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Port I/O Handler for OUT operations.
- *
- * @returns VBox status code.
- *
- * @param pDevIns The device instance.
- * @param pvUser User argument - ignored.
- * @param uPort Port number used for the IN operation.
- * @param u32 The value to output.
- * @param cb The value size in bytes.
- */
-PDMBOTHCBDECL(int) smcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
-{
- SMCState* s = PDMINS_2_DATA(pDevIns, SMCState *);
-
- NOREF(pvUser);
-
- Log(("SMC port write: %x (%d) %x\n", Port, cb, u32));
- /** @todo: status code? */
- if (cb != 1)
- return VINF_SUCCESS;
-
- switch (Port)
- {
- case APPLESMC_CMD_PORT:
- {
- switch (u32)
- {
- case APPLESMC_READ_CMD:
- s->status = 0x0c;
- break;
- }
- s->cmd = u32;
- s->read_pos = 0;
- s->data_pos = 0;
- break;
- }
- case APPLESMC_DATA_PORT:
- {
- switch(s->cmd)
- {
- case APPLESMC_READ_CMD:
- if (s->read_pos < 4)
- {
- s->key[s->read_pos] = u32;
- s->status = 0x04;
- }
- else
- if (s->read_pos == 4)
- {
- s->data_len = u32;
- s->status = 0x05;
- s->data_pos = 0;
- Log(("APPLESMC: Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], u32));
- applesmc_fill_data(s);
- }
- s->read_pos++;
- break;
- }
- }
- }
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
-static DECLCALLBACK(int) smcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
- SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
- Assert(iInstance == 0);
-
- /*
- * Store state.
- */
- pThis->pDevIns = pDevIns;
-
- /*
- * Validate and read the configuration.
- */
- PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceKey|GetKeyFromRealSMC", "");
-
- /*
- * Read the DeviceKey config value.
- */
- char *pszDeviceKey;
- int rc = CFGMR3QueryStringAllocDef(pCfg, "DeviceKey", &pszDeviceKey, "");
- if (RT_FAILURE(rc))
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Configuration error: Querying \"DeviceKey\" as a string failed"));
-
- size_t cchDeviceKey = strlen(pszDeviceKey);
- if (cchDeviceKey > 0)
- memcpy(&pThis->abOsk0[0], pszDeviceKey, RT_MIN(cchDeviceKey, sizeof(pThis->abOsk0)));
- if (cchDeviceKey > sizeof(pThis->abOsk0))
- memcpy(&pThis->abOsk1[0], &pszDeviceKey[sizeof(pThis->abOsk0)],
- RT_MIN(cchDeviceKey - sizeof(pThis->abOsk0), sizeof(pThis->abOsk1)));
-
- MMR3HeapFree(pszDeviceKey);
-
- /*
- * Query the key from the real hardware if asked to do so.
- */
- bool fGetKeyFromRealSMC;
- rc = CFGMR3QueryBoolDef(pCfg, "GetKeyFromRealSMC", &fGetKeyFromRealSMC, false);
- if (RT_FAILURE(rc))
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed"));
- if (fGetKeyFromRealSMC)
- {
- rc = PDMDevHlpCallR0(pDevIns, SMC_CALLR0_READ_OSK, 0 /*u64Arg*/);
- if (RT_FAILURE(rc))
- return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
- N_("Failed to query SMC value from the host"));
- }
-
- /*
- * For practical/historical reasons, the OSK[0|1] data is stored in a
- * global buffer in ring-3.
- */
- AssertCompile(sizeof(osk) == sizeof(pThis->abOsk0) + sizeof(pThis->abOsk1));
- AssertCompile(sizeof(char) == sizeof(uint8_t));
- memcpy(osk, pThis->abOsk0, sizeof(pThis->abOsk0));
- memcpy(&osk[sizeof(pThis->abOsk0)], pThis->abOsk1, sizeof(pThis->abOsk1));
-
- /*
- * Register the IO ports.
- */
- rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_DATA_PORT, 1, NULL,
- smcIOPortWrite, smcIOPortRead,
- NULL, NULL, "SMC Data");
- if (RT_FAILURE(rc))
- return rc;
- rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_CMD_PORT, 1, NULL,
- smcIOPortWrite, smcIOPortRead,
- NULL, NULL, "SMC Commands");
- if (RT_FAILURE(rc))
- return rc;
-
- /* Register saved state management */
- rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcSaveExec, smcLoadExec);
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Initialize the device state.
- */
- smcReset(pDevIns);
-
- /**
- * @todo: Register statistics.
- */
- PDMDevHlpDBGFInfoRegister(pDevIns, "smc", "Display SMC status. (no arguments)", smcInfo);
-
- return VINF_SUCCESS;
-}
-
-/**
- * The device registration structure.
- */
-const PDMDEVREG g_DeviceSMC =
-{
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "smc",
- /* szRCMod */
- "VBoxDD2GC.gc",
- /* szR0Mod */
- "VBoxDD2R0.r0",
- /* pszDescription */
- "System Management Controller (SMC) Device",
- /* fFlags */
- PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36| PDM_DEVREG_FLAGS_R0,
- /* fClass */
- PDM_DEVREG_CLASS_MISC,
- /* cMaxInstances */
- 1,
- /* cbInstance */
- sizeof(SMCState),
- /* pfnConstruct */
- smcConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- smcReset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnQueryInterface. */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
-};
-
-#endif /* IN_RING3 */
-
-#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/Storage/DevAHCI.cpp b/src/VBox/Devices/Storage/DevAHCI.cpp
index c903604..d7e9911 100644
--- a/src/VBox/Devices/Storage/DevAHCI.cpp
+++ b/src/VBox/Devices/Storage/DevAHCI.cpp
@@ -1077,6 +1077,23 @@ static void ahciPortResetFinish(PAHCIPort pAhciPort)
else
pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
+ /* We received a COMINIT from the device. Tell the guest. */
+ ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
+ pAhciPort->regSERR |= AHCI_PORT_SERR_X;
+ pAhciPort->regTFD |= ATA_STAT_BUSY;
+
+ if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
+ {
+ ahciPostFirstD2HFisIntoMemory(pAhciPort);
+ ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
+
+ if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
+ {
+ int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
+ AssertRC(rc);
+ }
+ }
+
pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
(0x03 << 0); /* Device detected and communication established. */
@@ -1096,23 +1113,6 @@ static void ahciPortResetFinish(PAHCIPort pAhciPort)
break;
}
- /* We received a COMINIT from the device. Tell the guest. */
- ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
- pAhciPort->regSERR |= AHCI_PORT_SERR_X;
- pAhciPort->regTFD |= ATA_STAT_BUSY;
-
- if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
- {
- ahciPostFirstD2HFisIntoMemory(pAhciPort);
- ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
-
- if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
- {
- int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
- AssertRC(rc);
- }
- }
-
ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
}
#endif
@@ -1704,6 +1704,9 @@ static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
if (rc != VINF_SUCCESS)
return rc;
+ /* Update interrupt status register first. */
+ ahci->regHbaIs |= ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
+
if (u32Value > 0)
{
/*
@@ -6738,7 +6741,11 @@ static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
if (RT_FAILURE(rc))
+ {
+ /* In case we can't allocate enough memory fail the request with an overflow error. */
AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
+ pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
+ }
}
if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
@@ -6936,6 +6943,7 @@ static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con
pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
+ pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
pHlp->pfnPrintf(pHlp, "\n");
}
}
diff --git a/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp b/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
index 9f53298..72913f3 100644
--- a/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
+++ b/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
@@ -798,6 +798,15 @@ static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
return rc;
}
+/** @copydoc PDMIMEDIA::pfnReadPcBios */
+static DECLCALLBACK(int) drvdiskintReadPcBios(PPDMIMEDIA pInterface,
+ uint64_t off, void *pvBuf, size_t cbRead)
+{
+ PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
+
+ return pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
+}
+
/** @copydoc PDMIMEDIA::pfnWrite */
static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
uint64_t off, const void *pvBuf,
@@ -1377,6 +1386,7 @@ static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg,
/* IMedia */
pThis->IMedia.pfnRead = drvdiskintRead;
+ pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
pThis->IMedia.pfnWrite = drvdiskintWrite;
pThis->IMedia.pfnFlush = drvdiskintFlush;
pThis->IMedia.pfnGetSize = drvdiskintGetSize;
diff --git a/src/VBox/Devices/USB/DevOHCI.cpp b/src/VBox/Devices/USB/DevOHCI.cpp
index f832459..c21fddb 100644
--- a/src/VBox/Devices/USB/DevOHCI.cpp
+++ b/src/VBox/Devices/USB/DevOHCI.cpp
@@ -368,6 +368,8 @@ typedef struct OHCI
R3PTRTYPE(PPDMTHREAD) hThreadFrame;
/** Event semaphore to interact with the framer thread. */
R3PTRTYPE(RTSEMEVENT) hSemEventFrame;
+ /** Event semaphore to release the thread waiting for the framer thread to stop. */
+ R3PTRTYPE(RTSEMEVENTMULTI) hSemEventFrameStopped;
/** Flag whether the framer thread should processing frames. */
volatile bool fBusStarted;
/** Alignment. */
@@ -783,6 +785,7 @@ RT_C_DECLS_BEGIN
/* Update host controller state to reflect a device attach */
static void rhport_power(POHCIROOTHUB pRh, unsigned iPort, bool fPowerUp);
static void ohciBusResume(POHCI ohci, bool fHardware);
+static void ohciBusStop(POHCI pThis);
static DECLCALLBACK(void) ohciRhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
static DECLCALLBACK(bool) ohciRhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
@@ -1101,6 +1104,9 @@ static void ohciDoReset(POHCI pThis, uint32_t fNewMode, bool fResetOnLinux)
Log(("ohci: %s reset%s\n", fNewMode == OHCI_USB_RESET ? "hardware" : "software",
fResetOnLinux ? " (reset on linux)" : ""));
+ /* Stop the bus in any case, disabling walking the lists. */
+ ohciBusStop(pThis);
+
/*
* Cancel all outstanding URBs.
*
@@ -1117,6 +1123,9 @@ static void ohciDoReset(POHCI pThis, uint32_t fNewMode, bool fResetOnLinux)
pThis->ctl |= OHCI_CTL_RWC; /* We're the firmware, set RemoteWakeupConnected. */
else
pThis->ctl &= OHCI_CTL_IR | OHCI_CTL_RWC; /* IR and RWC are preserved on software reset. */
+
+ /* Clear the HCFS bits first to make setting the new state work. */
+ pThis->ctl &= ~OHCI_CTL_HCFS;
pThis->ctl |= fNewMode;
pThis->status = 0;
pThis->intr_status = 0;
@@ -3826,7 +3835,12 @@ static DECLCALLBACK(int) ohciR3ThreadFrame(PPDMDEVINS pDevIns, PPDMTHREAD pThrea
while ( !ASMAtomicReadBool(&pThis->fBusStarted)
&& pThread->enmState == PDMTHREADSTATE_RUNNING
&& RT_SUCCESS(rc))
+ {
+ /* Signal the waiter that we are stopped now. */
+ rc = RTSemEventMultiSignal(pThis->hSemEventFrameStopped);
+ AssertRC(rc);
rc = RTSemEventWait(pThis->hSemEventFrame, RT_INDEFINITE_WAIT);
+ }
AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc), rc);
if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
@@ -3895,8 +3909,9 @@ static void ohciBusStart(POHCI pThis)
Log(("ohci: %s: Bus started\n", pThis->PciDev.name));
pThis->SofTime = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns));
- ASMAtomicXchgBool(&pThis->fBusStarted, true);
- RTSemEventSignal(pThis->hSemEventFrame);
+ bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, true);
+ if (!fBusActive)
+ RTSemEventSignal(pThis->hSemEventFrame);
}
/**
@@ -3904,8 +3919,19 @@ static void ohciBusStart(POHCI pThis)
*/
static void ohciBusStop(POHCI pThis)
{
- ASMAtomicXchgBool(&pThis->fBusStarted, false);
- RTSemEventSignal(pThis->hSemEventFrame);
+ bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, false);
+ if (fBusActive)
+ {
+ int rc = RTSemEventMultiReset(pThis->hSemEventFrameStopped);
+ AssertRC(rc);
+
+ /* Signal the frame thread to stop. */
+ RTSemEventSignal(pThis->hSemEventFrame);
+
+ /* Wait for signal from the thrad that it stopped. */
+ rc = RTSemEventMultiWait(pThis->hSemEventFrameStopped, RT_INDEFINITE_WAIT);
+ AssertRC(rc);
+ }
VUSBIDevPowerOff(pThis->RootHub.pIDev);
}
@@ -5452,7 +5478,6 @@ static DECLCALLBACK(void) ohciR3Reset(PPDMDEVINS pDevIns)
* Important: Don't confuse UsbReset with hardware reset. Hardware reset is
* just one way of getting into the UsbReset state.
*/
- ohciBusStop(pThis);
ohciDoReset(pThis, OHCI_USB_RESET, true /* reset devices */);
}
@@ -5569,7 +5594,10 @@ static DECLCALLBACK(int) ohciR3Destruct(PPDMDEVINS pDevIns)
/*
* Destroy event sempahores.
*/
- RTSemEventDestroy(pThis->hSemEventFrame);
+ if (pThis->hSemEventFrame)
+ RTSemEventDestroy(pThis->hSemEventFrame);
+ if (pThis->hSemEventFrameStopped)
+ RTSemEventMultiDestroy(pThis->hSemEventFrameStopped);
if (RTCritSectIsInitialized(&pThis->CritSect))
RTCritSectDelete(&pThis->CritSect);
PDMR3CritSectDelete(&pThis->CsIrq);
@@ -5727,6 +5755,9 @@ static DECLCALLBACK(int) ohciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
rc = RTSemEventCreate(&pThis->hSemEventFrame);
AssertRCReturn(rc, rc);
+ rc = RTSemEventMultiCreate(&pThis->hSemEventFrameStopped);
+ AssertRCReturn(rc, rc);
+
rc = RTCritSectInit(&pThis->CritSect);
if (RT_FAILURE(rc))
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
diff --git a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
index 6db66b2..c9487c9 100644
--- a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
+++ b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
@@ -608,8 +608,11 @@ static DECLCALLBACK(int) vusbRhCancelAllUrbsWorker(PVUSBDEV pDev)
{
/*
* Cancel the URBS.
+ *
+ * Not using th CritAsyncUrbs critical section here is safe
+ * as the I/O thread is the only thread accessing this struture at the
+ * moment.
*/
- RTCritSectEnter(&pDev->CritSectAsyncUrbs);
PVUSBURB pUrb = pDev->pAsyncUrbHead;
while (pUrb)
@@ -619,7 +622,6 @@ static DECLCALLBACK(int) vusbRhCancelAllUrbsWorker(PVUSBDEV pDev)
vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
pUrb = pNext;
}
- RTCritSectLeave(&pDev->CritSectAsyncUrbs);
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/USB/VUSBDevice.cpp b/src/VBox/Devices/USB/VUSBDevice.cpp
index 4790fcb..f01eb2e 100644
--- a/src/VBox/Devices/USB/VUSBDevice.cpp
+++ b/src/VBox/Devices/USB/VUSBDevice.cpp
@@ -34,11 +34,6 @@
#include "VUSBInternal.h"
-/** Asserts that the give device state is valid. */
-#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
- AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
-
-
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
@@ -216,6 +211,31 @@ static void map_interface(PVUSBDEV pDev, PCVUSBDESCINTERFACEEX pIfDesc)
}
}
+
+/**
+ * Worker that resets the pipe data on select config and detach.
+ *
+ * This leaves the critical section unmolested
+ *
+ * @param pPipe The pipe which data should be reset.
+ */
+static void vusbDevResetPipeData(PVUSBPIPE pPipe)
+{
+ vusbMsgFreeExtraData(pPipe->pCtrl);
+ pPipe->pCtrl = NULL;
+
+ if (pPipe->hReadAhead)
+ {
+ vusbReadAheadStop(pPipe->hReadAhead);
+ pPipe->hReadAhead = NULL;
+ }
+
+ RT_ZERO(pPipe->in);
+ RT_ZERO(pPipe->out);
+ pPipe->async = 0;
+}
+
+
bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
{
LogFlow(("vusbDevDoSelectConfig: pDev=%p[%s] pCfgDesc=%p:{.iConfiguration=%d}\n",
@@ -226,13 +246,8 @@ bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
*/
unsigned i;
for (i = 0; i < VUSB_PIPE_MAX; i++)
- {
if (i != VUSB_PIPE_DEFAULT)
- {
- vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
- memset(&pDev->aPipes[i], 0, sizeof(pDev->aPipes[i]));
- }
- }
+ vusbDevResetPipeData(&pDev->aPipes[i]);
memset(pDev->paIfStates, 0, pCfgDesc->Core.bNumInterfaces * sizeof(pDev->paIfStates[0]));
/*
@@ -292,7 +307,7 @@ static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
* Check that the device is in a valid state.
* (The caller has already checked that it's not being reset.)
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState == VUSB_DEVICE_STATE_DEFAULT)
{
LogFlow(("vusbDevStdReqSetConfig: %s: default dev state !!?\n", pDev->pUsbIns->pszName));
@@ -307,9 +322,9 @@ static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
}
if (iCfg == 0)
- pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
else
- pDev->enmState = VUSB_DEVICE_STATE_CONFIGURED;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_CONFIGURED);
if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
{
int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5,
@@ -342,7 +357,7 @@ static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
* Check that the device is in a valid state.
* (The caller has already checked that it's not being reset.)
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if ( enmState != VUSB_DEVICE_STATE_CONFIGURED
&& enmState != VUSB_DEVICE_STATE_ADDRESS)
{
@@ -357,7 +372,7 @@ static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
}
uint8_t iCfg;
- if (pDev->enmState == VUSB_DEVICE_STATE_ADDRESS)
+ if (enmState == VUSB_DEVICE_STATE_ADDRESS)
iCfg = 0;
else
iCfg = pDev->pCurCfgDesc->Core.bConfigurationValue;
@@ -384,7 +399,7 @@ static bool vusbDevStdReqGetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
* Check that the device is in a valid state.
* (The caller has already checked that it's not being reset.)
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
{
LogFlow(("vusbDevStdReqGetInterface: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
@@ -430,7 +445,7 @@ static bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
* Check that the device is in a valid state.
* (The caller has already checked that it's not being reset.)
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
{
LogFlow(("vusbDevStdReqSetInterface: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
@@ -492,7 +507,7 @@ static bool vusbDevStdReqSetAddress(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
* Check that the device is in a valid state.
* (The caller has already checked that it's not being reset.)
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if ( enmState != VUSB_DEVICE_STATE_DEFAULT
&& enmState != VUSB_DEVICE_STATE_ADDRESS)
{
@@ -663,10 +678,10 @@ static void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf
}
VUSBDESCSTRING StringDesc;
- StringDesc.bLength = sizeof(StringDesc) + cwc * sizeof(RTUTF16);
+ StringDesc.bLength = (uint8_t)(sizeof(StringDesc) + cwc * sizeof(RTUTF16));
StringDesc.bDescriptorType = VUSB_DT_STRING;
COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
- COPY_DATA(pbBuf, cbLeft, wsz, cwc * sizeof(RTUTF16));
+ COPY_DATA(pbBuf, cbLeft, wsz, (uint32_t)cwc * sizeof(RTUTF16));
/* updated the size of the output buffer. */
*pcbBuf -= cbLeft;
@@ -683,7 +698,7 @@ static void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLa
VUSBDESCLANGID LangIdDesc;
size_t cbDesc = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
- LangIdDesc.bLength = RT_MIN(0xff, cbDesc);
+ LangIdDesc.bLength = (uint8_t)RT_MIN(0xff, cbDesc);
LangIdDesc.bDescriptorType = VUSB_DT_STRING;
COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
@@ -889,8 +904,7 @@ bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void
/*
* Check that the device is in a valid state.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
- VUSBDEV_ASSERT_VALID_STATE(enmState);
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState == VUSB_DEVICE_STATE_RESET)
{
LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
@@ -974,7 +988,7 @@ void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
/*
* Check that the device is in a valid state.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
VUSBDEV_ASSERT_VALID_STATE(enmState);
if ( enmState == VUSB_DEVICE_STATE_ATTACHED
|| enmState == VUSB_DEVICE_STATE_DETACHED)
@@ -1006,15 +1020,15 @@ void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
if (pRh->pDefaultAddress != NULL)
{
vusbDevAddressUnHash(pRh->pDefaultAddress);
- pRh->pDefaultAddress->enmState = VUSB_DEVICE_STATE_POWERED;
+ vusbDevSetState(pRh->pDefaultAddress, VUSB_DEVICE_STATE_POWERED);
Log(("2 DEFAULT ADDRS\n"));
}
pRh->pDefaultAddress = pDev;
- pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
}
else
- pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
pDev->u8Address = u8Address;
vusbDevAddressHash(pDev);
@@ -1130,7 +1144,7 @@ static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser)
while (!ASMAtomicReadBool(&pDev->fTerminate))
{
- if (pDev->enmState != VUSB_DEVICE_STATE_RESET)
+ if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT);
/* Process any URBs waiting to be cancelled first. */
@@ -1218,23 +1232,13 @@ int vusbDevDetach(PVUSBDEV pDev)
pDev->pHub->pOps->pfnDetach(pDev->pHub, pDev);
pDev->i16Port = -1;
- pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_DETACHED);
pDev->pHub = NULL;
/* Remove the configuration */
pDev->pCurCfgDesc = NULL;
- for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
- {
- vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
- RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
-
- if (pDev->aPipes[i].hReadAhead)
- {
- vusbReadAheadStop(pDev->aPipes[i].hReadAhead);
- pDev->aPipes[i].hReadAhead = NULL;
- }
- }
- memset(pDev->aPipes, 0, sizeof(pDev->aPipes));
+ for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
+ vusbDevResetPipeData(&pDev->aPipes[i]);
return VINF_SUCCESS;
}
@@ -1251,9 +1255,9 @@ void vusbDevDestroy(PVUSBDEV pDev)
/*
* Deal with pending async reset.
+ * (anything but reset)
*/
- if (pDev->enmState == VUSB_DEVICE_STATE_RESET)
- pDev->enmState = VUSB_DEVICE_STATE_DEFAULT; /* anything but reset */
+ vusbDevSetStateCmp(pDev, VUSB_DEVICE_STATE_DEFAULT, VUSB_DEVICE_STATE_RESET);
/*
* Detach and free resources.
@@ -1263,6 +1267,11 @@ void vusbDevDestroy(PVUSBDEV pDev)
RTMemFree(pDev->paIfStates);
TMR3TimerDestroy(pDev->pResetTimer);
pDev->pResetTimer = NULL;
+ for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
+ {
+ Assert(pDev->aPipes[i].pCtrl == NULL);
+ RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
+ }
/*
* Destroy I/O thread and request queue last because they might still be used
@@ -1274,6 +1283,7 @@ void vusbDevDestroy(PVUSBDEV pDev)
AssertRC(rc);
RTCritSectDelete(&pDev->CritSectAsyncUrbs);
+ /* Not using vusbDevSetState() deliberately here because it would assert on the state. */
pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
}
@@ -1312,7 +1322,7 @@ static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, vo
/*
* Switch to the default state.
*/
- pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
pDev->u16Status = 0;
vusbDevDoSelectConfig(pDev, &g_Config0);
if (!vusbDevIsRh(pDev))
@@ -1405,7 +1415,7 @@ static int vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer,
* on the EMT thread.
* @thread EMT
*/
-DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
+DECLCALLBACK(int) vusbIDeviceReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
{
PVUSBDEV pDev = (PVUSBDEV)pDevice;
Assert(!pfnDone || pVM);
@@ -1414,14 +1424,12 @@ DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSB
/*
* Only one reset operation at a time.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
- VUSBDEV_ASSERT_VALID_STATE(enmState);
- if (enmState == VUSB_DEVICE_STATE_RESET)
+ const VUSBDEVICESTATE enmStateOld = vusbDevSetState(pDev, VUSB_DEVICE_STATE_RESET);
+ if (enmStateOld == VUSB_DEVICE_STATE_RESET)
{
LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
return VERR_VUSB_DEVICE_IS_RESETTING;
}
- pDev->enmState = VUSB_DEVICE_STATE_RESET;
/*
* First, cancel all async URBs.
@@ -1466,7 +1474,7 @@ DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSB
* @returns VBox status code.
* @param pInterface Pointer to the device interface structure.
*/
-DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
+DECLCALLBACK(int) vusbIDevicePowerOn(PVUSBIDEVICE pInterface)
{
PVUSBDEV pDev = (PVUSBDEV)pInterface;
LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1474,8 +1482,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
/*
* Check that the device is in a valid state.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
- VUSBDEV_ASSERT_VALID_STATE(enmState);
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState == VUSB_DEVICE_STATE_DETACHED)
{
Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1491,7 +1498,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
* Do the job.
*/
if (enmState == VUSB_DEVICE_STATE_ATTACHED)
- pDev->enmState = VUSB_DEVICE_STATE_POWERED;
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_POWERED);
return VINF_SUCCESS;
}
@@ -1503,7 +1510,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
* @returns VBox status code.
* @param pInterface Pointer to the device interface structure.
*/
-DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
+DECLCALLBACK(int) vusbIDevicePowerOff(PVUSBIDEVICE pInterface)
{
PVUSBDEV pDev = (PVUSBDEV)pInterface;
LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1511,8 +1518,7 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
/*
* Check that the device is in a valid state.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
- VUSBDEV_ASSERT_VALID_STATE(enmState);
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState == VUSB_DEVICE_STATE_DETACHED)
{
Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1534,8 +1540,7 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, pInterface, 0);
}
- pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
-
+ vusbDevSetState(pDev, VUSB_DEVICE_STATE_ATTACHED);
return VINF_SUCCESS;
}
@@ -1546,9 +1551,9 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
* @returns Device state.
* @param pInterface Pointer to the device interface structure.
*/
-DECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface)
+DECLCALLBACK(VUSBDEVICESTATE) vusbIDeviceGetState(PVUSBIDEVICE pInterface)
{
- return ((PVUSBDEV)pInterface)->enmState;
+ return vusbDevGetState((PVUSBDEV)pInterface);
}
@@ -1687,10 +1692,10 @@ int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns)
Assert(!pDev->IDevice.pfnPowerOff);
Assert(!pDev->IDevice.pfnGetState);
- pDev->IDevice.pfnReset = vusbDevReset;
- pDev->IDevice.pfnPowerOn = vusbDevPowerOn;
- pDev->IDevice.pfnPowerOff = vusbDevPowerOff;
- pDev->IDevice.pfnGetState = vusbDevGetState;
+ pDev->IDevice.pfnReset = vusbIDeviceReset;
+ pDev->IDevice.pfnPowerOn = vusbIDevicePowerOn;
+ pDev->IDevice.pfnPowerOff = vusbIDevicePowerOff;
+ pDev->IDevice.pfnGetState = vusbIDeviceGetState;
pDev->pUsbIns = pUsbIns;
pDev->pNext = NULL;
pDev->pNextHash = NULL;
diff --git a/src/VBox/Devices/USB/VUSBInternal.h b/src/VBox/Devices/USB/VUSBInternal.h
index c9832d7..da10db6 100644
--- a/src/VBox/Devices/USB/VUSBInternal.h
+++ b/src/VBox/Devices/USB/VUSBInternal.h
@@ -169,8 +169,7 @@ typedef struct VUSBDEV
PVUSBDEV pNextHash;
/** Pointer to the hub this device is attached to. */
PVUSBHUB pHub;
- /** The device state.
- * Only EMT changes this value. */
+ /** The device state. */
VUSBDEVICESTATE volatile enmState;
/** The device address. */
@@ -263,10 +262,6 @@ int vusbDevDetach(PVUSBDEV pDev);
DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev);
size_t vusbDevMaxInterfaces(PVUSBDEV dev);
-DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM);
-DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface);
-DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface);
-DECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface);
void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address);
bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf);
@@ -497,6 +492,13 @@ DECLINLINE(void) vusbUrbUnlink(PVUSBURB pUrb)
# define vusbUrbAssert(pUrb) do {} while (0)
#endif
+/**
+ * @def VUSBDEV_ASSERT_VALID_STATE
+ * Asserts that the give device state is valid.
+ */
+#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
+ AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
+
/** Executes a function synchronously. */
#define VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC RT_BIT_32(0)
@@ -533,6 +535,51 @@ DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev)
}
+/**
+ * Returns the state of the USB device.
+ *
+ * @returns State of the USB device.
+ * @param pDev Pointer to the device.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevGetState(PVUSBDEV pDev)
+{
+ VUSBDEVICESTATE enmState = (VUSBDEVICESTATE)ASMAtomicReadU32((volatile uint32_t *)&pDev->enmState);
+ VUSBDEV_ASSERT_VALID_STATE(enmState);
+ return enmState;
+}
+
+
+/**
+ * Sets the given state for the USB device.
+ *
+ * @returns The old state of the device.
+ * @param pDev Pointer to the device.
+ * @param enmState The new state to set.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevSetState(PVUSBDEV pDev, VUSBDEVICESTATE enmState)
+{
+ VUSBDEV_ASSERT_VALID_STATE(enmState);
+ VUSBDEVICESTATE enmStateOld = (VUSBDEVICESTATE)ASMAtomicXchgU32((volatile uint32_t *)&pDev->enmState, enmState);
+ VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+ return enmStateOld;
+}
+
+
+/**
+ * Compare and exchange the states for the given USB device.
+ *
+ * @returns true if the state was changed.
+ * @returns false if the state wasn't changed.
+ * @param pDev Pointer to the device.
+ * @param enmStateNew The new state to set.
+ * @param enmStateOld The old state to compare with.
+ */
+DECLINLINE(bool) vusbDevSetStateCmp(PVUSBDEV pDev, VUSBDEVICESTATE enmStateNew, VUSBDEVICESTATE enmStateOld)
+{
+ VUSBDEV_ASSERT_VALID_STATE(enmStateNew);
+ VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+ return ASMAtomicCmpXchgU32((volatile uint32_t *)&pDev->enmState, enmStateNew, enmStateOld);
+}
/** Strings for the CTLSTAGE enum values. */
extern const char * const g_apszCtlStates[4];
diff --git a/src/VBox/Devices/USB/VUSBUrb.cpp b/src/VBox/Devices/USB/VUSBUrb.cpp
index e1a5f3c..853c129 100644
--- a/src/VBox/Devices/USB/VUSBUrb.cpp
+++ b/src/VBox/Devices/USB/VUSBUrb.cpp
@@ -1834,7 +1834,7 @@ int vusbUrbSubmit(PVUSBURB pUrb)
/*
* Check that the device is in a valid state.
*/
- const VUSBDEVICESTATE enmState = pDev->enmState;
+ const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
if (enmState == VUSB_DEVICE_STATE_RESET)
{
LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
@@ -1970,7 +1970,7 @@ void vusbUrbDoReapAsync(PVUSBURB pHead, RTMSINTERVAL cMillies)
PVUSBDEV pDev = pUrb->VUsb.pDev;
/* Don't touch resetting devices - paranoid safety precaution. */
- if (pDev->enmState != VUSB_DEVICE_STATE_RESET)
+ if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
{
/*
* Reap most URBs pending on a single device.
diff --git a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
index 312c6b6..df05840 100644
--- a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
+++ b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
@@ -280,8 +280,9 @@ static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProxyDev, int iIf, bool fCon
*/
static void usbProxyLinuxUrbLinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx)
{
+ LogFlowFunc(("pDevLnx=%p pUrbLnx=%p\n", pDevLnx, pUrbLnx));
Assert(RTCritSectIsOwner(&pDevLnx->CritSect));
- Assert(!pUrbLnx->pSplitHead);
+ Assert(!pUrbLnx->pSplitHead || pUrbLnx->pSplitHead == pUrbLnx);
RTListAppend(&pDevLnx->ListInFlight, &pUrbLnx->NodeList);
}
@@ -293,6 +294,7 @@ static void usbProxyLinuxUrbLinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLN
*/
static void usbProxyLinuxUrbUnlinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx)
{
+ LogFlowFunc(("pDevLnx=%p pUrbLnx=%p\n", pDevLnx, pUrbLnx));
RTCritSectEnter(&pDevLnx->CritSect);
/*
@@ -301,7 +303,6 @@ static void usbProxyLinuxUrbUnlinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURB
Assert(!pUrbLnx->pSplitHead || pUrbLnx->pSplitHead == pUrbLnx);
RTListNodeRemove(&pUrbLnx->NodeList);
- pUrbLnx->pSplitHead = pUrbLnx->pSplitNext = NULL;
RTCritSectLeave(&pDevLnx->CritSect);
}
@@ -318,6 +319,8 @@ static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYUR
PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
PUSBPROXYURBLNX pUrbLnx;
+ LogFlowFunc(("pProxyDev=%p pSplitHead=%p\n", pProxyDev, pSplitHead));
+
RTCritSectEnter(&pDevLnx->CritSect);
/*
@@ -341,6 +344,7 @@ static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYUR
pUrbLnx->pSplitNext = NULL;
pUrbLnx->fCanceledBySubmit = false;
pUrbLnx->fSplitElementReaped = false;
+ LogFlowFunc(("returns pUrbLnx=%p\n", pUrbLnx));
return pUrbLnx;
}
@@ -355,13 +359,13 @@ static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx
{
PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
- RTCritSectEnter(&pDevLnx->CritSect);
+ LogFlowFunc(("pProxyDev=%p pUrbLnx=%p\n", pProxyDev, pUrbLnx));
/*
* Link it into the free list.
*/
+ RTCritSectEnter(&pDevLnx->CritSect);
RTListAppend(&pDevLnx->ListFree, &pUrbLnx->NodeList);
-
RTCritSectLeave(&pDevLnx->CritSect);
}
@@ -376,6 +380,8 @@ static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLN
{
PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
+ LogFlowFunc(("pProxyDev=%p pUrbLnx=%p\n", pProxyDev, pUrbLnx));
+
RTCritSectEnter(&pDevLnx->CritSect);
pUrbLnx = pUrbLnx->pSplitHead;
@@ -1305,6 +1311,8 @@ static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUS
uint32_t cbLeft = pCur->cbSplitRemaining;
uint8_t *pb = (uint8_t *)pCur->KUrb.buffer;
+ LogFlowFunc(("pProxyDev=%p pHead=%p pCur=%p\n", pProxyDev, pHead, pCur));
+
Assert(cbLeft != 0);
pNew = pCur->pSplitNext = usbProxyLinuxUrbAlloc(pProxyDev, pHead);
if (!pNew)
@@ -1323,6 +1331,7 @@ static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUS
cbLeft -= pNew->KUrb.buffer_length;
Assert(cbLeft < INT32_MAX);
pNew->cbSplitRemaining = cbLeft;
+ LogFlowFunc(("returns pNew=%p\n", pNew));
return pNew;
}
@@ -1522,6 +1531,7 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
continue;
if (errno == ENODEV)
{
+ rc = RTErrConvertFromErrno(errno);
Log(("usbProxyLinuxUrbQueue: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
if (pUrb->enmType == VUSBXFERTYPE_MSG)
usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
@@ -1529,7 +1539,7 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
RTCritSectLeave(&pDevLnx->CritSect);
usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
usbProxLinuxUrbUnplugged(pProxyDev);
- return RTErrConvertFromErrno(errno);
+ return rc;
}
/*
@@ -1543,8 +1553,9 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
if ( errno == EINVAL
&& pUrb->cbData >= 8*_1K)
{
+ rc = usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb);
RTCritSectLeave(&pDevLnx->CritSect);
- return usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb);
+ return rc;
}
Log(("usb-linux: Queue URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
@@ -1790,6 +1801,7 @@ static DECLCALLBACK(PVUSBURB) usbProxyLinuxUrbReap(PUSBPROXYDEV pProxyDev, RTMSI
pUrb->enmStatus = vusbProxyLinuxUrbGetStatus(pCur);
}
pUrb->cbData = pbEnd - &pUrb->abData[0];
+ usbProxyLinuxUrbUnlinkInFlight(pDevLnx, pUrbLnx);
usbProxyLinuxUrbFreeSplitList(pProxyDev, pUrbLnx);
}
else
diff --git a/src/VBox/Devices/build/VBoxDD.cpp b/src/VBox/Devices/build/VBoxDD.cpp
index 3173a36..f7023ff 100644
--- a/src/VBox/Devices/build/VBoxDD.cpp
+++ b/src/VBox/Devices/build/VBoxDD.cpp
@@ -80,11 +80,9 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceHPET);
if (RT_FAILURE(rc))
return rc;
-#ifdef VBOX_WITH_SMC_NEW
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSmc);
if (RT_FAILURE(rc))
return rc;
-#endif
#ifdef VBOX_WITH_EFI
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceEFI);
if (RT_FAILURE(rc))
diff --git a/src/VBox/Devices/build/VBoxDD2.cpp b/src/VBox/Devices/build/VBoxDD2.cpp
index cdff317..8946b77 100644
--- a/src/VBox/Devices/build/VBoxDD2.cpp
+++ b/src/VBox/Devices/build/VBoxDD2.cpp
@@ -64,11 +64,6 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceIOAPIC);
if (RT_FAILURE(rc))
return rc;
-#ifndef VBOX_WITH_SMC_NEW
- rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSMC);
- if (RT_FAILURE(rc))
- return rc;
-#endif
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceLPC);
if (RT_FAILURE(rc))
return rc;
diff --git a/src/VBox/Devices/build/VBoxDD2.h b/src/VBox/Devices/build/VBoxDD2.h
index 4cc62bc..80000f4 100644
--- a/src/VBox/Devices/build/VBoxDD2.h
+++ b/src/VBox/Devices/build/VBoxDD2.h
@@ -45,9 +45,6 @@ extern DECLIMPORT(const unsigned) g_cbNetBiosBinary;
#endif /* !IN_VBOXDD2 */
extern const PDMDEVREG g_DeviceAPIC;
extern const PDMDEVREG g_DeviceIOAPIC;
-#ifndef VBOX_WITH_SMC_NEW
-extern const PDMDEVREG g_DeviceSMC;
-#endif
extern const PDMDEVREG g_DeviceLPC;
RT_C_DECLS_END
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
index a703393..06bdfa4 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
@@ -65,7 +65,7 @@
#undef LOG_GROUP
#include "../PC/DevLPC.cpp"
#undef LOG_GROUP
-#include "../PC/DevSMC.cpp"
+#include "../EFI/DevSmc.cpp"
#undef LOG_GROUP
#include "../Storage/DevATA.cpp"
#ifdef VBOX_WITH_USB
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 4a06c2b..54b62a9 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -40,6 +40,8 @@
#undef LOG_GROUP
#include "../Bus/DevPciIch9.cpp"
#undef LOG_GROUP
+#include "../EFI/DevSmc.cpp"
+#undef LOG_GROUP
#include "../Graphics/DevVGA.cpp"
#undef LOG_GROUP
#include "../Input/DevPS2.cpp"
@@ -212,6 +214,23 @@ int main()
GEN_CHECK_OFF(ICH9PCIGLOBALS, u64PciConfigMMioLength);
GEN_CHECK_OFF(ICH9PCIGLOBALS, aPciBus);
+ /* EFI/DevSMC.cpp */
+ GEN_CHECK_SIZE(DEVSMC);
+ GEN_CHECK_OFF(DEVSMC, bCmd);
+ GEN_CHECK_OFF(DEVSMC, offKey);
+ GEN_CHECK_OFF(DEVSMC, offValue);
+ GEN_CHECK_OFF(DEVSMC, cKeys);
+ GEN_CHECK_OFF(DEVSMC, CurKey);
+ GEN_CHECK_OFF(DEVSMC, u);
+ GEN_CHECK_OFF(DEVSMC, u.s);
+ GEN_CHECK_OFF(DEVSMC, u.s.bState);
+ GEN_CHECK_OFF(DEVSMC, u.s.bStatusCode);
+ GEN_CHECK_OFF(DEVSMC, u.s.bStatusCode);
+ GEN_CHECK_OFF(DEVSMC, szOsk0And1);
+ GEN_CHECK_OFF(DEVSMC, bDollaryNumber);
+ GEN_CHECK_OFF(DEVSMC, bShutdownReason);
+ GEN_CHECK_OFF(DEVSMC, bNinjaActionTimerJob);
+
/* DevVGA.cpp */
GEN_CHECK_SIZE(VGASTATE);
GEN_CHECK_OFF(VGASTATE, vram_ptrR3);
@@ -567,6 +586,7 @@ int main()
GEN_CHECK_OFF(ACPIState, pPmTimerR3);
GEN_CHECK_OFF(ACPIState, pPmTimerR0);
GEN_CHECK_OFF(ACPIState, pPmTimerRC);
+ GEN_CHECK_OFF(ACPIState, uPmTimerVal);
GEN_CHECK_OFF(ACPIState, gpe0_en);
GEN_CHECK_OFF(ACPIState, gpe0_sts);
GEN_CHECK_OFF(ACPIState, uBatteryIndex);
@@ -588,7 +608,8 @@ int main()
GEN_CHECK_OFF(ACPIState, fCpuHotPlug);
GEN_CHECK_OFF(ACPIState, IBase);
GEN_CHECK_OFF(ACPIState, IACPIPort);
- GEN_CHECK_OFF(ACPIState, pDevIns);
+ GEN_CHECK_OFF(ACPIState, pDevInsR3);
+ GEN_CHECK_OFF(ACPIState, pDevInsR0);
GEN_CHECK_OFF(ACPIState, pDrvBase);
GEN_CHECK_OFF(ACPIState, pDrv);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
index ced18c1..11faf67 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
@@ -2359,29 +2359,35 @@ static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot
AssertPtrReturn(ppszSourceRoot, VERR_INVALID_POINTER);
char *pszNewRoot = RTStrDup(pszSource);
- AssertPtrReturn(pszNewRoot, VERR_NO_MEMORY);
+ if (!pszNewRoot)
+ return VERR_NO_MEMORY;
size_t lenRoot = strlen(pszNewRoot);
if ( lenRoot
- && pszNewRoot[lenRoot - 1] == '/'
- && pszNewRoot[lenRoot - 1] == '\\'
- && lenRoot > 1
- && pszNewRoot[lenRoot - 2] == '/'
- && pszNewRoot[lenRoot - 2] == '\\')
+ && ( pszNewRoot[lenRoot - 1] == '/'
+ || pszNewRoot[lenRoot - 1] == '\\')
+ )
{
- *ppszSourceRoot = pszNewRoot;
- if (lenRoot > 1)
- *ppszSourceRoot[lenRoot - 2] = '\0';
- *ppszSourceRoot[lenRoot - 1] = '\0';
+ pszNewRoot[lenRoot - 1] = '\0';
}
- else
+
+ if ( lenRoot > 1
+ && ( pszNewRoot[lenRoot - 2] == '/'
+ || pszNewRoot[lenRoot - 2] == '\\')
+ )
+ {
+ pszNewRoot[lenRoot - 2] = '\0';
+ }
+
+ if (!lenRoot)
{
/* If there's anything (like a file name or a filter),
* strip it! */
RTPathStripFilename(pszNewRoot);
- *ppszSourceRoot = pszNewRoot;
}
+ *ppszSourceRoot = pszNewRoot;
+
return VINF_SUCCESS;
}
diff --git a/src/VBox/Frontends/VirtualBox/Makefile.kmk b/src/VBox/Frontends/VirtualBox/Makefile.kmk
index 490f8e3..b0828d3 100644
--- a/src/VBox/Frontends/VirtualBox/Makefile.kmk
+++ b/src/VBox/Frontends/VirtualBox/Makefile.kmk
@@ -114,7 +114,8 @@ VirtualBox_DEFS += \
$(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL) \
$(if $(VBOX_GUI_WITH_HIDPI),VBOX_GUI_WITH_HIDPI) \
$(if $(VBOX_GUI_WITH_PIDFILE),VBOX_GUI_WITH_PIDFILE) \
- $(if $(VBOX_GUI_WITH_KEYS_RESET_HANDLER),VBOX_GUI_WITH_KEYS_RESET_HANDLER)
+ $(if $(VBOX_GUI_WITH_KEYS_RESET_HANDLER),VBOX_GUI_WITH_KEYS_RESET_HANDLER) \
+ $(if $(VBOX_GUI_WITH_CUSTOMIZATIONS1),VBOX_GUI_WITH_CUSTOMIZATIONS1)
ifdef VBOX_WITH_DEBUGGER_GUI
VirtualBox_DEFS += VBOX_WITH_DEBUGGER_GUI
if "$(KBUILD_TYPE)" != "release"
diff --git a/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp b/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
index 3c7b8cb..e3cd7e3 100644
--- a/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
@@ -2258,7 +2258,7 @@ int VBoxVHWAImage::vhwaSurfaceCanCreate(struct VBOXVHWACMD_SURF_CANCREATE *pCmd)
if (pCmd->SurfInfo.PixelFormat.flags & VBOXVHWA_PF_RGB)
{
if (pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 32
- || pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 24)
+ && pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 24)
{
Assert (0);
pCmd->u.out.ErrInfo = -1;
diff --git a/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp b/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
index 10270f5..6f7e3d7 100644
--- a/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
@@ -482,11 +482,11 @@ QString QIFileDialog::getSaveFileName (const QString &aStartWith,
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = topParent ? topParent->winId() : 0;
- ofn.lpstrFilter = (TCHAR *) winFilters.isNull() ? 0 : winFilters.utf16();
+ ofn.lpstrFilter = (TCHAR *)(winFilters.isNull() ? 0 : winFilters.utf16());
ofn.lpstrFile = buf;
ofn.nMaxFile = sizeof (buf) - 1;
- ofn.lpstrInitialDir = (TCHAR *) workDir.isNull() ? 0 : workDir.utf16();
- ofn.lpstrTitle = (TCHAR *) title.isNull() ? 0 : title.utf16();
+ ofn.lpstrInitialDir = (TCHAR *)(workDir.isNull() ? 0 : workDir.utf16());
+ ofn.lpstrTitle = (TCHAR *)(title.isNull() ? 0 : title.utf16());
ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
OFN_EXPLORER | OFN_ENABLEHOOK |
OFN_NOTESTFILECREATE | (m_fConfirmOverwrite ? OFN_OVERWRITEPROMPT : 0));
@@ -731,11 +731,11 @@ QStringList QIFileDialog::getOpenFileNames (const QString &aStartWith,
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = topParent ? topParent->winId() : 0;
- ofn.lpstrFilter = (TCHAR *) winFilters.isNull() ? 0 : winFilters.utf16();
+ ofn.lpstrFilter = (TCHAR *)(winFilters.isNull() ? 0 : winFilters.utf16());
ofn.lpstrFile = buf;
ofn.nMaxFile = sizeof (buf) - 1;
- ofn.lpstrInitialDir = (TCHAR *) workDir.isNull() ? 0 : workDir.utf16();
- ofn.lpstrTitle = (TCHAR *) title.isNull() ? 0 : title.utf16();
+ ofn.lpstrInitialDir = (TCHAR *)(workDir.isNull() ? 0 : workDir.utf16());
+ ofn.lpstrTitle = (TCHAR *)(title.isNull() ? 0 : title.utf16());
ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
OFN_EXPLORER | OFN_ENABLEHOOK |
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
index 1fe2afe..a0bf7df 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
@@ -75,6 +75,9 @@ const char* UIDefs::GUI_LastGuestSizeHintWasFullscreen = "GUI/LastGuestSizeHintW
const char* UIDefs::GUI_Fullscreen = "GUI/Fullscreen";
const char* UIDefs::GUI_Seamless = "GUI/Seamless";
const char* UIDefs::GUI_Scale = "GUI/Scale";
+#ifdef Q_WS_X11
+const char* UIDefs::GUI_Fullscreen_LegacyMode = "GUI/Fullscreen/LegacyMode";
+#endif /* Q_WS_X11 */
const char* UIDefs::GUI_VirtualScreenToHostScreen = "GUI/VirtualScreenToHostScreen";
const char* UIDefs::GUI_AutoresizeGuest = "GUI/AutoresizeGuest";
const char* UIDefs::GUI_AutomountGuestScreens = "GUI/AutomountGuestScreens";
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
index 20b643e..fb7f330 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
@@ -144,6 +144,9 @@ namespace UIDefs
extern const char* GUI_Fullscreen;
extern const char* GUI_Seamless;
extern const char* GUI_Scale;
+#ifdef Q_WS_X11
+ extern const char* GUI_Fullscreen_LegacyMode;
+#endif /* Q_WS_X11 */
extern const char* GUI_VirtualScreenToHostScreen;
extern const char* GUI_AutoresizeGuest;
extern const char* GUI_AutomountGuestScreens;
@@ -234,7 +237,8 @@ enum MacOSXRelease
MacOSXRelease_SnowLeopard,
MacOSXRelease_Lion,
MacOSXRelease_MountainLion,
- MacOSXRelease_Mavericks
+ MacOSXRelease_Mavericks,
+ MacOSXRelease_Yosemite
};
#endif /* Q_WS_MAC */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
index a3474e8..f622362 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
@@ -330,6 +330,9 @@ MacOSXRelease VBoxGlobal::osRelease()
if (uname(&info) != -1)
{
/* Parse known .release types: */
+ if (QString(info.release).startsWith("14."))
+ return MacOSXRelease_Yosemite;
+ else
if (QString(info.release).startsWith("13."))
return MacOSXRelease_Mavericks;
else
@@ -639,130 +642,6 @@ QList<ulong> XGetStrut(Window window)
}
#endif /* ifdef Q_WS_X11 */
-const QRect VBoxGlobal::availableGeometry(int iScreen) const
-{
- /* Prepare empty result: */
- QRect result;
-
-#ifdef Q_WS_X11
-
- /* Get current display: */
- Display* pDisplay = QX11Info::display();
-
- /* Get current application desktop: */
- QDesktopWidget *pDesktopWidget = QApplication::desktop();
-
- /* If it's a virtual desktop: */
- if (pDesktopWidget->isVirtualDesktop())
- {
- /* If it's a Xinerama desktop: */
- if (XineramaIsActive(pDisplay))
- {
- /* Get desktops list: */
- QList<QRect> desktops = XGetDesktopList();
-
- /* Combine to get full virtual region: */
- QRegion virtualRegion;
- foreach (QRect desktop, desktops)
- virtualRegion += desktop;
- virtualRegion = virtualRegion.boundingRect();
-
- /* Remember initial virtual desktop: */
- QRect virtualDesktop = virtualRegion.boundingRect();
- //AssertMsgFailed(("LOG... Virtual desktop is: %dx%dx%dx%d\n", virtualDesktop.x(), virtualDesktop.y(),
- // virtualDesktop.width(), virtualDesktop.height()));
-
- /* Set available geometry to screen geometry initially: */
- result = desktops[iScreen];
-
- /* Feat available geometry of virtual desktop to respect all the struts: */
- QList<Window> list = XGetWindowIDList();
- for (int i = 0; i < list.size(); ++ i)
- {
- /* Get window: */
- Window wid = list[i];
- QList<ulong> struts = XGetStrut(wid);
-
- /* If window has strut: */
- if (struts.size())
- {
- ulong uLeftShift = struts[0];
- ulong uLeftFromY = struts[4];
- ulong uLeftToY = struts[5];
-
- ulong uRightShift = struts[1];
- ulong uRightFromY = struts[6];
- ulong uRightToY = struts[7];
-
- ulong uTopShift = struts[2];
- ulong uTopFromX = struts[8];
- ulong uTopToX = struts[9];
-
- ulong uBottomShift = struts[3];
- ulong uBottomFromX = struts[10];
- ulong uBottomToX = struts[11];
-
- if (uLeftShift)
- {
- QRect sr(QPoint(0, uLeftFromY),
- QSize(uLeftShift, uLeftToY - uLeftFromY + 1));
-
- //AssertMsgFailed(("LOG... Subtract left strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
- virtualRegion -= sr;
- }
-
- if (uRightShift)
- {
- QRect sr(QPoint(virtualDesktop.x() + virtualDesktop.width() - uRightShift, uRightFromY),
- QSize(virtualDesktop.x() + virtualDesktop.width(), uRightToY - uRightFromY + 1));
-
- //AssertMsgFailed(("LOG... Subtract right strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
- virtualRegion -= sr;
- }
-
- if (uTopShift)
- {
- QRect sr(QPoint(uTopFromX, 0),
- QSize(uTopToX - uTopFromX + 1, uTopShift));
-
- //AssertMsgFailed(("LOG... Subtract top strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
- virtualRegion -= sr;
- }
-
- if (uBottomShift)
- {
- QRect sr(QPoint(uBottomFromX, virtualDesktop.y() + virtualDesktop.height() - uBottomShift),
- QSize(uBottomToX - uBottomFromX + 1, uBottomShift));
-
- //AssertMsgFailed(("LOG... Subtract bottom strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
- virtualRegion -= sr;
- }
- }
- }
-
- /* Get final available geometry: */
- result = (virtualRegion & result).boundingRect();
- }
- }
-
- /* If result is still NULL: */
- if (result.isNull())
- {
- /* Use QT default functionality: */
- result = pDesktopWidget->availableGeometry(iScreen);
- }
-
- //AssertMsgFailed(("LOG... Final geometry: %dx%dx%dx%d\n", result.x(), result.y(), result.width(), result.height()));
-
-#else /* ifdef Q_WS_X11 */
-
- result = QApplication::desktop()->availableGeometry(iScreen);
-
-#endif /* ifndef Q_WS_X11 */
-
- return result;
-}
-
/**
* Returns the list of few guest OS types, queried from
* IVirtualBox corresponding to every family id.
@@ -3496,6 +3375,15 @@ bool VBoxGlobal::shouldWeAllowApplicationUpdate(CVirtualBox &vbox)
}
#endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
+#ifdef Q_WS_X11
+/* static */
+bool VBoxGlobal::legacyFullscreenModeRequested(CVirtualBox vbox)
+{
+ /* 'False' unless feature requested through the extra-data: */
+ return isApprovedByExtraData(vbox, GUI_Fullscreen_LegacyMode);
+}
+#endif /* Q_WS_X11 */
+
/* static */
bool VBoxGlobal::shouldWeShowMachine(CMachine &machine)
{
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
index 450ddf8..25d36cd 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
@@ -128,8 +128,6 @@ public:
const char *vmRenderModeStr() const { return vm_render_mode_str; }
bool isKWinManaged() const { return mIsKWinManaged; }
- const QRect availableGeometry(int iScreen = 0) const;
-
bool shouldRestoreCurrentSnapshot() const { return mRestoreCurrentSnapshot; }
bool isPatmDisabled() const { return mDisablePatm; }
bool isCsamDisabled() const { return mDisableCsam; }
@@ -360,6 +358,9 @@ public:
#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
static bool shouldWeAllowApplicationUpdate(CVirtualBox &vbox);
#endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
+#ifdef Q_WS_X11
+ static bool legacyFullscreenModeRequested(CVirtualBox vbox);
+#endif /* Q_WS_X11 */
static bool shouldWeShowMachine(CMachine &machine);
static bool shouldWeAllowMachineReconfiguration(CMachine &machine,
bool fIncludingMachineGeneralCheck = false,
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
index 553662b..c75eae6 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
@@ -208,6 +208,12 @@ bool darwinIsInFullscreenMode(NativeNSWindowRef pWindow)
return [pWindow styleMask] & NSFullScreenWindowMask;
}
+bool darwinIsOnActiveSpace(NativeNSWindowRef pWindow)
+{
+ /* Check whether passed pWindow is on active space. */
+ return [pWindow isOnActiveSpace];
+}
+
bool darwinScreensHaveSeparateSpaces()
{
/* Check whether screens have separate spaces.
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
index 3967cba..615ad92 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
@@ -158,6 +158,11 @@ bool darwinIsInFullscreenMode(QWidget *pWidget)
return ::darwinIsInFullscreenMode(::darwinToNativeWindow(pWidget));
}
+bool darwinIsOnActiveSpace(QWidget *pWidget)
+{
+ return ::darwinIsOnActiveSpace(::darwinToNativeWindow(pWidget));
+}
+
void darwinInstallResizeDelegate(QWidget *pWidget)
{
::darwinInstallResizeDelegate(::darwinToNativeWindow(pWidget));
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
index d9f2878..8bbda94 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
@@ -82,6 +82,7 @@ void darwinEnableFullscreenSupport(NativeNSWindowRef pWindow);
void darwinEnableTransienceSupport(NativeNSWindowRef pWindow);
void darwinToggleFullscreenMode(NativeNSWindowRef pWindow);
bool darwinIsInFullscreenMode(NativeNSWindowRef pWindow);
+bool darwinIsOnActiveSpace(NativeNSWindowRef pWindow);
bool darwinScreensHaveSeparateSpaces();
bool darwinOpenFile(NativeNSStringRef pstrFile);
@@ -250,6 +251,7 @@ void darwinEnableFullscreenSupport(QWidget *pWidget);
void darwinEnableTransienceSupport(QWidget *pWidget);
void darwinToggleFullscreenMode(QWidget *pWidget);
bool darwinIsInFullscreenMode(QWidget *pWidget);
+bool darwinIsOnActiveSpace(QWidget *pWidget);
bool darwinOpenFile(const QString &strFile);
double darwinBackingScaleFactor(QWidget *pWidget);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
index ef4c02f..b9120c3 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
@@ -291,11 +291,12 @@ UIMachineWindow* UIMachineLogic::activeMachineWindow() const
return mainMachineWindow();
}
-/** Adjusts guest screen size for each the machine-window we have. */
-void UIMachineLogic::maybeAdjustGuestScreenSize()
+void UIMachineLogic::adjustMachineWindowsGeometry()
{
+ /* By default, the only thing we need is to
+ * adjust machine-view size(s) if necessary: */
foreach(UIMachineWindow *pMachineWindow, machineWindows())
- pMachineWindow->machineView()->maybeAdjustGuestScreenSize();
+ pMachineWindow->adjustMachineViewSize();
}
#ifdef Q_WS_MAC
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
index d5637b8..6e03fa3 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
@@ -80,8 +80,8 @@ public:
bool isPreventAutoClose() const { return m_fIsPreventAutoClose; }
void setPreventAutoClose(bool fIsPreventAutoClose) { m_fIsPreventAutoClose = fIsPreventAutoClose; }
- /* API: Guest screen size stuff: */
- virtual void maybeAdjustGuestScreenSize();
+ /** Adjusts machine-window(s) geometry if necessary. */
+ virtual void adjustMachineWindowsGeometry();
/* Wrapper to open Machine settings / Network page: */
void openNetworkAdaptersDialog() { sltOpenNetworkAdaptersDialog(); }
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
index 0404e97..f3385fc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
@@ -75,9 +75,9 @@ public:
/* Public setters: */
virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {}
- /** Adjusts guest screen size to correspond current machine-window size.
+ /** Adjusts guest-screen size to correspond current visual-style.
* @note Reimplemented in sub-classes. Base implementation does nothing. */
- virtual void maybeAdjustGuestScreenSize() {}
+ virtual void adjustGuestScreenSize() {}
/* Framebuffer aspect ratio: */
double aspectRatio() const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
index be5048c..ce28562 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
@@ -203,6 +203,13 @@ CMachine UIMachineWindow::machine() const
return session().GetMachine();
}
+void UIMachineWindow::adjustMachineViewSize()
+{
+ /* By default, the only thing we need is to
+ * adjust guest-screen size if necessary: */
+ machineView()->adjustGuestScreenSize();
+}
+
#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
void UIMachineWindow::setMask(const QRegion ®ion)
{
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
index 37c0cb2..dffc9ea 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
@@ -62,11 +62,14 @@ public:
CSession& session() const;
CMachine machine() const;
- /** Adjusts machine-window size to correspond current guest screen size.
+ /** Adjusts machine-window size to correspond current machine-view size.
* @param fAdjustPosition determines whether is it necessary to adjust position too.
* @note Reimplemented in sub-classes. Base implementation does nothing. */
virtual void normalizeGeometry(bool fAdjustPosition) { Q_UNUSED(fAdjustPosition); }
+ /** Adjusts machine-view size to correspond current machine-window size. */
+ virtual void adjustMachineViewSize();
+
#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
/* Virtual caller for base class setMask: */
virtual void setMask(const QRegion ®ion);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
index 0bbe1fe..06785c4 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
@@ -276,8 +276,8 @@ void UISession::powerUp()
if (isSaved())
{
msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", 0, 0);
- /* After restoring from 'saved' state, guest screen size should be adjusted: */
- machineLogic()->maybeAdjustGuestScreenSize();
+ /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
+ machineLogic()->adjustMachineWindowsGeometry();
}
else
msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png");
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
index 6066a12..355f7bf 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
@@ -83,10 +83,9 @@ bool UIMachineLogicFullscreen::checkAvailability()
return true;
}
-/** Adjusts guest screen count/size for the machine-logic we have. */
-void UIMachineLogicFullscreen::maybeAdjustGuestScreenSize()
+void UIMachineLogicFullscreen::adjustMachineWindowsGeometry()
{
- LogRel(("UIMachineLogicFullscreen::maybeAdjustGuestScreenSize"));
+ LogRel(("UIMachineLogicFullscreen::adjustMachineWindowsGeometry\n"));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
@@ -99,7 +98,7 @@ void UIMachineLogicFullscreen::maybeAdjustGuestScreenSize()
foreach (UIMachineWindow *pMachineWindow, machineWindows())
pMachineWindow->showInNecessaryMode();
}
- /* Revalidate native fullscreen for ML and next: */
+ /* For ML and next revalidate native fullscreen: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Make sure all machine-window(s) have proper geometry: */
@@ -360,14 +359,14 @@ void UIMachineLogicFullscreen::sltMachineStateChanged()
/* If machine-state changed from 'paused' to 'running': */
if (uisession()->isRunning() && uisession()->wasPaused())
{
- LogRelFlow(("UIMachineLogicFullscreen: "
- "Machine-state changed from 'paused' to 'running': "
- "Updating screen-layout...\n"));
+ LogRel(("UIMachineLogicFullscreen::sltMachineStateChanged:"
+ "Machine-state changed from 'paused' to 'running': "
+ "Adjust machine-window geometry...\n"));
/* Make sure further code will be called just once: */
uisession()->forgetPreviousMachineState();
- /* Adjust guest-screen size if necessary: */
- maybeAdjustGuestScreenSize();
+ /* Adjust machine-window geometry if necessary: */
+ adjustMachineWindowsGeometry();
}
}
@@ -501,6 +500,8 @@ void UIMachineLogicFullscreen::prepareMachineWindows()
/* Register to native notifications: */
UICocoaApplication::instance()->registerToNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this,
UIMachineLogicFullscreen::nativeHandlerForApplicationActivation);
+ UICocoaApplication::instance()->registerToNotificationOfWorkspace("NSWorkspaceActiveSpaceDidChangeNotification", this,
+ UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange);
}
/* We have to make sure that we are getting the front most process.
@@ -589,6 +590,7 @@ void UIMachineLogicFullscreen::cleanupMachineWindows()
{
/* Unregister from native notifications: */
UICocoaApplication::instance()->unregisterFromNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this);
+ UICocoaApplication::instance()->unregisterFromNotificationOfWorkspace("NSWorkspaceActiveSpaceDidChangeNotification", this);
}
/* For Lion and previous fade to black: */
@@ -707,12 +709,16 @@ void UIMachineLogicFullscreen::fadeToNormal()
void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMachineWindow)
{
+ /* Make sure that is full-screen machine-window: */
+ UIMachineWindowFullscreen *pMachineWindowFullscreen = qobject_cast<UIMachineWindowFullscreen*>(pMachineWindow);
+ AssertPtrReturnVoid(pMachineWindowFullscreen);
+
/* Make sure window is not already invalidated: */
if (m_invalidFullscreenMachineWindows.contains(pMachineWindow))
return;
/* Ignore window if it is in 'fullscreen transition': */
- if (qobject_cast<UIMachineWindowFullscreen*>(pMachineWindow)->isInFullscreenTransition())
+ if (pMachineWindowFullscreen->isInFullscreenTransition())
return;
/* Get screen ID: */
@@ -724,14 +730,17 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
if (uScreenID != 0 && !screensHaveSeparateSpaces())
{
/* We are hiding transient window if:
- * 1. application is inactive at all or
+ * 1. primary window is not on active user-space
* 2. there is no fullscreen window or it's invalidated. */
- if ( !UICocoaApplication::instance()->isActive()
+ if ( !darwinIsOnActiveSpace(machineWindows().first())
|| m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask transient machine-window #%d to hide.\n", (int)uScreenID));
+ /* Make sure mini-toolbar hidden: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(false);
+ /* Make sure window hidden: */
pMachineWindow->hide();
}
/* If there is valid fullscreen window: */
@@ -742,6 +751,8 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
/* Make sure window have proper geometry and shown: */
pMachineWindow->showInNecessaryMode();
+ /* Make sure mini-toolbar shown: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(true);
}
}
/* Validate window which can be fullscreen: */
@@ -765,6 +776,8 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
/* Update 'presentation mode': */
setPresentationModeEnabled(true);
+ /* Make sure mini-toolbar hidden: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(false);
/* Make sure window have proper geometry and shown: */
pMachineWindow->showInNecessaryMode();
@@ -778,6 +791,9 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to hide.\n", (int)uScreenID));
+ /* Make sure mini-toolbar hidden: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(false);
+ /* Make sure window hidden: */
pMachineWindow->hide();
/* Fade to normal: */
@@ -810,8 +826,11 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
/* Mark window as invalidated: */
m_invalidFullscreenMachineWindows << pMachineWindow;
+ /* Make sure mini-toolbar hidden: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(false);
/* Ask window to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited(pMachineWindow);
+ return;
}
/* If that window
@@ -821,9 +840,15 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to adjust guest geometry.\n", (int)uScreenID));
- /* Adjust guest screen size if necessary: */
- pMachineWindow->machineView()->maybeAdjustGuestScreenSize();
+ /* Make sure mini-toolbar shown: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(true);
+ /* Just adjust machine-view size if necessary: */
+ pMachineWindow->adjustMachineViewSize();
+ return;
}
+
+ /* Make sure mini-toolbar shown: */
+ pMachineWindowFullscreen->setMiniToolbarVisible(true);
}
}
}
@@ -851,36 +876,60 @@ void UIMachineLogicFullscreen::nativeHandlerForApplicationActivation(const QMap<
{
/* Make sure we have BundleIdentifier key: */
AssertReturnVoid(userInfo.contains("BundleIdentifier"));
+ /* Skip other applications: */
+ QStringList ourBundleIdentifiers;
+ ourBundleIdentifiers << "org.virtualbox.app.VirtualBox";
+ ourBundleIdentifiers << "org.virtualbox.app.VirtualBoxVM";
+ ourBundleIdentifiers << "com.citrix.DesktopPlayerVM";
+ if (!ourBundleIdentifiers.contains(userInfo.value("BundleIdentifier")))
+ return;
- /* On VirtualBox activation: */
- if (userInfo.value("BundleIdentifier") == "org.virtualbox.app.VirtualBox")
- {
- LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: BundleIdentifier = %s\n",
- userInfo.value("BundleIdentifier").toAscii().constData()));
+ /* Skip if 'screen have separate spaces': */
+ if (screensHaveSeparateSpaces())
+ return;
- /* Make sure all the transient machine-windows updated: */
- foreach (UIMachineWindow *pMachineWindow, machineWindows())
- if (pMachineWindow->screenId() != 0 && !screensHaveSeparateSpaces())
- {
- /* If there is no fullscreen window or it's invalidated: */
- if (m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
- {
- LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
- "Ask transient machine-window #%d to hide.\n", (int)pMachineWindow->screenId()));
-
- pMachineWindow->hide();
- }
- /* If there is valid fullscreen window: */
- else
- {
- LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
- "Ask transient machine-window #%d to show/normalize.\n", (int)pMachineWindow->screenId()));
+ /* Skip if there is another than needed user-space is active: */
+ if (!darwinIsOnActiveSpace(machineWindows().first()))
+ return;
- /* Make sure window have proper geometry and shown: */
- pMachineWindow->showInNecessaryMode();
- }
- }
+ LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
+ "Full-screen application activated.\n"));
+
+ /* Revalidate full-screen mode for transient machine-window(s): */
+ foreach (UIMachineWindow *pMachineWindow, machineWindows())
+ if (pMachineWindow->screenId() > 0)
+ revalidateNativeFullScreen(pMachineWindow);
+}
+
+/* static */
+void UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange(QObject *pObject, const QMap<QString, QString> &userInfo)
+{
+ /* Handle arrived notification: */
+ UIMachineLogicFullscreen *pLogic = qobject_cast<UIMachineLogicFullscreen*>(pObject);
+ AssertPtrReturnVoid(pLogic);
+ {
+ /* Redirect arrived notification: */
+ pLogic->nativeHandlerForActiveSpaceChange(userInfo);
}
}
+
+void UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange(const QMap<QString, QString>&)
+{
+ /* Skip if 'screen have separate spaces': */
+ if (screensHaveSeparateSpaces())
+ return;
+
+ /* Skip if there is another than needed user-space is active: */
+ if (!darwinIsOnActiveSpace(machineWindows().first()))
+ return;
+
+ LogRel(("UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange: "
+ "Full-screen user-space activated.\n"));
+
+ /* Revalidate full-screen mode for transient machine-window(s): */
+ foreach (UIMachineWindow *pMachineWindow, machineWindows())
+ if (pMachineWindow->screenId() > 0)
+ revalidateNativeFullScreen(pMachineWindow);
+}
#endif /* Q_WS_MAC */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
index 980ba32..2d63a95 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
@@ -61,8 +61,10 @@ protected:
/** Returns machine-window flags for 'Fullscreen' machine-logic and passed @a uScreenId. */
virtual Qt::WindowFlags windowFlags(ulong uScreenId) const { Q_UNUSED(uScreenId); return Qt::FramelessWindowHint; }
+ /** Adjusts machine-window geometry if necessary for 'Fullscreen'. */
+ virtual void adjustMachineWindowsGeometry();
+
/* Helpers: Multi-screen stuff: */
- void maybeAdjustGuestScreenSize();
int hostScreenForGuestScreen(int iScreenId) const;
bool hasHostScreenForGuestScreen(int iScreenId) const;
@@ -141,10 +143,15 @@ private:
/** Mac OS X: Revalidates 'fullscreen' mode for all windows. */
void revalidateNativeFullScreen();
- /** Mac OS X: Proxies native notification about active space change. */
+ /** Mac OS X: Proxies native notification about application activation. */
static void nativeHandlerForApplicationActivation(QObject *pObject, const QMap<QString, QString> &userInfo);
- /** Mac OS X: Handles native notification about active space change. */
+ /** Mac OS X: Handles native notification about application activation. */
void nativeHandlerForApplicationActivation(const QMap<QString, QString> &userInfo);
+
+ /** Mac OS X: Proxies native notification about active space change. */
+ static void nativeHandlerForActiveSpaceChange(QObject *pObject, const QMap<QString, QString> &userInfo);
+ /** Mac OS X: Handles native notification about active space change. */
+ void nativeHandlerForActiveSpaceChange(const QMap<QString, QString> &userInfo);
#endif /* Q_WS_MAC */
/* Variables: */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
index 6cfa25d..5bad43c 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
@@ -62,7 +62,7 @@ UIMachineViewFullscreen::~UIMachineViewFullscreen()
void UIMachineViewFullscreen::sltAdditionsStateChanged()
{
- maybeAdjustGuestScreenSize();
+ adjustGuestScreenSize();
}
bool UIMachineViewFullscreen::eventFilter(QObject *pWatched, QEvent *pEvent)
@@ -135,10 +135,9 @@ void UIMachineViewFullscreen::setGuestAutoresizeEnabled(bool fEnabled)
}
}
-/** Adjusts guest screen size to correspond current <i>working area</i> size. */
-void UIMachineViewFullscreen::maybeAdjustGuestScreenSize()
+void UIMachineViewFullscreen::adjustGuestScreenSize()
{
- /* Check if we should adjust guest to new size: */
+ /* Check if we should adjust guest-screen to new size: */
if (frameBuffer()->isAutoEnabled() ||
(int)frameBuffer()->width() != workingArea().size().width() ||
(int)frameBuffer()->height() != workingArea().size().height())
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
index 1b35322..ff12727 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
@@ -61,8 +61,10 @@ private:
/* Private setters: */
void setGuestAutoresizeEnabled(bool bEnabled);
+ /** Adjusts guest-screen size to correspond current <i>working area</i> size. */
+ void adjustGuestScreenSize();
+
/* Helpers: Geometry stuff: */
- void maybeAdjustGuestScreenSize();
QRect workingArea() const;
QSize calculateMaxGuestSize() const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
index c9f7f07..c1a5630 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
@@ -102,6 +102,15 @@ void UIMachineWindowFullscreen::handleNativeNotification(const QString &strNativ
emit sigNotifyAboutNativeFullscreenFailToEnter();
}
}
+
+void UIMachineWindowFullscreen::setMiniToolbarVisible(bool fVisible)
+{
+ /* Make sure mini-toolbar exists: */
+ if (!m_pMiniToolBar)
+ return;
+ /* Set mini-toolbar visibility to passed one: */
+ m_pMiniToolBar->setVisible(fVisible);
+}
#endif /* Q_WS_MAC */
void UIMachineWindowFullscreen::sltMachineStateChanged()
@@ -183,8 +192,13 @@ void UIMachineWindowFullscreen::sltRevokeFocus()
if (!isVisible())
return;
+#ifndef RT_OS_DARWIN
/* Revoke stolen focus: */
m_pMachineView->setFocus();
+#else /* RT_OS_DARWIN */
+ /* Revoke stolen activation: */
+ activateWindow();
+#endif /* RT_OS_DARWIN */
}
void UIMachineWindowFullscreen::prepareMenu()
@@ -268,6 +282,10 @@ void UIMachineWindowFullscreen::prepareMiniToolbar()
for (int i=0; i < actions.size(); ++i)
menus << actions.at(i)->menu();
m_pMiniToolBar->addMenus(menus);
+#ifdef RT_OS_DARWIN
+ connect(machineLogic(), SIGNAL(sigNotifyAbout3DOverlayVisibilityChange(bool)),
+ m_pMiniToolBar, SLOT(sltHandle3DOverlayVisibilityChange(bool)));
+#endif /* RT_OS_DARWIN */
#ifndef RT_OS_DARWIN
connect(m_pMiniToolBar, SIGNAL(sigMinimizeAction()), this, SLOT(showMinimized()));
#endif /* !RT_OS_DARWIN */
@@ -275,7 +293,8 @@ void UIMachineWindowFullscreen::prepareMiniToolbar()
gActionPool->action(UIActionIndexRuntime_Toggle_Fullscreen), SLOT(trigger()));
connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
gActionPool->action(UIActionIndexRuntime_Simple_Close), SLOT(trigger()));
- connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()), this, SLOT(sltRevokeFocus()));
+ connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()),
+ this, SLOT(sltRevokeFocus()), Qt::QueuedConnection);
}
void UIMachineWindowFullscreen::cleanupMiniToolbar()
@@ -369,12 +388,21 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
AssertPtrReturnVoid(pFullscreenLogic);
+#ifdef Q_WS_MAC
+ /* ML and next using native stuff: */
+ const bool fSupportsNativeFullScreen = vboxGlobal().osRelease() > MacOSXRelease_Lion;
+#endif /* Q_WS_MAC */
+
/* Make sure this window should be shown and mapped to some host-screen: */
if (!uisession()->isScreenVisible(m_uScreenId) ||
!pFullscreenLogic->hasHostScreenForGuestScreen(m_uScreenId))
{
/* Hide mini-toolbar: */
- if (m_pMiniToolBar)
+ if ( m_pMiniToolBar
+#ifdef Q_WS_MAC
+ && !fSupportsNativeFullScreen
+#endif /* Q_WS_MAC */
+ )
m_pMiniToolBar->hide();
/* Hide window: */
hide();
@@ -385,14 +413,12 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
if (isMinimized())
return;
- /* Which host-screen should that machine-window located on? */
- const int iHostScreen = pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId);
-
#ifdef Q_WS_X11
/* On X11 calling placeOnScreen() is only needed for legacy window managers
* which we do not test, so this is 'best effort' code. With window managers which
* support the _NET_WM_FULLSCREEN_MONITORS protocol this would interfere unreliable. */
- const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11();
+ const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11() &&
+ !VBoxGlobal::legacyFullscreenModeRequested(vboxGlobal().virtualBox());
if (!fSupportsNativeFullScreen)
placeOnScreen();
#else /* !Q_WS_X11 */
@@ -403,7 +429,6 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
#ifdef Q_WS_MAC
/* ML and next using native stuff, so we can call for simple show(),
* Lion and previous using Qt stuff, so we should call for showFullScreen(): */
- const bool fSupportsNativeFullScreen = vboxGlobal().osRelease() > MacOSXRelease_Lion;
if (fSupportsNativeFullScreen)
show();
else
@@ -419,7 +444,7 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
/* Tell recent window managers which screen this window should be mapped to.
* Apparently some window managers will not respond to requests for
* unmapped windows, so do this *after* the call to showFullScreen(). */
- VBoxGlobal::setFullScreenMonitorX11(this, iHostScreen);
+ VBoxGlobal::setFullScreenMonitorX11(this, pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId));
}
else
{
@@ -430,13 +455,34 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
}
#endif /* Q_WS_X11 */
- /* Adjust guest-screen size if necessary: */
- machineView()->maybeAdjustGuestScreenSize();
+ /* Adjust machine-view size if necessary: */
+ adjustMachineViewSize();
- /* Show/Move mini-toolbar into appropriate place: */
+ /* Show mini-toolbar: */
+ if ( m_pMiniToolBar
+#ifdef Q_WS_MAC
+ && !fSupportsNativeFullScreen
+#endif /* Q_WS_MAC */
+ )
+ m_pMiniToolBar->show();
+}
+
+void UIMachineWindowFullscreen::adjustMachineViewSize()
+{
+ /* Call to base-class: */
+ UIMachineWindow::adjustMachineViewSize();
+
+ /* If mini-toolbar present: */
if (m_pMiniToolBar)
{
- m_pMiniToolBar->show();
+ /* Make sure this window has fullscreen logic: */
+ UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
+ AssertPtrReturnVoid(pFullscreenLogic);
+
+ /* Which host-screen should that machine-window located on? */
+ const int iHostScreen = pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId);
+
+ /* Move mini-toolbar into appropriate place: */
m_pMiniToolBar->adjustGeometry(iHostScreen);
}
}
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
index 7584217..87e7336 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
@@ -54,6 +54,8 @@ protected:
void handleNativeNotification(const QString &strNativeNotificationName);
/** Mac OS X: Returns whether window is in 'fullscreen' transition. */
bool isInFullscreenTransition() const { return m_fIsInFullscreenTransition; }
+ /** Mac OS X: Defines whether mini-toolbar should be @a fVisible. */
+ void setMiniToolbarVisible(bool fVisible);
#endif /* Q_WS_MAC */
private slots:
@@ -90,6 +92,9 @@ private:
void placeOnScreen();
void showInNecessaryMode();
+ /** Adjusts machine-view size to correspond current machine-window size. */
+ virtual void adjustMachineViewSize();
+
/* Update stuff: */
void updateAppearanceOf(int iElement);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
index dd0419a..016e5e8 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
@@ -63,7 +63,7 @@ UIMachineViewNormal::~UIMachineViewNormal()
void UIMachineViewNormal::sltAdditionsStateChanged()
{
- maybeAdjustGuestScreenSize();
+ adjustGuestScreenSize();
}
bool UIMachineViewNormal::eventFilter(QObject *pWatched, QEvent *pEvent)
@@ -185,11 +185,10 @@ void UIMachineViewNormal::maybeResendSizeHint()
}
}
-/** Adjusts guest screen size to correspond current machine-window size. */
-void UIMachineViewNormal::maybeAdjustGuestScreenSize()
+void UIMachineViewNormal::adjustGuestScreenSize()
{
- /* Check if we should adjust guest to new size: */
- QSize centralWidgetSize = machineWindow()->centralWidget()->size();
+ /* Check if we should adjust guest-screen to new size: */
+ const QSize centralWidgetSize = machineWindow()->centralWidget()->size();
if ((int)frameBuffer()->width() != centralWidgetSize.width() ||
(int)frameBuffer()->height() != centralWidgetSize.height())
if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
index 233a19e..aa2ab61 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
@@ -66,8 +66,10 @@ private:
/** Resends guest size-hint if necessary. */
void maybeResendSizeHint();
+ /** Adjusts guest-screen size to correspond current <i>machine-window</i> size. */
+ void adjustGuestScreenSize();
+
/* Private helpers: */
- void maybeAdjustGuestScreenSize();
QRect workingArea() const;
QSize calculateMaxGuestSize() const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
index 57658a9..8ba24cc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
@@ -364,6 +364,15 @@ void UIMachineWindowNormal::prepareVisualState()
/* Call to base-class: */
UIMachineWindow::prepareVisualState();
+#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
+ /* Customer request: The background has to go black: */
+ QPalette palette(centralWidget()->palette());
+ palette.setColor(centralWidget()->backgroundRole(), Qt::black);
+ centralWidget()->setPalette(palette);
+ centralWidget()->setAutoFillBackground(true);
+ setAutoFillBackground(true);
+#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
+
/* Make sure host-combination LED will be updated: */
connect(&vboxGlobal().settings(), SIGNAL(propertyChanged(const char *, const char *)),
this, SLOT(sltProcessGlobalSettingChange(const char *, const char *)));
@@ -609,6 +618,7 @@ void UIMachineWindowNormal::showInNecessaryMode()
*/
void UIMachineWindowNormal::normalizeGeometry(bool fAdjustPosition)
{
+#ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
/* Skip if maximized: */
if (isMaximized())
return;
@@ -640,6 +650,11 @@ void UIMachineWindowNormal::normalizeGeometry(bool fAdjustPosition)
/* Finally, set the frame geometry: */
setGeometry(frameGeo.left() + dl, frameGeo.top() + dt,
frameGeo.width() - dl - dr, frameGeo.height() - dt - db);
+#else /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
+ /* Customer request: There should no be
+ * machine-window resize on machine-view resize: */
+ Q_UNUSED(fAdjustPosition);
+#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
}
void UIMachineWindowNormal::updateAppearanceOf(int iElement)
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
index de18d3b..1432951 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
@@ -76,10 +76,9 @@ bool UIMachineLogicSeamless::checkAvailability()
return true;
}
-/** Adjusts guest screen count/size for the machine-logic we have. */
-void UIMachineLogicSeamless::maybeAdjustGuestScreenSize()
+void UIMachineLogicSeamless::adjustMachineWindowsGeometry()
{
- LogRel(("UIMachineLogicSeamless::maybeAdjustGuestScreenSize"));
+ LogRel(("UIMachineLogicSeamless::adjustMachineWindowsGeometry\n"));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
@@ -135,14 +134,14 @@ void UIMachineLogicSeamless::sltMachineStateChanged()
/* If machine-state changed from 'paused' to 'running': */
if (uisession()->isRunning() && uisession()->wasPaused())
{
- LogRelFlow(("UIMachineLogicSeamless: "
- "Machine-state changed from 'paused' to 'running': "
- "Updating screen-layout...\n"));
+ LogRel(("UIMachineLogicSeamless::sltMachineStateChanged:"
+ "Machine-state changed from 'paused' to 'running': "
+ "Adjust machine-window geometry...\n"));
/* Make sure further code will be called just once: */
uisession()->forgetPreviousMachineState();
- /* Adjust guest-screen size if necessary: */
- maybeAdjustGuestScreenSize();
+ /* Adjust machine-window geometry if necessary: */
+ adjustMachineWindowsGeometry();
}
}
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
index e363de6..6904add 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
@@ -40,8 +40,10 @@ protected:
/** Returns machine-window flags for 'Seamless' machine-logic and passed @a uScreenId. */
virtual Qt::WindowFlags windowFlags(ulong uScreenId) const { Q_UNUSED(uScreenId); return Qt::FramelessWindowHint; }
+ /** Adjusts machine-window geometry if necessary for 'Seamless'. */
+ virtual void adjustMachineWindowsGeometry();
+
/* Helpers: Multi-screen stuff: */
- void maybeAdjustGuestScreenSize();
int hostScreenForGuestScreen(int iScreenId) const;
bool hasHostScreenForGuestScreen(int iScreenId) const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
index 4d7fffd..20a1edc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
@@ -71,7 +71,7 @@ UIMachineViewSeamless::~UIMachineViewSeamless()
void UIMachineViewSeamless::sltAdditionsStateChanged()
{
- maybeAdjustGuestScreenSize();
+ adjustGuestScreenSize();
}
void UIMachineViewSeamless::sltHandleSetVisibleRegion(QRegion region)
@@ -153,10 +153,9 @@ void UIMachineViewSeamless::cleanupSeamless()
session().GetConsole().GetDisplay().SetSeamlessMode(false);
}
-/** Adjusts guest screen size to correspond current <i>working area</i> size. */
-void UIMachineViewSeamless::maybeAdjustGuestScreenSize()
+void UIMachineViewSeamless::adjustGuestScreenSize()
{
- /* Check if we should adjust guest to new size: */
+ /* Check if we should adjust guest-screen to new size: */
if (frameBuffer()->isAutoEnabled() ||
(int)frameBuffer()->width() != workingArea().size().width() ||
(int)frameBuffer()->height() != workingArea().size().height())
@@ -173,7 +172,7 @@ QRect UIMachineViewSeamless::workingArea() const
/* Get corresponding screen: */
int iScreen = static_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(screenId());
/* Return available geometry for that screen: */
- return vboxGlobal().availableGeometry(iScreen);
+ return QApplication::desktop()->availableGeometry(iScreen);
}
QSize UIMachineViewSeamless::calculateMaxGuestSize() const
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
index eda6944..c9726f6 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
@@ -63,8 +63,10 @@ private:
//void cleanupFilters() {}
//void cleanupCommon() {}
+ /** Adjusts guest-screen size to correspond current <i>working area</i> size. */
+ void adjustGuestScreenSize();
+
/* Helpers: Geometry stuff: */
- void maybeAdjustGuestScreenSize();
QRect workingArea() const;
QSize calculateMaxGuestSize() const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
index bf3eefc..339767a 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
@@ -80,6 +80,22 @@ void UIMachineWindowSeamless::sltRevokeFocus()
m_pMachineView->setFocus();
}
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+void UIMachineWindowSeamless::sltUpdateMiniToolbarMask(const QRect &geo)
+{
+ /* Make sure mini-toolbar exists: */
+ AssertPtrReturnVoid(m_pMiniToolBar);
+
+ /* Remember mini-toolbar mask: */
+ m_maskMiniToolbar = geo;
+
+ /* Re-assign guest mask. */
+ setMask(m_maskGuest);
+}
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
void UIMachineWindowSeamless::prepareMenu()
{
/* Call to base-class: */
@@ -119,7 +135,7 @@ void UIMachineWindowSeamless::prepareVisualState()
#else /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
/* Make sure we have no background
* until the first one set-region-event: */
- setMask(m_maskRegion);
+ setMask(m_maskGuest);
#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
#ifndef Q_WS_MAC
@@ -162,6 +178,12 @@ void UIMachineWindowSeamless::prepareMiniToolbar()
connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
gActionPool->action(UIActionIndexRuntime_Simple_Close), SLOT(trigger()));
connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()), this, SLOT(sltRevokeFocus()));
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+ connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutGeometryChange(const QRect&)),
+ this, SLOT(sltUpdateMiniToolbarMask(const QRect&)));
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
}
#endif /* !Q_WS_MAC */
@@ -206,7 +228,7 @@ void UIMachineWindowSeamless::placeOnScreen()
/* Get corresponding screen: */
int iScreen = qobject_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(m_uScreenId);
/* And corresponding working area: */
- QRect workingArea = vboxGlobal().availableGeometry(iScreen);
+ QRect workingArea = QApplication::desktop()->availableGeometry(iScreen);
/* Move to the appropriate position: */
move(workingArea.topLeft());
@@ -245,15 +267,34 @@ void UIMachineWindowSeamless::showInNecessaryMode()
/* Show in normal mode: */
show();
- /* Adjust guest screen size if necessary: */
- machineView()->maybeAdjustGuestScreenSize();
+ /* Adjust machine-view size if necessary: */
+ adjustMachineViewSize();
#ifndef Q_WS_MAC
- /* Show/Move mini-toolbar into appropriate place: */
+ /* Show mini-toolbar: */
if (m_pMiniToolBar)
- {
m_pMiniToolBar->show();
- m_pMiniToolBar->adjustGeometry();
+#endif /* !Q_WS_MAC */
+}
+
+void UIMachineWindowSeamless::adjustMachineViewSize()
+{
+ /* Call to base-class: */
+ UIMachineWindow::adjustMachineViewSize();
+
+#ifndef Q_WS_MAC
+ /* If mini-toolbar present: */
+ if (m_pMiniToolBar)
+ {
+ /* Make sure this window has seamless logic: */
+ const UIMachineLogicSeamless *pSeamlessLogic = qobject_cast<UIMachineLogicSeamless*>(machineLogic());
+ AssertPtrReturnVoid(pSeamlessLogic);
+
+ /* Which host-screen should that machine-window located on? */
+ const int iHostScreen = pSeamlessLogic->hostScreenForGuestScreen(m_uScreenId);
+
+ /* Move mini-toolbar into appropriate place: */
+ m_pMiniToolBar->adjustGeometry(iHostScreen);
}
#endif /* !Q_WS_MAC */
}
@@ -298,34 +339,40 @@ void UIMachineWindowSeamless::showEvent(QShowEvent*)
#endif /* VBOX_WITH_TRANSLUCENT_SEAMLESS && Q_WS_WIN */
#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
-void UIMachineWindowSeamless::setMask(const QRegion ®ion)
+void UIMachineWindowSeamless::setMask(const QRegion &maskGuest)
{
- /* Prepare mask-region: */
- QRegion maskRegion(region);
+ /* Remember new guest mask: */
+ m_maskGuest = maskGuest;
+
+ /* Prepare full mask: */
+ QRegion maskFull(m_maskGuest);
- /* Shift region if left spacer width is NOT zero or top spacer height is NOT zero: */
+ /* Shift full mask if left or top spacer width is NOT zero: */
if (m_pLeftSpacer->geometry().width() || m_pTopSpacer->geometry().height())
- maskRegion.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
+ maskFull.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
- /* Seamless-window for empty region should be empty too,
+# ifdef Q_WS_X11
+ /* Take into account mini-toolbar mask if necessary: */
+ if (m_pMiniToolBar)
+ maskFull += m_maskMiniToolbar;
+# endif /* Q_WS_X11 */
+
+ /* Seamless-window for empty full mask should be empty too,
* but the QWidget::setMask() wrapper doesn't allow this.
- * Instead, we have a full painted screen of seamless-geometry size visible.
- * Moreover, we can't just hide the empty seamless-window as 'hiding'
- * 1. will collide with the multi-screen layout behavior and
- * 2. will cause a task-bar flicker on moving window from one screen to another.
- * As a *temporary* though quite a dirty workaround we have to make sure
- * region have at least one pixel. */
- if (maskRegion.isEmpty())
- maskRegion += QRect(0, 0, 1, 1);
- /* Make sure mask-region had changed: */
- if (m_maskRegion != maskRegion)
+ * Instead, we see a full guest-screen of available-geometry size.
+ * So we have to make sure full mask have at least one pixel. */
+ if (maskFull.isEmpty())
+ maskFull += QRect(0, 0, 1, 1);
+
+ /* Make sure full mask had changed: */
+ if (m_maskFull != maskFull)
{
/* Compose viewport region to update: */
- QRegion toUpdate = m_maskRegion + maskRegion;
- /* Remember new mask-region: */
- m_maskRegion = maskRegion;
- /* Assign new mask-region: */
- UIMachineWindow::setMask(m_maskRegion);
+ QRegion toUpdate = m_maskFull + maskFull;
+ /* Remember new full mask: */
+ m_maskFull = maskFull;
+ /* Assign new full mask: */
+ UIMachineWindow::setMask(m_maskFull);
/* Update viewport region finally: */
m_pMachineView->viewport()->update(toUpdate);
}
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
index a7bfea8..5e15568 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
@@ -48,6 +48,13 @@ private slots:
/** Revokes keyboard-focus. */
void sltRevokeFocus();
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+ /** Assigns mini-toolbar seamless mask. */
+ void sltUpdateMiniToolbarMask(const QRect &geo);
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
private:
/* Prepare helpers: */
@@ -68,6 +75,9 @@ private:
void placeOnScreen();
void showInNecessaryMode();
+ /** Adjusts machine-view size to correspond current machine-window size. */
+ virtual void adjustMachineViewSize();
+
#ifndef Q_WS_MAC
/* Update routines: */
void updateAppearanceOf(int iElement);
@@ -79,8 +89,8 @@ private:
#endif /* VBOX_WITH_TRANSLUCENT_SEAMLESS && Q_WS_WIN */
#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
- /* Helper: Masking stuff: */
- void setMask(const QRegion ®ion);
+ /** Assigns guest seamless mask. */
+ void setMask(const QRegion &maskGuest);
#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
/* Widgets: */
@@ -90,8 +100,14 @@ private:
#endif /* !Q_WS_MAC */
#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
- /* Variable: Masking stuff: */
- QRegion m_maskRegion;
+ /** Holds the full seamless mask. */
+ QRegion m_maskFull;
+ /** Holds the guest seamless mask. */
+ QRegion m_maskGuest;
+# ifdef Q_WS_X11
+ /** Holds the mini-toolbar seamless mask. */
+ QRect m_maskMiniToolbar;
+# endif /* Q_WS_X11 */
#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
/* Factory support: */
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h b/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
index 28a7040..c5d9fe0 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
@@ -53,7 +53,7 @@ class ModelItem
public:
ModelItem(int number, ModelItem_type type, ModelItem *pParent = NULL);
- ~ModelItem();
+ virtual ~ModelItem();
ModelItem *parent() const { return m_pParentItem; }
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
index 349f826..e008476 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
@@ -39,15 +39,20 @@
# include "VBoxUtils-darwin.h"
#endif /* Q_WS_MAC */
-#ifndef Q_WS_X11
-# define VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
-#endif /* !Q_WS_X11 */
UIRuntimeMiniToolBar::UIRuntimeMiniToolBar(QWidget *pParent,
GeometryType geometryType,
Qt::Alignment alignment,
bool fAutoHide /* = true */)
- : QWidget(pParent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
+ : QWidget(pParent,
+#if defined (Q_WS_WIN)
+ Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint
+#elif defined (Q_WS_MAC)
+ Qt::Window | Qt::FramelessWindowHint
+#elif defined (Q_WS_X11)
+ Qt::Widget
+#endif /* RT_OS_DARWIN */
+ )
/* Variables: General stuff: */
, m_geometryType(geometryType)
, m_alignment(alignment)
@@ -138,10 +143,15 @@ void UIRuntimeMiniToolBar::adjustGeometry(int iHostScreen /* = -1 */)
int iX = 0, iY = 0;
switch (m_geometryType)
{
- case GeometryType_Available: screenRect = vboxGlobal().availableGeometry(iHostScreen); break;
+ case GeometryType_Available: screenRect = QApplication::desktop()->availableGeometry(iHostScreen); break;
case GeometryType_Full: screenRect = QApplication::desktop()->screenGeometry(iHostScreen); break;
default: break;
}
+#ifdef Q_WS_X11
+ /* Disregard origin under X11,
+ * because this is widget, not window: */
+ screenRect.moveTopLeft(QPoint(0, 0));
+#endif /* Q_WS_X11 */
iX = screenRect.x() + screenRect.width() / 2 - width() / 2;
switch (m_alignment)
{
@@ -192,7 +202,12 @@ void UIRuntimeMiniToolBar::sltHoverLeave()
void UIRuntimeMiniToolBar::prepare()
{
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
+#ifdef RT_OS_DARWIN
+ /* Install own event filter: */
+ installEventFilter(this);
+#endif /* RT_OS_DARWIN */
+
+#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
/* Make sure we have no background
* until the first one paint-event: */
setAttribute(Qt::WA_NoSystemBackground);
@@ -208,7 +223,7 @@ void UIRuntimeMiniToolBar::prepare()
* - Under x11 host Qt has broken XComposite support (black background): */
setAttribute(Qt::WA_TranslucentBackground);
# endif /* Q_WS_WIN */
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
+#endif /* Q_WS_MAC || Q_WS_WIN */
/* Make sure we have no focus: */
setFocusPolicy(Qt::NoFocus);
@@ -283,9 +298,6 @@ void UIRuntimeMiniToolBar::prepare()
/* Adjust geometry finally: */
adjustGeometry();
-
- /* Show: */
- show();
}
void UIRuntimeMiniToolBar::cleanup()
@@ -329,6 +341,7 @@ void UIRuntimeMiniToolBar::leaveEvent(QEvent*)
bool UIRuntimeMiniToolBar::eventFilter(QObject *pWatched, QEvent *pEvent)
{
+#ifndef RT_OS_DARWIN
/* Due to Qt bug QMdiArea can
* 1. steal focus from current application focus-widget
* 3. and even request focus stealing if QMdiArea hidden yet.
@@ -336,6 +349,13 @@ bool UIRuntimeMiniToolBar::eventFilter(QObject *pWatched, QEvent *pEvent)
if (pWatched && m_pEmbeddedToolbar && pWatched == m_pEmbeddedToolbar &&
pEvent->type() == QEvent::FocusIn)
emit sigNotifyAboutFocusStolen();
+#else /* RT_OS_DARWIN */
+ /* Due to Qt bug on Mac OS X window will be activated
+ * even if has Qt::WA_ShowWithoutActivating attribute. */
+ if (pWatched == this &&
+ pEvent->type() == QEvent::WindowActivate)
+ emit sigNotifyAboutFocusStolen();
+#endif /* RT_OS_DARWIN */
/* Call to base-class: */
return QWidget::eventFilter(pWatched, pEvent);
}
@@ -382,6 +402,12 @@ void UIRuntimeMiniToolBar::setToolbarPosition(QPoint point)
* Mac host has native translucency support,
* Win host allows to enable it through Qt::WA_TranslucentBackground: */
setMask(m_pEmbeddedToolbar->geometry());
+
+# ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+ /* Notify listeners as well: */
+ const QRect windowGeo = geometry();
+ emit sigNotifyAboutGeometryChange(windowGeo.intersected(m_pEmbeddedToolbar->geometry().translated(windowGeo.topLeft())));
+# endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
#endif /* Q_WS_X11 */
}
@@ -538,10 +564,8 @@ void UIMiniToolBar::prepare()
/* Configure toolbar: */
setIconSize(QSize(16, 16));
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
/* Left margin: */
m_spacings << widgetForAction(addWidget(new QWidget));
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
/* Prepare push-pin: */
m_pAutoHideAction = new QAction(this);
@@ -592,10 +616,8 @@ void UIMiniToolBar::prepare()
connect(m_pCloseAction, SIGNAL(triggered()), this, SIGNAL(sigCloseAction()));
addAction(m_pCloseAction);
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
/* Right margin: */
m_spacings << widgetForAction(addWidget(new QWidget));
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
/* Resize to sizehint: */
resize(sizeHint());
@@ -603,7 +625,6 @@ void UIMiniToolBar::prepare()
void UIMiniToolBar::rebuildShape()
{
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
/* Rebuild shape: */
QPainterPath shape;
switch (m_alignment)
@@ -637,6 +658,5 @@ void UIMiniToolBar::rebuildShape()
/* Update: */
update();
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
}
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
index f55183e..1bfa0bb 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
@@ -66,6 +66,13 @@ signals:
/** Notifies listeners about we stole focus. */
void sigNotifyAboutFocusStolen();
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+ /** Notifies about geometry change. */
+ void sigNotifyAboutGeometryChange(const QRect &geo);
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
public:
/* Constructor/destructor: */
@@ -93,6 +100,11 @@ public:
private slots:
+#ifdef RT_OS_DARWIN
+ /** Handle 3D overlay visibility change. */
+ void sltHandle3DOverlayVisibilityChange(bool fVisible) { if (fVisible) activateWindow(); }
+#endif /* RT_OS_DARWIN */
+
/* Handlers: Toolbar stuff: */
void sltHandleToolbarResize();
void sltAutoHideToggled();
diff --git a/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp b/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
index 2144c1e..0dee59e 100644
--- a/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
@@ -186,7 +186,7 @@ QString UIWizardExportApp::uri(bool fWithFile) const
uri = QString("%1%2").arg(uri).arg(field("username").toString());
if (!field("password").toString().isEmpty())
uri = QString("%1:%2").arg(uri).arg(field("password").toString());
- if (!field("username").toString().isEmpty() || !field("username").toString().isEmpty())
+ if (!field("username").toString().isEmpty() || !field("password").toString().isEmpty())
uri = QString("%1@").arg(uri);
uri = QString("%1%2/%3/%4").arg(uri).arg("object.storage.network.com").arg(field("bucket").toString()).arg(path);
return uri;
diff --git a/src/VBox/HostDrivers/Support/Makefile.kmk b/src/VBox/HostDrivers/Support/Makefile.kmk
index 50f89c7..819eae5 100644
--- a/src/VBox/HostDrivers/Support/Makefile.kmk
+++ b/src/VBox/HostDrivers/Support/Makefile.kmk
@@ -222,6 +222,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldr.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldrEx.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldrPE.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/common/alloc/heapsimple.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-basics.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-cursor.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-default-allocator.cpp \
@@ -324,6 +325,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrCopy.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrNCmp.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrNLen.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/common/string/RTUtf16NLenEx.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/string/strchr.asm \
$(VBOX_PATH_RUNTIME_SRC)/common/string/strcmp.asm \
$(VBOX_PATH_RUNTIME_SRC)/common/string/strcpy.asm \
@@ -343,6 +345,9 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
$(VBOX_PATH_RUNTIME_SRC)/common/string/unidata-lower.cpp \
$(VBOX_PATH_RUNTIME_SRC)/common/time/time.cpp \
$(VBOX_PATH_RUNTIME_SRC)/generic/RTAssertShouldPanic-generic.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/generic/RTPathAbs-generic.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/generic/RTPathGetCurrentDrive-generic.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/generic/RTPathGetCurrentOnDrive-generic.cpp \
$(VBOX_PATH_RUNTIME_SRC)/generic/memsafer-generic.cpp \
$(VBOX_PATH_RUNTIME_SRC)/generic/uuid-generic.cpp \
\
@@ -357,6 +362,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
SUPR3HardenedStatic_SOURCES.win += \
win/SUPR3HardenedNoCrt-win.cpp \
$(VBOX_PATH_RUNTIME_SRC)/nt/RTErrConvertFromNtStatus.cpp \
+ $(VBOX_PATH_RUNTIME_SRC)/r3/nt/pathint-nt.cpp \
$(VBOX_PATH_RUNTIME_SRC)/win/RTErrConvertFromWin32.cpp \
$(VBOX_PATH_RUNTIME_SRC)/win/errmsgwin.cpp
@@ -397,6 +403,7 @@ SUPR3HardenedMain.cpp_DEFS = VBOX_SVN_REV=$(VBOX_SVN_REV)
# VBoxSupLib - Windows DLL for catching thread creation and termination.
#
VBoxSupLib_TEMPLATE = $(if-expr "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING),VBOXR3HARDENEDLIB,VBOXR3)
+VBoxSupLib_SDKS.win = VBOX_NTDLL
VBoxSupLib_LDFLAGS.win.amd64 = -Entry:DllMainEntrypoint
VBoxSupLib_LDFLAGS.win.x86 = -Entry:DllMainEntrypoint
VBoxSupLib_DEFS = \
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIOC.h b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
index c01da48..17b05a3 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvIOC.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
@@ -1,4 +1,4 @@
-/* $Revision: 94789 $ */
+/* $Revision: 96490 $ */
/** @file
* VirtualBox Support Driver - IOCtl definitions.
*/
@@ -61,6 +61,19 @@
# define SUP_NT_STATUS_IS_VBOX(a_rcNt) ( ((uint32_t)(a_rcNt) & 0xffff0000) == SUP_NT_STATUS_BASE )
# define SUP_NT_STATUS_TO_VBOX(a_rcNt) ( (int)((uint32_t)(a_rcNt) | UINT32_C(0xffff0000)) )
+/** NT device name for system access. */
+# define SUPDRV_NT_DEVICE_NAME_SYS L"\\Device\\VBoxDrv"
+/** NT device name for user access. */
+# define SUPDRV_NT_DEVICE_NAME_USR L"\\Device\\VBoxDrvU"
+# ifdef VBOX_WITH_HARDENING
+/** NT device name for hardened stub access. */
+# define SUPDRV_NT_DEVICE_NAME_STUB L"\\Device\\VBoxDrvStub"
+/** NT device name for getting error information for failed VBoxDrv or
+ * VBoxDrvStub open. */
+# define SUPDRV_NT_DEVICE_NAME_ERROR_INFO L"\\Device\\VBoxDrvErrorInfo"
+# endif
+
+
#elif defined(RT_OS_SOLARIS)
/* No automatic buffering, size limited to 255 bytes. */
# include <sys/ioccom.h>
@@ -197,7 +210,7 @@ typedef SUPREQHDR *PSUPREQHDR;
* @todo Pending work on next major version change:
* - Remove RTSpinlockReleaseNoInts.
*/
-#define SUPDRV_IOC_VERSION 0x001a0007
+#define SUPDRV_IOC_VERSION 0x001a0008
/** SUP_IOCTL_COOKIE. */
typedef struct SUPCOOKIE
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
index a881a44..026d478 100644
--- a/src/VBox/HostDrivers/Support/SUPLib.cpp
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -261,7 +261,8 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
/*
* Open the support driver.
*/
- int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted);
+ SUPINITOP enmWhat = kSupInitOp_Driver;
+ int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted, &enmWhat, NULL);
if (RT_SUCCESS(rc))
{
/*
@@ -278,7 +279,7 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x001a0000
- ? 0x001a0005
+ ? 0x001a0008
: SUPDRV_IOC_VERSION & 0xffff0000;
CookieReq.u.In.u32MinVersion = uMinVersion;
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
diff --git a/src/VBox/HostDrivers/Support/SUPLibInternal.h b/src/VBox/HostDrivers/Support/SUPLibInternal.h
index 90351cf..1676d4e 100644
--- a/src/VBox/HostDrivers/Support/SUPLibInternal.h
+++ b/src/VBox/HostDrivers/Support/SUPLibInternal.h
@@ -312,11 +312,19 @@ typedef FNSUPR3PREINIT *PFNSUPR3PREINIT;
typedef enum SUPR3HARDENEDMAINSTATE
{
SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED = 0,
- SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY,
+ SUPR3HARDENEDMAINSTATE_WIN_EARLY_INIT_CALLED,
+ SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED,
+ SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED,
+ SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED,
+ SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED,
+ SUPR3HARDENEDMAINSTATE_WIN_VERSION_INITIALIZED,
+ SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY,
+ SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED,
SUPR3HARDENEDMAINSTATE_INIT_RUNTIME,
SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN,
SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN,
- SUPR3HARDENEDMAINSTATE_END
+ SUPR3HARDENEDMAINSTATE_END,
+ SUPR3HARDENEDMAINSTATE_32BIT_HACK = 0x7fffffff
} SUPR3HARDENEDMAINSTATE;
@@ -327,6 +335,9 @@ extern DECLHIDDEN(uint32_t) g_u32Cookie;
extern DECLHIDDEN(uint32_t) g_u32SessionCookie;
extern DECLHIDDEN(SUPLIBDATA) g_supLibData;
extern DECLHIDDEN(SUPR3HARDENEDMAINSTATE) g_enmSupR3HardenedMainState;
+#ifdef RT_OS_WINDOWS
+extern DECLHIDDEN(bool) g_fSupEarlyProcessInit;
+#endif
/*******************************************************************************
@@ -335,7 +346,7 @@ extern DECLHIDDEN(SUPR3HARDENEDMAINSTATE) g_enmSupR3HardenedMainState;
RT_C_DECLS_BEGIN
int suplibOsInstall(void);
int suplibOsUninstall(void);
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted);
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo);
int suplibOsTerm(PSUPLIBDATA pThis);
int suplibOsHardenedVerifyInit(void);
int suplibOsHardenedVerifyTerm(void);
@@ -428,10 +439,17 @@ DECLHIDDEN(void) supR3HardenedGetPreInitData(PSUPPREINITDATA pPreInitData);
DECLHIDDEN(int) supR3HardenedRecvPreInitData(PCSUPPREINITDATA pPreInitData);
#ifdef RT_OS_WINDOWS
-DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags);
+DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge);
DECLHIDDEN(void) supR3HardenedWinInitVersion(void);
DECLHIDDEN(void) supR3HardenedWinInitImports(void);
-DECLHIDDEN(void) supR3HardenedWinVerifyProcess(void);
+# ifdef ___iprt_nt_nt_h___
+DECLHIDDEN(void) supR3HardenedWinGetVeryEarlyImports(uintptr_t uNtDllAddr,
+ PFNNTWAITFORSINGLEOBJECT *ppfnNtWaitForSingleObject,
+ PFNNTSETEVENT *ppfnNtSetEvent);
+# endif
+DECLHIDDEN(void) supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr);
+DECLHIDDEN(void) supR3HardenedWinInitSyscalls(bool fReportErrors);
+DECLHIDDEN(PFNRT) supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure);
DECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void);
DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(const char *pszProgName);
DECLHIDDEN(void) supR3HardenedWinFlushLoaderCache();
@@ -445,6 +463,11 @@ extern RTUTF16 g_wszSupLibHardenedExePath[1024];
# ifdef RTPATH_MAX
extern char g_szSupLibHardenedExePath[RTPATH_MAX];
# endif
+DECLHIDDEN(void) supR3HardenedWinCompactHeaps(void);
+DECLHIDDEN(void) supR3HardenedMainOpenDevice(void);
+DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix);
+DECLHIDDEN(void) supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
+ const char *pszFormat, va_list va);
#endif
SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages);
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
index 017a5e2..4f4780c 100644
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
@@ -118,6 +118,10 @@ typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, uint32_t fFlags, int c
char **papszArgs, const char *pszProgramPath);
typedef FNRTR3INITEX *PFNRTR3INITEX;
+/** @see RTLogRelPrintf */
+typedef DECLCALLBACK(void) FNRTLOGRELPRINTF(const char *pszFormat, ...);
+typedef FNRTLOGRELPRINTF *PFNRTLOGRELPRINTF;
+
/*******************************************************************************
* Global Variables *
@@ -153,9 +157,18 @@ static HANDLE g_hStartupLog = NULL;
#else
static int g_hStartupLog = -1;
#endif
+/** The number of bytes we've written to the startup log. */
+static uint32_t volatile g_cbStartupLog = 0;
/** The current SUPR3HardenedMain state / location. */
SUPR3HARDENEDMAINSTATE g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED;
+AssertCompileSize(g_enmSupR3HardenedMainState, sizeof(uint32_t));
+
+#ifdef RT_OS_WINDOWS
+/** Pointer to VBoxRT's RTLogRelPrintf function so we can write errors to the
+ * release log at runtime. */
+static PFNRTLOGRELPRINTF g_pfnRTLogRelPrintf = NULL;
+#endif
/*******************************************************************************
@@ -224,11 +237,17 @@ static int suplibHardenedStrCopyEx(char *pszDst, size_t cbDst, ...)
DECLNORETURN(void) suplibHardenedExit(RTEXITCODE rcExit)
{
for (;;)
+ {
#ifdef RT_OS_WINDOWS
- ExitProcess(rcExit);
+ if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ ExitProcess(rcExit);
+ if (RtlExitUserProcess != NULL)
+ RtlExitUserProcess(rcExit);
+ NtTerminateProcess(NtCurrentProcess(), rcExit);
#else
_Exit(rcExit);
#endif
+ }
}
@@ -244,14 +263,18 @@ static void suplibHardenedPrintStrN(const char *pch, size_t cch)
HANDLE hStdOut = NtCurrentPeb()->ProcessParameters->StandardOutput;
if (hStdOut != NULL)
{
-# if 0 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
- IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
- NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
- &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
-# else
- DWORD cbWritten;
- WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
-# endif
+ if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ {
+ DWORD cbWritten;
+ WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
+ }
+ /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
+ else if (NtWriteFile != NULL && ((uintptr_t)hStdOut & 3) == 0)
+ {
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
+ &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
+ }
}
#else
(void)write(2, pch, cch);
@@ -390,7 +413,8 @@ static DECLCALLBACK(size_t) suplibHardenedOutput(void *pvArg, const char *pachCh
{
suplibHardenedPrintStrN(pBuf->szBuf, pBuf->off);
# ifdef RT_OS_WINDOWS
- OutputDebugString(pBuf->szBuf);
+ if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ OutputDebugString(pBuf->szBuf);
# endif
pBuf->off = 0;
cbSpace = sizeof(pBuf->szBuf) - 1;
@@ -967,21 +991,20 @@ DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
#ifdef RT_OS_WINDOWS
if (g_hStartupLog == NULL)
{
- PRTUTF16 pwszPath;
- int rc = RTStrToUtf16(pszLogFile, &pwszPath);
+ int rc = RTNtPathOpen(pszLogFile,
+ GENERIC_WRITE | SYNCHRONIZE,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN_IF,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ OBJ_CASE_INSENSITIVE,
+ &g_hStartupLog,
+ NULL);
if (RT_SUCCESS(rc))
- {
- g_hStartupLog = CreateFileW(pwszPath,
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL /*| FILE_FLAG_WRITE_THROUGH*/,
- NULL);
- RTUtf16Free(pwszPath);
- }
- SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
- VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
+ SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
+ VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
+ else
+ g_hStartupLog = NULL;
}
#else
//g_hStartupLog = open()
@@ -993,7 +1016,8 @@ DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
{
#ifdef RT_OS_WINDOWS
- if (g_hStartupLog)
+ if ( g_hStartupLog != NULL
+ && g_cbStartupLog < 128*_1M)
{
char szBuf[5120];
PCLIENT_ID pSelfId = &((PTEB)NtCurrentTeb())->ClientId;
@@ -1006,6 +1030,8 @@ DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
if (!cch || szBuf[cch - 1] != '\n')
szBuf[cch++] = '\n';
+ ASMAtomicAddU32(&g_cbStartupLog, (uint32_t)cch);
+
IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
LARGE_INTEGER Offset;
Offset.QuadPart = -1; /* Write to end of file. */
@@ -1049,6 +1075,19 @@ DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWha
supR3HardenedLogV(pszMsgFmt, vaCopy);
va_end(vaCopy);
+#ifdef RT_OS_WINDOWS
+ /*
+ * The release log.
+ */
+ if (g_pfnRTLogRelPrintf)
+ {
+ va_copy(vaCopy, va);
+ g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %s enmWhat=%d rc=%Rrc (%#x)\n", pszWhere, enmWhat, rc);
+ g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %N\n", pszMsgFmt, &vaCopy);
+ va_end(vaCopy);
+ }
+#endif
+
/*
* Then to the console.
*/
@@ -1083,37 +1122,51 @@ DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWha
break;
}
-#ifdef SUP_HARDENED_SUID
/*
- * Drop any root privileges we might be holding, this won't return
- * if it fails but end up calling supR3HardenedFatal[V].
+ * Finally, TrustedError if appropriate.
*/
- supR3HardenedMainDropPrivileges();
-#endif /* SUP_HARDENED_SUID */
+ if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ {
+#ifdef SUP_HARDENED_SUID
+ /*
+ * Drop any root privileges we might be holding, this won't return
+ * if it fails but end up calling supR3HardenedFatal[V].
+ */
+ supR3HardenedMainDropPrivileges();
+#endif
- /*
- * Now try resolve and call the TrustedError entry point if we can
- * find it. We'll fork before we attempt this because that way the
- * session management in main will see us exiting immediately (if
- * it's involved with us).
- */
+ /*
+ * Now try resolve and call the TrustedError entry point if we can
+ * find it. We'll fork before we attempt this because that way the
+ * session management in main will see us exiting immediately (if
+ * it's involved with us).
+ */
#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
- int pid = fork();
- if (pid <= 0)
+ int pid = fork();
+ if (pid <= 0)
#endif
- {
- static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
- if (!s_fRecursive)
{
- s_fRecursive = true;
+ static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
+ if (!s_fRecursive)
+ {
+ s_fRecursive = true;
- PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
- if (pfnTrustedError)
- pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
+ PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
+ if (pfnTrustedError)
+ pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
- s_fRecursive = false;
+ s_fRecursive = false;
+ }
}
}
+#if defined(RT_OS_WINDOWS)
+ /*
+ * Report the error to the parent if this happens during early VM init.
+ */
+ else if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+ && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+ supR3HardenedWinReportErrorToParent(pszWhere, enmWhat, rc, pszMsgFmt, va);
+#endif
/*
* Quit
@@ -1139,8 +1192,29 @@ DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
supR3HardenedLogV(pszFormat, vaCopy);
va_end(vaCopy);
- suplibHardenedPrintPrefix();
- suplibHardenedPrintFV(pszFormat, va);
+#if defined(RT_OS_WINDOWS)
+ /*
+ * Report the error to the parent if this happens during early VM init.
+ */
+ if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+ && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+ supR3HardenedWinReportErrorToParent(NULL, kSupInitOp_Invalid, VERR_INTERNAL_ERROR, pszFormat, va);
+ else
+#endif
+ {
+#ifdef RT_OS_WINDOWS
+ if (g_pfnRTLogRelPrintf)
+ {
+ va_copy(vaCopy, va);
+ g_pfnRTLogRelPrintf("supR3HardenedFatalV: %N", pszFormat, &vaCopy);
+ va_end(vaCopy);
+ }
+#endif
+
+ suplibHardenedPrintPrefix();
+ suplibHardenedPrintFV(pszFormat, va);
+ }
+
suplibHardenedExit(RTEXITCODE_FAILURE);
}
@@ -1165,8 +1239,18 @@ DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat,
supR3HardenedLogV(pszFormat, vaCopy);
va_end(vaCopy);
+#ifdef RT_OS_WINDOWS
+ if (g_pfnRTLogRelPrintf)
+ {
+ va_copy(vaCopy, va);
+ g_pfnRTLogRelPrintf("supR3HardenedErrorV: %N", pszFormat, &vaCopy);
+ va_end(vaCopy);
+ }
+#endif
+
suplibHardenedPrintPrefix();
suplibHardenedPrintFV(pszFormat, va);
+
return rc;
}
@@ -1187,47 +1271,45 @@ DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, .
*
* @remarks This function will not return on failure.
*/
-static void supR3HardenedMainOpenDevice(void)
+DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
{
- int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/);
+ RTERRINFOSTATIC ErrInfo;
+ SUPINITOP enmWhat = kSupInitOp_Driver;
+ int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
+ &enmWhat, RTErrInfoInitStatic(&ErrInfo));
if (RT_SUCCESS(rc))
return;
+ if (RTErrInfoIsSet(&ErrInfo.Core))
+ supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
+
switch (rc)
{
/** @todo better messages! */
case VERR_VM_DRIVER_NOT_INSTALLED:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "Kernel driver not installed");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
case VERR_VM_DRIVER_NOT_ACCESSIBLE:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "Kernel driver not accessible");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
case VERR_VM_DRIVER_LOAD_ERROR:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "VERR_VM_DRIVER_LOAD_ERROR");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
case VERR_VM_DRIVER_OPEN_ERROR:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "VERR_VM_DRIVER_OPEN_ERROR");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
case VERR_VM_DRIVER_VERSION_MISMATCH:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "Kernel driver version mismatch");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
case VERR_ACCESS_DENIED:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "VERR_ACCESS_DENIED");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
case VERR_NO_MEMORY:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "Kernel memory allocation/mapping failed");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
default:
- supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
- "Unknown rc=%d", rc);
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
}
}
@@ -1472,18 +1554,21 @@ static void supR3HardenedMainInitRuntime(uint32_t fFlags)
if (!hMod)
supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
"LoadLibrary \"%s\" failed (rc=%d)",
- szPath, GetLastError());
+ szPath, RtlGetLastWin32Error());
PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
if (!pfnRTInitEx)
supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
"Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
- szPath, GetLastError());
+ szPath, RtlGetLastWin32Error());
PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
if (!pfnSUPPreInit)
supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
"Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
- szPath, GetLastError());
+ szPath, RtlGetLastWin32Error());
+
+ g_pfnRTLogRelPrintf = (PFNRTLOGRELPRINTF)GetProcAddress(hMod, SUP_HARDENED_SYM("RTLogRelPrintf"));
+ Assert(g_pfnRTLogRelPrintf); /* Not fatal in non-strict builds. */
#else
/* the dlopen crowd */
@@ -1614,11 +1699,11 @@ static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName
HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
if (!hMod)
supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
- szPath, GetLastError());
+ szPath, RtlGetLastWin32Error());
FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
if (!pfn)
supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
- szPath, GetLastError());
+ szPath, RtlGetLastWin32Error());
return (PFNSUPTRUSTEDMAIN)pfn;
#else
@@ -1659,16 +1744,20 @@ static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName
DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
{
SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
/*
* Note! At this point there is no IPRT, so we will have to stick
* to basic CRT functions that everyone agree upon.
*/
- g_pszSupLibHardenedProgName = pszProgName;
- g_fSupHardenedMain = fFlags;
+ g_pszSupLibHardenedProgName = pszProgName;
+ g_fSupHardenedMain = fFlags;
g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
- g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
+#ifdef RT_OS_WINDOWS
+ if (!g_fSupEarlyProcessInit)
+#endif
+ g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
#ifdef SUP_HARDENED_SUID
# ifdef RT_OS_LINUX
@@ -1677,7 +1766,6 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
* *might* not be able to access /proc/self/exe after the seteuid call.
*/
supR3HardenedGetFullExePath();
-
# endif
/*
@@ -1702,11 +1790,12 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
* something we can put some kind of reliable trust in. The first respawning aims
* at dropping compatibility layers and process "security" solutions.
*/
- if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+ if ( !g_fSupEarlyProcessInit
+ && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
&& supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
{
SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
- supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV);
+ supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, false /*fAvastKludge*/);
supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
return supR3HardenedWinReSpawn(1 /*iWhich*/);
}
@@ -1714,9 +1803,11 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
/*
* Windows: Initialize the image verification global data so we can verify the
* signature of the process image and hook the core of the DLL loader API so we
- * can check the signature of all DLLs mapped into the process.
+ * can check the signature of all DLLs mapped into the process. (Already done
+ * by early VM process init.)
*/
- supR3HardenedWinInit(fFlags);
+ if (!g_fSupEarlyProcessInit)
+ supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
#endif /* RT_OS_WINDOWS */
/*
@@ -1726,15 +1817,17 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
/*
* The next steps are only taken if we actually need to access the support
- * driver.
+ * driver. (Already done by early process init.)
*/
if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
{
#ifdef RT_OS_WINDOWS
/*
- * Windows: Verify the process (repeated by the kernel later.
+ * Windows: Must have done early process init if we get here.
*/
- supR3HardenedWinVerifyProcess();
+ if (!g_fSupEarlyProcessInit)
+ supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_Integrity, VERR_WRONG_ORDER,
+ "Early process init was somehow skipped.");
/*
* Windows: The second respawn. This time we make a special arrangement
@@ -1747,12 +1840,13 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
}
SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
supR3HardenedWinFlushLoaderCache();
-#endif /* RT_OS_WINDOWS */
+#else
/*
* Open the vboxdrv device.
*/
supR3HardenedMainOpenDevice();
+#endif /* !RT_OS_WINDOWS */
}
#ifdef RT_OS_WINDOWS
@@ -1762,7 +1856,7 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
supR3HardenedWinEnableThreadCreation();
supR3HardenedWinFlushLoaderCache();
supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
- g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY;
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
#endif
#ifdef SUP_HARDENED_SUID
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
index ee5f313..8e34c8a 100644
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
@@ -410,7 +410,7 @@ DECLHIDDEN(int) supR3HardenedVerifyFixedDir(SUPINSTDIR enmDir, bool fFatal)
}
else
{
- int err = GetLastError();
+ int err = RtlGetLastWin32Error();
rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
"supR3HardenedVerifyDir: Failed to open \"%s\": err=%d\n",
szPath, err);
@@ -524,7 +524,7 @@ static int supR3HardenedVerifyFileOpen(PCSUPINSTFILE pFile, bool fFatal, intptr_
}
else
{
- int err = GetLastError();
+ int err = RtlGetLastWin32Error();
if ( !pFile->fOptional
|| ( err != ERROR_FILE_NOT_FOUND
&& (err != ERROR_PATH_NOT_FOUND || pFile->enmDir != kSupID_Testcase) ) )
@@ -602,7 +602,7 @@ static int supR3HardenedVerifyFileSignature(PCSUPINSTFILE pFile, PSUPVERIFIEDFIL
if (fLeaveFileOpen && RT_SUCCESS(rc))
pVerified->hFile = hFileOpened;
else
- CloseHandle((HANDLE)hFileOpened);
+ NtClose((HANDLE)hFileOpened);
}
return rc;
@@ -676,7 +676,7 @@ static int supR3HardenedVerifyFileInternal(int iFile, bool fFatal, bool fLeaveFi
pVerified->fValidated = true;
if (!fLeaveFileOpen)
{
- CloseHandle((HANDLE)pVerified->hFile);
+ NtClose((HANDLE)pVerified->hFile);
pVerified->hFile = -1;
}
}
@@ -1419,7 +1419,8 @@ static int supR3HardenedVerifyFsObject(PCSUPR3HARDENEDFSOBJSTATE pFsObjState, bo
#endif
if (fBad)
return supR3HardenedSetError3(VERR_SUPLIB_WRITE_NON_SYS_GROUP, pErrInfo,
- "The group is not a system group and it has write access to '", pszPath, "'");
+ "An unknown (and thus untrusted) group has write access to '", pszPath,
+ "' and we therefore cannot trust the directory content or that of any subdirectory");
}
/*
@@ -1738,11 +1739,11 @@ DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, RTHCUINTPTR hNa
rc = supHardenedWinVerifyImageByHandleNoName(hVerify, fFlags, pErrInfo);
# endif
# endif
- CloseHandle(hVerify);
+ NtClose(hVerify);
}
else if (RT_SUCCESS(rc))
- rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
- "Error %u trying to open (or duplicate handle for) '%s'", GetLastError(), pszFilename);
+ rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+ "Error %u trying to open (or duplicate handle for) '%s'", RtlGetLastWin32Error(), pszFilename);
if (RT_FAILURE(rc))
return rc;
#endif
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
index 69567b8..cd73baf 100644
--- a/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
+++ b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
@@ -185,7 +185,7 @@ static int suplibDarwinOpenService(PSUPLIBDATA pThis)
}
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
index c5ca90d..f4c649b 100644
--- a/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
@@ -67,7 +67,7 @@
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
index e3d1a34..138f832 100644
--- a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
+++ b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
@@ -74,7 +74,7 @@
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
index 0f235ee..83145ce 100644
--- a/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
+++ b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
@@ -65,7 +65,7 @@
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
index 602854f..4e9ce2c 100644
--- a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
+++ b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
@@ -77,7 +77,7 @@
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h b/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h
deleted file mode 100644
index 2b8c8c8..0000000
--- a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h
+++ /dev/null
@@ -1,78 +0,0 @@
-SYSCALL(0x30);
-SYSCALL(0x31);
-SYSCALL(0x32);
-SYSCALL(0x33);
-SYSCALL(0x34);
-SYSCALL(0x35);
-SYSCALL(0x36);
-SYSCALL(0x37);
-SYSCALL(0x38);
-SYSCALL(0x39);
-SYSCALL(0x3A);
-SYSCALL(0x3B);
-SYSCALL(0x3C);
-SYSCALL(0x3D);
-SYSCALL(0x3E);
-SYSCALL(0x3F);
-SYSCALL(0x40);
-SYSCALL(0x41);
-SYSCALL(0x42);
-SYSCALL(0x43);
-SYSCALL(0x44);
-SYSCALL(0x45);
-SYSCALL(0x46);
-SYSCALL(0x47); /* XP64/W2K3-64, Vista, Windows 7 */
-SYSCALL(0x48); /* Windows 8.0 */
-SYSCALL(0x49); /* windows 8.1 */
-SYSCALL(0x4A);
-SYSCALL(0x4B);
-SYSCALL(0x4C);
-SYSCALL(0x4D);
-SYSCALL(0x4E);
-SYSCALL(0x4F);
-SYSCALL(0x51);
-SYSCALL(0x52);
-SYSCALL(0x53);
-SYSCALL(0x54);
-SYSCALL(0x55);
-SYSCALL(0x56);
-SYSCALL(0x57);
-SYSCALL(0x59);
-SYSCALL(0x5A);
-SYSCALL(0x5B);
-SYSCALL(0x5C);
-SYSCALL(0x5D);
-SYSCALL(0x5E);
-SYSCALL(0x5F);
-SYSCALL(0x60);
-SYSCALL(0x61);
-SYSCALL(0x62);
-SYSCALL(0x63);
-SYSCALL(0x64);
-SYSCALL(0x65);
-SYSCALL(0x66);
-SYSCALL(0x67);
-SYSCALL(0x68);
-SYSCALL(0x69);
-SYSCALL(0x6A);
-SYSCALL(0x6B);
-SYSCALL(0x6C);
-SYSCALL(0x6D);
-SYSCALL(0x6E);
-SYSCALL(0x6F);
-SYSCALL(0x70);
-SYSCALL(0x71);
-SYSCALL(0x72);
-SYSCALL(0x73);
-SYSCALL(0x74);
-SYSCALL(0x75);
-SYSCALL(0x76);
-SYSCALL(0x77);
-SYSCALL(0x78);
-SYSCALL(0x79);
-SYSCALL(0x7A);
-SYSCALL(0x7B);
-SYSCALL(0x7C);
-SYSCALL(0x7D);
-SYSCALL(0x7E);
-SYSCALL(0x7F);
diff --git a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h b/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h
deleted file mode 100644
index f80a4d3..0000000
--- a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h
+++ /dev/null
@@ -1,286 +0,0 @@
-SYSCALL(0x28);
-SYSCALL(0x29);
-SYSCALL(0x2A);
-SYSCALL(0x2B);
-SYSCALL(0x2C);
-SYSCALL(0x2D);
-SYSCALL(0x2E);
-SYSCALL(0x2F);
-SYSCALL(0x30);
-SYSCALL(0x31);
-
-SYSCALL(0x32); /* WinXP */
-SYSCALL(0x33);
-
-SYSCALL(0x34); /* W2K3 */
-SYSCALL(0x35);
-SYSCALL(0x36);
-SYSCALL(0x37);
-SYSCALL(0x38);
-SYSCALL(0x39);
-SYSCALL(0x3A);
-SYSCALL(0x3B);
-SYSCALL(0x3C);
-SYSCALL(0x3D);
-SYSCALL(0x3E);
-SYSCALL(0x3F);
-SYSCALL(0x40);
-SYSCALL(0x41);
-SYSCALL(0x42);
-SYSCALL(0x43);
-SYSCALL(0x44);
-SYSCALL(0x45);
-SYSCALL(0x46);
-SYSCALL(0x47);
-SYSCALL(0x48);
-SYSCALL(0x49);
-SYSCALL(0x4A);
-
-SYSCALL(0x4B); /* Vista */
-SYSCALL(0x4C);
-SYSCALL(0x4D);
-SYSCALL(0x4E);
-SYSCALL(0x4F);
-SYSCALL(0x50);
-SYSCALL(0x51);
-SYSCALL(0x52);
-SYSCALL(0x53);
-
-SYSCALL(0x54); /* Windows 7 */
-SYSCALL(0x55);
-SYSCALL(0x56);
-SYSCALL(0x57);
-SYSCALL(0x59);
-SYSCALL(0x5A);
-SYSCALL(0x5B);
-SYSCALL(0x5C);
-SYSCALL(0x5D);
-SYSCALL(0x5E);
-SYSCALL(0x5F);
-SYSCALL(0x60);
-SYSCALL(0x61);
-SYSCALL(0x62);
-SYSCALL(0x63);
-SYSCALL(0x64);
-SYSCALL(0x65);
-SYSCALL(0x66);
-SYSCALL(0x67);
-SYSCALL(0x68);
-SYSCALL(0x69);
-SYSCALL(0x6A);
-SYSCALL(0x6B);
-SYSCALL(0x6C);
-SYSCALL(0x6D);
-SYSCALL(0x6E);
-SYSCALL(0x6F);
-SYSCALL(0x70);
-SYSCALL(0x71);
-SYSCALL(0x72);
-SYSCALL(0x73);
-SYSCALL(0x74);
-SYSCALL(0x75);
-SYSCALL(0x76);
-SYSCALL(0x77);
-SYSCALL(0x78);
-SYSCALL(0x79);
-SYSCALL(0x7A);
-SYSCALL(0x7B);
-SYSCALL(0x7C);
-SYSCALL(0x7D);
-SYSCALL(0x7E);
-SYSCALL(0x7F);
-SYSCALL(0x80);
-SYSCALL(0x81);
-SYSCALL(0x82);
-SYSCALL(0x83);
-SYSCALL(0x84);
-SYSCALL(0x85);
-SYSCALL(0x86);
-SYSCALL(0x87);
-SYSCALL(0x88);
-SYSCALL(0x89);
-SYSCALL(0x8A);
-SYSCALL(0x8B);
-SYSCALL(0x8C);
-SYSCALL(0x8D);
-SYSCALL(0x8E);
-SYSCALL(0x8F);
-SYSCALL(0x90);
-SYSCALL(0x91);
-SYSCALL(0x92);
-SYSCALL(0x93);
-SYSCALL(0x94);
-SYSCALL(0x95);
-SYSCALL(0x96);
-SYSCALL(0x97);
-SYSCALL(0x98);
-SYSCALL(0x99);
-SYSCALL(0x9A);
-SYSCALL(0x9B);
-SYSCALL(0x9C);
-SYSCALL(0x9D);
-SYSCALL(0x9E);
-SYSCALL(0x9F);
-
-SYSCALL(0x100);
-SYSCALL(0x101);
-SYSCALL(0x102);
-SYSCALL(0x103);
-SYSCALL(0x104);
-SYSCALL(0x105);
-SYSCALL(0x106);
-SYSCALL(0x107);
-SYSCALL(0x108);
-SYSCALL(0x109);
-SYSCALL(0x10A);
-SYSCALL(0x10B);
-SYSCALL(0x10C);
-SYSCALL(0x10D);
-SYSCALL(0x10E);
-SYSCALL(0x10F);
-SYSCALL(0x110);
-SYSCALL(0x111);
-SYSCALL(0x112);
-SYSCALL(0x113);
-SYSCALL(0x114);
-SYSCALL(0x115);
-SYSCALL(0x116);
-SYSCALL(0x117);
-SYSCALL(0x118);
-SYSCALL(0x119);
-SYSCALL(0x11A);
-SYSCALL(0x11B);
-SYSCALL(0x11C);
-SYSCALL(0x11D);
-SYSCALL(0x11E);
-SYSCALL(0x11F);
-SYSCALL(0x120);
-SYSCALL(0x121);
-SYSCALL(0x122);
-SYSCALL(0x123);
-SYSCALL(0x124);
-SYSCALL(0x125);
-SYSCALL(0x126);
-SYSCALL(0x127);
-SYSCALL(0x128);
-SYSCALL(0x129);
-SYSCALL(0x12A);
-SYSCALL(0x12B);
-SYSCALL(0x12C);
-SYSCALL(0x12D);
-SYSCALL(0x12E);
-SYSCALL(0x12F);
-SYSCALL(0x130);
-SYSCALL(0x131);
-SYSCALL(0x132);
-SYSCALL(0x133);
-SYSCALL(0x134);
-SYSCALL(0x135);
-SYSCALL(0x136);
-SYSCALL(0x137);
-SYSCALL(0x138);
-SYSCALL(0x139);
-SYSCALL(0x13A);
-SYSCALL(0x13B);
-SYSCALL(0x13C);
-SYSCALL(0x13D);
-SYSCALL(0x13E);
-SYSCALL(0x13F);
-SYSCALL(0x140);
-SYSCALL(0x141);
-SYSCALL(0x142);
-SYSCALL(0x143);
-SYSCALL(0x144);
-SYSCALL(0x145);
-SYSCALL(0x146);
-SYSCALL(0x147);
-SYSCALL(0x148);
-SYSCALL(0x149);
-SYSCALL(0x14A);
-SYSCALL(0x14B);
-SYSCALL(0x14C);
-SYSCALL(0x14D);
-SYSCALL(0x14E);
-SYSCALL(0x14F);
-SYSCALL(0x150);
-SYSCALL(0x151);
-SYSCALL(0x152);
-SYSCALL(0x153);
-
-SYSCALL(0x154); /* Windows 8.1 */
-SYSCALL(0x155);
-SYSCALL(0x156);
-SYSCALL(0x157);
-SYSCALL(0x158);
-SYSCALL(0x159);
-SYSCALL(0x15A);
-SYSCALL(0x15B);
-SYSCALL(0x15C);
-SYSCALL(0x15D);
-SYSCALL(0x15E);
-SYSCALL(0x15F);
-SYSCALL(0x160);
-SYSCALL(0x161);
-SYSCALL(0x162);
-SYSCALL(0x163);
-SYSCALL(0x164);
-SYSCALL(0x165);
-SYSCALL(0x166);
-SYSCALL(0x167);
-SYSCALL(0x168);
-SYSCALL(0x169);
-SYSCALL(0x16A);
-SYSCALL(0x16B);
-SYSCALL(0x16C);
-SYSCALL(0x16D);
-SYSCALL(0x16E);
-SYSCALL(0x16F);
-SYSCALL(0x170);
-SYSCALL(0x171);
-SYSCALL(0x172);
-SYSCALL(0x173);
-SYSCALL(0x174);
-SYSCALL(0x175);
-SYSCALL(0x176);
-SYSCALL(0x177);
-SYSCALL(0x178);
-SYSCALL(0x179);
-SYSCALL(0x17A);
-SYSCALL(0x17B);
-SYSCALL(0x17C);
-SYSCALL(0x17D);
-SYSCALL(0x17E);
-SYSCALL(0x17F);
-SYSCALL(0x180);
-SYSCALL(0x181);
-SYSCALL(0x182);
-SYSCALL(0x183);
-SYSCALL(0x184);
-SYSCALL(0x185);
-SYSCALL(0x186);
-SYSCALL(0x187);
-SYSCALL(0x188);
-SYSCALL(0x189);
-SYSCALL(0x18A);
-SYSCALL(0x18B);
-SYSCALL(0x18C);
-SYSCALL(0x18D);
-SYSCALL(0x18E);
-SYSCALL(0x18F);
-SYSCALL(0x190);
-SYSCALL(0x191);
-SYSCALL(0x192);
-SYSCALL(0x193);
-SYSCALL(0x194);
-SYSCALL(0x195);
-SYSCALL(0x196);
-SYSCALL(0x197);
-SYSCALL(0x198);
-SYSCALL(0x199);
-SYSCALL(0x19A);
-SYSCALL(0x19B);
-SYSCALL(0x19C);
-SYSCALL(0x19D);
-SYSCALL(0x19E);
-SYSCALL(0x19F);
-
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
index 357ff8e..43f1d7f 100644
--- a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
@@ -40,6 +40,8 @@
#include <iprt/mem.h>
#include <iprt/process.h>
#include <iprt/power.h>
+#include <iprt/rand.h>
+#include <iprt/semaphore.h>
#include <iprt/spinlock.h>
#include <iprt/string.h>
#include <VBox/log.h>
@@ -60,19 +62,23 @@
/** The Pool tag (VBox). */
#define SUPDRV_NT_POOL_TAG 'xoBV'
-/** NT device name for system access. */
-#define DEVICE_NAME_NT_SYS L"\\Device\\VBoxDrv"
/** NT device name for user access. */
-#define DEVICE_NAME_NT_USR L"\\Device\\VBoxDrvU"
+#define DEVICE_NAME_NT_USR L"\\Device\\VBoxDrvU"
#ifdef VBOX_WITH_HARDENING
-/** NT device name for hardened stub access. */
-# define DEVICE_NAME_NT_STUB L"\\Device\\VBoxDrvStub"
-
/** Macro for checking for deflecting calls to the stub device. */
# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
- do { if ((a_pDevObj) == g_pDevObjStub) supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); } while (0)
+ do { if ((a_pDevObj) == g_pDevObjStub) \
+ return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+ } while (0)
+/** Macro for checking for deflecting calls to the stub and error info
+ * devices. */
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
+ do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
+ return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+ } while (0)
#else
-# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) do {} while (0)
#endif
/** Enables the fast I/O control code path. */
@@ -107,20 +113,55 @@ typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
#ifdef VBOX_WITH_HARDENING
/**
- * Device extension used by VBoxDrvS.
+ * Device extension used by VBoxDrvStub.
*/
typedef struct SUPDRVDEVEXTSTUB
{
/** Common header. */
SUPDRVDEVEXTUSR Common;
} SUPDRVDEVEXTSTUB;
-/** Pointer to the VBoxDrvS device extension. */
+/** Pointer to the VBoxDrvStub device extension. */
typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
/** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
#define SUPDRVDEVEXTSTUB_COOKIE UINT32_C(0x90abcdef)
/**
+ * Device extension used by VBoxDrvErrorInfo.
+ */
+typedef struct SUPDRVDEVEXTERRORINFO
+{
+ /** Common header. */
+ SUPDRVDEVEXTUSR Common;
+} SUPDRVDEVEXTERRORINFO;
+/** Pointer to the VBoxDrvErrorInfo device extension. */
+typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
+/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
+#define SUPDRVDEVEXTERRORINFO_COOKIE UINT32_C(0xBadC0ca0)
+
+/**
+ * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
+ */
+typedef struct SUPDRVNTERRORINFO
+{
+ /** The list entry (in g_ErrorInfoHead). */
+ RTLISTNODE ListEntry;
+ /** The ID of the process this error info belongs to. */
+ HANDLE hProcessId;
+ /** The ID of the thread owning this info. */
+ HANDLE hThreadId;
+ /** Milliseconds createion timestamp (for cleaning up). */
+ uint64_t uCreatedMsTs;
+ /** Number of bytes of valid info. */
+ uint32_t cchErrorInfo;
+ /** The error info. */
+ char szErrorInfo[2048];
+} SUPDRVNTERRORINFO;
+/** Pointer to error info. */
+typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
+
+
+/**
* The kind of process we're protecting.
*/
typedef enum SUPDRVNTPROTECTKIND
@@ -165,6 +206,9 @@ typedef struct SUPDRVNTPROTECT
uint32_t volatile cRefs;
/** The kind of process we're protecting. */
SUPDRVNTPROTECTKIND volatile enmProcessKind;
+ /** 7,: Hack to allow the supid themes service duplicate handle privileges to
+ * our process. */
+ bool fThemesFirstProcessCreateHandle : 1;
/** Vista, 7 & 8: Hack to allow more rights to the handle returned by
* NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
bool fFirstProcessCreateHandle : 1;
@@ -174,15 +218,16 @@ typedef struct SUPDRVNTPROTECT
/** 8.1: Hack to allow more rights to the handle returned by
* NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
bool fCsrssFirstProcessCreateHandle : 1;
- /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSR
- * during process creation. Only applicable to VmProcessUnconfirmed. */
- bool fCsrssFirstProcessDuplicateHandle : 1;
- /** 7,: Hack to allow the supid themes service duplicate handle privileges to
- * our process. */
- bool fThemesFirstProcessCreateHandle : 1;
+ /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSRSS
+ * during process creation. Only applicable to VmProcessUnconfirmed. On
+ * 32-bit systems we allow two as ZoneAlarm's system call hooks has been
+ * observed to do some seemingly unnecessary duplication work. */
+ int32_t volatile cCsrssFirstProcessDuplicateHandle;
/** The parent PID for VM processes, otherwise NULL. */
HANDLE hParentPid;
+ /** The TID of the thread opening VBoxDrv or VBoxDrvStub, NULL if not opened. */
+ HANDLE hOpenTid;
/** The PID of the CSRSS process associated with this process. */
HANDLE hCsrssPid;
/** Pointer to the CSRSS process structure (referenced). */
@@ -196,7 +241,7 @@ typedef struct SUPDRVNTPROTECT
struct SUPDRVNTPROTECT *pChild;
/** A process in the VmProcessUnconfirmed state will keep a weak
* reference to the parent's protection structure so it can clean up the pChild
- * refernece the parent has to it. */
+ * reference the parent has to it. */
struct SUPDRVNTPROTECT *pParent;
} u;
} SUPDRVNTPROTECT;
@@ -207,6 +252,8 @@ typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
/** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
# define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
+/** Pointer to ObGetObjectType. */
+typedef POBJECT_TYPE (NTAPI *PFNOBGETOBJECTTYPE)(PVOID);
/** Pointer to ObRegisterCallbacks. */
typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
/** Pointer to ObUnregisterCallbacks. */
@@ -217,6 +264,8 @@ typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_N
typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
/** Pointer to PsIsProtectedProcessLight. */
typedef BOOLEAN (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
+/** Pointer to ZwAlpcCreatePort. */
+typedef NTSTATUS (NTAPI *PFNZWALPCCREATEPORT)(PHANDLE, POBJECT_ATTRIBUTES, struct _ALPC_PORT_ATTRIBUTES *);
#endif /* VBOX_WITH_HARDENINIG */
@@ -237,6 +286,7 @@ static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP p
static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
static NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
+static NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
#ifdef VBOX_WITH_HARDENING
@@ -250,6 +300,8 @@ static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT
static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
static bool supdrvNtIsDebuggerAttached(void);
+static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
+
#endif
@@ -315,6 +367,8 @@ static AVLPVTREE g_NtProtectTree = NULL;
static PVOID g_pvObCallbacksCookie = NULL;
/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
uint32_t g_uNtVerCombined = 0;
+/** Pointer to ObGetObjectType if available.. */
+static PFNOBGETOBJECTTYPE g_pfnObGetObjectType = NULL;
/** Pointer to ObRegisterCallbacks if available.. */
static PFNOBREGISTERCALLBACKS g_pfnObRegisterCallbacks = NULL;
/** Pointer to ObUnregisterCallbacks if available.. */
@@ -325,6 +379,8 @@ static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutine
static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
/** Pointer to PsIsProtectedProcessLight. */
static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
+/** Pointer to ZwAlpcCreatePort. */
+static PFNZWALPCCREATEPORT g_pfnZwAlpcCreatePort = NULL;
# ifdef RT_ARCH_AMD64
extern "C" {
@@ -336,6 +392,18 @@ PFNRT g_pfnKiServiceLinkage = NULL;
PFNRT g_pfnKiServiceInternal = NULL;
}
# endif
+/** The primary ALPC port object type. (LpcPortObjectType at init time.) */
+static POBJECT_TYPE g_pAlpcPortObjectType1 = NULL;
+/** The secondary ALPC port object type. (Sampled at runtime.) */
+static POBJECT_TYPE volatile g_pAlpcPortObjectType2 = NULL;
+
+/** Pointer to the error information device instance. */
+static PDEVICE_OBJECT g_pDevObjErrorInfo = NULL;
+/** Fast mutex semaphore protecting the error info list. */
+static RTSEMMUTEX g_hErrorInfoLock = NIL_RTSEMMUTEX;
+/** Head of the error info (SUPDRVNTERRORINFO). */
+static RTLISTANCHOR g_ErrorInfoHead;
+
#endif
@@ -351,14 +419,14 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
* System device.
*/
UNICODE_STRING DevName;
- RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_SYS);
+ RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
if (NT_SUCCESS(rcNt))
{
/*
* User device.
*/
- RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_USR);
+ RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
if (NT_SUCCESS(rcNt))
{
@@ -370,7 +438,7 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
/*
* Hardened stub device.
*/
- RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_STUB);
+ RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
if (NT_SUCCESS(rcNt))
{
@@ -379,11 +447,33 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTSTUB_COOKIE;
-#endif
- /* Done. */
- return rcNt;
+ /*
+ * Hardened error information device.
+ */
+ RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+ rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
+ &g_pDevObjErrorInfo);
+ if (NT_SUCCESS(rcNt))
+ {
+ g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
+
+ if (NT_SUCCESS(rcNt))
+ {
+ PSUPDRVDEVEXTERRORINFO pDevExtStub = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+ pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
+ pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTERRORINFO_COOKIE;
+
+#endif
+ /* Done. */
+ return rcNt;
#ifdef VBOX_WITH_HARDENING
+ }
+
+ /* Bail out. */
+ IoDeleteDevice(g_pDevObjErrorInfo);
+ g_pDevObjErrorInfo = NULL;
+ }
}
/* Bail out. */
@@ -416,9 +506,16 @@ static void vboxdrvNtDestroyDevices(void)
PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
pDevExtStub->Common.pMainDrvExt = NULL;
}
+ if (g_pDevObjErrorInfo)
+ {
+ PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+ pDevExtErrorInfo->Common.pMainDrvExt = NULL;
+ }
#endif
#ifdef VBOX_WITH_HARDENING
+ IoDeleteDevice(g_pDevObjErrorInfo);
+ g_pDevObjErrorInfo = NULL;
IoDeleteDevice(g_pDevObjStub);
g_pDevObjStub = NULL;
#endif
@@ -493,7 +590,7 @@ ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
- pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtNotSupportedStub;
+ pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtRead;
pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
#ifdef VBOXDRV_WITH_FAST_IO
@@ -644,6 +741,16 @@ NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
rcNt = STATUS_ACCESS_DENIED;
}
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Anyone can open the error device.
+ */
+ else if (pDevObj == g_pDevObjErrorInfo)
+ {
+ pFileObj->FsContext = NULL;
+ return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
+ }
+#endif
else
{
#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
@@ -819,6 +926,8 @@ NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
pFileObj->FsContext = NULL;
}
}
+ else if (pDevObj == g_pDevObjErrorInfo)
+ supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
else
#endif
{
@@ -859,6 +968,8 @@ NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
pFileObj->FsContext = NULL;
}
}
+ else if (pDevObj == g_pDevObjErrorInfo)
+ supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
else
#endif
{
@@ -898,13 +1009,22 @@ static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOL
PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
{
- PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
+ /*
+ * Only the normal devices, not the stub or error info ones.
+ */
+ if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
+ {
+ pIoStatus->Status = STATUS_NOT_SUPPORTED;
+ pIoStatus->Information = 0;
+ return TRUE;
+ }
/*
* Check the input a little bit and get a the session references.
*/
- PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
- (PSUPDRVSESSION *)&pFileObj->FsContext);
+ PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
+ PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
+ (PSUPDRVSESSION *)&pFileObj->FsContext);
if (!pSession)
{
pIoStatus->Status = STATUS_TRUST_FAILURE;
@@ -1083,7 +1203,7 @@ static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOL
*/
NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+ VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
@@ -1225,7 +1345,7 @@ static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSes
*/
NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+ VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
@@ -1309,6 +1429,115 @@ NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pI
/**
+ * Implementation of the read major function for VBoxDrvErrorInfo.
+ *
+ * This is a stub function for the other devices.
+ *
+ * @returns NT status code.
+ * @param pDevObj The device object.
+ * @param pIrp The I/O request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ Log(("VBoxDrvNtRead\n"));
+
+ NTSTATUS rcNt;
+ pIrp->IoStatus.Information = 0;
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * VBoxDrvErrorInfo?
+ */
+ if (pDevObj == g_pDevObjErrorInfo)
+ {
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ if ( pStack
+ && (pIrp->Flags & IRP_BUFFERED_IO))
+ {
+ /*
+ * Look up the process error information.
+ */
+ HANDLE hCurThreadId = PsGetCurrentThreadId();
+ HANDLE hCurProcessId = PsGetCurrentProcessId();
+ int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ PSUPDRVNTERRORINFO pCur;
+ RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
+ {
+ if ( pCur->hProcessId == hCurProcessId
+ && pCur->hThreadId == hCurThreadId)
+ break;
+ }
+
+ /*
+ * Did we find error info and is the caller requesting data within it?
+ * If so, cehck the destination buffer and copy the data into it.
+ */
+ if ( pCur
+ && pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
+ && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
+ {
+ PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
+ if (pvDstBuf)
+ {
+ uint32_t offRead = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
+ uint32_t cbToRead = pCur->cchErrorInfo - (uint32_t)offRead;
+ if (cbToRead > pStack->Parameters.Read.Length)
+ {
+ cbToRead = pStack->Parameters.Read.Length;
+ RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
+ }
+ memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
+ pIrp->IoStatus.Information = cbToRead;
+
+ rcNt = STATUS_SUCCESS;
+ }
+ else
+ rcNt = STATUS_INVALID_ADDRESS;
+ }
+ /*
+ * End of file. Free the info.
+ */
+ else if (pCur)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ rcNt = STATUS_END_OF_FILE;
+ }
+ /*
+ * We found no error info. Return EOF.
+ */
+ else
+ rcNt = STATUS_END_OF_FILE;
+
+ RTSemMutexRelease(g_hErrorInfoLock);
+ }
+ else
+ rcNt = STATUS_UNSUCCESSFUL;
+ }
+ else
+ rcNt = STATUS_INVALID_PARAMETER;
+ }
+ else
+#endif /* VBOX_WITH_HARDENING */
+ {
+ /*
+ * Stub.
+ */
+ rcNt = STATUS_NOT_SUPPORTED;
+ }
+
+ /*
+ * Complete the request.
+ */
+ pIrp->IoStatus.Status = rcNt;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ return rcNt;
+}
+
+
+/**
* Stub function for functions we don't implemented.
*
* @returns STATUS_NOT_SUPPORTED
@@ -1900,6 +2129,157 @@ static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
/**
+ * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
+ *
+ * @returns true if done, false if not.
+ * @param pwszPortNm The port path.
+ * @param ppObjType The object type return variable, updated when
+ * returning true.
+ */
+static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
+{
+ bool fDone = false;
+
+ UNICODE_STRING UniStrPortNm;
+ UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
+ UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
+ UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
+
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ HANDLE hPort;
+ NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
+ if (NT_SUCCESS(rcNt))
+ {
+ PVOID pvObject;
+ rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
+ KernelMode, &pvObject, NULL /*pHandleInfo*/);
+ if (NT_SUCCESS(rcNt))
+ {
+ POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
+ if (pObjType)
+ {
+ SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
+ *ppObjType = pObjType;
+ fDone = true;
+ }
+ ObDereferenceObject(pvObject);
+ }
+ NtClose(hPort);
+ }
+ return fDone;
+}
+
+
+/**
+ * Attempts to retrieve the ALPC Port object type.
+ *
+ * We've had at least three reports that using LpcPortObjectType when trying to
+ * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
+ * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
+ * exported) so that it differs from the actual ApiPort type, or maybe this
+ * unknown entity is intercepting our attempt to reference the port and
+ * tries to mislead us. The paranoid explanataion is of course that some evil
+ * root kit like software is messing with the OS, however, it's possible that
+ * this is valid kernel behavior that 99.8% of our users and 100% of the
+ * developers are not triggering for some reason.
+ *
+ * The code here creates an ALPC port object and gets it's type. It will cache
+ * the result in g_pAlpcPortObjectType2 on success.
+ *
+ * @returns Object type.
+ * @param uSessionId The session id.
+ * @param pszSessionId The session id formatted as a string.
+ */
+static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
+{
+ POBJECT_TYPE pObjType = *LpcPortObjectType;
+
+ if ( g_pfnZwAlpcCreatePort
+ && g_pfnObGetObjectType)
+ {
+ int rc;
+ ssize_t cchTmp; NOREF(cchTmp);
+ char szTmp[16];
+ RTUTF16 wszPortNm[128];
+ size_t offRand;
+
+ /*
+ * First attempt is in the session directory.
+ */
+ rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
+ Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
+ offRand = RTUtf16Len(wszPortNm);
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+ Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ AssertRCSuccess(rc);
+
+ bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+ if (!fDone)
+ {
+ wszPortNm[offRand] = '\0';
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ AssertRCSuccess(rc);
+
+ fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+ }
+ if (!fDone)
+ {
+ /*
+ * Try base names.
+ */
+ if (uSessionId == 0)
+ rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
+ else
+ {
+ rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
+ }
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
+ Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
+ offRand = RTUtf16Len(wszPortNm);
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+ Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ AssertRCSuccess(rc);
+
+ bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+ if (!fDone)
+ {
+ wszPortNm[offRand] = '\0';
+ cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+ Assert(cchTmp > 0);
+ rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+ AssertRCSuccess(rc);
+
+ fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+ }
+ }
+
+ /* Cache the result in g_pAlpcPortObjectType2. */
+ if ( g_pAlpcPortObjectType2 == NULL
+ && pObjType != g_pAlpcPortObjectType1
+ && fDone)
+ g_pAlpcPortObjectType2 = pObjType;
+
+ }
+
+ return pObjType;
+}
+
+
+/**
* Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
* current process.
*
@@ -1921,19 +2301,23 @@ static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
* We'll try use the ApiPort LPC object for the session we're in to track
* down the CSRSS process. So, we start by constructing a path to it.
*/
- int rc;
+ int rc;
uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
+ char szSessionId[16];
WCHAR wszApiPort[48];
if (uSessionId == 0)
+ {
+ szSessionId[0] = '0';
+ szSessionId[1] = '\0';
rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
+ }
else
{
- char szTmp[64];
- ssize_t cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), uSessionId, 10, 0, 0, 0);
+ ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
AssertReturn(cchTmp > 0, (int)cchTmp);
rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
if (RT_SUCCESS(rc))
- rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szTmp);
+ rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
if (RT_SUCCESS(rc))
rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
}
@@ -1952,14 +2336,35 @@ static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
0,
NULL /*pAccessState*/,
STANDARD_RIGHTS_READ,
- *LpcPortObjectType,
+ g_pAlpcPortObjectType1,
KernelMode,
NULL /*pvParseContext*/,
&pvApiPortObj);
+ if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
+ && g_pAlpcPortObjectType2 != NULL)
+ rcNt = ObReferenceObjectByName(&ApiPortStr,
+ 0,
+ NULL /*pAccessState*/,
+ STANDARD_RIGHTS_READ,
+ g_pAlpcPortObjectType2,
+ KernelMode,
+ NULL /*pvParseContext*/,
+ &pvApiPortObj);
+ if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
+ && g_pfnObGetObjectType
+ && g_pfnZwAlpcCreatePort)
+ rcNt = ObReferenceObjectByName(&ApiPortStr,
+ 0,
+ NULL /*pAccessState*/,
+ STANDARD_RIGHTS_READ,
+ supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
+ KernelMode,
+ NULL /*pvParseContext*/,
+ &pvApiPortObj);
if (!NT_SUCCESS(rcNt))
{
SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
- return VERR_SUPDRV_APIPORT_OPEN_ERROR;
+ return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
}
/*
@@ -2176,6 +2581,31 @@ static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
/** @name Process Creation Callbacks.
* @{ */
+
+/**
+ * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
+ *
+ * @param hProcessId The ID of the dead process.
+ */
+static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
+{
+ int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ PSUPDRVNTERRORINFO pCur, pNext;
+ RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
+ {
+ if (pCur->hProcessId == hProcessId)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ }
+ }
+ RTSemMutexRelease(g_hErrorInfoLock);
+ }
+}
+
+
/**
* Common worker used by the process creation hooks as well as the process
* handle creation hooks to check if a VM process is being created.
@@ -2239,7 +2669,7 @@ static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE
pNtChild->fFirstProcessCreateHandle = true;
pNtChild->fFirstThreadCreateHandle = true;
pNtChild->fCsrssFirstProcessCreateHandle = true;
- pNtChild->fCsrssFirstProcessDuplicateHandle = true;
+ pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
pNtChild->fThemesFirstProcessCreateHandle = true;
pNtChild->hParentPid = pNtParent->AvlCore.Key;
pNtChild->hCsrssPid = pNtParent->hCsrssPid;
@@ -2422,7 +2852,10 @@ supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, B
* Process termination, do clean ups.
*/
else
+ {
supdrvNtProtectUnprotectDeadProcess(hNewPid);
+ supdrvNtErrorInfoCleanupProcess(hNewPid);
+ }
}
@@ -2478,7 +2911,10 @@ supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNew
* Process termination, do clean ups.
*/
else
+ {
supdrvNtProtectUnprotectDeadProcess(hNewPid);
+ supdrvNtErrorInfoCleanupProcess(hNewPid);
+ }
}
/** @} */
@@ -2620,6 +3056,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
&& pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
&& pNtProtect->fCsrssFirstProcessCreateHandle
&& pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
&& supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
{
pNtProtect->fCsrssFirstProcessCreateHandle = false;
@@ -2646,6 +3083,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
&& pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
&& pNtProtect->fThemesFirstProcessCreateHandle
&& pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
&& supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
{
pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
@@ -2686,15 +3124,16 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
This is the CSRSS.EXE end of special case #1. */
if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
&& pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
- && pNtProtect->fCsrssFirstProcessDuplicateHandle
+ && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
&& pOpInfo->KernelHandle == 0
+ && pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires
&& pNtProtect->hParentPid
== PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
&& pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
- && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
+ && ExGetPreviousMode() == UserMode
+ && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
{
- pNtProtect->fCsrssFirstProcessDuplicateHandle = false;
- if (pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
+ if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
{
/* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
@@ -2838,6 +3277,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
&& pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
&& pNtProtect->fFirstThreadCreateHandle
&& pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
&& pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
{
if ( !pOpInfo->KernelHandle
@@ -2860,6 +3300,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
&& ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
|| enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
&& pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
&& supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
{
fAllowedRights |= THREAD_IMPERSONATE;
@@ -2904,6 +3345,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
|| enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
&& pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
&& pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
&& supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
{
fAllowedRights |= THREAD_IMPERSONATE;
@@ -2982,6 +3424,7 @@ static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUP
pNtProtect->cRefs = 1;
pNtProtect->enmProcessKind = enmProcessKind;
pNtProtect->hParentPid = NULL;
+ pNtProtect->hOpenTid = NULL;
pNtProtect->hCsrssPid = NULL;
pNtProtect->pCsrssProcess = NULL;
@@ -3041,7 +3484,7 @@ static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
pNtProtect->u.pChild = NULL;
pChild->u.pParent = NULL;
pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
- uint32_t cChildRefs = ASMAtomicIncU32(&pChild->cRefs);
+ uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
if (!cChildRefs)
pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
else
@@ -3087,14 +3530,114 @@ static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
/**
+ * Validates a few facts about the stub process when the VM process opens
+ * vboxdrv.
+ *
+ * This makes sure the stub process is still around and that it has neither
+ * debugger nor extra threads in it.
+ *
+ * @returns VBox status code.
+ * @param pNtProtect The unconfirmed VM process currently trying to
+ * open vboxdrv.
+ * @param pErrInfo Additional error information.
+ */
+static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
+{
+ /*
+ * Grab a reference to the parent stub process.
+ */
+ SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
+ PSUPDRVNTPROTECT pNtStub = NULL;
+ RTSpinlockAcquire(g_hNtProtectLock);
+ if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
+ {
+ pNtStub = pNtProtect->u.pParent; /* weak reference. */
+ if (pNtStub)
+ {
+ enmStub = pNtStub->enmProcessKind;
+ if (enmStub == kSupDrvNtProtectKind_StubParent)
+ {
+ uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
+ Assert(cRefs > 0 && cRefs < 1024);
+ }
+ else
+ pNtStub = NULL;
+ }
+ }
+ RTSpinlockRelease(g_hNtProtectLock);
+
+ /*
+ * We require the stub process to be present.
+ */
+ if (!pNtStub)
+ return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
+
+ /*
+ * Open the parent process and thread so we can check for debuggers and unwanted threads.
+ */
+ int rc;
+ PEPROCESS pStubProcess;
+ NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
+ if (NT_SUCCESS(rcNt))
+ {
+ HANDLE hStubProcess;
+ rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
+ 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
+ if (NT_SUCCESS(rcNt))
+ {
+ PETHREAD pStubThread;
+ rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
+ if (NT_SUCCESS(rcNt))
+ {
+ HANDLE hStubThread;
+ rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
+ 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Do some simple sanity checking.
+ */
+ rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
+ if (RT_SUCCESS(rc))
+ rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
+
+ /* Clean up. */
+ rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
+ "Error opening stub thread %p (tid %p, pid %p): %#x",
+ pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
+ "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
+ rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
+ "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
+ ObDereferenceObject(pStubProcess);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
+ "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
+
+ supdrvNtProtectRelease(pNtStub);
+ return rc;
+}
+
+
+/**
* Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
* process and its thread.
*
* @returns VBox status code.
* @param pNtProtect The NT protect structure for getting information
* about special processes.
+ * @param pErrInfo Where to return additional error details.
*/
-static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect)
+static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
{
/*
* What to protect.
@@ -3123,13 +3666,14 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
RTMemFree(pbBuf);
pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
if (!pbBuf)
- return VERR_NO_MEMORY;
+ return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
}
if (!NT_SUCCESS(rcNt))
{
RTMemFree(pbBuf);
- return RTErrConvertFromNtStatus(rcNt);
+ return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
+ "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
}
}
@@ -3159,7 +3703,7 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
if (pHandleInfo->Object == pProtectedProcess)
{
- /* Handles within the protected process is fine. */
+ /* Handles within the protected process are fine. */
if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
|| pHandleInfo->UniqueProcessId == hProtectedPid)
{
@@ -3176,10 +3720,11 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
continue;
}
- /* The system process is allowed having one open process handle in
- Windows 8.1 and later. */
- if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
- && cSystemProcessHandles < 1
+ /* The system process is allowed having two open process handle in
+ Windows 8.1 and later, and one in earlier. This is probably a
+ little overly paranoid as I think we can safely trust the
+ system process... */
+ if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? 2 : 1)
&& pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
{
cSystemProcessHandles++;
@@ -3243,7 +3788,24 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
- rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+ rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
+ *pErrInfo->pszMsg
+ ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
+ : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
+ pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
+ pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
+
+ /* Try add the process name. */
+ PEPROCESS pOffendingProcess;
+ rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
+ if (NT_SUCCESS(rcNt))
+ {
+ const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
+ if (pszName && *pszName)
+ rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
+
+ ObDereferenceObject(pOffendingProcess);
+ }
}
}
@@ -3268,30 +3830,39 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
* on VM processes.
*/
int rc = VINF_SUCCESS;
- if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
- rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect);
+ PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
if (RT_SUCCESS(rc))
{
- char szErr[256];
- RT_ZERO(szErr);
+ pErrorInfo->hProcessId = PsGetCurrentProcessId();
+ pErrorInfo->hThreadId = PsGetCurrentThreadId();
RTERRINFO ErrInfo;
- RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
+ RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
- rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY,
- NULL /*pcFixes*/, &ErrInfo);
- if (RT_FAILURE(rc))
- RTLogWriteDebugger(szErr, strlen(szErr));
+ if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+ rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
+ if (RT_SUCCESS(rc))
+ {
+ rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
+ NULL /*pcFixes*/, &ErrInfo);
+ if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+ rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
+ }
}
+ else
+ rc = VERR_NO_MEMORY;
/*
* Upgrade and return.
*/
+ HANDLE hOpenTid = PsGetCurrentThreadId();
RTSpinlockAcquire(g_hNtProtectLock);
/* Stub process verficiation is pretty much straight forward. */
if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
+ {
pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
-
+ pNtProtect->hOpenTid = hOpenTid;
+ }
/* The VM process verification is a little bit more complicated
because we need to drop the parent process reference as well. */
else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
@@ -3307,7 +3878,10 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
ASMAtomicDecU32(&pNtProtect->cRefs);
if (RT_SUCCESS(rc))
+ {
pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
+ pNtProtect->hOpenTid = hOpenTid;
+ }
else
pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
}
@@ -3334,6 +3908,44 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
}
RTSpinlockRelease(g_hNtProtectLock);
+
+ /*
+ * Free error info on success, keep it on failure.
+ */
+ if (RT_SUCCESS(rc))
+ RTMemFree(pErrorInfo);
+ else if (pErrorInfo)
+ {
+ pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
+ if (!pErrorInfo->cchErrorInfo)
+ pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
+ "supdrvNtProtectVerifyProcess: rc=%d", rc);
+ if (RT_FAILURE(rc))
+ RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
+
+ int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc2))
+ {
+ pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
+
+ /* Free old entries. */
+ PSUPDRVNTERRORINFO pCur;
+ while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
+ && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ }
+
+ /* Insert our new entry. */
+ RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
+
+ RTSemMutexRelease(g_hErrorInfoLock);
+ }
+ else
+ RTMemFree(pErrorInfo);
+ }
+
return rc;
}
@@ -3384,6 +3996,16 @@ static void supdrvNtProtectTerm(void)
RTSpinlockDestroy(g_hNtProtectLock);
g_NtProtectTree = NIL_RTSPINLOCK;
+ RTSemMutexDestroy(g_hErrorInfoLock);
+ g_hErrorInfoLock = NIL_RTSEMMUTEX;
+
+ PSUPDRVNTERRORINFO pCur;
+ while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ RTMemFree(pCur);
+ }
+
supHardenedWinTermImageVerifier();
}
@@ -3432,6 +4054,9 @@ static NTSTATUS supdrvNtProtectInit(void)
/* Resolve methods we want but isn't available everywhere. */
UNICODE_STRING RoutineName;
+ RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
+ g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
+
RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
@@ -3447,6 +4072,9 @@ static NTSTATUS supdrvNtProtectInit(void)
RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
+ RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
+ g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
+
RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
@@ -3527,6 +4155,18 @@ static NTSTATUS supdrvNtProtectInit(void)
return STATUS_PROCEDURE_NOT_FOUND;
}
+# ifdef VBOX_STRICT
+ if ( g_uNtVerCombined >= SUP_NT_VER_W70
+ && ( g_pfnObGetObjectType == NULL
+ || g_pfnZwAlpcCreatePort == NULL) )
+ {
+ LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
+ return STATUS_PROCEDURE_NOT_FOUND;
+ }
+# endif
+
+ /* LPC object type. */
+ g_pAlpcPortObjectType1 = *LpcPortObjectType;
/* The spinlock protecting our structures. */
int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
@@ -3534,119 +4174,131 @@ static NTSTATUS supdrvNtProtectInit(void)
return VBoxDrvNtErr2NtStatus(rc);
g_NtProtectTree = NULL;
- /* Image stuff + certificates. */
NTSTATUS rcNt;
- rc = supHardenedWinInitImageVerifier(NULL);
+
+ /* The mutex protecting the error information. */
+ RTListInit(&g_ErrorInfoHead);
+ rc = RTSemMutexCreate(&g_hErrorInfoLock);
if (RT_SUCCESS(rc))
{
- /*
- * Intercept process creation and termination.
- */
- if (g_pfnPsSetCreateProcessNotifyRoutineEx)
- rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
- else
- rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
- if (NT_SUCCESS(rcNt))
+ /* Image stuff + certificates. */
+ rc = supHardenedWinInitImageVerifier(NULL);
+ if (RT_SUCCESS(rc))
{
/*
- * Intercept process and thread handle creation calls.
- * The preferred method is only available on Vista SP1+.
+ * Intercept process creation and termination.
*/
- if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
+ if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+ rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
+ else
+ rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
+ if (NT_SUCCESS(rcNt))
{
- static OB_OPERATION_REGISTRATION s_aObOperations[] =
+ /*
+ * Intercept process and thread handle creation calls.
+ * The preferred method is only available on Vista SP1+.
+ */
+ if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
{
+ static OB_OPERATION_REGISTRATION s_aObOperations[] =
{
- PsProcessType,
- OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
- supdrvNtProtectCallback_ProcessHandlePre,
- supdrvNtProtectCallback_ProcessHandlePost,
- },
+ {
+ PsProcessType,
+ OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+ supdrvNtProtectCallback_ProcessHandlePre,
+ supdrvNtProtectCallback_ProcessHandlePost,
+ },
+ {
+ PsThreadType,
+ OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+ supdrvNtProtectCallback_ThreadHandlePre,
+ supdrvNtProtectCallback_ThreadHandlePost,
+ },
+ };
+ static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
{
- PsThreadType,
- OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
- supdrvNtProtectCallback_ThreadHandlePre,
- supdrvNtProtectCallback_ThreadHandlePost,
- },
- };
- static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
- {
- /* .Version = */ OB_FLT_REGISTRATION_VERSION,
- /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
- /* .Altitude.Length = */ 0,
- /* .Altitude.MaximumLength = */ 0,
- /* .Altitude.Buffer = */ NULL,
- /* .RegistrationContext = */ NULL,
- /* .OperationRegistration = */ &s_aObOperations[0]
- };
- static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
- {
- L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
- L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
- L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
- L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
- };
-
- rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
- for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
- {
- s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
- s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
- s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
-
- rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
- if (NT_SUCCESS(rcNt))
+ /* .Version = */ OB_FLT_REGISTRATION_VERSION,
+ /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
+ /* .Altitude.Length = */ 0,
+ /* .Altitude.MaximumLength = */ 0,
+ /* .Altitude.Buffer = */ NULL,
+ /* .RegistrationContext = */ NULL,
+ /* .OperationRegistration = */ &s_aObOperations[0]
+ };
+ static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
{
- /*
- * Happy ending.
- */
- return STATUS_SUCCESS;
+ L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
+ L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
+ L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
+ L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
+ };
+
+ rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
+ {
+ s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
+ s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
+ s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
+
+ rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Happy ending.
+ */
+ return STATUS_SUCCESS;
+ }
}
+ LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
+ g_pvObCallbacksCookie = NULL;
}
- LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
- g_pvObCallbacksCookie = NULL;
- }
- else
- {
- /*
- * For the time being, we do not implement extra process
- * protection on pre-Vista-SP1 systems as they are lacking
- * necessary KPIs. XP is end of life, we do not wish to
- * spend more time on it, so we don't put up a fuss there.
- * Vista users without SP1 can install SP1 (or later), darn it,
- * so refuse to load.
- */
- /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
- * stuff to a couple of object types. */
+ else
+ {
+ /*
+ * For the time being, we do not implement extra process
+ * protection on pre-Vista-SP1 systems as they are lacking
+ * necessary KPIs. XP is end of life, we do not wish to
+ * spend more time on it, so we don't put up a fuss there.
+ * Vista users without SP1 can install SP1 (or later), darn it,
+ * so refuse to load.
+ */
+ /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
+ * stuff to a couple of object types. */
# ifndef VBOX_WITH_VISTA_NO_SP
- if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
+ if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
# else
- if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
+ if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
# endif
- {
- DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
- rcNt = STATUS_SXS_VERSION_CONFLICT;
+ {
+ DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
+ rcNt = STATUS_SXS_VERSION_CONFLICT;
+ }
+ else
+ {
+ Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
+ return rcNt = STATUS_SUCCESS;
+ }
+ g_pvObCallbacksCookie = NULL;
}
+
+ /*
+ * Drop process create/term notifications.
+ */
+ if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+ g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
else
- {
- Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
- return rcNt = STATUS_SUCCESS;
- }
- g_pvObCallbacksCookie = NULL;
+ PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
}
-
- /*
- * Drop process create/term notifications.
- */
- if (g_pfnPsSetCreateProcessNotifyRoutineEx)
- g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
else
- PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
+ LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
+ g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
+ supHardenedWinTermImageVerifier();
}
else
- LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
- g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
- supHardenedWinTermImageVerifier();
+ rcNt = VBoxDrvNtErr2NtStatus(rc);
+
+ RTSemMutexDestroy(g_hErrorInfoLock);
+ g_hErrorInfoLock = NIL_RTSEMMUTEX;
}
else
rcNt = VBoxDrvNtErr2NtStatus(rc);
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h b/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
index 8f9966b..c20055e 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
@@ -53,8 +53,29 @@ typedef enum SUPHARDNTVPKIND
SUPHARDNTVPKIND_SELF_PURIFICATION,
SUPHARDNTVPKIND_32BIT_HACK = 0x7fffffff
} SUPHARDNTVPKIND;
-DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind,
+/** @name SUPHARDNTVP_F_XXX - Flags for supHardenedWinVerifyProcess
+ * @{ */
+/** Replace unwanted executable memory allocations with a new one that's filled
+ * with a safe read-write copy (default is just to free it).
+ *
+ * This is one way we attempt to work around buggy protection software that
+ * either result in host BSOD or VBox application malfunction. Here the current
+ * shit list:
+ * - Trend Micro's data protection software includes a buggy driver called
+ * sakfile.sys that has been observed crashing accessing user memory that we
+ * probably freed. I'd love to report this to Trend Micro, but unfortunately
+ * they doesn't advertise (or have?) an email address for reporting security
+ * vulnerabilities in the their software. Having wasted time looking and not
+ * very sorry for having to disclosing the bug here.
+ * - Maybe one more.
+ */
+#define SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW RT_BIT_32(0)
+/** @} */
+DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, uint32_t fFlags,
uint32_t *pcFixes, PRTERRINFO pErrInfo);
+DECLHIDDEN(int) supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo);
+DECLHIDDEN(int) supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo);
+
DECLHIDDEN(bool) supHardViUtf16PathIsEqualEx(PCRTUTF16 pawcLeft, size_t cwcLeft, const char *pszRight);
DECLHIDDEN(bool) supHardViUniStrPathStartsWithUniStr(UNICODE_STRING const *pUniStrLeft,
@@ -71,8 +92,11 @@ typedef struct SUPHNTVIRDR
{
/** The core reader structure. */
RTLDRREADER Core;
- /** The file handle . */
+ /** The file handle. */
HANDLE hFile;
+ /** Handle to event sempahore in case we're force to deal with asynchronous
+ * I/O. */
+ HANDLE hEvent;
/** Current file offset. */
RTFOFF off;
/** The file size. */
@@ -137,12 +161,17 @@ typedef struct SUPHNTLDRCACHEENTRY
uint8_t *pbBits;
/** Set if verified. */
bool fVerified;
+ /** Whether we've got valid cacheable image bit.s */
+ bool fValidBits;
+ /** The image base address. */
+ uintptr_t uImageBase;
} SUPHNTLDRCACHEENTRY;
/** Pointer to a loader cache entry. */
typedef SUPHNTLDRCACHEENTRY *PSUPHNTLDRCACHEENTRY;
DECLHIDDEN(int) supHardNtLdrCacheOpen(const char *pszName, PSUPHNTLDRCACHEENTRY *ppEntry);
DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUTF16 pwszName, PRTERRINFO pErrInfo);
-DECLHIDDEN(int) supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, PRTERRINFO pErrInfo);
+DECLHIDDEN(int) supHardNtLdrCacheEntryGetBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, RTLDRADDR uBaseAddress,
+ PFNRTLDRIMPORT pfnGetImport, void *pvUser, PRTERRINFO pErrInfo);
/** Which directory under the system root to get. */
@@ -164,14 +193,14 @@ typedef struct SUPSYSROOTDIRBUF
} SUPSYSROOTDIRBUF;
extern SUPSYSROOTDIRBUF g_System32NtPath;
extern SUPSYSROOTDIRBUF g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
extern SUPSYSROOTDIRBUF g_ProgramFilesNtPath;
extern SUPSYSROOTDIRBUF g_CommonFilesNtPath;
# if ARCH_BITS == 64
extern SUPSYSROOTDIRBUF g_ProgramFilesX86NtPath;
extern SUPSYSROOTDIRBUF g_CommonFilesX86NtPath;
# endif
-#endif
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
extern SUPSYSROOTDIRBUF g_SupLibHardenedExeNtPath;
extern uint32_t g_offSupLibHardenedExeNtName;
@@ -194,18 +223,23 @@ extern PFNNTQUERYVIRTUALMEMORY g_pfnNtQueryVirtualMemory;
#define SUP_MAKE_NT_VER_SIMPLE(a_uMajor, a_uMinor) SUP_MAKE_NT_VER_COMBINED(a_uMajor, a_uMinor, 0, 0, 0)
extern uint32_t g_uNtVerCombined;
+/** @name NT version constants for less-than checks.
+ * @{ */
/** Combined NT version number for XP. */
#define SUP_NT_VER_XP SUP_MAKE_NT_VER_SIMPLE(5,1)
/** Combined NT version number for Windows server 2003 & XP64. */
#define SUP_NT_VER_W2K3 SUP_MAKE_NT_VER_SIMPLE(5,2)
/** Combined NT version number for Vista. */
#define SUP_NT_VER_VISTA SUP_MAKE_NT_VER_SIMPLE(6,0)
+/** Combined NT version number for Vista with SP1. */
+#define SUP_NT_VER_VISTA_SP1 SUP_MAKE_NT_VER_COMBINED(6,0,6001,1,0)
/** Combined NT version number for Windows 7. */
#define SUP_NT_VER_W70 SUP_MAKE_NT_VER_SIMPLE(6,1)
/** Combined NT version number for Windows 8.0. */
#define SUP_NT_VER_W80 SUP_MAKE_NT_VER_SIMPLE(6,2)
/** Combined NT version number for Windows 8.1. */
#define SUP_NT_VER_W81 SUP_MAKE_NT_VER_SIMPLE(6,3)
+/** @} */
# endif
@@ -213,9 +247,6 @@ extern uint32_t g_uNtVerCombined;
# include <iprt/mem.h>
# include <iprt/string.h>
-# define suplibHardenedAllocZ RTMemAllocZ
-# define suplibHardenedReAlloc RTMemRealloc
-# define suplibHardenedFree RTMemFree
# define suplibHardenedMemComp memcmp
# define suplibHardenedMemCopy memcpy
# define suplibHardenedMemSet memset
@@ -226,7 +257,7 @@ extern uint32_t g_uNtVerCombined;
# define suplibHardenedStrNCmp strncmp
# else /* IN_SUP_HARDENED_R3 */
# include <iprt/mem.h>
-#if 0
+# if 0
# define memcmp suplibHardenedMemComp
# define memcpy suplibHardenedMemCopy
# define memset suplibHardenedMemSet
@@ -235,10 +266,7 @@ extern uint32_t g_uNtVerCombined;
# define strcat suplibHardenedStrCat
# define strcmp suplibHardenedStrCmp
# define strncmp suplibHardenedStrNCmp
-#endif
-DECLHIDDEN(void *) suplibHardenedAllocZ(size_t cb);
-DECLHIDDEN(void *) suplibHardenedReAlloc(void *pvOld, size_t cbNew);
-DECLHIDDEN(void) suplibHardenedFree(void *pv);
+# endif
# endif /* IN_SUP_HARDENED_R3 */
#endif /* SUP_CERTIFICATES_ONLY */
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
index ac45b58..d7656b3 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
@@ -121,7 +121,7 @@ static RTCRSTORE g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
SUPSYSROOTDIRBUF g_System32NtPath;
/** The full \\SystemRoot\\WinSxS path. */
SUPSYSROOTDIRBUF g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
/** The full 'Program Files' path. */
SUPSYSROOTDIRBUF g_ProgramFilesNtPath;
# ifdef RT_ARCH_AMD64
@@ -134,7 +134,7 @@ SUPSYSROOTDIRBUF g_CommonFilesNtPath;
/** The full 'Common Files (x86)' path. */
SUPSYSROOTDIRBUF g_CommonFilesX86NtPath;
# endif
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_MORE*/
static union
{
@@ -144,7 +144,9 @@ static union
/** The TrustedInstaller SID (Vista+). */
g_TrustedInstallerSid,
/** Local system ID (S-1-5-21). */
- g_LocalSystemSid;
+ g_LocalSystemSid,
+/** Builtin Administrators group alias (S-1-5-32-544). */
+ g_AdminsGroupSid;
/** Set after we've retrived other SPC root certificates from the system. */
@@ -208,93 +210,67 @@ static DECLCALLBACK(int) supHardNtViRdrRead(PRTLDRREADER pReader, void *pvBuf, s
{
PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
+ NTSTATUS rcNt;
+ /* Check for type overflow (paranoia). */
if ((ULONG)cb != cb)
return VERR_OUT_OF_RANGE;
-
- /*
- * For some reason I'm getting occational read error in an XP VM with
- * STATUS_FAILED_DRIVER_ENTRY. Redoing the call again works in the
- * debugger, so try do that automatically.
- */
- for (uint32_t iTry = 0;; iTry++)
- {
- LARGE_INTEGER offNt;
- offNt.QuadPart = off;
-
- IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
- NTSTATUS rcNt = NtReadFile(pNtViRdr->hFile,
- NULL /*hEvent*/,
- NULL /*ApcRoutine*/,
- NULL /*ApcContext*/,
- &Ios,
- pvBuf,
- (ULONG)cb,
- &offNt,
- NULL);
- if (NT_SUCCESS(rcNt))
- rcNt = Ios.Status;
- if (NT_SUCCESS(rcNt))
- {
- if (Ios.Information == cb)
- {
- pNtViRdr->off = off + cb;
- return VINF_SUCCESS;
- }
#ifdef IN_RING3
- supR3HardenedError(VERR_READ_ERROR, false,
- "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
- Ios.Information, off, cb, pNtViRdr->szFilename);
+ /* Make sure the event semaphore is reset (normally we don't use one). */
+ if (pNtViRdr->hEvent)
+ {
+ rcNt = NtClearEvent(pNtViRdr->hEvent);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrConvertFromNtStatus(rcNt);
+ }
#endif
- pNtViRdr->off = -1;
- return VERR_READ_ERROR;
- }
- /*
- * Delay a little before we retry?
- */
-#ifdef IN_RING3
- if (iTry == 0)
- NtYieldExecution();
- else if (iTry >= 1)
- {
- LARGE_INTEGER Time;
- Time.QuadPart = -1000000 / 100; /* 1ms in 100ns units, relative time. */
- NtDelayExecution(TRUE, &Time);
- }
+ /* Perform the read. */
+ LARGE_INTEGER offNt;
+ offNt.QuadPart = off;
+
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ rcNt = NtReadFile(pNtViRdr->hFile,
+ pNtViRdr->hEvent,
+ NULL /*ApcRoutine*/,
+ NULL /*ApcContext*/,
+ &Ios,
+ pvBuf,
+ (ULONG)cb,
+ &offNt,
+ NULL);
+
+#ifdef IN_RING0
+ /* In ring-0 the handles shall be synchronized and not alertable. */
+ AssertMsg(rcNt == STATUS_SUCCESS || !NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+#else
+ /* In ring-3 we like our handles synchronized and non-alertable, but we
+ sometimes have to take what we can get. So, deal with pending I/O as
+ best we can. */
+ if (rcNt == STATUS_PENDING)
+ rcNt = NtWaitForSingleObject(pNtViRdr->hEvent ? pNtViRdr->hEvent : pNtViRdr->hFile, FALSE /*Alertable*/, NULL);
#endif
- /*
- * Before we give up, we'll try split up the request in case the
- * kernel is low on memory or similar. For simplicity reasons, we do
- * this in a recursion fashion.
- */
- if (iTry >= 2)
+ if (NT_SUCCESS(rcNt))
+ rcNt = Ios.Status;
+ if (NT_SUCCESS(rcNt))
+ {
+ /* We require the caller to not read beyond the end of the file since
+ we don't have any way to communicate that we've read less that
+ requested. */
+ if (Ios.Information == cb)
{
- if (cb >= _8K)
- {
- size_t const cbBlock = RT_ALIGN_Z(cb / 4, 512);
- while (cb > 0)
- {
- size_t cbThisRead = RT_MIN(cb, cbBlock);
- int rc = supHardNtViRdrRead(&pNtViRdr->Core, pvBuf, cbThisRead, off);
- if (RT_FAILURE(rc))
- return rc;
- off += cbThisRead;
- cb -= cbThisRead;
- pvBuf = (uint8_t *)pvBuf + cbThisRead;
- }
- return VINF_SUCCESS;
- }
-
+ pNtViRdr->off = off + cb; /* (just for show) */
+ return VINF_SUCCESS;
+ }
#ifdef IN_RING3
- supR3HardenedError(VERR_READ_ERROR, false, "supHardNtViRdrRead: Error %#x reading %#zx bytes at %#llx in '%s'.\n",
- rcNt, off, cb, pNtViRdr->szFilename);
+ supR3HardenedError(VERR_READ_ERROR, false,
+ "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
+ Ios.Information, off, cb, pNtViRdr->szFilename);
#endif
- pNtViRdr->off = -1;
- return VERR_READ_ERROR;
- }
}
+ pNtViRdr->off = -1;
+ return VERR_READ_ERROR;
}
@@ -346,7 +322,13 @@ static DECLCALLBACK(int) supHardNtViRdrDestroy(PRTLDRREADER pReader)
pNtViRdr->Core.uMagic = ~RTLDRREADER_MAGIC;
pNtViRdr->hFile = NULL;
-
+#ifdef IN_RING3
+ if (pNtViRdr->hEvent)
+ {
+ NtClose(pNtViRdr->hEvent);
+ pNtViRdr->hEvent = NULL;
+ }
+#endif
RTMemFree(pNtViRdr);
return VINF_SUCCESS;
}
@@ -373,6 +355,31 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
return VERR_LDRVI_FILE_LENGTH_ERROR;
/*
+ * Figure the file mode so we can see whether we'll be needing an event
+ * semaphore for waiting on reads. This may happen in very unlikely
+ * NtCreateSection scenarios.
+ */
+#if defined(IN_RING3) || defined(VBOX_STRICT)
+ Ios.Status = STATUS_UNSUCCESSFUL;
+ ULONG fMode;
+ rcNt = NtQueryInformationFile(hFile, &Ios, &fMode, sizeof(fMode), FileModeInformation);
+ if (!NT_SUCCESS(rcNt) || !NT_SUCCESS(Ios.Status))
+ return VERR_SUP_VP_FILE_MODE_ERROR;
+#endif
+
+ HANDLE hEvent = NULL;
+#ifdef IN_RING3
+ if (!(fMode & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)))
+ {
+ rcNt = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
+ if (!NT_SUCCESS(rcNt))
+ return VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED;
+ }
+#else
+ Assert(fMode & FILE_SYNCHRONOUS_IO_NONALERT);
+#endif
+
+ /*
* Calc the file name length and allocate memory for the reader instance.
*/
size_t cchFilename = 0;
@@ -382,7 +389,13 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
int rc = VERR_NO_MEMORY;
PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)RTMemAllocZ(sizeof(*pNtViRdr) + cchFilename);
if (!pNtViRdr)
+ {
+#ifdef IN_RING3
+ if (hEvent != NULL)
+ NtClose(hEvent);
+#endif
return VERR_NO_MEMORY;
+ }
/*
* Initialize the structure.
@@ -405,6 +418,7 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
pNtViRdr->Core.pfnUnmap = supHardNtViRdrUnmap;
pNtViRdr->Core.pfnDestroy = supHardNtViRdrDestroy;
pNtViRdr->hFile = hFile;
+ pNtViRdr->hEvent = hEvent;
pNtViRdr->off = 0;
pNtViRdr->cbFile = StdInfo.EndOfFile.QuadPart;
pNtViRdr->fFlags = fFlags;
@@ -451,9 +465,17 @@ static bool supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(HANDLE hFile, PCR
* turned up owned by the local system user, and we cannot operate without
* the plugin loaded once it's installed (WinVerityTrust fails).
*
- * Note! We cannot really allow Builtin\Administrators here it's the default
- * owner of anything an admin user creates. (We must, unforutnately,
- * allow that in system32 though.)
+ * We'd like to avoid allowing Builtin\Administrators here since it's the
+ * default owner of anything an admin user creates (at least when elevated).
+ * Seems windows update or someone ends up installing or modifying system
+ * DLL ownership to this group, so for system32 and winsxs it's unavoidable.
+ * And, not surprise, a bunch of products, including AV, firewalls and similar
+ * ends up with their files installed with this group as owner. For instance
+ * if we wish to have NAT continue working, we need to allow this.
+ *
+ * Hopefully, we can limit the allowed files to these owners though, so
+ * we won't be subject to ordinary (non-admin, or not elevated) users
+ * downloading or be tricked into putting evil DLLs around the place...
*/
PSID pOwner = uBuf.Rel.Control & SE_SELF_RELATIVE ? &uBuf.abView[uBuf.Rel.Owner] : uBuf.Abs.Owner;
Assert((uintptr_t)pOwner - (uintptr_t)&uBuf < sizeof(uBuf) - sizeof(SID));
@@ -461,6 +483,11 @@ static bool supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(HANDLE hFile, PCR
return true;
if (RtlEqualSid(pOwner, &g_LocalSystemSid))
return true;
+ if (RtlEqualSid(pOwner, &g_AdminsGroupSid))
+ {
+ SUP_DPRINTF(("%ls: Owner is administrators group.\n", pwszName));
+ return true;
+ }
SUP_DPRINTF(("%ls: Owner is not trusted installer (%.*Rhxs)\n",
pwszName, ((uint8_t *)pOwner)[1] /*SubAuthorityCount*/ * sizeof(ULONG) + 8, pOwner));
@@ -1065,27 +1092,38 @@ DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pw
* Check the trusted installer bit first, if requested as it's somewhat
* cheaper than the rest.
*
- * We relax this for system32, like we used to, as there are apparently
- * some systems out there where the user, admin, or someone has changed the
- * ownership of core windows DLLs like user32.dll. Since we need user32.dll
- * and will be checking it's digital signature, it's reasonably safe to let
- * this thru. (The report was of SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS
+ * We relax this for system32 and a little for WinSxS, like we used to, as
+ * there are apparently some systems out there where the user, admin, or
+ * someone has changed the ownership of core windows DLLs like user32.dll
+ * and comctl32.dll. Since we need user32.dll and will be checking it's
+ * digital signature, it's reasonably safe to let this thru. (The report
+ * was of SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS
* owning user32.dll, see public ticket 13187, VBoxStartup.3.log.)
*
* We've also had problems with graphics driver components like ig75icd64.dll
* and atig6pxx.dll not being owned by TrustedInstaller, with the result
* that 3D got broken (mod by zero issue in test build 5). These were also
* SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS.
+ *
+ * In one report by 'thor' the WinSxS resident comctl32.dll was owned by
+ * SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS (with 4.3.16).
*/
+ /** @todo Since we're now allowing Builtin\Administrators after all, perhaps we
+ * could drop these system32 + winsxs hacks?? */
if ( (pNtViRdr->fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
&& !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(pNtViRdr->hFile, pwszName))
{
- if (!supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
- g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR),
- true /*fCheckSlash*/))
+ if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
+ g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR),
+ true /*fCheckSlash*/))
+ SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in system32).\n", pwszName));
+ else if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
+ g_WinSxSNtPath.UniStr.Buffer, g_WinSxSNtPath.UniStr.Length / sizeof(WCHAR),
+ true /*fCheckSlash*/))
+ SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in WinSxS).\n", pwszName));
+ else
return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER,
"supHardenedWinVerifyImageByHandle: TrustedInstaller is not the owner of '%ls'.", pwszName);
- SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in system32).\n", pwszName));
}
/*
@@ -1416,8 +1454,7 @@ static int supHardNtViCertStoreInit(PRTCRSTORE phStore,
}
-
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
/**
* Initializes the windows paths.
*/
@@ -1605,7 +1642,7 @@ static void supHardenedWinInitImageVerifierWinPaths(void)
}
}
}
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
/**
@@ -1629,7 +1666,7 @@ DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
{
SUP_DPRINTF(("System32: %ls\n", g_System32NtPath.UniStr.Buffer));
SUP_DPRINTF(("WinSxS: %ls\n", g_WinSxSNtPath.UniStr.Buffer));
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
supHardenedWinInitImageVerifierWinPaths();
#endif
@@ -1681,12 +1718,18 @@ DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
*RtlSubAuthoritySid(&g_TrustedInstallerSid, 4) = 1853292631;
*RtlSubAuthoritySid(&g_TrustedInstallerSid, 5) = 2271478464;
- if (NT_SUCCESS(rcNt))
- rcNt = RtlInitializeSid(&g_LocalSystemSid, &s_NtAuth, 1);
+ rcNt = RtlInitializeSid(&g_LocalSystemSid, &s_NtAuth, 1);
if (NT_SUCCESS(rcNt))
{
*RtlSubAuthoritySid(&g_LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
- return VINF_SUCCESS;
+
+ rcNt = RtlInitializeSid(&g_AdminsGroupSid, &s_NtAuth, 2);
+ if (NT_SUCCESS(rcNt))
+ {
+ *RtlSubAuthoritySid(&g_AdminsGroupSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
+ *RtlSubAuthoritySid(&g_AdminsGroupSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
+ return VINF_SUCCESS;
+ }
}
}
rc = RTErrConvertFromNtStatus(rcNt);
@@ -1878,13 +1921,13 @@ DECLHIDDEN(HMODULE) supR3HardenedWinLoadSystem32Dll(const char *pszName)
if ( hMod == NULL
&& fFlags
&& g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
- && GetLastError() == ERROR_INVALID_PARAMETER)
+ && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
{
fFlags = 0;
hMod = LoadLibraryExW(wszName, NULL, fFlags);
}
if (hMod == NULL)
- supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, GetLastError(), wszName);
+ supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, RtlGetLastWin32Error(), wszName);
return hMod;
}
@@ -1906,7 +1949,7 @@ static void supR3HardenedWinRetrieveTrustedRootCAs(void)
#define RESOLVE_CRYPT32_API(a_Name, a_pfnType) \
a_pfnType pfn##a_Name = (a_pfnType)GetProcAddress(hCrypt32, #a_Name); \
- if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", GetLastError())
+ if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", RtlGetLastWin32Error())
RESOLVE_CRYPT32_API(CertOpenStore, PFNCERTOPENSTORE);
RESOLVE_CRYPT32_API(CertCloseStore, PFNCERTCLOSESTORE);
RESOLVE_CRYPT32_API(CertEnumCertificatesInStore, PFNCERTENUMCERTIFICATESINSTORE);
@@ -1993,7 +2036,7 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
suplibHardenedStrCat(szPath, "/VBoxSupLib.DLL");
HMODULE hSupLibMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, true /*fSystem32Only*/);
if (hSupLibMod == NULL)
- supR3HardenedFatal("Error loading '%s': %u", szPath, GetLastError());
+ supR3HardenedFatal("Error loading '%s': %u", szPath, RtlGetLastWin32Error());
# endif
/*
@@ -2003,7 +2046,7 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
if (iTls != TLS_OUT_OF_INDEXES)
g_iTlsWinVerifyTrustRecursion = iTls;
else
- supR3HardenedError(GetLastError(), false /*fFatal*/, "TlsAlloc failed");
+ supR3HardenedError(RtlGetLastWin32Error(), false /*fFatal*/, "TlsAlloc failed");
/*
* Resolve it.
@@ -2013,12 +2056,12 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
do { \
g_pfn##a_Name = (a_pfnType)GetProcAddress(hWintrust, #a_Name); \
if (g_pfn##a_Name == NULL && (a_uMinWinVer) < g_uNtVerCombined) \
- supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", GetLastError()); \
+ supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", RtlGetLastWin32Error()); \
} while (0)
PFNWINVERIFYTRUST pfnWinVerifyTrust = (PFNWINVERIFYTRUST)GetProcAddress(hWintrust, "WinVerifyTrust");
if (!pfnWinVerifyTrust)
- supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", GetLastError());
+ supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", RtlGetLastWin32Error());
RESOLVE_CRYPT_API(CryptCATAdminAcquireContext, PFNCRYPTCATADMINACQUIRECONTEXT, 0);
RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle, PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE, 0);
@@ -2151,23 +2194,25 @@ static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uin
const char *pszErrConst = NULL;
switch (hrc)
{
- case TRUST_E_SYSTEM_ERROR: pszErrConst = "TRUST_E_SYSTEM_ERROR"; break;
- case TRUST_E_NO_SIGNER_CERT: pszErrConst = "TRUST_E_NO_SIGNER_CERT"; break;
- case TRUST_E_COUNTER_SIGNER: pszErrConst = "TRUST_E_COUNTER_SIGNER"; break;
- case TRUST_E_CERT_SIGNATURE: pszErrConst = "TRUST_E_CERT_SIGNATURE"; break;
- case TRUST_E_TIME_STAMP: pszErrConst = "TRUST_E_TIME_STAMP"; break;
- case TRUST_E_BAD_DIGEST: pszErrConst = "TRUST_E_BAD_DIGEST"; break;
- case TRUST_E_BASIC_CONSTRAINTS: pszErrConst = "TRUST_E_BASIC_CONSTRAINTS"; break;
- case TRUST_E_FINANCIAL_CRITERIA: pszErrConst = "TRUST_E_FINANCIAL_CRITERIA"; break;
- case TRUST_E_PROVIDER_UNKNOWN: pszErrConst = "TRUST_E_PROVIDER_UNKNOWN"; break;
- case TRUST_E_ACTION_UNKNOWN: pszErrConst = "TRUST_E_ACTION_UNKNOWN"; break;
- case TRUST_E_SUBJECT_FORM_UNKNOWN: pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN"; break;
- case TRUST_E_SUBJECT_NOT_TRUSTED: pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED"; break;
- case TRUST_E_NOSIGNATURE: pszErrConst = "TRUST_E_NOSIGNATURE"; break;
- case TRUST_E_FAIL: pszErrConst = "TRUST_E_FAIL"; break;
- case TRUST_E_EXPLICIT_DISTRUST: pszErrConst = "TRUST_E_EXPLICIT_DISTRUST"; break;
- case CERT_E_CHAINING: pszErrConst = "CERT_E_CHAINING"; break;
- case CERT_E_REVOCATION_FAILURE: pszErrConst = "CERT_E_REVOCATION_FAILURE"; break;
+ case TRUST_E_SYSTEM_ERROR: pszErrConst = "TRUST_E_SYSTEM_ERROR"; break;
+ case TRUST_E_NO_SIGNER_CERT: pszErrConst = "TRUST_E_NO_SIGNER_CERT"; break;
+ case TRUST_E_COUNTER_SIGNER: pszErrConst = "TRUST_E_COUNTER_SIGNER"; break;
+ case TRUST_E_CERT_SIGNATURE: pszErrConst = "TRUST_E_CERT_SIGNATURE"; break;
+ case TRUST_E_TIME_STAMP: pszErrConst = "TRUST_E_TIME_STAMP"; break;
+ case TRUST_E_BAD_DIGEST: pszErrConst = "TRUST_E_BAD_DIGEST"; break;
+ case TRUST_E_BASIC_CONSTRAINTS: pszErrConst = "TRUST_E_BASIC_CONSTRAINTS"; break;
+ case TRUST_E_FINANCIAL_CRITERIA: pszErrConst = "TRUST_E_FINANCIAL_CRITERIA"; break;
+ case TRUST_E_PROVIDER_UNKNOWN: pszErrConst = "TRUST_E_PROVIDER_UNKNOWN"; break;
+ case TRUST_E_ACTION_UNKNOWN: pszErrConst = "TRUST_E_ACTION_UNKNOWN"; break;
+ case TRUST_E_SUBJECT_FORM_UNKNOWN: pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN"; break;
+ case TRUST_E_SUBJECT_NOT_TRUSTED: pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED"; break;
+ case TRUST_E_NOSIGNATURE: pszErrConst = "TRUST_E_NOSIGNATURE"; break;
+ case TRUST_E_FAIL: pszErrConst = "TRUST_E_FAIL"; break;
+ case TRUST_E_EXPLICIT_DISTRUST: pszErrConst = "TRUST_E_EXPLICIT_DISTRUST"; break;
+ case CERT_E_CHAINING: pszErrConst = "CERT_E_CHAINING"; break;
+ case CERT_E_REVOCATION_FAILURE: pszErrConst = "CERT_E_REVOCATION_FAILURE"; break;
+ case CRYPT_E_FILE_ERROR: pszErrConst = "CRYPT_E_FILE_ERROR"; break;
+ case CRYPT_E_REVOKED: pszErrConst = "CRYPT_E_REVOKED"; break;
}
if (pszErrConst)
rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
@@ -2253,6 +2298,7 @@ static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszNa
/*
* On Windows 8.0 and later there are more than one digest choice.
*/
+ int fNoSignedCatalogFound = -1;
rc = VERR_LDRVI_NOT_SIGNED;
static struct
{
@@ -2339,16 +2385,21 @@ l_fresh_context:
{
if (!fFreshContext)
{
- SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", GetLastError(), iCat));
+ SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", RtlGetLastWin32Error(), iCat));
if (hCatInfoPrev != NULL)
g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/);
g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/);
goto l_fresh_context;
}
+ ULONG ulErr = RtlGetLastWin32Error();
+ fNoSignedCatalogFound = ulErr == ERROR_NOT_FOUND && fNoSignedCatalogFound != 0;
if (iCat == 0)
- SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", GetLastError()));
+ SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed ERRROR_NOT_FOUND (%u)\n", ulErr));
+ else if (iCat == 0)
+ SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", ulErr));
break;
}
+ fNoSignedCatalogFound = 0;
Assert(hCatInfoPrev == NULL);
hCatInfoPrev = hCatInfo;
@@ -2410,9 +2461,9 @@ l_fresh_context:
}
else
{
- rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
+ rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
"CryptCATCatalogInfoFromContext failed: %d [file=%s]",
- GetLastError(), pwszName);
+ RtlGetLastWin32Error(), pwszName);
SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATCatalogInfoFromContext failed\n"));
}
iCat++;
@@ -2426,16 +2477,16 @@ l_fresh_context:
rc = RTErrInfoSetF(pErrInfo, rc2, "RTUtf16PrintHexBytes failed: %Rrc", rc);
}
else
- rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
- "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", GetLastError(), pwszName);
+ rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+ "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
if (!ASMAtomicCmpXchgPtr(&s_aHashes[i].hCachedCatAdmin, hCatAdmin, NULL))
if (!g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/))
AssertFailed();
}
else
- rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
- "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", GetLastError(), pwszName);
+ rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+ "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
iPolicy++;
} while ( fTryNextPolicy
&& iPolicy < RT_ELEMENTS(s_aPolicies));
@@ -2452,6 +2503,45 @@ l_fresh_context:
if (hFileClose != NULL)
NtClose(hFileClose);
+ /*
+ * DLLs that are likely candidates for local modifications.
+ */
+ if (rc == VERR_LDRVI_NOT_SIGNED)
+ {
+ bool fCoreSystemDll = false;
+ PCRTUTF16 pwsz;
+ uint32_t cwcName = (uint32_t)RTUtf16Len(pwszName);
+ uint32_t cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR);
+ if (supHardViUtf16PathStartsWithEx(pwszName, cwcName, g_System32NtPath.UniStr.Buffer, cwcOther, true /*fCheckSlash*/))
+ {
+ pwsz = pwszName + cwcOther + 1;
+ if ( supHardViUtf16PathIsEqual(pwsz, "uxtheme.dll")
+ || supHardViUtf16PathIsEqual(pwsz, "user32.dll")
+ || supHardViUtf16PathIsEqual(pwsz, "gdi32.dll")
+ || supHardViUtf16PathIsEqual(pwsz, "opengl32.dll")
+ || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "KernelBase.dll"))
+ || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "kernel32.dll"))
+ || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "ntdll.dll"))
+ )
+ {
+ if (RTErrInfoIsSet(pErrInfo))
+ RTErrInfoAdd(pErrInfo, rc, "\n");
+ RTErrInfoAddF(pErrInfo, rc, "'%ls' is most likely modified.", pwszName);
+ }
+ }
+
+ /* Kludge for ancient windows versions we don't want to support but
+ users still wants to use. Keep things as safe as possible without
+ unnecessary effort. Problem is that 3rd party catalog files cannot
+ easily be found. Showstopper for ATI users. */
+ if ( fNoSignedCatalogFound == 1
+ && g_uNtVerCombined < SUP_NT_VER_VISTA
+ && !fCoreSystemDll)
+ {
+ rc = VINF_LDRVI_NOT_SIGNED;
+ }
+ }
+
return rc;
}
@@ -2493,7 +2583,7 @@ DECLHIDDEN(int) supHardenedWinVerifyImageTrust(HANDLE hFile, PCRTUTF16 pwszName,
}
else
{
- uint32_t const idCurrentThread = GetCurrentThreadId();
+ uint32_t const idCurrentThread = RTNtCurrentThreadId();
fNoRecursion = ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX);
}
if (fNoRecursion)
@@ -2557,7 +2647,7 @@ DECLHIDDEN(bool) supHardenedWinIsWinVerifyTrustCallable(void)
return g_pfnWinVerifyTrust != NULL
&& ( g_iTlsWinVerifyTrustRecursion != UINT32_MAX
? (uintptr_t)TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0
- : g_idActiveThread != GetCurrentThreadId() );
+ : g_idActiveThread != RTNtCurrentThreadId() );
}
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
index 6312896..4d7c91c 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
@@ -128,6 +128,8 @@ typedef struct SUPHNTVPSTATE
{
/** Type of verification to perform. */
SUPHARDNTVPKIND enmKind;
+ /** Combination of SUPHARDNTVP_F_XXX. */
+ uint32_t fFlags;
/** The result. */
int rcResult;
/** Number of fixes we've done.
@@ -809,15 +811,14 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
* Get relocated bits.
*/
uint8_t *pbBits;
- rc = supHardNtLdrCacheEntryAllocBits(pImage->pCacheEntry, &pbBits, pThis->pErrInfo);
- if (RT_FAILURE(rc))
- return rc;
if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
- rc = RTLdrGetBits(pImage->pCacheEntry->hLdrMod, pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis);
+ rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis,
+ pThis->pErrInfo);
else
- rc = RTLdrGetBits(pImage->pCacheEntry->hLdrMod, pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis);
+ rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis,
+ pThis->pErrInfo);
if (RT_FAILURE(rc))
- return supHardNtVpSetInfo2(pThis, rc, "%s: RTLdrGetBits failed: %Rrc", pImage->pszName, rc);
+ return rc;
/* XP SP3 does not set ImageBase to load address. It fixes up the image on load time though. */
if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
@@ -843,26 +844,22 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
if (RT_FAILURE(rc))
return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
- aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64);
+ aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
/* Ignore our LdrLoadDll hack. */
rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrLoadDll", &uValue);
if (RT_FAILURE(rc))
return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrLoadDll': %Rrc", pImage->pszName, rc);
aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
- aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64);
+ aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
}
- if ( pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION
- || pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY)
- {
- /* Ignore our patched LdrInitializeThunk hack. */
- rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
- if (RT_FAILURE(rc))
- return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
- aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
- aSkipAreas[cSkipAreas++].cb = 10;
- }
+ /* Ignore our patched LdrInitializeThunk hack. */
+ rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
+ if (RT_FAILURE(rc))
+ return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
+ aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
+ aSkipAreas[cSkipAreas++].cb = 14;
/* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrSystemDllInitBlock", &uValue);
@@ -927,7 +924,9 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
break;
case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE:
fProt = PAGE_READWRITE;
- if (!suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll */
+ if ( pThis->enmKind != SUPHARDNTVPKIND_VERIFY_ONLY
+ && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION
+ && !suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll. Changed by proc init. */
fProt = PAGE_READONLY;
break;
case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE:
@@ -953,11 +952,14 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
pImage->pszName, i, pThis->aSecHdrs[i].Characteristics, uSectRva, cbMap);
}
- /* The section bits, only child purification verifies all bits . */
- if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
- || ( (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
+ /* The section bits. Child purification verifies all, normal
+ verification verifies all except where the executable is
+ concerned (due to opening vboxdrv during early process init). */
+ if ( ( (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
&& !(pThis->aSecHdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
- || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ)
+ || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ
+ || (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY && pImage->fDll)
+ || pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
{
rc = VINF_SUCCESS;
if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
@@ -1033,7 +1035,7 @@ static int supHardNtVpVerifyImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, H
* @param hThread The thread.
* @param pErrInfo Pointer to error info structure. Optional.
*/
-static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
{
/*
* Use the ThreadAmILastThread request to check that there is only one
@@ -1056,7 +1058,6 @@ static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInf
}
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
/**
* Verifies that there isn't a debugger attached to the process.
*
@@ -1064,8 +1065,9 @@ static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInf
* @param hProcess The process.
* @param pErrInfo Pointer to error info structure. Optional.
*/
-static int supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
{
+#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
/*
* Use the ProcessDebugPort request to check there is no debugger
* currently attached to the process.
@@ -1081,9 +1083,9 @@ static int supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
if (uPtr != 0)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_DEBUGGED,
"Debugger attached (%#zx)", uPtr);
+#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
return VINF_SUCCESS;
}
-#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
/**
@@ -1490,15 +1492,73 @@ static int supHardNtVpScanVirtualMemory(PSUPHNTVPSTATE pThis, HANDLE hProcess)
*/
if (MemInfo.Type == MEM_PRIVATE)
{
- SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
- uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
PVOID pvFree = MemInfo.BaseAddress;
SIZE_T cbFree = MemInfo.RegionSize;
- rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
- if (!NT_SUCCESS(rcNt))
- supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
- "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
- MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+ if (!(pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW))
+ {
+ SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
+ uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
+
+ rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
+ if (!NT_SUCCESS(rcNt))
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+ "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
+ MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+ }
+ else
+ {
+ /* The Trend Micro sakfile.sys and Digital Guardian dgmaster.sys BSOD kludge. */
+ SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Replacing exec mem at %p (%p LB %#zx)\n",
+ uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
+ void *pvCopy = RTMemAllocZ(cbFree);
+ if (pvCopy)
+ {
+ rcNt = supHardNtVpReadMem(pThis->hProcess, (uintptr_t)pvFree, pvCopy, cbFree);
+ if (!NT_SUCCESS(rcNt))
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+ "Error reading data from original alloc: %#x (%p LB %#zx)",
+ rcNt, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+
+ rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
+ if (NT_SUCCESS(rcNt))
+ {
+ pvFree = MemInfo.BaseAddress; cbFree = MemInfo.RegionSize; /* fudge */
+ NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE); /* fudge */
+
+ pvFree = MemInfo.BaseAddress;
+ cbFree = MemInfo.RegionSize;
+ rcNt = NtAllocateVirtualMemory(pThis->hProcess, &pvFree, 0, &cbFree, MEM_COMMIT, PAGE_READWRITE);
+ if (!NT_SUCCESS(rcNt))
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+ "NtAllocateVirtualMemory (%p LB %#zx) failed with rcNt=%#x allocating "
+ "replacement memory for working around buggy protection software. "
+ "See VBoxStartup.log for more details",
+ MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+ else if (pvFree != MemInfo.BaseAddress)
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+ "We wanted NtAllocateVirtualMemory to get us %p LB %#zx, but it returned %p LB %#zx.",
+ MemInfo.BaseAddress, MemInfo.RegionSize, pvFree, cbFree, rcNt);
+ else
+ {
+ SIZE_T cbWritten;
+ rcNt = NtWriteVirtualMemory(pThis->hProcess, MemInfo.BaseAddress, pvCopy, MemInfo.RegionSize,
+ &cbWritten);
+ if (!NT_SUCCESS(rcNt))
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+ "NtWriteVirtualMemory (%p LB %#zx) failed: %#x",
+ MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+ }
+ }
+ else
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+ "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
+ MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+ RTMemFree(pvCopy);
+ }
+ else
+ supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+ "RTMemAllocZ(%#zx) failed", MemInfo.RegionSize);
+ }
}
/*
* Unmap mapped memory, failing that, drop exec privileges.
@@ -1585,7 +1645,7 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUT
/**
- * Allocates a image bits buffer for use with RTLdrGetBits.
+ * Allocates a image bits buffer and calls RTLdrGetBits on them.
*
* An assumption here is that there won't ever be concurrent use of the cache.
* It's currently 104% single threaded, non-reentrant. Thus, we can't reuse the
@@ -1594,10 +1654,20 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUT
* @returns VBox status code
* @param pEntry The loader cache entry.
* @param ppbBits Where to return the pointer to the allocation.
- * @param pErRInfo Where to return extened error information.
+ * @param uBaseAddress The image base address, see RTLdrGetBits.
+ * @param pfnGetImport Import getter, see RTLdrGetBits.
+ * @param pvUser The user argument for @a pfnGetImport.
+ * @param pErrInfo Where to return extened error information.
*/
-DECLHIDDEN(int) supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtLdrCacheEntryGetBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits,
+ RTLDRADDR uBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
+ PRTERRINFO pErrInfo)
{
+ int rc;
+
+ /*
+ * First time around we have to allocate memory before we can get the image bits.
+ */
if (!pEntry->pbBits)
{
size_t cbBits = RTLdrSize(pEntry->hLdrMod);
@@ -1605,13 +1675,41 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uin
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_IMAGE_TOO_BIG, "Image %s is too large: %zu bytes (%#zx).",
pEntry->pszName, cbBits, cbBits);
- pEntry->pbBits = (uint8_t *)suplibHardenedAllocZ(cbBits);
+ pEntry->pbBits = (uint8_t *)RTMemAllocZ(cbBits);
if (!pEntry->pbBits)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "Failed to allocate %zu bytes for image %s.",
cbBits, pEntry->pszName);
+
+ pEntry->fValidBits = false; /* paranoia */
+
+ rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
+ if (RT_FAILURE(rc))
+ return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
+ pEntry->pszName, rc);
+ pEntry->uImageBase = uBaseAddress;
+ pEntry->fValidBits = pfnGetImport == NULL;
+
}
+ /*
+ * Cache hit? No?
+ *
+ * Note! We cannot currently cache image bits for images with imports as we
+ * don't control the way they're resolved. Fortunately, NTDLL and
+ * the VM process images all have no imports.
+ */
+ else if ( !pEntry->fValidBits
+ || pEntry->uImageBase != uBaseAddress
+ || pfnGetImport)
+ {
+ pEntry->fValidBits = false;
- /** @todo Try cache RTLdrGetBits calls too. */
+ rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
+ if (RT_FAILURE(rc))
+ return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
+ pEntry->pszName, rc);
+ pEntry->uImageBase = uBaseAddress;
+ pEntry->fValidBits = pfnGetImport == NULL;
+ }
*ppbBits = pEntry->pbBits;
return VINF_SUCCESS;
@@ -1628,7 +1726,7 @@ static void supHardNTLdrCacheDeleteEntry(PSUPHNTLDRCACHEENTRY pEntry)
{
if (pEntry->pbBits)
{
- suplibHardenedFree(pEntry->pbBits);
+ RTMemFree(pEntry->pbBits);
pEntry->pbBits = NULL;
}
@@ -1650,8 +1748,10 @@ static void supHardNTLdrCacheDeleteEntry(PSUPHNTLDRCACHEENTRY pEntry)
pEntry->hFile = NULL;
}
- pEntry->pszName = NULL;
- pEntry->fVerified = false;
+ pEntry->pszName = NULL;
+ pEntry->fVerified = false;
+ pEntry->fValidBits = false;
+ pEntry->uImageBase = 0;
}
#ifdef IN_RING3
@@ -1710,14 +1810,14 @@ static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *ps
#endif
NTSTATUS rcNt = NtCreateFile(&hFile,
- GENERIC_READ,
+ GENERIC_READ | SYNCHRONIZE,
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
- FILE_NON_DIRECTORY_FILE, /** @todo nonalert? */
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
@@ -1759,12 +1859,23 @@ static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *ps
/*
* Fill in the cache entry.
*/
- pEntry->pszName = pszName;
- pEntry->hLdrMod = hLdrMod;
- pEntry->pNtViRdr = pNtViRdr;
- pEntry->hFile = hFile;
- pEntry->pbBits = NULL;
- pEntry->fVerified = false;
+ pEntry->pszName = pszName;
+ pEntry->hLdrMod = hLdrMod;
+ pEntry->pNtViRdr = pNtViRdr;
+ pEntry->hFile = hFile;
+ pEntry->pbBits = NULL;
+ pEntry->fVerified = false;
+ pEntry->fValidBits = false;
+ pEntry->uImageBase = ~(uintptr_t)0;
+
+#ifdef IN_SUP_HARDENED_R3
+ /*
+ * Log the image timestamp when in the hardened exe.
+ */
+ uint64_t uTimestamp = 0;
+ rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uint64_t));
+ SUP_DPRINTF(("%s: timestamp %#llx (rc=%Rrc)\n", pszName, uTimestamp, rc));
+#endif
return VINF_SUCCESS;
}
@@ -1786,9 +1897,9 @@ DECLHIDDEN(int) supHardNtLdrCacheOpen(const char *pszName, PSUPHNTLDRCACHEENTRY
* Locate the dll.
*/
uint32_t i = 0;
- while (i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls))
- if (!strcmp(pszName, g_apszSupNtVpAllowedDlls[i]))
- break;
+ while ( i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls)
+ && strcmp(pszName, g_apszSupNtVpAllowedDlls[i]))
+ i++;
if (i >= RT_ELEMENTS(g_apszSupNtVpAllowedDlls))
return VERR_FILE_NOT_FOUND;
pszName = g_apszSupNtVpAllowedDlls[i];
@@ -1916,7 +2027,7 @@ static int supHardNtVpCheckExe(PSUPHNTVPSTATE pThis, HANDLE hProcess)
*/
int rc;
ULONG cbUniStr = sizeof(UNICODE_STRING) + RTPATH_MAX * sizeof(RTUTF16);
- PUNICODE_STRING pUniStr = (PUNICODE_STRING)suplibHardenedAllocZ(cbUniStr);
+ PUNICODE_STRING pUniStr = (PUNICODE_STRING)RTMemAllocZ(cbUniStr);
if (!pUniStr)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_MEMORY,
"Error allocating %zu bytes for process name.", cbUniStr);
@@ -1937,7 +2048,7 @@ static int supHardNtVpCheckExe(PSUPHNTVPSTATE pThis, HANDLE hProcess)
else
rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR,
"NtQueryInformationProcess/ProcessImageFileName failed: %#x", rcNt);
- suplibHardenedFree(pUniStr);
+ RTMemFree(pUniStr);
if (RT_FAILURE(rc))
return rc;
@@ -2032,7 +2143,7 @@ static int supHardNtVpCheckDlls(PSUPHNTVPSTATE pThis, HANDLE hProcess)
if (iNtDll == UINT32_MAX)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_NTDLL_MAPPING,
"The process has no NTDLL.DLL.");
- if (iKernel32 == UINT32_MAX && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
+ if (iKernel32 == UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_KERNEL32_MAPPING,
"The process has no KERNEL32.DLL.");
else if (iKernel32 != UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
@@ -2072,11 +2183,12 @@ static int supHardNtVpCheckDlls(PSUPHNTVPSTATE pThis, HANDLE hProcess)
* @param hProcess The process to verify.
* @param hThread A thread in the process (the caller).
* @param enmKind The kind of process verification to perform.
+ * @param fFlags Valid combination of SUPHARDNTVP_F_XXX flags.
* @param pErrInfo Pointer to error info structure. Optional.
* @param pcFixes Where to return the number of fixes made during
* purification. Optional.
*/
-DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind,
+DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, uint32_t fFlags,
uint32_t *pcFixes, PRTERRINFO pErrInfo)
{
if (pcFixes)
@@ -2089,19 +2201,18 @@ DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUP
int rc = VINF_SUCCESS;
if (enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
rc = supHardNtVpThread(hProcess, hThread, pErrInfo);
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
if (RT_SUCCESS(rc))
rc = supHardNtVpDebugger(hProcess, pErrInfo);
-#endif
if (RT_SUCCESS(rc))
{
/*
* Allocate and initialize memory for the state.
*/
- PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
+ PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)RTMemAllocZ(sizeof(*pThis));
if (pThis)
{
pThis->enmKind = enmKind;
+ pThis->fFlags = fFlags;
pThis->rcResult = VINF_SUCCESS;
pThis->hProcess = hProcess;
pThis->pErrInfo = pErrInfo;
@@ -2127,7 +2238,7 @@ DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUP
for (uint32_t i = 0; i < pThis->cImages; i++)
supHardNTLdrCacheDeleteEntry(&pThis->aImages[i].CacheEntry);
#endif
- suplibHardenedFree(pThis);
+ RTMemFree(pThis);
}
else
rc = supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY_STATE,
diff --git a/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
index 655c68a..99ef643 100644
--- a/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
@@ -109,14 +109,14 @@ int suplibOsHardenedVerifyTerm(void)
}
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Make sure the image verifier is fully initialized.
*/
int rc = suplibOsHardenedVerifyInit();
if (RT_FAILURE(rc))
- return rc;
+ return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc);
/*
* Done if of pre-inited.
@@ -157,70 +157,109 @@ int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
hDevice = RTNT_INVALID_HANDLE_VALUE;
NTSTATUS rcNt = NtCreateFile(&hDevice,
- GENERIC_READ | GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
- FILE_NON_DIRECTORY_FILE,
+ FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
rcNt = Ios.Status;
- if (!NT_SUCCESS(rcNt))
+ if (NT_SUCCESS(rcNt))
{
-#ifndef IN_SUP_HARDENED_R3
/*
- * Failed to open, try starting the service and reopen the device
- * exactly once.
+ * We're good.
*/
- if (cTry == 0 && !NT_SUCCESS(rcNt))
- {
- cTry++;
- suplibOsStartService();
- continue;
- }
+ pThis->hDevice = hDevice;
+ pThis->fUnrestricted = fUnrestricted;
+ return VINF_SUCCESS;
+ }
+
+#ifndef IN_SUP_HARDENED_R3
+ /*
+ * Failed to open, try starting the service and reopen the device
+ * exactly once.
+ */
+ if (cTry == 0 && !NT_SUCCESS(rcNt))
+ {
+ cTry++;
+ suplibOsStartService();
+ continue;
+ }
#endif
- switch (rcNt)
+
+ /*
+ * Translate the error code.
+ */
+ switch (rcNt)
+ {
+ /** @todo someone must test what is actually returned. */
+ case STATUS_DEVICE_DOES_NOT_EXIST:
+ case STATUS_DEVICE_NOT_CONNECTED:
+ //case ERROR_BAD_DEVICE:
+ case STATUS_DEVICE_REMOVED:
+ //case ERROR_DEVICE_NOT_AVAILABLE:
+ rc = VERR_VM_DRIVER_LOAD_ERROR;
+ break;
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ rc = VERR_VM_DRIVER_NOT_INSTALLED;
+ break;
+ case STATUS_ACCESS_DENIED:
+ case STATUS_SHARING_VIOLATION:
+ rc = VERR_VM_DRIVER_NOT_ACCESSIBLE;
+ break;
+ case STATUS_UNSUCCESSFUL:
+ rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
+ break;
+ case STATUS_TRUST_FAILURE:
+ rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
+ break;
+ case STATUS_TOO_LATE:
+ rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+ break;
+ default:
+ if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
+ rc = SUP_NT_STATUS_TO_VBOX(rcNt);
+ else
+ rc = VERR_VM_DRIVER_OPEN_ERROR;
+ break;
+ }
+
+#ifdef IN_SUP_HARDENED_R3
+ /*
+ * Get more details from VBoxDrvErrorInfo if present.
+ */
+ if (pErrInfo && pErrInfo->cbMsg > 32)
+ {
+ /* Prefix. */
+ size_t cchPrefix;
+ const char *pszDefine = RTErrGetDefine(rc);
+ if (strncmp(pszDefine, RT_STR_TUPLE("Unknown")))
+ cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%s): ", rcNt, pszDefine);
+ else
+ cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc);
+
+ /* Get error info. */
+ supR3HardenedWinReadErrorInfoDevice(pErrInfo->pszMsg + cchPrefix, pErrInfo->cbMsg - cchPrefix, "");
+ if (pErrInfo->pszMsg[cchPrefix] != '\0')
{
- /** @todo someone must test what is actually returned. */
- case STATUS_DEVICE_DOES_NOT_EXIST:
- case STATUS_DEVICE_NOT_CONNECTED:
- //case ERROR_BAD_DEVICE:
- case STATUS_DEVICE_REMOVED:
- //case ERROR_DEVICE_NOT_AVAILABLE:
- return VERR_VM_DRIVER_LOAD_ERROR;
- case STATUS_OBJECT_PATH_NOT_FOUND:
- case STATUS_NO_SUCH_DEVICE:
- case STATUS_NO_SUCH_FILE:
- case STATUS_OBJECT_NAME_NOT_FOUND:
- return VERR_VM_DRIVER_NOT_INSTALLED;
- case STATUS_ACCESS_DENIED:
- case STATUS_SHARING_VIOLATION:
- return VERR_VM_DRIVER_NOT_ACCESSIBLE;
- case STATUS_UNSUCCESSFUL:
- return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
- case STATUS_TRUST_FAILURE:
- return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
- case STATUS_TOO_LATE:
- return VERR_SUPDRV_HARDENING_EVIL_HANDLE;
- default:
- if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
- return SUP_NT_STATUS_TO_VBOX(rcNt);
- return VERR_VM_DRIVER_OPEN_ERROR;
+ pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
+ pErrInfo->rc = rc;
+ *penmWhat = kSupInitOp_Integrity;
}
+ else
+ pErrInfo->pszMsg[0] = '\0';
}
- break;
+#endif
+ return rc;
}
-
- /*
- * We're done.
- */
- pThis->hDevice = hDevice;
- pThis->fUnrestricted = fUnrestricted;
- return VINF_SUCCESS;
}
@@ -364,6 +403,8 @@ static int suplibOsStopService(void)
}
CloseServiceHandle(hSMgr);
}
+ else
+ rc = RTErrConvertFromWin32(dwErr);
return rc;
}
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
index 29c8eae..5f7b467 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
@@ -91,7 +91,7 @@
do { \
BOOL fRcAssert = (a_Expr); \
if (fRcAssert == FALSE) \
- supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, GetLastError()); \
+ supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, RtlGetLastWin32Error()); \
} while (0)
@@ -173,9 +173,95 @@ typedef struct VERIFIERCACHEIMPORT
typedef VERIFIERCACHEIMPORT *PVERIFIERCACHEIMPORT;
+/**
+ * Child requests.
+ */
+typedef enum SUPR3WINCHILDREQ
+{
+ /** Perform child purification and close full access handles (must be zero). */
+ kSupR3WinChildReq_PurifyChildAndCloseHandles = 0,
+ /** Close the events, we're good on our own from here on. */
+ kSupR3WinChildReq_CloseEvents,
+ /** Reporting error. */
+ kSupR3WinChildReq_Error,
+ /** End of valid requests. */
+ kSupR3WinChildReq_End
+} SUPR3WINCHILDREQ;
+
+/**
+ * Child process parameters.
+ */
+typedef struct SUPR3WINPROCPARAMS
+{
+ /** The event semaphore the child will be waiting on. */
+ HANDLE hEvtChild;
+ /** The event semaphore the parent will be waiting on. */
+ HANDLE hEvtParent;
+
+ /** The address of the NTDLL. This is only valid during the very early
+ * initialization as we abuse for thread creation protection. */
+ uintptr_t uNtDllAddr;
+
+ /** The requested operation (set by the child). */
+ SUPR3WINCHILDREQ enmRequest;
+ /** The last status. */
+ int32_t rc;
+ /** The init operation the error relates to if message, kSupInitOp_Invalid if
+ * not message. */
+ SUPINITOP enmWhat;
+ /** Where if message. */
+ char szWhere[80];
+ /** Error message / path name string space. */
+ char szErrorMsg[4096];
+} SUPR3WINPROCPARAMS;
+
+
+/**
+ * Child process data structure for use during child process init setup and
+ * purification.
+ */
+typedef struct SUPR3HARDNTCHILD
+{
+ /** Process handle. */
+ HANDLE hProcess;
+ /** Primary thread handle. */
+ HANDLE hThread;
+ /** Handle to the parent process, if we're the middle (stub) process. */
+ HANDLE hParent;
+ /** The event semaphore the child will be waiting on. */
+ HANDLE hEvtChild;
+ /** The event semaphore the parent will be waiting on. */
+ HANDLE hEvtParent;
+ /** The address of NTDLL in the child. */
+ uintptr_t uNtDllAddr;
+ /** The address of NTDLL in this process. */
+ uintptr_t uNtDllParentAddr;
+ /** Which respawn number this is (1 = stub, 2 = VM). */
+ int iWhich;
+ /** The basic process info. */
+ PROCESS_BASIC_INFORMATION BasicInfo;
+ /** The probable size of the PEB. */
+ size_t cbPeb;
+ /** The pristine process environment block. */
+ PEB Peb;
+ /** The child process parameters. */
+ SUPR3WINPROCPARAMS ProcParams;
+} SUPR3HARDNTCHILD;
+/** Pointer to a child process data structure. */
+typedef SUPR3HARDNTCHILD *PSUPR3HARDNTCHILD;
+
+
/*******************************************************************************
* Global Variables *
*******************************************************************************/
+/** Process parameters. Specified by parent if VM process, see
+ * supR3HardenedVmProcessInit. */
+static SUPR3WINPROCPARAMS g_ProcParams = { NULL, NULL, 0, (SUPR3WINCHILDREQ)0, 0 };
+/** Set if supR3HardenedEarlyProcessInit was invoked. */
+bool g_fSupEarlyProcessInit = false;
+/** Set if the stub device has been opened (stub process only). */
+bool g_fSupStubOpened = false;
+
/** @name Global variables initialized by suplibHardenedWindowsMain.
* @{ */
/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
@@ -194,27 +280,40 @@ uint32_t g_offSupLibHardenedExeNtName;
/** @name Hook related variables.
* @{ */
-/** The jump back address of the patched NtCreateSection. */
-extern "C" PFNRT g_pfnNtCreateSectionJmpBack = NULL;
/** Pointer to the bit of assembly code that will perform the original
* NtCreateSection operation. */
static NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
PLARGE_INTEGER, ULONG, ULONG, HANDLE);
-#if 0
-/** The jump back address of the patched LdrLoadDll. */
-extern "C" PFNRT g_pfnLdrLoadDllJmpBack = NULL;
-#endif
+/** Pointer to the NtCreateSection function in NtDll (for patching purposes). */
+static uint8_t *g_pbNtCreateSection;
+/** The patched NtCreateSection bytes (for restoring). */
+static uint8_t g_abNtCreateSectionPatch[16];
/** Pointer to the bit of assembly code that will perform the original
* LdrLoadDll operation. */
static NTSTATUS (NTAPI * g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
+/** Pointer to the LdrLoadDll function in NtDll (for patching purposes). */
+static uint8_t *g_pbLdrLoadDll;
+/** The patched LdrLoadDll bytes (for restoring). */
+static uint8_t g_abLdrLoadDllPatch[16];
+
/** The hash table of verifier cache . */
static PVERIFIERCACHEENTRY volatile g_apVerifierCache[128];
/** Queue of cached images which needs WinVerifyTrust to check them. */
static PVERIFIERCACHEENTRY volatile g_pVerifierCacheTodoWvt = NULL;
/** Queue of cached images which needs their imports checked. */
static PVERIFIERCACHEIMPORT volatile g_pVerifierCacheTodoImports = NULL;
+
+/** The windows path to dir \\SystemRoot\\System32 directory (technically
+ * this whatever \KnownDlls\KnownDllPath points to). */
+SUPSYSROOTDIRBUF g_System32WinPath;
/** @ */
+/** Positive if the DLL notification callback has been registered, counts
+ * registration attempts as negative. */
+static int g_cDllNotificationRegistered = 0;
+/** The registration cookie of the DLL notification callback. */
+static PVOID g_pvDllNotificationCookie = NULL;
+
/** Static error info structure used during init. */
static RTERRINFOSTATIC g_ErrInfoStatic;
@@ -228,6 +327,42 @@ static bool g_fSupInitThunkSelfPatched;
* thread creation in this process. */
static uint8_t g_abLdrInitThunkSelfBackup[16];
+/** Mask of adversaries that we've detected (SUPHARDNT_ADVERSARY_XXX). */
+static uint32_t g_fSupAdversaries = 0;
+/** @name SUPHARDNT_ADVERSARY_XXX - Adversaries
+ * @{ */
+/** Symantec endpoint protection or similar including SysPlant.sys. */
+#define SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT RT_BIT_32(0)
+/** Symantec Norton 360. */
+#define SUPHARDNT_ADVERSARY_SYMANTEC_N360 RT_BIT_32(1)
+/** Avast! */
+#define SUPHARDNT_ADVERSARY_AVAST RT_BIT_32(2)
+/** TrendMicro OfficeScan and probably others. */
+#define SUPHARDNT_ADVERSARY_TRENDMICRO RT_BIT_32(3)
+/** TrendMicro potentially buggy sakfile.sys. */
+#define SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE RT_BIT_32(4)
+/** McAfee. */
+#define SUPHARDNT_ADVERSARY_MCAFEE RT_BIT_32(5)
+/** Kaspersky or OEMs of it. */
+#define SUPHARDNT_ADVERSARY_KASPERSKY RT_BIT_32(6)
+/** Malwarebytes Anti-Malware (MBAM). */
+#define SUPHARDNT_ADVERSARY_MBAM RT_BIT_32(7)
+/** AVG Internet Security. */
+#define SUPHARDNT_ADVERSARY_AVG RT_BIT_32(8)
+/** Panda Security. */
+#define SUPHARDNT_ADVERSARY_PANDA RT_BIT_32(9)
+/** Microsoft Security Essentials. */
+#define SUPHARDNT_ADVERSARY_MSE RT_BIT_32(10)
+/** Comodo. */
+#define SUPHARDNT_ADVERSARY_COMODO RT_BIT_32(11)
+/** Check Point's Zone Alarm (may include Kaspersky). */
+#define SUPHARDNT_ADVERSARY_ZONE_ALARM RT_BIT_32(12)
+/** Digital guardian. */
+#define SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN RT_BIT_32(13)
+/** Unknown adversary detected while waiting on child. */
+#define SUPHARDNT_ADVERSARY_UNKNOWN RT_BIT_32(31)
+/** @} */
+
/*******************************************************************************
* Internal Functions *
@@ -235,17 +370,9 @@ static uint8_t g_abLdrInitThunkSelfBackup[16];
static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
bool *pfQuietFailure);
-
-#ifdef RT_ARCH_AMD64
-# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
-# include "NtCreateSection-template-amd64-syscall-type-1.h"
-# undef SYSCALL
-#endif
-#ifdef RT_ARCH_X86
-# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
-# include "NtCreateSection-template-x86-syscall-type-1.h"
-# undef SYSCALL
-#endif
+static void supR3HardenedWinRegisterDllNotificationCallback(void);
+static void supR3HardenedWinReInstallHooks(bool fFirst);
+DECLASM(void) supR3HardenedEarlyProcessInitThunk(void);
@@ -288,52 +415,25 @@ static size_t suplibHardenedWStrLen(PCRTUTF16 pwsz)
/**
- * Allocate zero filled memory on the heap.
- *
- * @returns Pointer to the memory. Will never return NULL, triggers a fatal
- * error instead.
- * @param cb The number of bytes to allocate.
+ * Our version of GetTickCount.
+ * @returns Millisecond timestamp.
*/
-DECLHIDDEN(void *) suplibHardenedAllocZ(size_t cb)
+static uint64_t supR3HardenedWinGetMilliTS(void)
{
- void *pv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
- if (!pv)
- supR3HardenedFatal("HeapAlloc failed to allocate %zu bytes.\n", cb);
- return pv;
-}
+ PKUSER_SHARED_DATA pUserSharedData = (PKUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
+ /* use interrupt time */
+ LARGE_INTEGER Time;
+ do
+ {
+ Time.HighPart = pUserSharedData->InterruptTime.High1Time;
+ Time.LowPart = pUserSharedData->InterruptTime.LowPart;
+ } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart);
-/**
- * Reallocates memory on the heap.
- *
- * @returns Pointer to the resized memory block. Will never return NULL,
- * triggers a fatal error instead.
- * @param pvOld The old memory block.
- * @param cbNew The new block size.
- */
-DECLHIDDEN(void *) suplibHardenedReAlloc(void *pvOld, size_t cbNew)
-{
- if (!pvOld)
- return suplibHardenedAllocZ(cbNew);
- void *pv = HeapReAlloc(GetProcessHeap(), 0 /*dwFlags*/, pvOld, cbNew);
- if (!pv)
- supR3HardenedFatal("HeapReAlloc failed to allocate %zu bytes.\n", cbNew);
- return pv;
+ return (uint64_t)Time.QuadPart / 10000;
}
-/**
- * Frees memory allocated by suplibHardenedAlloc, suplibHardenedAllocZ or
- * suplibHardenedReAlloc.
- *
- * @param pv Pointer to the memeory to be freed.
- */
-DECLHIDDEN(void) suplibHardenedFree(void *pv)
-{
- if (pv)
- HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pv);
-}
-
/**
* Wrapper around LoadLibraryEx that deals with the UTF-8 to UTF-16 conversion
@@ -373,7 +473,7 @@ DECLHIDDEN(void *) supR3HardenedWinLoadLibrary(const char *pszName, bool fSystem
if ( !pvRet
&& fFlags
&& g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
- && GetLastError() == ERROR_INVALID_PARAMETER)
+ && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, 0);
return pvRet;
@@ -482,8 +582,8 @@ static bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 paw
RTUTF16 wcRight = *pawcRight++;
if (wcLeft != wcRight)
{
- wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\';
- wcLeft = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
+ wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\';
+ wcRight = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
if (wcLeft != wcRight)
return false;
}
@@ -510,8 +610,7 @@ static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE h
/*
* Allocate and initalize a new entry.
*/
- PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
+ PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)RTMemAllocZ(sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
if (pEntry)
{
pEntry->pNext = NULL;
@@ -556,7 +655,7 @@ static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE h
}
/* Duplicate entry (may happen due to races). */
- HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pEntry);
+ RTMemFree(pEntry);
}
NtClose(hFile);
}
@@ -728,7 +827,7 @@ DECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PC
uint32_t cbNameAligned = RT_ALIGN_32(cbName, sizeof(RTUTF16));
uint32_t cbNeeded = RT_OFFSETOF(VERIFIERCACHEIMPORT, szName[cbNameAligned])
+ (pawcDir ? (cwcDir + 1) * sizeof(RTUTF16) : 0);
- PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeeded);
+ PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)RTMemAllocZ(cbNeeded);
if (pImport)
{
/* Init it. */
@@ -800,6 +899,7 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Processing '%s'...\n", pCur->szName));
NTSTATUS rcNt;
+ NTSTATUS rcNtRedir = 0x22222222;
HANDLE hFile = INVALID_HANDLE_VALUE;
RTUTF16 wszPath[260 + 260]; /* Assumes we've limited the import name length to 256. */
AssertCompile(sizeof(wszPath) > sizeof(g_System32NtPath));
@@ -826,18 +926,18 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
UNICODE_STRING UniStrDynamic = { 0, 0, NULL };
PUNICODE_STRING pUniStrResult = NULL;
- rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
- &UniStrName,
- (PUNICODE_STRING)&s_DefaultSuffix,
- &UniStrStatic,
- &UniStrDynamic,
- &pUniStrResult,
- NULL /*pNewFlags*/,
- NULL /*pcbFilename*/,
- NULL /*pcbNeeded*/);
- if (NT_SUCCESS(rcNt))
+ rcNtRedir = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
+ &UniStrName,
+ (PUNICODE_STRING)&s_DefaultSuffix,
+ &UniStrStatic,
+ &UniStrDynamic,
+ &pUniStrResult,
+ NULL /*pNewFlags*/,
+ NULL /*pcbFilename*/,
+ NULL /*pcbNeeded*/);
+ if (NT_SUCCESS(rcNtRedir))
{
- IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, pUniStrResult,
OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
@@ -854,7 +954,14 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
rcNt = Ios.Status;
- if (!NT_SUCCESS(rcNt))
+ if (NT_SUCCESS(rcNt))
+ {
+ /* For accurate logging. */
+ size_t cwcCopy = RT_MIN(pUniStrResult->Length / sizeof(RTUTF16), RT_ELEMENTS(wszPath) - 1);
+ memcpy(wszPath, pUniStrResult->Buffer, cwcCopy * sizeof(RTUTF16));
+ wszPath[cwcCopy] = '\0';
+ }
+ else
hFile = INVALID_HANDLE_VALUE;
RtlFreeUnicodeString(&UniStrDynamic);
}
@@ -937,7 +1044,8 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
*/
if (hFile != INVALID_HANDLE_VALUE)
{
- SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls'\n", pCur->szName, wszPath));
+ SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls' [rcNtRedir=%#x]\n",
+ pCur->szName, wszPath, rcNtRedir));
ULONG fAccess = 0;
ULONG fProtect = 0;
@@ -952,7 +1060,7 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
else
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName));
- HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pCur);
+ RTMemFree(pCur);
} while (pTodo);
}
}
@@ -1076,7 +1184,7 @@ static void supR3HardenedWinFix8dot3Path(HANDLE hFile, PUNICODE_STRING pUniStr)
RTUTF16 wc;
PRTUTF16 pwszFixEnd = pwszFix;
- while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '//')
+ while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '/')
pwszFixEnd++;
if (wc == '\0')
break;
@@ -1442,7 +1550,7 @@ static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAcc
"supR3HardenedScreenImage/%s: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n",
pszCaller, rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg);
if (hMyFile != hFile)
- NtClose(hMyFile);
+ supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fWinVerifyTrust, fFlags);
return STATUS_TRUST_FAILURE;
}
@@ -1534,7 +1642,7 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
| PAGE_EXECUTE_READWRITE));
if (fImage || fExecMap || fExecProt)
{
- DWORD dwSavedLastError = GetLastError();
+ DWORD dwSavedLastError = RtlGetLastWin32Error();
bool fCallRealApi;
//SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 1\n"));
@@ -1542,7 +1650,7 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
"NtCreateSection", true /*fAvoidWinVerifyTrust*/, NULL /*pfQuietFailure*/);
//SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
- SetLastError(dwSavedLastError);
+ RtlRestoreLastWin32Error(dwSavedLastError);
if (!NT_SUCCESS(rcNt))
return rcNt;
@@ -1561,6 +1669,40 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
/**
+ * Helper for supR3HardenedMonitor_LdrLoadDll.
+ *
+ * @returns NT status code.
+ * @param pwszPath The path destination buffer.
+ * @param cwcPath The size of the path buffer.
+ * @param pUniStrResult The result string.
+ * @param pOrgName The orignal name (for errors).
+ * @param pcwc Where to return the actual length.
+ */
+static NTSTATUS supR3HardenedCopyRedirectionResult(WCHAR *pwszPath, size_t cwcPath, PUNICODE_STRING pUniStrResult,
+ PUNICODE_STRING pOrgName, UINT *pcwc)
+{
+ UINT cwc;
+ *pcwc = cwc = pUniStrResult->Length / sizeof(WCHAR);
+ if (pUniStrResult->Buffer == pwszPath)
+ pwszPath[cwc] = '\0';
+ else
+ {
+ if (cwc > cwcPath - 1)
+ {
+ supR3HardenedError(VINF_SUCCESS, false,
+ "supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
+ pOrgName->Length / sizeof(WCHAR), pOrgName->Buffer,
+ pUniStrResult->Length / sizeof(WCHAR), pUniStrResult->Buffer);
+ return STATUS_NAME_TOO_LONG;
+ }
+ memcpy(&pwszPath[0], pUniStrResult->Buffer, pUniStrResult->Length);
+ pwszPath[cwc] = '\0';
+ }
+ return STATUS_SUCCESS;
+}
+
+
+/**
* Hooks that intercepts LdrLoadDll calls.
*
* Two purposes:
@@ -1580,10 +1722,20 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
static NTSTATUS NTAPI
supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod)
{
- DWORD dwSavedLastError = GetLastError();
+ DWORD dwSavedLastError = RtlGetLastWin32Error();
NTSTATUS rcNt;
/*
+ * Make sure the DLL notification callback is registered. If we could, we
+ * would've done this during early process init, but due to lack of heap
+ * and uninitialized loader lock, it's not possible that early on.
+ *
+ * The callback protects our NtDll hooks from getting unhooked by
+ * "friendly" fire from the AV crowd.
+ */
+ supR3HardenedWinRegisterDllNotificationCallback();
+
+ /*
* Process WinVerifyTrust todo before and after.
*/
supR3HardenedWinVerifyCacheProcessWvtTodos();
@@ -1594,12 +1746,13 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
if (!pName || pName->Length == 0)
{
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n");
- SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_INVALID_PARAMETER));
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x (pName=%p)\n", STATUS_INVALID_PARAMETER, pName));
+ RtlRestoreLastWin32Error(dwSavedLastError);
return STATUS_INVALID_PARAMETER;
}
- SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls\n",
+ /*SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls\n",
(unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
- !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
+ !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));*/
/*
* Reject long paths that's close to the 260 limit without looking.
@@ -1608,6 +1761,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
{
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length);
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
+ RtlRestoreLastWin32Error(dwSavedLastError);
return STATUS_NAME_TOO_LONG;
}
@@ -1616,7 +1770,12 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
*/
bool fSkipValidation = false;
WCHAR wszPath[260];
+ static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
+ UNICODE_STRING UniStrStatic = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
+ UNICODE_STRING UniStrDynamic = { 0, 0, NULL };
+ PUNICODE_STRING pUniStrResult = NULL;
UNICODE_STRING ResolvedName;
+
if ( ( pName->Length >= 4 * sizeof(WCHAR)
&& RT_C_IS_ALPHA(pName->Buffer[0])
&& pName->Buffer[1] == ':'
@@ -1625,8 +1784,41 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
&& RTPATH_IS_SLASH(pName->Buffer[1]) )
)
{
- memcpy(wszPath, pName->Buffer, pName->Length);
- wszPath[pName->Length / sizeof(WCHAR)] = '\0';
+ rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
+ pName,
+ (PUNICODE_STRING)&s_DefaultSuffix,
+ &UniStrStatic,
+ &UniStrDynamic,
+ &pUniStrResult,
+ NULL /*pNewFlags*/,
+ NULL /*pcbFilename*/,
+ NULL /*pcbNeeded*/);
+ if (NT_SUCCESS(rcNt))
+ {
+ UINT cwc;
+ rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
+ RtlFreeUnicodeString(&UniStrDynamic);
+ if (!NT_SUCCESS(rcNt))
+ {
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
+ RtlRestoreLastWin32Error(dwSavedLastError);
+ return rcNt;
+ }
+
+ ResolvedName.Buffer = wszPath;
+ ResolvedName.Length = (USHORT)(cwc * sizeof(WCHAR));
+ ResolvedName.MaximumLength = ResolvedName.Length + sizeof(WCHAR);
+
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: '%.*ls' -> '%.*ls' [redir]\n",
+ (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer,
+ ResolvedName.Length / sizeof(WCHAR), ResolvedName.Buffer, rcNt));
+ pName = &ResolvedName;
+ }
+ else
+ {
+ memcpy(wszPath, pName->Buffer, pName->Length);
+ wszPath[pName->Length / sizeof(WCHAR)] = '\0';
+ }
}
/*
* Not an absolute path. Check if it's one of those special API set DLLs
@@ -1678,6 +1870,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
"supR3HardenedMonitor_LdrLoadDll: relative name not permitted: %.*ls\n",
cwcName, pawcName);
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_OBJECT_NAME_INVALID));
+ RtlRestoreLastWin32Error(dwSavedLastError);
return STATUS_OBJECT_NAME_INVALID;
}
@@ -1686,11 +1879,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
* API here, which as always is a bit risky... ASSUMES that the API
* returns a full DOS path.
*/
- UINT cwc;
- static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
- UNICODE_STRING UniStrStatic = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
- UNICODE_STRING UniStrDynamic = { 0, 0, NULL };
- PUNICODE_STRING pUniStrResult = NULL;
+ UINT cwc;
rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
pName,
(PUNICODE_STRING)&s_DefaultSuffix,
@@ -1702,25 +1891,14 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
NULL /*pcbNeeded*/);
if (NT_SUCCESS(rcNt))
{
- cwc = pUniStrResult->Length / sizeof(WCHAR);
- if (pUniStrResult != &UniStrDynamic)
- wszPath[cwc] = '\0';
- else
+ rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
+ RtlFreeUnicodeString(&UniStrDynamic);
+ if (!NT_SUCCESS(rcNt))
{
- if (pUniStrResult->Length > sizeof(wszPath) - sizeof(WCHAR))
- {
- supR3HardenedError(VINF_SUCCESS, false,
- "supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
- pName->Length / sizeof(WCHAR), pName->Buffer,
- pUniStrResult->Length / sizeof(WCHAR), pUniStrResult->Buffer);
- RtlFreeUnicodeString(&UniStrDynamic);
- SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
- return STATUS_NAME_TOO_LONG;
- }
- memcpy(&wszPath[0], pUniStrResult->Buffer, pUniStrResult->Length);
- wszPath[cwc] = '\0';
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
+ RtlRestoreLastWin32Error(dwSavedLastError);
+ return rcNt;
}
- RtlFreeUnicodeString(&UniStrDynamic);
}
else
{
@@ -1728,21 +1906,17 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
* Search for the DLL. Only System32 is allowed as the target of
* a search on the API level, all VBox calls will have full paths.
*/
- cwc = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath) - 32);
- if (!cwc)
- {
- supR3HardenedError(VINF_SUCCESS, false,
- "supR3HardenedMonitor_LdrLoadDll: GetSystemDirectoryW failed: %u\n", GetLastError());
- SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_UNEXPECTED_IO_ERROR));
- return STATUS_UNEXPECTED_IO_ERROR;
- }
+ AssertCompile(sizeof(g_System32WinPath.awcBuffer) <= sizeof(wszPath));
+ cwc = g_System32WinPath.UniStr.Length / sizeof(RTUTF16); Assert(cwc > 2);
if (cwc + 1 + cwcName + fNeedDllSuffix * 4 >= RT_ELEMENTS(wszPath))
{
supR3HardenedError(VINF_SUCCESS, false,
"supR3HardenedMonitor_LdrLoadDll: Name too long (system32): %.*ls\n", cwcName, pawcName);
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
+ RtlRestoreLastWin32Error(dwSavedLastError);
return STATUS_NAME_TOO_LONG;
}
+ memcpy(wszPath, g_System32WinPath.UniStr.Buffer, cwc * sizeof(RTUTF16));
wszPath[cwc++] = '\\';
memcpy(&wszPath[cwc], pawcName, cwcName * sizeof(WCHAR));
cwc += cwcName;
@@ -1772,9 +1946,37 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
* the real API as we've replaced any searchable name with a full name
* and the real API can come up with a fitting status code for it.
*/
- HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
- if (hFile != INVALID_HANDLE_VALUE)
+ HANDLE hRootDir;
+ UNICODE_STRING NtPathUniStr;
+ int rc = RTNtPathFromWinUtf16Ex(&NtPathUniStr, &hRootDir, wszPath, RTSTR_MAX);
+ if (RT_FAILURE(rc))
+ {
+ supR3HardenedError(rc, false,
+ "supR3HardenedMonitor_LdrLoadDll: RTNtPathFromWinUtf16Ex failed on '%ls': %Rrc\n", wszPath, rc);
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_OBJECT_NAME_INVALID));
+ RtlRestoreLastWin32Error(dwSavedLastError);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
+
+ rcNt = NtCreateFile(&hFile,
+ FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
+ &ObjAttr,
+ &Ios,
+ NULL /* Allocation Size*/,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ rcNt = Ios.Status;
+ if (NT_SUCCESS(rcNt))
{
ULONG fAccess = 0;
ULONG fProtect = 0;
@@ -1791,6 +1993,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
wszPath, rcNt);
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
}
+ RtlRestoreLastWin32Error(dwSavedLastError);
return rcNt;
}
@@ -1798,142 +2001,187 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
}
else
{
- DWORD dwErr = GetLastError();
- SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u\n", wszPath, dwErr));
+ DWORD dwErr = RtlGetLastWin32Error();
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u (NtPath=%.*ls)\n",
+ wszPath, dwErr, NtPathUniStr.Length / sizeof(RTUTF16), NtPathUniStr.Buffer));
}
+ RTNtPathFree(&NtPathUniStr, &hRootDir);
}
/*
* Screened successfully enough. Call the real thing.
*/
- SetLastError(dwSavedLastError);
+ SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
+ (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
+ !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
+ RtlRestoreLastWin32Error(dwSavedLastError);
rcNt = g_pfnLdrLoadDllReal(pwszSearchPath, pfFlags, pName, phMod);
/*
* Log the result and process pending WinVerifyTrust work if we can.
*/
- dwSavedLastError = GetLastError();
+ dwSavedLastError = RtlGetLastWin32Error();
if (NT_SUCCESS(rcNt) && phMod)
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath));
else
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
+
supR3HardenedWinVerifyCacheProcessWvtTodos();
- SetLastError(dwSavedLastError);
+ RtlRestoreLastWin32Error(dwSavedLastError);
return rcNt;
}
-#ifdef RT_ARCH_AMD64
/**
- * Tries to allocate memory between @a uStart and @a uEnd.
+ * DLL load and unload notification callback.
+ *
+ * This is a safety against our LdrLoadDll hook being replaced by protection
+ * software. Though, we prefer the LdrLoadDll hook to this one as it allows us
+ * to call WinVerifyTrust more freely.
*
- * @returns Pointer to the memory on success. NULL on failure.
- * @param uStart The start address.
- * @param uEnd The end address. This is lower than @a uStart
- * if @a iDirection is negative, and higher if
- * positive.
- * @param iDirection The search direction.
- * @param cbAlloc The number of bytes to allocate.
+ * @param ulReason The reason we're called, see
+ * LDR_DLL_NOTIFICATION_REASON_XXX.
+ * @param pData Reason specific data. (Format is currently the same for
+ * both load and unload.)
+ * @param pvUser User parameter (ignored).
+ *
+ * @remarks Vista and later.
+ * @remarks The loader lock is held when we're called, at least on Windows 7.
*/
-static void *supR3HardenedWinAllocHookMemory(uintptr_t uStart, uintptr_t uEnd, intptr_t iDirection, size_t cbAlloc)
+static VOID CALLBACK supR3HardenedDllNotificationCallback(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser)
{
- size_t const cbAllocGranularity = _64K;
- size_t const uAllocGranularityMask = ~(cbAllocGranularity - 1);
- HANDLE const hProc = NtCurrentProcess();
+ NOREF(pvUser);
/*
- * Make uEnd the last valid return address.
+ * Screen the image on load. We will normally get a verification cache
+ * hit here because of the LdrLoadDll and NtCreateSection hooks, so it
+ * should be relatively cheap to recheck. In case our NtDll patches
+ * got re
+ *
+ * This ASSUMES that we get informed after the fact as indicated by the
+ * available documentation.
*/
- if (iDirection > 0)
+ if (ulReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
{
- SUPR3HARDENED_ASSERT(uEnd > cbAlloc);
- uEnd -= cbAlloc;
- uEnd &= uAllocGranularityMask;
- }
- else
- uEnd = RT_ALIGN_Z(uEnd, cbAllocGranularity);
+ SUP_DPRINTF(("supR3HardenedDllNotificationCallback: load %p LB %#010x %.*ls [fFlags=%#x]\n",
+ pData->Loaded.DllBase, pData->Loaded.SizeOfImage,
+ pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+ pData->Loaded.Flags));
+
+ /* Convert the windows path to an NT path and open it. */
+ HANDLE hRootDir;
+ UNICODE_STRING NtPathUniStr;
+ int rc = RTNtPathFromWinUtf16Ex(&NtPathUniStr, &hRootDir, pData->Loaded.FullDllName->Buffer,
+ pData->Loaded.FullDllName->Length / sizeof(WCHAR));
+ if (RT_FAILURE(rc))
+ {
+ supR3HardenedFatal("supR3HardenedDllNotificationCallback: RTNtPathFromWinUtf16Ex failed on '%.*ls': %Rrc\n",
+ pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer, rc);
+ return;
+ }
+
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
+
+ NTSTATUS rcNt = NtCreateFile(&hFile,
+ FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
+ &ObjAttr,
+ &Ios,
+ NULL /* Allocation Size*/,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ rcNt = Ios.Status;
+ if (!NT_SUCCESS(rcNt))
+ {
+ supR3HardenedFatal("supR3HardenedDllNotificationCallback: NtCreateFile failed on '%.*ls' / '%.*ls': %#x\n",
+ pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+ NtPathUniStr.Length / sizeof(WCHAR), NtPathUniStr.Buffer, rcNt);
+ RTNtPathFree(&NtPathUniStr, &hRootDir);
+ return;
+ }
+ /* Do the screening. */
+ ULONG fAccess = 0;
+ ULONG fProtect = 0;
+ bool fCallRealApi = false;
+ bool fQuietFailure = false;
+ rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi,
+ "LdrLoadDll", true /*fAvoidWinVerifyTrust*/, &fQuietFailure);
+ NtClose(hFile);
+ if (!NT_SUCCESS(rcNt))
+ {
+ supR3HardenedFatal("supR3HardenedDllNotificationCallback: supR3HardenedScreenImage failed on '%.*ls' / '%.*ls': %#x\n",
+ pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+ NtPathUniStr.Length / sizeof(WCHAR), NtPathUniStr.Buffer, rcNt);
+ RTNtPathFree(&NtPathUniStr, &hRootDir);
+ return;
+ }
+ RTNtPathFree(&NtPathUniStr, &hRootDir);
+ }
/*
- * Search for free memory.
+ * Log the unload call.
*/
- uintptr_t uCur = uStart & uAllocGranularityMask;
- for (;;)
+ else if (ulReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED)
{
- /*
- * Examine the memory at this address, if it's free, try make the allocation here.
- */
- SIZE_T cbIgn;
- MEMORY_BASIC_INFORMATION MemInfo;
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryVirtualMemory(hProc,
- (void *)uCur,
- MemoryBasicInformation,
- &MemInfo,
- sizeof(MemInfo),
- &cbIgn));
- if ( MemInfo.State == MEM_FREE
- && MemInfo.RegionSize >= cbAlloc)
- {
- for (;;)
- {
- SUPR3HARDENED_ASSERT((uintptr_t)MemInfo.BaseAddress <= uCur);
+ SUP_DPRINTF(("supR3HardenedDllNotificationCallback: Unload %p LB %#010x %.*ls [flags=%#x]\n",
+ pData->Unloaded.DllBase, pData->Unloaded.SizeOfImage,
+ pData->Unloaded.FullDllName->Length / sizeof(WCHAR), pData->Unloaded.FullDllName->Buffer,
+ pData->Unloaded.Flags));
+ }
+ /*
+ * Just log things we don't know and then return without caching anything.
+ */
+ else
+ {
+ static uint32_t s_cLogEntries = 0;
+ if (s_cLogEntries++ < 32)
+ SUP_DPRINTF(("supR3HardenedDllNotificationCallback: ulReason=%u pData=%p\n", ulReason, pData));
+ return;
+ }
- PVOID pvMem = (PVOID)uCur;
- SIZE_T cbMem = cbAlloc;
- NTSTATUS rcNt = NtAllocateVirtualMemory(hProc, &pvMem, 0 /*ZeroBits*/, &cbAlloc,
- MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
- if (NT_SUCCESS(rcNt))
- {
- if ( iDirection > 0
- ? (uintptr_t)pvMem >= uStart
- && (uintptr_t)pvMem <= uEnd
- : (uintptr_t)pvMem >= uEnd
- && (uintptr_t)pvMem <= uStart)
- return pvMem;
- NtFreeVirtualMemory(hProc, &pvMem, &cbMem, MEM_RELEASE);
- }
+ /*
+ * Use this opportunity to make sure our NtDll patches are still in place,
+ * since they may be replaced by indecent protection software solutions.
+ */
+ supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+}
- /* Advance within the free area and try again? */
- uintptr_t uNext = iDirection > 0 ? uCur + cbAllocGranularity : uCur - cbAllocGranularity;
- uNext &= uAllocGranularityMask;
- if ( iDirection > 0
- ? uNext <= uCur
- || uNext > uEnd
- || uNext - (uintptr_t)MemInfo.BaseAddress > MemInfo.RegionSize
- || MemInfo.RegionSize - (uNext - (uintptr_t)MemInfo.BaseAddress) < cbAlloc
- : uNext >= uCur
- || uNext < uEnd
- || uNext < (uintptr_t)MemInfo.BaseAddress)
- break;
- uCur = uNext;
- }
- }
- /*
- * Advance to the next memory region.
- */
- if (iDirection > 0)
+/**
+ * Registers the DLL notification callback if it hasn't already been registered.
+ */
+static void supR3HardenedWinRegisterDllNotificationCallback(void)
+{
+ /*
+ * The notification API was added in Vista, so it's an optional (weak) import.
+ */
+ if ( LdrRegisterDllNotification != NULL
+ && g_cDllNotificationRegistered <= 0
+ && g_cDllNotificationRegistered > -32)
+ {
+ NTSTATUS rcNt = LdrRegisterDllNotification(0, supR3HardenedDllNotificationCallback, NULL, &g_pvDllNotificationCookie);
+ if (NT_SUCCESS(rcNt))
{
- uCur = (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize;
- uCur = RT_ALIGN_Z(uCur, cbAllocGranularity);
- if (uCur >= uEnd)
- break;
+ SUP_DPRINTF(("Registered Dll notification callback with NTDLL.\n"));
+ g_cDllNotificationRegistered = 1;
}
else
{
- uCur = (uintptr_t)(MemInfo.AllocationBase ? MemInfo.AllocationBase : MemInfo.BaseAddress);
- if (uCur > uEnd)
- uCur -= cbAlloc;
- uCur &= uAllocGranularityMask;
- if (uCur < uEnd)
- break;
+ supR3HardenedError(rcNt, false /*fFatal*/, "LdrRegisterDllNotification failed: %#x\n", rcNt);
+ g_cDllNotificationRegistered--;
}
}
- return NULL;
}
-#endif
static void supR3HardenedWinHookFailed(const char *pszWhich, uint8_t const *pbPrologue)
@@ -2053,49 +2301,146 @@ DECLHIDDEN(void) supR3HardenedWinCreateParentWatcherThread(HMODULE hVBoxRT)
/**
- * Install hooks for intercepting calls dealing with mapping shared libraries
- * into the process.
+ * Checks if the calling thread is the only one in the process.
*
- * This allows us to prevent undesirable shared libraries from being loaded.
+ * @returns true if we're positive we're alone, false if not.
+ */
+static bool supR3HardenedWinAmIAlone(void)
+{
+ ULONG fAmIAlone = 0;
+ ULONG cbIgn = 0;
+ NTSTATUS rcNt = NtQueryInformationThread(NtCurrentThread(), ThreadAmILastThread, &fAmIAlone, sizeof(fAmIAlone), &cbIgn);
+ Assert(NT_SUCCESS(rcNt));
+ return NT_SUCCESS(rcNt) && fAmIAlone != 0;
+}
+
+
+/**
+ * Simplify NtProtectVirtualMemory interface.
*
- * @remarks We assume we're alone in this process, so no seralizing trickery is
- * necessary when installing the patch.
+ * Modifies protection for the current process. Caller must know the current
+ * protection as it's not returned.
*
- * @remarks We would normally just copy the prologue sequence somewhere and add
- * a jump back at the end of it. But because we wish to avoid
- * allocating executable memory, we need to have preprepared assembly
- * "copies". This makes the non-system call patching a little tedious
- * and inflexible.
+ * @returns NT status code.
+ * @param pvMem The memory to change protection for.
+ * @param cbMem The amount of memory to change.
+ * @param fNewProt The new protection.
*/
-DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
+static NTSTATUS supR3HardenedWinProtectMemory(PVOID pvMem, SIZE_T cbMem, ULONG fNewProt)
{
- NTSTATUS rcNt;
+ ULONG fOldProt = 0;
+ return NtProtectVirtualMemory(NtCurrentProcess(), &pvMem, &cbMem, fNewProt, &fOldProt);
+}
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
- /*
- * Install a anti debugging hack before we continue. This prevents most
- * notifications from ending up in the debugger. (Also applied to the
- * child process when respawning.)
- */
- rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
- if (!NT_SUCCESS(rcNt))
- supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
- "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
-#endif
- /*
- * Disable hard error popups so we can quietly refuse images to be loaded.
- */
- ULONG fHardErr = 0;
- rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
- if (!NT_SUCCESS(rcNt))
- supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
- "NtQueryInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
- if (fHardErr & PROCESS_HARDERR_CRITICAL_ERROR)
+/**
+ * Installs or reinstalls the NTDLL patches.
+ */
+static void supR3HardenedWinReInstallHooks(bool fFirstCall)
+{
+ struct
{
- fHardErr &= ~PROCESS_HARDERR_CRITICAL_ERROR;
- rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
- if (!NT_SUCCESS(rcNt))
+ size_t cbPatch;
+ uint8_t const *pabPatch;
+ uint8_t **ppbApi;
+ const char *pszName;
+ } const s_aPatches[] =
+ {
+ { sizeof(g_abNtCreateSectionPatch), g_abNtCreateSectionPatch, &g_pbNtCreateSection, "NtCreateSection" },
+ { sizeof(g_abLdrLoadDllPatch), g_abLdrLoadDllPatch, &g_pbLdrLoadDll, "LdrLoadDll" },
+ };
+
+ ULONG fAmIAlone = ~(ULONG)0;
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aPatches); i++)
+ {
+ uint8_t *pbApi = *s_aPatches[i].ppbApi;
+ if (memcmp(pbApi, s_aPatches[i].pabPatch, s_aPatches[i].cbPatch) != 0)
+ {
+ /*
+ * Log the incident if it's not the initial call.
+ */
+ static uint32_t volatile s_cTimes = 0;
+ if (!fFirstCall && s_cTimes < 128)
+ {
+ s_cTimes++;
+ SUP_DPRINTF(("supR3HardenedWinReInstallHooks: Reinstalling %s (%p: %.*Rhxs).\n",
+ s_aPatches[i].pszName, pbApi, s_aPatches[i].cbPatch, pbApi));
+ }
+
+ Assert(s_aPatches[i].cbPatch >= 4);
+
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READWRITE));
+
+ /*
+ * If we're alone, just memcpy the patch in.
+ */
+
+ if (fAmIAlone == ~(ULONG)0)
+ fAmIAlone = supR3HardenedWinAmIAlone();
+ if (fAmIAlone)
+ memcpy(pbApi, s_aPatches[i].pabPatch, s_aPatches[i].cbPatch);
+ else
+ {
+ /*
+ * Not alone. Start by injecting a JMP $-2, then waste some
+ * CPU cycles to get the other threads a good chance of getting
+ * out of the code before we replace it.
+ */
+ RTUINT32U uJmpDollarMinus;
+ uJmpDollarMinus.au8[0] = 0xeb;
+ uJmpDollarMinus.au8[1] = 0xfe;
+ uJmpDollarMinus.au8[2] = pbApi[2];
+ uJmpDollarMinus.au8[3] = pbApi[3];
+ ASMAtomicXchgU32((uint32_t volatile *)pbApi, uJmpDollarMinus.u);
+
+ NtYieldExecution();
+ NtYieldExecution();
+
+ /* Copy in the tail bytes of the patch, then xchg the jmp $-2. */
+ if (s_aPatches[i].cbPatch > 4)
+ memcpy(&pbApi[4], &s_aPatches[i].pabPatch[4], s_aPatches[i].cbPatch - 4);
+ ASMAtomicXchgU32((uint32_t volatile *)pbApi, *(uint32_t *)s_aPatches[i].pabPatch);
+ }
+
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READ));
+ }
+ }
+}
+
+
+/**
+ * Install hooks for intercepting calls dealing with mapping shared libraries
+ * into the process.
+ *
+ * This allows us to prevent undesirable shared libraries from being loaded.
+ *
+ * @remarks We assume we're alone in this process, so no seralizing trickery is
+ * necessary when installing the patch.
+ *
+ * @remarks We would normally just copy the prologue sequence somewhere and add
+ * a jump back at the end of it. But because we wish to avoid
+ * allocating executable memory, we need to have preprepared assembly
+ * "copies". This makes the non-system call patching a little tedious
+ * and inflexible.
+ */
+static void supR3HardenedWinInstallHooks(void)
+{
+ NTSTATUS rcNt;
+
+ /*
+ * Disable hard error popups so we can quietly refuse images to be loaded.
+ */
+ ULONG fHardErr = 0;
+ rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
+ "NtQueryInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
+ if (fHardErr & PROCESS_HARDERR_CRITICAL_ERROR)
+ {
+ fHardErr &= ~PROCESS_HARDERR_CRITICAL_ERROR;
+ rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
+ if (!NT_SUCCESS(rcNt))
supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
"NtSetInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
}
@@ -2103,36 +2448,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
/*
* Locate the routines first so we can allocate memory that's near enough.
*/
- HMODULE hmodNtDll = GetModuleHandleW(L"NTDLL");
- SUPR3HARDENED_ASSERT(hmodNtDll != NULL);
-
- FARPROC pfnNtCreateSection = GetProcAddress(hmodNtDll, "NtCreateSection");
+ PFNRT pfnNtCreateSection = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "NtCreateSection");
SUPR3HARDENED_ASSERT(pfnNtCreateSection != NULL);
//SUPR3HARDENED_ASSERT(pfnNtCreateSection == (FARPROC)NtCreateSection);
- FARPROC pfnLdrLoadDll = GetProcAddress(hmodNtDll, "LdrLoadDll");
+ PFNRT pfnLdrLoadDll = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "LdrLoadDll");
SUPR3HARDENED_ASSERT(pfnLdrLoadDll != NULL);
//SUPR3HARDENED_ASSERT(pfnLdrLoadDll == (FARPROC)LdrLoadDll);
-
-#ifdef RT_ARCH_AMD64
/*
- * For 64-bit hosts we need some memory within a +/-2GB range of the
- * actual function to be able to patch it.
+ * Exec page setup & management.
*/
- uintptr_t uStart = RT_MAX((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
- size_t cbMem = _4K;
- void *pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart - _2G + PAGE_SIZE, -1, cbMem);
- if (!pvMem)
- {
- uintptr_t uStart = RT_MIN((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
- pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart + _2G - PAGE_SIZE, 1, cbMem);
- if (!pvMem)
- supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY,
- "Failed to allocate memory within the +/-2GB range from NTDLL.\n");
- }
- uintptr_t *puJmpTab = (uintptr_t *)pvMem;
-#endif
+ uint32_t offExecPage = 0;
+ memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE);
/*
* Hook #1 - NtCreateSection.
@@ -2140,14 +2468,15 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
* it's mapped and we still have a file handle to work with.
*/
uint8_t * const pbNtCreateSection = (uint8_t *)(uintptr_t)pfnNtCreateSection;
+ g_pbNtCreateSection = pbNtCreateSection;
+ memcpy(g_abNtCreateSectionPatch, pbNtCreateSection, sizeof(g_abNtCreateSectionPatch));
+
+ g_pfnNtCreateSectionReal = NtCreateSection; /* our direct syscall */
#ifdef RT_ARCH_AMD64
/*
* Patch 64-bit hosts.
*/
- PFNRT pfnCallReal = NULL;
- uint8_t offJmpBack = UINT8_MAX;
-
/* Pattern #1: XP64/W2K3-64 thru Windows 8.1
0:000> u ntdll!NtCreateSection
ntdll!NtCreateSection:
@@ -2157,53 +2486,18 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
00000000`779f175a c3 ret
00000000`779f175b 0f1f440000 nop dword ptr [rax+rax]
The variant is the value loaded into eax: W2K3=??, Vista=47h?, W7=47h, W80=48h, W81=49h */
- if ( pbNtCreateSection[ 0] == 0x4c /* mov r10, rcx */
- && pbNtCreateSection[ 1] == 0x8b
- && pbNtCreateSection[ 2] == 0xd1
- && pbNtCreateSection[ 3] == 0xb8 /* mov eax, 000000xxh */
- && pbNtCreateSection[ 5] == 0x00
- && pbNtCreateSection[ 6] == 0x00
- && pbNtCreateSection[ 7] == 0x00
- && pbNtCreateSection[ 8] == 0x0f /* syscall */
- && pbNtCreateSection[ 9] == 0x05
- && pbNtCreateSection[10] == 0xc3 /* ret */
-
-/* b8 22 35 ed 0 48 63 c0 ff e0 c3 f 1f 44 0 0 - necros2 - agnitum firewall? */
- )
- {
- offJmpBack = 8; /* the 3rd instruction (syscall). */
- switch (pbNtCreateSection[4])
- {
-# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
-# include "NtCreateSection-template-amd64-syscall-type-1.h"
-# undef SYSCALL
- }
- }
- if (!pfnCallReal)
- supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
-
- g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
- *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal;
- *puJmpTab = (uintptr_t)supR3HardenedMonitor_NtCreateSection;
- DWORD dwOldProt;
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
- PAGE_EXECUTE_READWRITE, &dwOldProt));
- pbNtCreateSection[0] = 0xff;
- pbNtCreateSection[1] = 0x25;
- *(uint32_t *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]);
-
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
- PAGE_EXECUTE_READ, &dwOldProt));
- puJmpTab++;
+ /* Assemble the patch. */
+ g_abNtCreateSectionPatch[0] = 0x48; /* mov rax, qword */
+ g_abNtCreateSectionPatch[1] = 0xb8;
+ *(uint64_t *)&g_abNtCreateSectionPatch[2] = (uint64_t)supR3HardenedMonitor_NtCreateSection;
+ g_abNtCreateSectionPatch[10] = 0xff; /* jmp rax */
+ g_abNtCreateSectionPatch[11] = 0xe0;
#else
/*
* Patch 32-bit hosts.
*/
- PFNRT pfnCallReal = NULL;
- uint8_t offJmpBack = UINT8_MAX;
-
/* Pattern #1: XP thru Windows 7
kd> u ntdll!NtCreateSection
ntdll!NtCreateSection:
@@ -2223,55 +2517,13 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
6a15eac9 8bd4 mov edx,esp
6a15eacb 0f34 sysenter
6a15eacd c3 ret
- The variable bit is the value loaded into eax: W81=154h
- Note! One nice thing here is that we can share code pattern #1. */
-
- if ( pbNtCreateSection[ 0] == 0xb8 /* mov eax, 000000xxh*/
- && pbNtCreateSection[ 2] <= 0x02
- && pbNtCreateSection[ 3] == 0x00
- && pbNtCreateSection[ 4] == 0x00
- && ( ( pbNtCreateSection[ 5] == 0xba /* mov edx, offset SharedUserData!SystemCallStub */
- && pbNtCreateSection[ 6] == 0x00
- && pbNtCreateSection[ 7] == 0x03
- && pbNtCreateSection[ 8] == 0xfe
- && pbNtCreateSection[ 9] == 0x7f
- && pbNtCreateSection[10] == 0xff /* call [edx] */
- && pbNtCreateSection[11] == 0x12
- && pbNtCreateSection[12] == 0xc2 /* ret 1ch */
- && pbNtCreateSection[13] == 0x1c
- && pbNtCreateSection[14] == 0x00)
-
- || ( pbNtCreateSection[ 5] == 0xe8 /* call [$+3] */
- && RT_ABS(*(int32_t *)&pbNtCreateSection[6]) < 0x10
- && pbNtCreateSection[10] == 0xc2 /* ret 1ch */
- && pbNtCreateSection[11] == 0x1c
- && pbNtCreateSection[12] == 0x00 )
- )
- )
- {
- offJmpBack = 5; /* the 2nd instruction. */
- switch (*(uint32_t const *)&pbNtCreateSection[1])
- {
-# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
-# include "NtCreateSection-template-x86-syscall-type-1.h"
-# undef SYSCALL
- }
- }
- if (!pfnCallReal)
- supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
-
- g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
- *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal;
+ The variable bit is the value loaded into eax: W81=154h */
- DWORD dwOldProt;
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
- PAGE_EXECUTE_READWRITE, &dwOldProt));
- pbNtCreateSection[0] = 0xe9;
- *(uint32_t *)&pbNtCreateSection[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection
- - (uintptr_t)&pbNtCreateSection[1+4];
+ /* Assemble the patch. */
+ g_abNtCreateSectionPatch[0] = 0xe9; /* jmp rel32 */
+ *(uint32_t *)&g_abNtCreateSectionPatch[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection
+ - (uintptr_t)&pbNtCreateSection[1+4];
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
- PAGE_EXECUTE_READ, &dwOldProt));
#endif
/*
@@ -2284,165 +2536,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
* we're at the mercy of the compiler.
*/
uint8_t * const pbLdrLoadDll = (uint8_t *)(uintptr_t)pfnLdrLoadDll;
- uint32_t offExecPage = 0;
- memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE);
+ g_pbLdrLoadDll = pbLdrLoadDll;
+ memcpy(g_abLdrLoadDllPatch, pbLdrLoadDll, sizeof(g_abLdrLoadDllPatch));
+
+ DISSTATE Dis;
+ uint32_t cbInstr;
+ uint32_t offJmpBack = 0;
#ifdef RT_ARCH_AMD64
/*
* Patch 64-bit hosts.
*/
-# if 0
- /* Pattern #1:
- Windows 8.1:
- 0:000> u ntdll!LdrLoadDll
- ntdll!LdrLoadDll:
- 00007ffa`814ccd44 488bc4 mov rax,rsp
- 00007ffa`814ccd47 48895808 mov qword ptr [rax+8],rbx
- 00007ffa`814ccd4b 48896810 mov qword ptr [rax+10h],rbp
- 00007ffa`814ccd4f 48897018 mov qword ptr [rax+18h],rsi
- 00007ffa`814ccd53 48897820 mov qword ptr [rax+20h],rdi
- 00007ffa`814ccd57 4156 push r14
- 00007ffa`814ccd59 4883ec70 sub rsp,70h
- 00007ffa`814ccd5d f6059cd2100009 test byte ptr [ntdll!LdrpDebugFlags (00007ffa`815da000)],9
- */
- if ( pbLdrLoadDll[0] == 0x48 /* mov rax,rsp */
- && pbLdrLoadDll[1] == 0x8b
- && pbLdrLoadDll[2] == 0xc4
- && pbLdrLoadDll[3] == 0x48 /* mov qword ptr [rax+8],rbx */
- && pbLdrLoadDll[4] == 0x89
- && pbLdrLoadDll[5] == 0x58
- && pbLdrLoadDll[6] == 0x08)
- {
- offJmpBack = 7; /* the 3rd instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
- }
- /*
- Pattern #2:
- Windows 8.0:
- 0:000> u ntdll_w8_64!LdrLoadDll
- ntdll_w8_64!LdrLoadDll:
- 00007ffa`52ffa7c0 48895c2408 mov qword ptr [rsp+8],rbx
- 00007ffa`52ffa7c5 4889742410 mov qword ptr [rsp+10h],rsi
- 00007ffa`52ffa7ca 48897c2418 mov qword ptr [rsp+18h],rdi
- 00007ffa`52ffa7cf 55 push rbp
- 00007ffa`52ffa7d0 4156 push r14
- 00007ffa`52ffa7d2 4157 push r15
- 00007ffa`52ffa7d4 488bec mov rbp,rsp
- 00007ffa`52ffa7d7 4883ec60 sub rsp,60h
- 00007ffa`52ffa7db 8b05df321000 mov eax,dword ptr [ntdll_w8_64!LdrpDebugFlags (00007ffa`530fdac0)]
- 00007ffa`52ffa7e1 4d8bf1 mov r14,r9
-
- */
- else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+8],rbx */
- && pbLdrLoadDll[1] == 0x89
- && pbLdrLoadDll[2] == 0x5c
- && pbLdrLoadDll[3] == 0x24
- && pbLdrLoadDll[4] == 0x08
- && pbLdrLoadDll[5] == 0x48 /* mov qword ptr [rsp+10h],rsi */
- && pbLdrLoadDll[6] == 0x89
- && pbLdrLoadDll[7] == 0x74
- && pbLdrLoadDll[8] == 0x24
- && pbLdrLoadDll[9] == 0x10)
- {
- offJmpBack = 10; /* the 3rd instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
- }
- /*
- Pattern #3:
- Windows 7:
- ntdll_w7_64!LdrLoadDll:
- 00000000`58be4a20 48895c2410 mov qword ptr [rsp+10h],rbx
- 00000000`58be4a25 48896c2418 mov qword ptr [rsp+18h],rbp
- 00000000`58be4a2a 56 push rsi
- 00000000`58be4a2b 57 push rdi
- 00000000`58be4a2c 4154 push r12
- 00000000`58be4a2e 4883ec50 sub rsp,50h
- 00000000`58be4a32 f605976e100009 test byte ptr [ntdll_w7_64!ShowSnaps (00000000`58ceb8d0)],9
- 00000000`58be4a39 498bf1 mov rsi,r9
-
- */
- else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+10h],rbx */
- && pbLdrLoadDll[1] == 0x89
- && pbLdrLoadDll[2] == 0x5c
- && pbLdrLoadDll[3] == 0x24
- && pbLdrLoadDll[4] == 0x10)
- {
- offJmpBack = 5; /* the 2nd instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type3;
- }
- /*
- Pattern #4:
- Windows Vista:
- 0:000> u ntdll_vista_64!LdrLoadDll
- ntdll_vista_64!LdrLoadDll:
- 00000000`58c11f60 fff3 push rbx
- 00000000`58c11f62 56 push rsi
- 00000000`58c11f63 57 push rdi
- 00000000`58c11f64 4154 push r12
- 00000000`58c11f66 4155 push r13
- 00000000`58c11f68 4156 push r14
- 00000000`58c11f6a 4157 push r15
- 00000000`58c11f6c 4881ecb0020000 sub rsp,2B0h
- 00000000`58c11f73 488b05367b0e00 mov rax,qword ptr [ntdll_vista_64!_security_cookie (00000000`58cf9ab0)]
- 00000000`58c11f7a 4833c4 xor rax,rsp
- 00000000`58c11f7d 48898424a0020000 mov qword ptr [rsp+2A0h],rax
-
- */
- else if ( pbLdrLoadDll[0] == 0xff /* push rbx */
- && pbLdrLoadDll[1] == 0xf3
- && pbLdrLoadDll[2] == 0x56 /* push rsi */
- && pbLdrLoadDll[3] == 0x57 /* push rdi */
- && pbLdrLoadDll[4] == 0x41 /* push r12 */
- && pbLdrLoadDll[5] == 0x54)
- {
- offJmpBack = 6; /* the 5th instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type4;
- }
- /*
- Pattern #5:
- Windows XP64:
- 0:000> u ntdll!LdrLoadDll
- ntdll!LdrLoadDll:
- 00000000`78efa580 4c8bdc mov r11,rsp
- 00000000`78efa583 4881ece8020000 sub rsp,2E8h
- 00000000`78efa58a 49895bf8 mov qword ptr [r11-8],rbx
- 00000000`78efa58e 498973f0 mov qword ptr [r11-10h],rsi
- 00000000`78efa592 49897be8 mov qword ptr [r11-18h],rdi
- 00000000`78efa596 4d8963e0 mov qword ptr [r11-20h],r12
- 00000000`78efa59a 4d896bd8 mov qword ptr [r11-28h],r13
- 00000000`78efa59e 4d8973d0 mov qword ptr [r11-30h],r14
- 00000000`78efa5a2 4d897bc8 mov qword ptr [r11-38h],r15
- 00000000`78efa5a6 488b051bd10a00 mov rax,qword ptr [ntdll!_security_cookie (00000000`78fa76c8)]
- 00000000`78efa5ad 48898424a0020000 mov qword ptr [rsp+2A0h],rax
- 00000000`78efa5b5 4d8bf9 mov r15,r9
- 00000000`78efa5b8 4c8bf2 mov r14,rdx
- 00000000`78efa5bb 4c8be9 mov r13,rcx
- 00000000`78efa5be 4c89442458 mov qword ptr [rsp+58h],r8
- 00000000`78efa5c3 66c74424680000 mov word ptr [rsp+68h],0
-
- */
- else if ( pbLdrLoadDll[0] == 0x4c /* mov r11,rsp */
- && pbLdrLoadDll[1] == 0x8b
- && pbLdrLoadDll[2] == 0xdc
- && pbLdrLoadDll[3] == 0x48 /* sub rsp,2e8h */
- && pbLdrLoadDll[4] == 0x81
- && pbLdrLoadDll[5] == 0xec
- && pbLdrLoadDll[6] == 0xe8
- && pbLdrLoadDll[7] == 0x02
- && pbLdrLoadDll[8] == 0x00
- && pbLdrLoadDll[9] == 0x00)
- {
- offJmpBack = 10; /* the 3rd instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type5;
- }
- else
- supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
-# else
- /* Just use the disassembler to skip 6 bytes or more. */
- DISSTATE Dis;
- uint32_t cbInstr;
- offJmpBack = 0;
- while (offJmpBack < 6)
+ /* Just use the disassembler to skip 12 bytes or more. */
+ while (offJmpBack < 12)
{
cbInstr = 1;
int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr);
@@ -2452,7 +2558,6 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
offJmpBack += cbInstr;
}
-# endif
/* Assemble the code for resuming the call.*/
*(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
@@ -2467,116 +2572,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
*(uint64_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack];
offExecPage = RT_ALIGN_32(offJmpBack + 8, 16);
- /* Patch the function. */
- *puJmpTab = (uintptr_t)supR3HardenedMonitor_LdrLoadDll;
-
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READWRITE, &dwOldProt));
-
- Assert(offJmpBack >= 6);
- pbLdrLoadDll[0] = 0xff;
- pbLdrLoadDll[1] = 0x25;
- *(uint32_t *)&pbLdrLoadDll[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbLdrLoadDll[2+4]);
-
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
- puJmpTab++;
+ /* Assemble the LdrLoadDll patch. */
+ Assert(offJmpBack >= 12);
+ g_abLdrLoadDllPatch[0] = 0x48; /* mov rax, qword */
+ g_abLdrLoadDllPatch[1] = 0xb8;
+ *(uint64_t *)&g_abLdrLoadDllPatch[2] = (uint64_t)supR3HardenedMonitor_LdrLoadDll;
+ g_abLdrLoadDllPatch[10] = 0xff; /* jmp rax */
+ g_abLdrLoadDllPatch[11] = 0xe0;
#else
/*
* Patch 32-bit hosts.
*/
-# if 0
- /* Pattern #1:
- Windows 7:
- 0:000> u ntdll!LdrLoadDll
- ntdll!LdrLoadDll:
- 77aff585 8bff mov edi,edi
- 77aff587 55 push ebp
- 77aff588 8bec mov ebp,esp
- 77aff58a 51 push ecx
- 77aff58b 51 push ecx
- 77aff58c a1f8bdaf77 mov eax,dword ptr [ntdll!LdrpLogLevelStateTable+0x24 (77afbdf8)]
-
- Windows 8 rtm:
- 0:000:x86> u ntdll_67150000!LdrLoadDll
- ntdll_67150000!LdrLoadDll:
- 67189f3f 8bff mov edi,edi
- 67189f41 55 push ebp
- 67189f42 8bec mov ebp,esp
- 67189f44 8b0d10eb2467 mov ecx,dword ptr [ntdll_67150000!LdrpDebugFlags (6724eb10)]
-
- Windows 8.1:
- 0:000:x86> u ntdll_w81_32!LdrLoadDll
- ntdll_w81_32!LdrLoadDll:
- 6718aade 8bff mov edi,edi
- 6718aae0 55 push ebp
- 6718aae1 8bec mov ebp,esp
- 6718aae3 83ec14 sub esp,14h
- 6718aae6 f6050040246709 test byte ptr [ntdll_w81_32!LdrpDebugFlags (67244000)],9
-
- Pattern #2:
- Windows XP:
- 0:000:x86> u ntdll_xp!LdrLoadDll
- ntdll_xp!LdrLoadDll:
- 77f569d2 6858020000 push 258h
- 77f569d7 68d866f777 push offset ntdll_xp!`string'+0x12c (77f766d8)
- 77f569dc e83bb20200 call ntdll_xp!_SEH_prolog (77f81c1c)
- 77f569e1 33db xor ebx,ebx
- 77f569e3 66895de0 mov word ptr [ebp-20h],bx
- 77f569e7 33c0 xor eax,eax
- 77f569e9 8d7de2 lea edi,[ebp-1Eh]
- 77f569ec ab stos dword ptr es:[edi]
-
- Windows Server 2003:
- 0:000:x86> u ntdll_w2k3_32!LdrLoadDll
- ntdll_w2k3_32!LdrLoadDll:
- 7c833f63 6840020000 push 240h
- 7c833f68 68b040837c push offset ntdll_w2k3_32!`string'+0x12c (7c8340b0)
- 7c833f6d e8a942ffff call ntdll_w2k3_32!_SEH_prolog (7c82821b)
- 7c833f72 a13077887c mov eax,dword ptr [ntdll_w2k3_32!__security_cookie (7c887730)]
- 7c833f77 8945e4 mov dword ptr [ebp-1Ch],eax
- 7c833f7a 8b4508 mov eax,dword ptr [ebp+8]
- 7c833f7d 8985b0fdffff mov dword ptr [ebp-250h],eax
- 7c833f83 8b450c mov eax,dword ptr [ebp+0Ch]
-
- Windows Vista SP0 & SP1:
- 0:000:x86> u ntdll_vista_sp0_32!LdrLoadDll
- ntdll_vista_sp0_32!LdrLoadDll:
- 69b0eb00 6844020000 push 244h
- 69b0eb05 6838e9b269 push offset ntdll_vista_sp0_32! ?? ::FNODOBFM::`string'+0x39e (69b2e938)
- 69b0eb0a e835420300 call ntdll_vista_sp0_32!_SEH_prolog4_GS (69b42d44)
- 69b0eb0f 8b4508 mov eax,dword ptr [ebp+8]
- 69b0eb12 8985acfdffff mov dword ptr [ebp-254h],eax
- 69b0eb18 8b450c mov eax,dword ptr [ebp+0Ch]
- 69b0eb1b 8985c0fdffff mov dword ptr [ebp-240h],eax
- 69b0eb21 8b4510 mov eax,dword ptr [ebp+10h]
- */
-
- if ( pbLdrLoadDll[0] == 0x8b /* mov edi, edi - for hot patching */
- && pbLdrLoadDll[1] == 0xff
- && pbLdrLoadDll[2] == 0x55 /* push ebp */
- && pbLdrLoadDll[3] == 0x8b /* mov ebp,esp */
- && pbLdrLoadDll[4] == 0xec)
- {
- offJmpBack = 5; /* the 3rd instruction. */
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
- }
- else if (pbLdrLoadDll[0] == 0x68 /* push dword XXXXXXXX */)
- {
- offJmpBack = 5;
- pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
- g_supR3HardenedJmpBack_LdrLoadDll_Type2_PushDword = *(uint32_t const *)&pbLdrLoadDll[1];
- }
- else
- supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
-
- g_pfnLdrLoadDllJmpBack = (PFNRT)(uintptr_t)(pbLdrLoadDll + offJmpBack);
- *(PFNRT *)&g_pfnLdrLoadDllReal = pfnCallReal;
-
-# else
- /* Just use the disassembler to skip 6 bytes or more. */
- DISSTATE Dis;
- uint32_t cbInstr;
- offJmpBack = 0;
+ /* Just use the disassembler to skip 5 bytes or more. */
while (offJmpBack < 5)
{
cbInstr = 1;
@@ -2593,125 +2601,310 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack);
offExecPage += offJmpBack;
- g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9;
+ g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9; /* jmp rel32 */
*(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack]
- (uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage + 4];
offExecPage = RT_ALIGN_32(offJmpBack + 4, 16);
-# endif
-
- /* Patch LdrLoadDLl. */
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16,
- PAGE_EXECUTE_READWRITE, &dwOldProt));
+ /* Assemble the LdrLoadDll patch. */
+ memcpy(g_abLdrLoadDllPatch, pbLdrLoadDll, sizeof(g_abLdrLoadDllPatch));
Assert(offJmpBack >= 5);
- pbLdrLoadDll[0] = 0xe9;
- *(uint32_t *)&pbLdrLoadDll[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
-
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
+ g_abLdrLoadDllPatch[0] = 0xe9;
+ *(uint32_t *)&g_abLdrLoadDllPatch[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
#endif
/*
* Seal the rwx page.
*/
- SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), g_abSupHardReadWriteExecPage, PAGE_SIZE,
- PAGE_EXECUTE_READ, &dwOldProt));
-}
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(g_abSupHardReadWriteExecPage, PAGE_SIZE, PAGE_EXECUTE_READ));
-
-/**
- * Verifies the process integrity.
- */
-DECLHIDDEN(void) supR3HardenedWinVerifyProcess(void)
-{
- RTErrInfoInitStatic(&g_ErrInfoStatic);
- int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(),
- SUPHARDNTVPKIND_VERIFY_ONLY, NULL /*pcFixes*/, &g_ErrInfoStatic.Core);
- if (RT_FAILURE(rc))
- supR3HardenedFatalMsg("supR3HardenedWinVerifyProcess", kSupInitOp_Integrity, rc,
- "Failed to verify process integrity: %s", g_ErrInfoStatic.szMsg);
+ /*
+ * Install the patches.
+ */
+ supR3HardenedWinReInstallHooks(true /*fFirstCall*/);
}
-/**
- * Gets the SID of the user associated with the process.
- *
- * @returns @c true if we've got a login SID, @c false if not.
- * @param pSidUser Where to return the user SID.
- * @param cbSidUser The size of the user SID buffer.
- * @param pSidLogin Where to return the login SID.
- * @param cbSidLogin The size of the login SID buffer.
- */
-static bool supR3HardenedGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
-{
- HANDLE hToken;
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));
- union
- {
- TOKEN_USER UserInfo;
- TOKEN_GROUPS Groups;
- uint8_t abPadding[4096];
- } uBuf;
- ULONG cbRet = 0;
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
- SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidUser, pSidUser, uBuf.UserInfo.User.Sid));
- bool fLoginSid = false;
- NTSTATUS rcNt = NtQueryInformationToken(hToken, TokenLogonSid, &uBuf, sizeof(uBuf), &cbRet);
- if (NT_SUCCESS(rcNt))
- {
- for (DWORD i = 0; i < uBuf.Groups.GroupCount; i++)
- if ((uBuf.Groups.Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
- {
- SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidLogin, pSidLogin, uBuf.Groups.Groups[i].Sid));
- fLoginSid = true;
- break;
- }
- }
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hToken));
- return fLoginSid;
-}
+
+/*
+ *
+ * T h r e a d c r e a t i o n c o n t r o l
+ * T h r e a d c r e a t i o n c o n t r o l
+ * T h r e a d c r e a t i o n c o n t r o l
+ *
+ */
/**
- * Build security attributes for the process or the primary thread (@a fProcess)
+ * Common code used for child and parent to make new threads exit immediately.
*
- * Process DACLs can be bypassed using the SeDebugPrivilege (generally available
- * to admins, i.e. normal windows users), or by taking ownership and/or
- * modifying the DACL. However, it restricts
+ * This patches the LdrInitializeThunk code to call NtTerminateThread with
+ * STATUS_SUCCESS instead of doing the NTDLL initialization.
*
- * @param pSecAttrs Where to return the security attributes.
- * @param pCleanup Cleanup record.
- * @param fProcess Set if it's for the process, clear if it's for
- * the primary thread.
+ * @returns VBox status code.
+ * @param hProcess The process to do this to.
+ * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
+ * override.
+ * @param pvNtTerminateThread The address of the NtTerminateThread function in
+ * the NTDLL instance we're patching. (Must be +/-
+ * 2GB from the thunk code.)
+ * @param pabBackup Where to back up the original instruction bytes
+ * at pvLdrInitThunk.
+ * @param cbBackup The size of the backup area. Must be 16 bytes.
+ * @param pErrInfo Where to return extended error information.
+ * Optional.
*/
-static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
+static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
+ uint8_t *pabBackup, size_t cbBackup, PRTERRINFO pErrInfo)
{
+ SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
+ SUPR3HARDENED_ASSERT(cbBackup == 16);
+ SUPR3HARDENED_ASSERT(RT_ABS((intptr_t)pvLdrInitThunk - (intptr_t)pvNtTerminateThread) < 16*_1M);
+
/*
- * Safe return values.
+ * Back up the thunk code.
*/
- suplibHardenedMemSet(pCleanup, 0, sizeof(*pCleanup));
+ SIZE_T cbIgnored;
+ NTSTATUS rcNt = NtReadVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtDisableThreadCreation: NtReadVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
- pSecAttrs->nLength = sizeof(*pSecAttrs);
- pSecAttrs->bInheritHandle = FALSE;
- pSecAttrs->lpSecurityDescriptor = NULL;
+ /*
+ * Cook up replacement code that calls NtTerminateThread.
+ */
+ uint8_t abReplacement[16];
+ memcpy(abReplacement, pabBackup, sizeof(abReplacement));
-/** @todo This isn't at all complete, just sketches... */
+#ifdef RT_ARCH_AMD64
+ abReplacement[0] = 0x31; /* xor ecx, ecx */
+ abReplacement[1] = 0xc9;
+ abReplacement[2] = 0x31; /* xor edx, edx */
+ abReplacement[3] = 0xd2;
+ abReplacement[4] = 0xe8; /* call near NtTerminateThread */
+ *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
+ abReplacement[9] = 0xcc; /* int3 */
+#elif defined(RT_ARCH_X86)
+ abReplacement[0] = 0x6a; /* push 0 */
+ abReplacement[1] = 0x00;
+ abReplacement[2] = 0x6a; /* push 0 */
+ abReplacement[3] = 0x00;
+ abReplacement[4] = 0xe8; /* call near NtTerminateThread */
+ *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
+ abReplacement[9] = 0xcc; /* int3 */
+#else
+# error "Unsupported arch."
+#endif
/*
- * Create an ACL detailing the access of the above groups.
+ * Install the replacment code.
*/
- SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
+ PVOID pvProt = pvLdrInitThunk;
+ SIZE_T cbProt = cbBackup;
+ ULONG fOldProt = 0;
+ rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
- ULONG fDeny = DELETE | WRITE_DAC | WRITE_OWNER;
- ULONG fAllow = SYNCHRONIZE | READ_CONTROL;
- ULONG fAllowLogin = SYNCHRONIZE | READ_CONTROL;
- if (fProcess)
- {
- fDeny |= PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
- | PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA
- | PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
+ rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtDisableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+
+ pvProt = pvLdrInitThunk;
+ cbProt = cbBackup;
+ rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Undo the effects of supR3HardNtDisableThreadCreationEx.
+ *
+ * @returns VBox status code.
+ * @param hProcess The process to do this to.
+ * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
+ * override.
+ * @param pabBackup Where to back up the original instruction bytes
+ * at pvLdrInitThunk.
+ * @param cbBackup The size of the backup area. Must be 16 bytes.
+ * @param pErrInfo Where to return extended error information.
+ * Optional.
+ */
+static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
+ PRTERRINFO pErrInfo)
+{
+ SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
+ SUPR3HARDENED_ASSERT(cbBackup == 16);
+
+ PVOID pvProt = pvLdrInitThunk;
+ SIZE_T cbProt = cbBackup;
+ ULONG fOldProt = 0;
+ NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+
+ SIZE_T cbIgnored;
+ rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
+ rcNt);
+
+ pvProt = pvLdrInitThunk;
+ cbProt = cbBackup;
+ rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+ "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
+ rcNt);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Disable thread creation for the current process.
+ *
+ * @remarks Doesn't really disables it, just makes the threads exit immediately
+ * without executing any real code.
+ */
+static void supR3HardenedWinDisableThreadCreation(void)
+{
+ /* Cannot use the imported NtTerminateThread as it's pointing to our own
+ syscall assembly code. */
+ static PFNRT s_pfnNtTerminateThread = NULL;
+ if (s_pfnNtTerminateThread == NULL)
+ s_pfnNtTerminateThread = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "NtTerminateThread");
+ SUPR3HARDENED_ASSERT(s_pfnNtTerminateThread);
+
+ int rc = supR3HardNtDisableThreadCreationEx(NtCurrentProcess(),
+ (void *)(uintptr_t)&LdrInitializeThunk,
+ (void *)(uintptr_t)s_pfnNtTerminateThread,
+ g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
+ NULL /* pErrInfo*/);
+ g_fSupInitThunkSelfPatched = RT_SUCCESS(rc);
+}
+
+
+/**
+ * Undoes the effects of supR3HardenedWinDisableThreadCreation.
+ */
+DECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void)
+{
+ if (g_fSupInitThunkSelfPatched)
+ {
+ int rc = supR3HardNtEnableThreadCreationEx(NtCurrentProcess(),
+ (void *)(uintptr_t)&LdrInitializeThunk,
+ g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
+ RTErrInfoInitStatic(&g_ErrInfoStatic));
+ if (RT_FAILURE(rc))
+ supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
+ g_fSupInitThunkSelfPatched = false;
+ }
+}
+
+
+
+
+/*
+ *
+ * R e s p a w n
+ * R e s p a w n
+ * R e s p a w n
+ *
+ */
+
+
+/**
+ * Gets the SID of the user associated with the process.
+ *
+ * @returns @c true if we've got a login SID, @c false if not.
+ * @param pSidUser Where to return the user SID.
+ * @param cbSidUser The size of the user SID buffer.
+ * @param pSidLogin Where to return the login SID.
+ * @param cbSidLogin The size of the login SID buffer.
+ */
+static bool supR3HardNtChildGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
+{
+ HANDLE hToken;
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));
+ union
+ {
+ TOKEN_USER UserInfo;
+ TOKEN_GROUPS Groups;
+ uint8_t abPadding[4096];
+ } uBuf;
+ ULONG cbRet = 0;
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidUser, pSidUser, uBuf.UserInfo.User.Sid));
+
+ bool fLoginSid = false;
+ NTSTATUS rcNt = NtQueryInformationToken(hToken, TokenLogonSid, &uBuf, sizeof(uBuf), &cbRet);
+ if (NT_SUCCESS(rcNt))
+ {
+ for (DWORD i = 0; i < uBuf.Groups.GroupCount; i++)
+ if ((uBuf.Groups.Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
+ {
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidLogin, pSidLogin, uBuf.Groups.Groups[i].Sid));
+ fLoginSid = true;
+ break;
+ }
+ }
+
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hToken));
+
+ return fLoginSid;
+}
+
+
+/**
+ * Build security attributes for the process or the primary thread (@a fProcess)
+ *
+ * Process DACLs can be bypassed using the SeDebugPrivilege (generally available
+ * to admins, i.e. normal windows users), or by taking ownership and/or
+ * modifying the DACL. However, it restricts
+ *
+ * @param pSecAttrs Where to return the security attributes.
+ * @param pCleanup Cleanup record.
+ * @param fProcess Set if it's for the process, clear if it's for
+ * the primary thread.
+ */
+static void supR3HardNtChildInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
+{
+ /*
+ * Safe return values.
+ */
+ suplibHardenedMemSet(pCleanup, 0, sizeof(*pCleanup));
+
+ pSecAttrs->nLength = sizeof(*pSecAttrs);
+ pSecAttrs->bInheritHandle = FALSE;
+ pSecAttrs->lpSecurityDescriptor = NULL;
+
+/** @todo This isn't at all complete, just sketches... */
+
+ /*
+ * Create an ACL detailing the access of the above groups.
+ */
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
+
+ ULONG fDeny = DELETE | WRITE_DAC | WRITE_OWNER;
+ ULONG fAllow = SYNCHRONIZE | READ_CONTROL;
+ ULONG fAllowLogin = SYNCHRONIZE | READ_CONTROL;
+ if (fProcess)
+ {
+ fDeny |= PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
+ | PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA
+ | PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
fAllow |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
fAllowLogin |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
@@ -2759,8 +2952,8 @@ static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURIT
#endif
#if 1
- bool fHasLoginSid = supR3HardenedGetUserAndLogSids(&pCleanup->User.Sid, sizeof(pCleanup->User),
- &pCleanup->Login.Sid, sizeof(pCleanup->Login));
+ bool fHasLoginSid = supR3HardNtChildGetUserAndLogSids(&pCleanup->User.Sid, sizeof(pCleanup->User),
+ &pCleanup->Login.Sid, sizeof(pCleanup->Login));
# if 1
/* Grant minimal access to the user. */
@@ -2784,7 +2977,7 @@ static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURIT
/*
* Create a security descriptor with the above ACL.
*/
- PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)suplibHardenedAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
+ PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)RTMemAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
pCleanup->pSecDesc = pSecDesc;
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
@@ -2830,7 +3023,7 @@ DECLINLINE(bool) suplibCommandLineIsArgSeparator(int ch)
* @param iWhich Which respawn we're to check for, 1 being the first
* one, and 2 the second and final.
*/
-static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iWhich)
+static PRTUTF16 supR3HardNtChildConstructCmdLine(PUNICODE_STRING pString, int iWhich)
{
SUPR3HARDENED_ASSERT(iWhich == 1 || iWhich == 2);
@@ -2883,10 +3076,10 @@ static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iW
size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_1_ARG0) - 1) / sizeof(SUPR3_RESPAWN_1_ARG0[0]) /* Respawn exe name. */
+ !!cwcArgs + cwcArgs; /* if arguments present, add space + arguments. */
if (cwcCmdLine * sizeof(WCHAR) >= 0xfff0)
- supR3HardenedFatalMsg("supR3HardenedWinConstructCmdLine", kSupInitOp_Misc, VERR_OUT_OF_RANGE,
+ supR3HardenedFatalMsg("supR3HardNtChildConstructCmdLine", kSupInitOp_Misc, VERR_OUT_OF_RANGE,
"Command line is too long (%u chars)!", cwcCmdLine);
- PRTUTF16 pwszCmdLine = (PRTUTF16)HeapAlloc(GetProcessHeap(), 0 /* dwFlags*/, (cwcCmdLine + 1) * sizeof(RTUTF16));
+ PRTUTF16 pwszCmdLine = (PRTUTF16)RTMemAlloc((cwcCmdLine + 1) * sizeof(RTUTF16));
SUPR3HARDENED_ASSERT(pwszCmdLine != NULL);
/*
@@ -2917,565 +3110,630 @@ static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iW
/**
- * Check if the zero terminated NT unicode string is the path to the given
- * system32 DLL.
+ * Terminates the child process.
*
- * @returns true if it is, false if not.
- * @param pUniStr The zero terminated NT unicode string path.
- * @param pszName The name of the system32 DLL.
+ * @param hProcess The process handle.
+ * @param pszWhere Who's having child rasing troubles.
+ * @param rc The status code to report.
+ * @param pszFormat The message format string.
+ * @param ... Message format arguments.
*/
-static bool supR3HardNtIsNamedSystem32Dll(PUNICODE_STRING pUniStr, const char *pszName)
+static void supR3HardenedWinKillChild(HANDLE hProcess, const char *pszWhere, int rc, const char *pszFormat, ...)
{
- if (pUniStr->Length > g_System32NtPath.UniStr.Length)
+ /*
+ * Terminate the process ASAP and display error.
+ */
+ NtTerminateProcess(hProcess, RTEXITCODE_FAILURE);
+
+ va_list va;
+ va_start(va, pszFormat);
+ supR3HardenedErrorV(rc, false /*fFatal*/, pszFormat, va);
+ va_end(va);
+
+ /*
+ * Wait for the process to really go away.
+ */
+ PROCESS_BASIC_INFORMATION BasicInfo;
+ NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+ bool fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
+ if (!fExitOk)
{
- if (memcmp(pUniStr->Buffer, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
+ NTSTATUS rcNtWait;
+ uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+ do
{
- if (pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR)] == '\\')
- {
- if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
- return true;
- }
- }
+ NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
+
+ LARGE_INTEGER Timeout;
+ Timeout.QuadPart = -20000000; /* 2 second */
+ rcNtWait = NtWaitForSingleObject(hProcess, TRUE /*Alertable*/, &Timeout);
+
+ rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+ fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
+ } while ( !fExitOk
+ && ( rcNtWait == STATUS_TIMEOUT
+ || rcNtWait == STATUS_USER_APC
+ || rcNtWait == STATUS_ALERTED)
+ && supR3HardenedWinGetMilliTS() - uMsTsStart < 60 * 1000);
+ if (fExitOk)
+ supR3HardenedError(rc, false /*fFatal*/,
+ "NtDuplicateObject failed and we failed to kill child: rc=%u (%#x) rcNtWait=%#x hProcess=%p\n",
+ rc, rc, rcNtWait, hProcess);
}
- return false;
+ /*
+ * Final error message.
+ */
+ va_start(va, pszFormat);
+ supR3HardenedFatalMsgV(pszWhere, kSupInitOp_Misc, rc, pszFormat, va);
+ va_end(va);
}
/**
- * Common code used for child and parent to make new threads exit immediately.
+ * Checks the child process when hEvtParent is signalled.
*
- * This patches the LdrInitializeThunk code to call NtTerminateThread with
- * STATUS_SUCCESS instead of doing the NTDLL initialization.
+ * This will read the request data from the child and check it against expected
+ * request. If an error is signalled, we'll raise it and make sure the child
+ * terminates before terminating the calling process.
*
- * @returns VBox status code.
- * @param hProcess The process to do this to.
- * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
- * override.
- * @param pvNtTerminateThread The address of the NtTerminateThread function in
- * the NTDLL instance we're patching. (Must be +/-
- * 2GB from the thunk code.)
- * @param pabBackup Where to back up the original instruction bytes
- * at pvLdrInitThunk.
- * @param cbBackup The size of the backup area. Must be 16 bytes.
- * @param pErrInfo Where to return extended error information.
- * Optional.
+ * @param pThis The child process data structure.
+ * @param enmExpectedRequest The expected child request.
+ * @param pszWhat What we're waiting for.
*/
-static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
- uint8_t *pabBackup, size_t cbBackup, PRTERRINFO pErrInfo)
+static void supR3HardNtChildProcessRequest(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, const char *pszWhat)
{
- SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
- SUPR3HARDENED_ASSERT(cbBackup == 16);
- SUPR3HARDENED_ASSERT(RT_ABS((intptr_t)pvLdrInitThunk - (intptr_t)pvNtTerminateThread) < 16*_1M);
+ /*
+ * Read the process parameters from the child.
+ */
+ uintptr_t uChildAddr = (uintptr_t)pThis->Peb.ImageBaseAddress
+ + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
+ SIZE_T cbIgnored = 0;
+ RT_ZERO(pThis->ProcParams);
+ NTSTATUS rcNt = NtReadVirtualMemory(pThis->hProcess, (PVOID)uChildAddr,
+ &pThis->ProcParams, sizeof(pThis->ProcParams), &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildProcessRequest", rcNt,
+ "NtReadVirtualMemory(,%p,) failed reading child process status: %#x\n", uChildAddr, rcNt);
/*
- * Back up the thunk code.
+ * Is it the expected request?
*/
- SIZE_T cbIgnored;
- NTSTATUS rcNt = NtReadVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+ if (pThis->ProcParams.enmRequest == enmExpectedRequest)
+ return;
+
+ /*
+ * No, not the expected request. If it's an error request, tell the child
+ * to terminate itself, otherwise we'll have to terminate it.
+ */
+ pThis->ProcParams.szErrorMsg[sizeof(pThis->ProcParams.szErrorMsg) - 1] = '\0';
+ pThis->ProcParams.szWhere[sizeof(pThis->ProcParams.szWhere) - 1] = '\0';
+ SUP_DPRINTF(("supR3HardenedWinCheckChild: enmRequest=%d rc=%d enmWhat=%d %s: %s\n",
+ pThis->ProcParams.enmRequest, pThis->ProcParams.rc, pThis->ProcParams.enmWhat,
+ pThis->ProcParams.szWhere, pThis->ProcParams.szErrorMsg));
+
+ if (pThis->ProcParams.enmRequest != kSupR3WinChildReq_Error)
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinCheckChild", VERR_INVALID_PARAMETER,
+ "Unexpected child request #%d. Was expecting #%d (%s).\n",
+ pThis->ProcParams.enmRequest, enmExpectedRequest, pszWhat);
+
+ rcNt = NtSetEvent(pThis->hEvtChild, NULL);
if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtDisableThreadCreation: NtReadVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildProcessRequest", rcNt, "NtSetEvent failed: %#x\n", rcNt);
+
+ /* Wait for it to terminate. */
+ LARGE_INTEGER Timeout;
+ Timeout.QuadPart = -50000000; /* 5 seconds */
+ rcNt = NtWaitForSingleObject(pThis->hProcess, FALSE /*Alertable*/, &Timeout);
+ if (rcNt != STATUS_WAIT_0)
+ {
+ SUP_DPRINTF(("supR3HardNtChildProcessRequest: Child is taking too long to quit (rcWait=%#x), killing it...\n", rcNt));
+ NtTerminateProcess(pThis->hProcess, DBG_TERMINATE_PROCESS);
+ }
/*
- * Cook up replacement code that calls NtTerminateThread.
+ * Report the error in the same way as it occured in the guest.
*/
- uint8_t abReplacement[16];
- memcpy(abReplacement, pabBackup, sizeof(abReplacement));
-
-#ifdef RT_ARCH_AMD64
- abReplacement[0] = 0x31; /* xor ecx, ecx */
- abReplacement[1] = 0xc9;
- abReplacement[2] = 0x31; /* xor edx, edx */
- abReplacement[3] = 0xd2;
- abReplacement[4] = 0xe8; /* call near NtTerminateThread */
- *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
- abReplacement[9] = 0xcc; /* int3 */
-#elif defined(RT_ARCH_X86)
- abReplacement[0] = 0x6a; /* push 0 */
- abReplacement[1] = 0x00;
- abReplacement[2] = 0x6a; /* push 0 */
- abReplacement[3] = 0x00;
- abReplacement[4] = 0xe8; /* call near NtTerminateThread */
- *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
- abReplacement[9] = 0xcc; /* int3 */
-#else
-# error "Unsupported arch."
-#endif
-
- /*
- * Install the replacment code.
- */
- PVOID pvProt = pvLdrInitThunk;
- SIZE_T cbProt = cbBackup;
- ULONG fOldProt = 0;
- rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
-
- rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtDisableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
-
- pvProt = pvLdrInitThunk;
- cbProt = cbBackup;
- rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
-
- return VINF_SUCCESS;
-}
+ if (pThis->ProcParams.enmWhat == kSupInitOp_Invalid)
+ supR3HardenedFatalMsg("supR3HardenedWinCheckChild", kSupInitOp_Misc, pThis->ProcParams.rc,
+ "%s", pThis->ProcParams.szErrorMsg);
+ else
+ supR3HardenedFatalMsg(pThis->ProcParams.szWhere, pThis->ProcParams.enmWhat, pThis->ProcParams.rc,
+ "%s", pThis->ProcParams.szErrorMsg);
+}
/**
- * Undo the effects of supR3HardNtDisableThreadCreationEx.
+ * Waits for the child to make a certain request or terminate.
*
- * @returns VBox status code.
- * @param hProcess The process to do this to.
- * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
- * override.
- * @param pabBackup Where to back up the original instruction bytes
- * at pvLdrInitThunk.
- * @param cbBackup The size of the backup area. Must be 16 bytes.
- * @param pErrInfo Where to return extended error information.
- * Optional.
+ * The stub process will also wait on it's parent to terminate.
+ * This call will only return if the child made the expected request.
+ *
+ * @param pThis The child process data structure.
+ * @param enmExpectedRequest The child request to wait for.
+ * @param cMsTimeout The number of milliseconds to wait (at least).
+ * @param pszWhat What we're waiting for.
*/
-static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
- PRTERRINFO pErrInfo)
+static void supR3HardNtChildWaitFor(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, RTMSINTERVAL cMsTimeout,
+ const char *pszWhat)
{
- SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
- SUPR3HARDENED_ASSERT(cbBackup == 16);
+ /*
+ * The wait loop.
+ * Will return when the expected request arrives.
+ * Will break out when one of the processes terminates.
+ */
+ NTSTATUS rcNtWait;
+ LARGE_INTEGER Timeout;
+ uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+ uint64_t cMsElapsed = 0;
+ for (;;)
+ {
+ /*
+ * Assemble handles to wait for.
+ */
+ ULONG cHandles = 1;
+ HANDLE ahHandles[3];
+ ahHandles[0] = pThis->hProcess;
+ if (pThis->hEvtParent)
+ ahHandles[cHandles++] = pThis->hEvtParent;
+ if (pThis->hParent)
+ ahHandles[cHandles++] = pThis->hParent;
- PVOID pvProt = pvLdrInitThunk;
- SIZE_T cbProt = cbBackup;
- ULONG fOldProt = 0;
- NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+ /*
+ * Do the waiting according to the callers wishes.
+ */
+ if ( enmExpectedRequest == kSupR3WinChildReq_End
+ || cMsTimeout == RT_INDEFINITE_WAIT)
+ rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*Timeout*/);
+ else
+ {
+ Timeout.QuadPart = -(int64_t)(cMsTimeout - cMsElapsed) * 10000;
+ rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, &Timeout);
+ }
- SIZE_T cbIgnored;
- rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
- rcNt);
+ /*
+ * Process child request.
+ */
+ if (rcNtWait == STATUS_WAIT_0 + 1 && pThis->hEvtParent != NULL)
+ {
+ supR3HardNtChildProcessRequest(pThis, enmExpectedRequest, pszWhat);
+ SUP_DPRINTF(("supR3HardNtChildWaitFor: Found expected request %d (%s) after %llu ms.\n",
+ enmExpectedRequest, pszWhat, supR3HardenedWinGetMilliTS() - uMsTsStart));
+ return; /* Expected request received. */
+ }
- pvProt = pvLdrInitThunk;
- cbProt = cbBackup;
- rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
- rcNt);
+ /*
+ * Process termination?
+ */
+ if ( (ULONG)rcNtWait - (ULONG)STATUS_WAIT_0 < cHandles
+ || (ULONG)rcNtWait - (ULONG)STATUS_ABANDONED_WAIT_0 < cHandles)
+ break;
- return VINF_SUCCESS;
-}
+ /*
+ * Check sanity.
+ */
+ if ( rcNtWait != STATUS_TIMEOUT
+ && rcNtWait != STATUS_USER_APC
+ && rcNtWait != STATUS_ALERTED)
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildWaitFor", rcNtWait,
+ "NtWaitForMultipleObjects returned %#x waiting for #%d (%s)\n",
+ rcNtWait, enmExpectedRequest, pszWhat);
+ /*
+ * Calc elapsed time for the next timeout calculation, checking to see
+ * if we've timed out already.
+ */
+ cMsElapsed = supR3HardenedWinGetMilliTS() - uMsTsStart;
+ if ( cMsElapsed > cMsTimeout
+ && cMsTimeout != RT_INDEFINITE_WAIT
+ && enmExpectedRequest != kSupR3WinChildReq_End)
+ {
+ if (rcNtWait == STATUS_USER_APC || rcNtWait == STATUS_ALERTED)
+ cMsElapsed = cMsTimeout - 1; /* try again */
+ else
+ {
+ /* We timed out. */
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildWaitFor", rcNtWait,
+ "Timed out after %llu ms waiting for child request #%d (%s).\n",
+ cMsElapsed, enmExpectedRequest, pszWhat);
+ }
+ }
+ }
-/**
- * Disable thread creation for the current process.
- *
- * @remarks Doesn't really disables it, just makes the threads exit immediately
- * without executing any real code.
- */
-static void supR3HardenedWinDisableThreadCreation(void)
-{
- /* Cannot use the imported NtTerminateThread as it's pointing to our own
- syscall assembly code. */
- FARPROC pfnNtTerminateThread = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtTerminateThread");
- SUPR3HARDENED_ASSERT(pfnNtTerminateThread);
+ /*
+ * Proxy the termination code of the child, if it exited already.
+ */
+ PROCESS_BASIC_INFORMATION BasicInfo;
+ NTSTATUS rcNt1 = NtQueryInformationProcess(pThis->hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+ NTSTATUS rcNt2 = STATUS_PENDING;
+ NTSTATUS rcNt3 = STATUS_PENDING;
+ if ( !NT_SUCCESS(rcNt1)
+ || BasicInfo.ExitStatus == STATUS_PENDING)
+ {
+ rcNt2 = NtTerminateProcess(pThis->hProcess, RTEXITCODE_FAILURE);
+ Timeout.QuadPart = NT_SUCCESS(rcNt2) ? -20000000 /* 2 sec */ : -1280000 /* 128 ms */;
+ rcNt3 = NtWaitForSingleObject(pThis->hProcess, FALSE /*Alertable*/, NULL /*Timeout*/);
+ BasicInfo.ExitStatus = RTEXITCODE_FAILURE;
+ }
- int rc = supR3HardNtDisableThreadCreationEx(NtCurrentProcess(),
- (void *)(uintptr_t)&LdrInitializeThunk,
- (void *)(uintptr_t)pfnNtTerminateThread,
- g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
- NULL /* pErrInfo*/);
- g_fSupInitThunkSelfPatched = RT_SUCCESS(rc);
+ SUP_DPRINTF(("supR3HardNtChildWaitFor[%d]: Quitting: ExitCode=%#x (rcNtWait=%#x, rcNt1=%#x, rcNt2=%#x, rcNt3=%#x, %llu ms, %s);\n",
+ pThis->iWhich, BasicInfo.ExitStatus, rcNtWait, rcNt1, rcNt2, rcNt3,
+ supR3HardenedWinGetMilliTS() - uMsTsStart, pszWhat));
+ suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
}
/**
- * Undoes the effects of supR3HardenedWinDisableThreadCreation.
+ * Closes full access child thread and process handles, making a harmless
+ * duplicate of the process handle first.
+ *
+ * The hProcess member of the child process data structure will be change to the
+ * harmless handle, while the hThread will be set to NULL.
+ *
+ * @param pThis The child process data structure.
*/
-DECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void)
+static void supR3HardNtChildCloseFullAccessHandles(PSUPR3HARDNTCHILD pThis)
{
- if (g_fSupInitThunkSelfPatched)
+ /*
+ * The thread handle.
+ */
+ NTSTATUS rcNt = NtClose(pThis->hThread);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", rcNt, "NtClose(hThread) failed: %#x", rcNt);
+ pThis->hThread = NULL;
+
+ /*
+ * Duplicate the process handle into a harmless one.
+ */
+ HANDLE hProcWait;
+ ULONG fRights = SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_VM_READ;
+ if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
+ fRights |= PROCESS_QUERY_LIMITED_INFORMATION;
+ else
+ fRights |= PROCESS_QUERY_INFORMATION;
+ rcNt = NtDuplicateObject(NtCurrentProcess(), pThis->hProcess,
+ NtCurrentProcess(), &hProcWait,
+ fRights, 0 /*HandleAttributes*/, 0);
+ if (rcNt == STATUS_ACCESS_DENIED)
{
- int rc = supR3HardNtEnableThreadCreationEx(NtCurrentProcess(),
- (void *)(uintptr_t)&LdrInitializeThunk,
- g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
- RTErrInfoInitStatic(&g_ErrInfoStatic));
- if (RT_FAILURE(rc))
- supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
- g_fSupInitThunkSelfPatched = false;
+ supR3HardenedError(rcNt, false /*fFatal*/,
+ "supR3HardenedWinDoReSpawn: NtDuplicateObject(,,,,%#x,,) -> %#x, retrying with only %#x...\n",
+ fRights, rcNt, SYNCHRONIZE);
+ rcNt = NtDuplicateObject(NtCurrentProcess(), pThis->hProcess,
+ NtCurrentProcess(), &hProcWait,
+ SYNCHRONIZE, 0 /*HandleAttributes*/, 0);
}
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", rcNt,
+ "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
+ /*
+ * Close the process handle and replace it with the harmless one.
+ */
+ rcNt = NtClose(pThis->hProcess);
+ pThis->hProcess = hProcWait;
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", VERR_INVALID_NAME,
+ "NtClose failed on child process handle: %#x\n", rcNt);
}
-
-/*
- * Child-Process Purification - release it from dubious influences.
- *
- * AV software and other things injecting themselves into the embryonic
- * and budding process to intercept API calls and what not. Unfortunately
- * this is also the behavior of viruses, malware and other unfriendly
- * software, so we won't stand for it. AV software can scan our image
- * as they are loaded via kernel hooks, that's sufficient. No need for
- * matching half of NTDLL or messing with the import table of the
- * process executable.
+/**
+ * This restores the child PEB and tweaks a couple of fields before we do the
+ * child purification and let the process run normally.
+ *
+ * @param pThis The child process data structure.
*/
-
-typedef struct SUPR3HARDNTPUCH
-{
- /** Process handle. */
- HANDLE hProcess;
- /** Primary thread handle. */
- HANDLE hThread;
- /** Error buffer. */
- PRTERRINFO pErrInfo;
- /** The address of NTDLL in the child. */
- uintptr_t uNtDllAddr;
- /** The address of NTDLL in this process. */
- uintptr_t uNtDllParentAddr;
- /** The basic process info. */
- PROCESS_BASIC_INFORMATION BasicInfo;
- /** The probable size of the PEB. */
- size_t cbPeb;
- /** The pristine process environment block. */
- PEB Peb;
-} SUPR3HARDNTPUCH;
-typedef SUPR3HARDNTPUCH *PSUPR3HARDNTPUCH;
-
-
-static int supR3HardNtPuChScrewUpPebForInitialImageEvents(PSUPR3HARDNTPUCH pThis)
+static void supR3HardNtChildSanitizePeb(PSUPR3HARDNTCHILD pThis)
{
/*
- * Not sure if any of the cracker software uses the PEB at this point, but
- * just in case they do make some of the PEB fields a little less useful.
+ * Make a copy of the pre-execution PEB.
*/
PEB Peb = pThis->Peb;
- /* Make ImageBaseAddress useless. */
- Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress ^ UINT32_C(0x5f139000));
-#ifdef RT_ARCH_AMD64
- Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress | UINT64_C(0x0313000000000000));
+#if 0
+ /*
+ * There should not be any activation context, so if there is, we scratch the memory associated with it.
+ */
+ int rc = 0;
+ if (RT_SUCCESS(rc) && Peb.pShimData && !((uintptr_t)Peb.pShimData & PAGE_OFFSET_MASK))
+ rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.pShimData, PAGE_SIZE, "pShimData", pErrInfo);
+ if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
+ rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
+ if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
+ rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
+ if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
+ rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
+ if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
+ rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
+ if (RT_FAILURE(rc))
+ return rc;
#endif
/*
- * Write the PEB.
+ * Clear compatibility and activation related fields.
+ */
+ Peb.AppCompatFlags.QuadPart = 0;
+ Peb.AppCompatFlagsUser.QuadPart = 0;
+ Peb.pShimData = NULL;
+ Peb.AppCompatInfo = NULL;
+#if 0
+ Peb.ActivationContextData = NULL;
+ Peb.ProcessAssemblyStorageMap = NULL;
+ Peb.SystemDefaultActivationContextData = NULL;
+ Peb.SystemAssemblyStorageMap = NULL;
+ /*Peb.Diff0.W6.IsProtectedProcess = 1;*/
+#endif
+
+ /*
+ * Write back the PEB.
*/
SIZE_T cbActualMem = pThis->cbPeb;
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
- return VINF_SUCCESS;
-}
-
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildSanitizePeb", rcNt,
+ "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
-/**
- * Unmaps a DLL from the child process that was previously mapped by
- * supR3HardNtPuChMapDllIntoChild.
- *
- * @returns Pointer to the DLL mapping on success, NULL on failure.
- * @param pThis The child purification instance data.
- * @param pvBase The base address of the mapping. Nothing done
- * if NULL.
- * @param pszShort The short name (for logging).
- */
-static void supR3HardNtPuChUnmapDllFromChild(PSUPR3HARDNTPUCH pThis, PVOID pvBase, const char *pszShort)
-{
- if (pvBase)
- {
- /*SUP_DPRINTF(("supR3HardNtPuChUnmapDllFromChild: Calling NtUnmapViewOfSection on %p / %s\n", pvBase, pszShort));*/
- NTSTATUS rcNt = NtUnmapViewOfSection(pThis->hProcess, pvBase);
- if (!NT_SUCCESS(!rcNt))
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtUnmapViewOfSection failed on %s: %#x (%p)\n",
- pszShort, rcNt, pvBase));
- }
}
/**
- * Maps a DLL into the child process.
+ * Purifies the child process after very early init has been performed.
*
- * @returns Pointer to the DLL mapping on success, NULL on failure.
- * @param pThis The child purification instance data.
- * @param pNtName The path to the DLL.
- * @param pszShort The short name (for logging).
+ * @param pThis The child process data structure.
*/
-static PVOID supR3HardNtPuChMapDllIntoChild(PSUPR3HARDNTPUCH pThis, PUNICODE_STRING pNtName, const char *pszShort)
+static void supR3HardNtChildPurify(PSUPR3HARDNTCHILD pThis)
{
- HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
- IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
- OBJECT_ATTRIBUTES ObjAttr;
- InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
- NTSTATUS rcNt = NtCreateFile(&hFile,
- GENERIC_READ | GENERIC_EXECUTE,
- &ObjAttr,
- &Ios,
- NULL /* Allocation Size*/,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ,
- FILE_OPEN,
- FILE_NON_DIRECTORY_FILE,
- NULL /*EaBuffer*/,
- 0 /*EaLength*/);
- if (NT_SUCCESS(rcNt))
- rcNt = Ios.Status;
- PVOID pvRet = NULL;
- if (NT_SUCCESS(rcNt))
+ /*
+ * We loop until we no longer make any fixes. This is similar to what
+ * we do (or used to do, really) in the fAvastKludge case of
+ * supR3HardenedWinInit. We might be up against asynchronous changes,
+ * which we fudge by waiting a short while before earch purification. This
+ * is arguably a fragile technique, but it's currently the best we've got.
+ * Fortunately, most AVs seems to either favor immediate action on initial
+ * load events or (much better for us) later events like kernel32.
+ */
+ uint64_t uMsTsOuterStart = supR3HardenedWinGetMilliTS();
+ uint32_t cMsFudge = g_fSupAdversaries ? 512 : 256;
+ uint32_t cTotalFixes = 0;
+ uint32_t cFixes;
+ for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
{
- HANDLE hSection = RTNT_INVALID_HANDLE_VALUE;
- rcNt = NtCreateSection(&hSection,
- SECTION_MAP_EXECUTE | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_QUERY,
- NULL /* pObjAttr*/, NULL /*pMaxSize*/,
- PAGE_EXECUTE, SEC_IMAGE, hFile);
- if (NT_SUCCESS(rcNt))
+ /*
+ * Delay.
+ */
+ uint32_t cSleeps = 0;
+ uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+ do
{
- SIZE_T cbView = 0;
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: mapping view of %s\n", pszShort)); /* For SEP. */
- rcNt = NtMapViewOfSection(hSection, pThis->hProcess, &pvRet, 0 /*ZeroBits*/, 0 /*CommitSize*/,
- NULL /*pOffSect*/, &cbView, ViewShare, 0 /*AllocationType*/, PAGE_READWRITE);
- if (NT_SUCCESS(rcNt))
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: %s mapped at %p LB %#x\n", pszShort, pvRet, cbView));
- else
- {
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtMapViewOfSection failed on %s: %#x\n", pszShort, rcNt));
- pvRet = NULL;
- }
- NtClose(hSection);
+ NtYieldExecution();
+ LARGE_INTEGER Time;
+ Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
+ NtDelayExecution(FALSE, &Time);
+ cSleeps++;
+ } while ( supR3HardenedWinGetMilliTS() - uMsTsStart <= cMsFudge
+ || cSleeps < 8);
+ SUP_DPRINTF(("supR3HardNtChildPurify: Startup delay kludge #1/%u: %u ms, %u sleeps\n",
+ iLoop, supR3HardenedWinGetMilliTS() - uMsTsStart, cSleeps));
+
+ /*
+ * Purify.
+ */
+ cFixes = 0;
+ int rc = supHardenedWinVerifyProcess(pThis->hProcess, pThis->hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION,
+ g_fSupAdversaries & ( SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE
+ | SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN)
+ ? SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW : 0,
+ &cFixes, RTErrInfoInitStatic(&g_ErrInfoStatic));
+ if (RT_FAILURE(rc))
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildPurify", rc,
+ "supHardenedWinVerifyProcess failed with %Rrc: %s", rc, g_ErrInfoStatic.szMsg);
+ if (cFixes == 0)
+ {
+ SUP_DPRINTF(("supR3HardNtChildPurify: Done after %llu ms and %u fixes (loop #%u).\n",
+ supR3HardenedWinGetMilliTS() - uMsTsOuterStart, cTotalFixes, iLoop));
+ return; /* We're probably good. */
}
+ cTotalFixes += cFixes;
+
+ if (!g_fSupAdversaries)
+ g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
+ cMsFudge = 512;
+
+ /*
+ * Log the KiOpPrefetchPatchCount value if available, hoping it might
+ * sched some light on spider38's case.
+ */
+ ULONG cPatchCount = 0;
+ NTSTATUS rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
+ &cPatchCount, sizeof(cPatchCount), NULL);
+ if (NT_SUCCESS(rcNt))
+ SUP_DPRINTF(("supR3HardNtChildPurify: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
+ cFixes, g_fSupAdversaries, cPatchCount));
else
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtCreateSection failed on %s: %#x\n", pszShort, rcNt));
- NtClose(hFile);
+ SUP_DPRINTF(("supR3HardNtChildPurify: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
}
- else
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Error opening %s: %#x\n", pszShort, rcNt));
- return pvRet;
+
+ /*
+ * We've given up fixing the child process. Probably fighting someone
+ * that monitors their patches or/and our activities.
+ */
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildPurify", VERR_TRY_AGAIN,
+ "Unable to purify child process! After 16 tries over %llu ms, we still %u fix(es) in the last pass.",
+ supR3HardenedWinGetMilliTS() - uMsTsOuterStart, cFixes);
}
+
/**
- * Trigger the initial image events without actually initializing the process.
- *
- * This is a trick to force sysplant.sys to call its hand by tripping the image
- * loaded event for the main executable and ntdll images. This will happen when
- * the first thread in a process starts executing in PspUserThreadStartup. We
- * create a second thread that quits immediately by means of temporarily
- * replacing ntdll!LdrInitializeThunk by a NtTerminateThread call.
- * (LdrInitializeThunk is called by way of an APC queued the thread is created,
- * thus NtSetContextThread is of no use.)
+ * Sets up the early process init.
*
- * @returns VBox status code.
- * @param pThis The child cleanup
- * @param pErrInfo For extended error information.
+ * @param pThis The child process data structure.
*/
-static int supR3HardNtPuChTriggerInitialImageEvents(PSUPR3HARDNTPUCH pThis)
+static void supR3HardNtChildSetUpChildInit(PSUPR3HARDNTCHILD pThis)
{
+ uintptr_t const uChildExeAddr = (uintptr_t)pThis->Peb.ImageBaseAddress;
+
+ /*
+ * Plant the process parameters. This ASSUMES the handle inheritance is
+ * performed when creating the child process.
+ */
+ RT_ZERO(pThis->ProcParams);
+ pThis->ProcParams.hEvtChild = pThis->hEvtChild;
+ pThis->ProcParams.hEvtParent = pThis->hEvtParent;
+ pThis->ProcParams.uNtDllAddr = pThis->uNtDllAddr;
+ pThis->ProcParams.enmRequest = kSupR3WinChildReq_Error;
+ pThis->ProcParams.rc = VINF_SUCCESS;
+
+ uintptr_t uChildAddr = uChildExeAddr + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
+ SIZE_T cbIgnored;
+ NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, (PVOID)uChildAddr, &pThis->ProcParams,
+ sizeof(pThis->ProcParams), &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+ "NtWriteVirtualMemory(,%p,) failed writing child process parameters: %#x\n", uChildAddr, rcNt);
+
/*
- * Use the on-disk image for the ntdll entrypoints here.
+ * Locate the LdrInitializeThunk address in the child as well as pristine
+ * code bits for it.
*/
PSUPHNTLDRCACHEENTRY pLdrEntry;
int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
if (RT_FAILURE(rc))
- return RTErrInfoSetF(pThis->pErrInfo, rc, "supHardNtLdrCacheOpen failed on NTDLL: %Rrc", rc);
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+ "supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
+
+ uint8_t *pbChildNtDllBits;
+ rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbChildNtDllBits, pThis->uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
+ if (RT_FAILURE(rc))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+ "supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
RTLDRADDR uLdrInitThunk;
- rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
+ rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbChildNtDllBits, pThis->uNtDllAddr, UINT32_MAX,
"LdrInitializeThunk", &uLdrInitThunk);
if (RT_FAILURE(rc))
- return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating LdrInitializeThunk in NTDLL: %Rrc", rc);
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+ "Error locating LdrInitializeThunk in NTDLL: %Rrc", rc);
PVOID pvLdrInitThunk = (PVOID)(uintptr_t)uLdrInitThunk;
-
- RTLDRADDR uNtTerminateThread;
- rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
- "NtTerminateThread", &uNtTerminateThread);
- if (RT_FAILURE(rc))
- return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating NtTerminateThread in NTDLL: %Rrc", rc);
-
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: uLdrInitThunk=%p uNtTerminateThread=%p\n",
- (uintptr_t)uLdrInitThunk, (uintptr_t)uNtTerminateThread));
+ SUP_DPRINTF(("supR3HardenedWinSetupChildInit: uLdrInitThunk=%p\n", (uintptr_t)uLdrInitThunk));
/*
- * Patch the child's LdrInitializeThunk to exit the thread immediately.
+ * Calculate the address of our code in the child process.
*/
- uint8_t abBackup[16];
- rc = supR3HardNtDisableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, (void *)(uintptr_t)uNtTerminateThread,
- abBackup, sizeof(abBackup), pThis->pErrInfo);
- if (RT_FAILURE(rc))
- return rc;
+ uintptr_t uEarlyProcInitEP = uChildExeAddr + ( (uintptr_t)&supR3HardenedEarlyProcessInitThunk
+ - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
/*
- * To further muddle the waters, we map the executable image and ntdll.dll
- * a 2nd time into the process before we actually start executing the thread
- * and trigger the genuine image load events.
- *
- * Update: Turns out Symantec Endpoint Protection deadlocks when we map the
- * executable into the process like this. The system only works
- * halfways after that Powerbutton, impossible to shutdown without
- * using the power or reset button. The order of the two mappings
- * below doesn't matter. Haven't had time to look at stack yet.
- * Observed on W7/64, SEP v12.1.4112.4156.
- *
+ * Compose the LdrInitializeThunk replacement bytes.
+ * Note! The amount of code we replace here must be less or equal to what
+ * the process verification code ignores.
*/
-#if 0
- PVOID pvExe2 = supR3HardNtPuChMapDllIntoChild(pThis, &g_SupLibHardenedExeNtPath.UniStr, "executable[2nd]");
+ uint8_t abNew[16];
+ memcpy(abNew, pbChildNtDllBits + ((uintptr_t)uLdrInitThunk - pThis->uNtDllAddr), sizeof(abNew));
+#ifdef RT_ARCH_AMD64
+ abNew[0] = 0xff;
+ abNew[1] = 0x25;
+ *(uint32_t *)&abNew[2] = 0;
+ *(uint64_t *)&abNew[6] = uEarlyProcInitEP;
+#elif defined(RT_ARCH_X86)
+ abNew[0] = 0xe9;
+ *(uint32_t *)&abNew[1] = uEarlyProcInitEP - ((uint32_t)uLdrInitThunk + 5);
#else
- PVOID pvExe2 = NULL;
+# error "Unsupported arch."
#endif
- UNICODE_STRING NtName1 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\ntdll.dll");
- PVOID pvNtDll2 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName1, "ntdll.dll[2nd]");
-
- /*
- * Create the thread, waiting 10 seconds for it to complete.
- */
- CLIENT_ID Thread2Id;
- HANDLE hThread2;
- NTSTATUS rcNt = RtlCreateUserThread(pThis->hProcess,
- NULL /* SecurityAttribs */,
- FALSE /* CreateSuspended */,
- 0 /* ZeroBits */,
- 0 /* MaximumStackSize */,
- 0 /* CommittedStackSize */,
- (PFNRT)2 /* StartAddress */,
- NULL /*Parameter*/ ,
- &hThread2,
- &Thread2Id);
- if (NT_SUCCESS(rcNt))
- {
- LARGE_INTEGER Timeout;
- Timeout.QuadPart = -10 * 10000000; /* 10 seconds */
- NtWaitForSingleObject(hThread2, FALSE /* Alertable */, &Timeout);
- NtTerminateThread(hThread2, DBG_TERMINATE_THREAD);
- NtClose(hThread2);
- }
-
- /*
- * Map kernel32.dll and kernelbase.dll (if applicable) into the process.
- * This triggers should image load events that may set of AV activities
- * that we'd rather see early than later.
- */
- UNICODE_STRING NtName2 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\kernel32.dll");
- PVOID pvKernel32 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName2, "kernel32.dll");
-
- UNICODE_STRING NtName3 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\KernelBase.dll");
- PVOID pvKernelBase = g_uNtVerCombined >= SUP_NT_VER_VISTA
- ? supR3HardNtPuChMapDllIntoChild(pThis, &NtName3, "KernelBase.dll")
- : NULL;
/*
- * Fudge factor for letting kernel threads get a chance to mess up our
- * process asynchronously.
+ * Install the LdrInitializeThunk replacement code in the child process.
*/
- DWORD dwStart = GetTickCount();
- NtYieldExecution();
-
- LARGE_INTEGER Time;
- Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
- NtDelayExecution(FALSE, &Time);
-
- NtYieldExecution();
-
- Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
- NtDelayExecution(FALSE, &Time);
-
- NtYieldExecution();
- SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Startup delay kludge #1: %u ms\n", GetTickCount() - dwStart));
+ PVOID pvProt = pvLdrInitThunk;
+ SIZE_T cbProt = sizeof(abNew);
+ ULONG fOldProt;
+ rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+ "NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
- /*
- * Unmap the image we mapped into the guest above.
- */
- supR3HardNtPuChUnmapDllFromChild(pThis, pvKernel32, "kernel32.dll");
- supR3HardNtPuChUnmapDllFromChild(pThis, pvKernelBase, "KernelBase.dll");
- supR3HardNtPuChUnmapDllFromChild(pThis, pvNtDll2, "ntdll.dll[2nd]");
- supR3HardNtPuChUnmapDllFromChild(pThis, pvExe2, "executable[2nd]");
+ rcNt = NtWriteVirtualMemory(pThis->hProcess, pvLdrInitThunk, abNew, sizeof(abNew), &cbIgnored);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+ "NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
- /*
- * Restore the original thunk code and protection.
- * We do this after waiting as anyone trying to kick of threads in the
- * process will get nothing done as long as our patch is in place.
- */
- rc = supR3HardNtEnableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, abBackup, sizeof(abBackup), pThis->pErrInfo);
- if (RT_FAILURE(rc))
- return rc;
+ pvProt = pvLdrInitThunk;
+ cbProt = sizeof(abNew);
+ rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+ "NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x", rcNt);
- return VINF_SUCCESS;
+ /* Caller starts child execution. */
+ SUP_DPRINTF(("supR3HardenedWinSetupChildInit: Start child.\n"));
}
-#if 0
-static int supR3HardenedWinScratchChildMemory(HANDLE hProcess, void *pv, size_t cb, const char *pszWhat, PRTERRINFO pErrInfo)
-{
- SUP_DPRINTF(("supR3HardenedWinScratchChildMemory: %p %#x\n", pv, cb));
-
- PVOID pvCopy = pv;
- SIZE_T cbCopy = cb;
- NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
- if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtProtectVirtualMemory/%s (%p LB %#zx) failed: %#x",
- pszWhat, pv, cb, rcNt);
- return VINF_SUCCESS;
-}
-#endif
-static int supR3HardNtPuChSanitizePeb(PSUPR3HARDNTPUCH pThis)
+/**
+ * This messes with the child PEB before we trigger the initial image events.
+ *
+ * @param pThis The child process data structure.
+ */
+static void supR3HardNtChildScrewUpPebForInitialImageEvents(PSUPR3HARDNTCHILD pThis)
{
/*
- * Make a copy of the pre-execution PEB.
+ * Not sure if any of the cracker software uses the PEB at this point, but
+ * just in case they do make some of the PEB fields a little less useful.
*/
PEB Peb = pThis->Peb;
-#if 0
- /*
- * There should not be any activation context, so if there is, we scratch the memory associated with it.
- */
- int rc = 0;
- if (RT_SUCCESS(rc) && Peb.pShimData && !((uintptr_t)Peb.pShimData & PAGE_OFFSET_MASK))
- rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.pShimData, PAGE_SIZE, "pShimData", pErrInfo);
- if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
- rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
- if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
- rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
- if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
- rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
- if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
- rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
- if (RT_FAILURE(rc))
- return rc;
-#endif
-
- /*
- * Clear compatibility and activation related fields.
- */
- Peb.AppCompatFlags.QuadPart = 0;
- Peb.AppCompatFlagsUser.QuadPart = 0;
- Peb.pShimData = NULL;
- Peb.AppCompatInfo = NULL;
-#if 0
- Peb.ActivationContextData = NULL;
- Peb.ProcessAssemblyStorageMap = NULL;
- Peb.SystemDefaultActivationContextData = NULL;
- Peb.SystemAssemblyStorageMap = NULL;
- /*Peb.Diff0.W6.IsProtectedProcess = 1;*/
+ /* Make ImageBaseAddress useless. */
+ Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress ^ UINT32_C(0x5f139000));
+#ifdef RT_ARCH_AMD64
+ Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress | UINT64_C(0x0313000000000000));
#endif
/*
- * Write back the PEB.
+ * Write the PEB.
*/
SIZE_T cbActualMem = pThis->cbPeb;
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildScrewUpPebForInitialImageEvents", rcNt,
+ "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
+}
+
+
+/**
+ * Check if the zero terminated NT unicode string is the path to the given
+ * system32 DLL.
+ *
+ * @returns true if it is, false if not.
+ * @param pUniStr The zero terminated NT unicode string path.
+ * @param pszName The name of the system32 DLL.
+ */
+static bool supR3HardNtIsNamedSystem32Dll(PUNICODE_STRING pUniStr, const char *pszName)
+{
+ if (pUniStr->Length > g_System32NtPath.UniStr.Length)
+ {
+ if (memcmp(pUniStr->Buffer, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
+ {
+ if (pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR)] == '\\')
+ {
+ if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
+ return true;
+ }
+ }
+ }
- return VINF_SUCCESS;
+ return false;
}
-static void supR3HardNtPuChFindNtdll(PSUPR3HARDNTPUCH pThis)
+/**
+ * Worker for supR3HardNtChildGatherData that locates NTDLL in the child
+ * process.
+ *
+ * @param pThis The child process data structure.
+ */
+static void supR3HardNtChildFindNtdll(PSUPR3HARDNTCHILD pThis)
{
/*
* Find NTDLL in this process first and take that as a starting point.
@@ -3544,65 +3802,87 @@ static void supR3HardNtPuChFindNtdll(PSUPR3HARDNTPUCH pThis)
uPtrWhere += MemInfo.RegionSize;
}
-#ifdef DEBUG
- supR3HardenedFatal("%s: ntdll.dll not found in child.", __FUNCTION__);
-#endif
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildFindNtdll", VERR_MODULE_NOT_FOUND, "ntdll.dll not found in child process.");
}
-
-static int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
+/**
+ * Gather child data.
+ *
+ * @param This The child process data structure.
+ */
+static void supR3HardNtChildGatherData(PSUPR3HARDNTCHILD pThis)
{
/*
- * Initialize the purifier instance data.
+ * Basic info.
*/
- SUPR3HARDNTPUCH This;
- This.hProcess = hProcess;
- This.hThread = hThread;
- This.pErrInfo = pErrInfo;
-
ULONG cbActual = 0;
- NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
- &This.BasicInfo, sizeof(This.BasicInfo), &cbActual);
+ NTSTATUS rcNt = NtQueryInformationProcess(pThis->hProcess, ProcessBasicInformation,
+ &pThis->BasicInfo, sizeof(pThis->BasicInfo), &cbActual);
if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
- "NtQueryInformationProcess/ProcessBasicInformation failed: %#x", rcNt);
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildGatherData", rcNt,
+ "NtQueryInformationProcess/ProcessBasicInformation failed: %#x", rcNt);
+
+ /*
+ * If this is the middle (stub) process, we wish to wait for both child
+ * and parent. So open the parent process. Not fatal if we cannnot.
+ */
+ if (pThis->iWhich > 1)
+ {
+ PROCESS_BASIC_INFORMATION SelfInfo;
+ rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &SelfInfo, sizeof(SelfInfo), &cbActual);
+ if (NT_SUCCESS(rcNt))
+ {
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+ CLIENT_ID ClientId;
+ ClientId.UniqueProcess = (HANDLE)SelfInfo.InheritedFromUniqueProcessId;
+ ClientId.UniqueThread = NULL;
+
+ rcNt = NtOpenProcess(&pThis->hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
+#ifdef DEBUG
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
+#endif
+ if (!NT_SUCCESS(rcNt))
+ {
+ pThis->hParent = NULL;
+ SUP_DPRINTF(("supR3HardNtChildGatherData: Failed to open parent process (%#p): %#x\n", ClientId.UniqueProcess, rcNt));
+ }
+ }
+ }
+
+ /*
+ * Process environment block.
+ */
if (g_uNtVerCombined < SUP_NT_VER_W2K3)
- This.cbPeb = PEB_SIZE_W51;
+ pThis->cbPeb = PEB_SIZE_W51;
else if (g_uNtVerCombined < SUP_NT_VER_VISTA)
- This.cbPeb = PEB_SIZE_W52;
+ pThis->cbPeb = PEB_SIZE_W52;
else if (g_uNtVerCombined < SUP_NT_VER_W70)
- This.cbPeb = PEB_SIZE_W6;
+ pThis->cbPeb = PEB_SIZE_W6;
else if (g_uNtVerCombined < SUP_NT_VER_W80)
- This.cbPeb = PEB_SIZE_W7;
+ pThis->cbPeb = PEB_SIZE_W7;
else if (g_uNtVerCombined < SUP_NT_VER_W81)
- This.cbPeb = PEB_SIZE_W80;
+ pThis->cbPeb = PEB_SIZE_W80;
else
- This.cbPeb = PEB_SIZE_W81;
+ pThis->cbPeb = PEB_SIZE_W81;
- SUP_DPRINTF(("supR3HardenedWinPurifyChild: PebBaseAddress=%p cbPeb=%#x\n", This.BasicInfo.PebBaseAddress, This.cbPeb));
+ SUP_DPRINTF(("supR3HardNtChildGatherData: PebBaseAddress=%p cbPeb=%#x\n",
+ pThis->BasicInfo.PebBaseAddress, pThis->cbPeb));
SIZE_T cbActualMem;
- RT_ZERO(This.Peb);
- rcNt = NtReadVirtualMemory(hProcess, This.BasicInfo.PebBaseAddress, &This.Peb, sizeof(This.Peb), &cbActualMem);
+ RT_ZERO(pThis->Peb);
+ rcNt = NtReadVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &pThis->Peb, sizeof(pThis->Peb), &cbActualMem);
if (!NT_SUCCESS(rcNt))
- return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtReadVirtualMemory/Peb failed: %#x", rcNt);
-
- supR3HardNtPuChFindNtdll(&This);
+ supR3HardenedWinKillChild(pThis, "supR3HardNtChildGatherData", rcNt,
+ "NtReadVirtualMemory/Peb failed: %#x", rcNt);
/*
- * Do the work, the last bit we tag along with the process verfication code.
+ * Locate NtDll.
*/
- int rc = supR3HardNtPuChScrewUpPebForInitialImageEvents(&This);
- if (RT_SUCCESS(rc))
- rc = supR3HardNtPuChTriggerInitialImageEvents(&This);
- if (RT_SUCCESS(rc))
- rc = supR3HardNtPuChSanitizePeb(&This);
- if (RT_SUCCESS(rc))
- rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, NULL /*pcFixes*/, pErrInfo);
-
- return rc;
+ supR3HardNtChildFindNtdll(pThis);
}
@@ -3612,10 +3892,8 @@ static int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, PRTERRIN
* @returns Never, will call exit or raise fatal error.
* @param iWhich Which respawn we're to check for, 1 being the
* first one, and 2 the second and final.
- *
- * @todo Split up this function.
*/
-static int supR3HardenedWinDoReSpawn(int iWhich)
+static void supR3HardenedWinDoReSpawn(int iWhich)
{
NTSTATUS rcNt;
PPEB pPeb = NtCurrentPeb();
@@ -3624,15 +3902,32 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
SUPR3HARDENED_ASSERT(g_cSuplibHardenedWindowsMainCalls == 1);
/*
+ * Init the child process data structure, creating the child communication
+ * event sempahores.
+ */
+ SUPR3HARDNTCHILD This;
+ RT_ZERO(This);
+ This.iWhich = iWhich;
+
+ OBJECT_ATTRIBUTES ObjAttrs;
+ This.hEvtChild = NULL;
+ InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtChild, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
+
+ This.hEvtParent = NULL;
+ InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtParent, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
+
+ /*
* Set up security descriptors.
*/
SECURITY_ATTRIBUTES ProcessSecAttrs;
MYSECURITYCLEANUP ProcessSecAttrsCleanup;
- supR3HardenedInitSecAttrs(&ProcessSecAttrs, &ProcessSecAttrsCleanup, true /*fProcess*/);
+ supR3HardNtChildInitSecAttrs(&ProcessSecAttrs, &ProcessSecAttrsCleanup, true /*fProcess*/);
SECURITY_ATTRIBUTES ThreadSecAttrs;
MYSECURITYCLEANUP ThreadSecAttrsCleanup;
- supR3HardenedInitSecAttrs(&ThreadSecAttrs, &ThreadSecAttrsCleanup, false /*fProcess*/);
+ supR3HardNtChildInitSecAttrs(&ThreadSecAttrs, &ThreadSecAttrsCleanup, false /*fProcess*/);
#if 1
/*
@@ -3651,6 +3946,9 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
/** @todo experiment with protected process stuff later on. */
}
+ SiEx.StartupInfo.dwFlags |= pParentProcParams->WindowFlags & STARTF_USESHOWWINDOW;
+ SiEx.StartupInfo.wShowWindow = (WORD)pParentProcParams->ShowWindowFlags;
+
SiEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
SiEx.StartupInfo.hStdInput = pParentProcParams->StandardInput;
SiEx.StartupInfo.hStdOutput = pParentProcParams->StandardOutput;
@@ -3659,7 +3957,7 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
/*
* Construct the command line and launch the process.
*/
- PRTUTF16 pwszCmdLine = supR3HardenedWinConstructCmdLine(NULL, iWhich);
+ PRTUTF16 pwszCmdLine = supR3HardNtChildConstructCmdLine(NULL, iWhich);
supR3HardenedWinEnableThreadCreation();
PROCESS_INFORMATION ProcessInfoW32;
@@ -3676,13 +3974,13 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
"Error relaunching VirtualBox VM process: %u\n"
"Command line: '%ls'",
- GetLastError(), pwszCmdLine);
+ RtlGetLastWin32Error(), pwszCmdLine);
supR3HardenedWinDisableThreadCreation();
SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): New child %x.%x [kernel32].\n",
iWhich, ProcessInfoW32.dwProcessId, ProcessInfoW32.dwThreadId));
- HANDLE hProcess = ProcessInfoW32.hProcess;
- HANDLE hThread = ProcessInfoW32.hThread;
+ This.hProcess = ProcessInfoW32.hProcess;
+ This.hThread = ProcessInfoW32.hThread;
#else
@@ -3695,7 +3993,7 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
W32ImageName.MaximumLength = W32ImageName.Length + sizeof(WCHAR);
UNICODE_STRING CmdLine;
- supR3HardenedWinConstructCmdLine(&CmdLine, iWhich);
+ supR3HardNtChildConstructCmdLine(&CmdLine, iWhich);
PRTL_USER_PROCESS_PARAMETERS pProcParams = NULL;
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateProcessParameters(&pProcParams,
@@ -3738,178 +4036,239 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
iWhich, ProcessInfo.ClientId.UniqueProcess, ProcessInfo.ClientId.UniqueThread));
RtlDestroyProcessParameters(pProcParams);
- HANDLE hProcess = ProcessInfoNt.ProcessHandle;
- HANDLE hThread = ProcessInfoNt.ThreadHandle;
+ This.hProcess = ProcessInfoNt.ProcessHandle;
+ This.hThread = ProcessInfoNt.ThreadHandle;
#endif
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
/*
* Apply anti debugger notification trick to the thread. (Also done in
- * supR3HardenedWinInstallHooks.)
+ * supR3HardenedWinInit.) This may fail with STATUS_ACCESS_DENIED and
+ * maybe other errors.
*/
- rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
+ rcNt = NtSetInformationThread(This.hThread, ThreadHideFromDebugger, NULL, 0);
if (!NT_SUCCESS(rcNt))
- {
- NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
- supR3HardenedError(rcNt, true /*fFatal*/, "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
- }
+ SUP_DPRINTF(("supR3HardenedWinReSpawn: NtSetInformationThread/ThreadHideFromDebugger failed: %#x (harmless)\n", rcNt));
#endif
/*
- * Clean up the process.
+ * Perform very early child initialization.
*/
- int rc = supR3HardenedWinPurifyChild(hProcess, hThread, RTErrInfoInitStatic(&g_ErrInfoStatic));
- if (RT_FAILURE(rc))
- {
- NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
- supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
- }
+ supR3HardNtChildGatherData(&This);
+ supR3HardNtChildScrewUpPebForInitialImageEvents(&This);
+ supR3HardNtChildSetUpChildInit(&This);
+
+ ULONG cSuspendCount = 0;
+ rcNt = NtResumeThread(This.hThread, &cSuspendCount);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedWinKillChild(&This, "supR3HardenedWinDoReSpawn", rcNt, "NtResumeThread failed: %#x", rcNt);
/*
- * Start the process execution.
+ * Santizie the pre-NTDLL child when it's ready.
+ *
+ * AV software and other things injecting themselves into the embryonic
+ * and budding process to intercept API calls and what not. Unfortunately
+ * this is also the behavior of viruses, malware and other unfriendly
+ * software, so we won't stand for it. AV software can scan our image
+ * as they are loaded via kernel hooks, that's sufficient. No need for
+ * patching half of NTDLL or messing with the import table of the
+ * process executable.
*/
- ULONG cSuspendCount = 0;
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtResumeThread(hThread, &cSuspendCount));
+ supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_PurifyChildAndCloseHandles, 2000 /*ms*/, "PurifyChildAndCloseHandles");
+ supR3HardNtChildPurify(&This);
+ supR3HardNtChildSanitizePeb(&This);
/*
* Close the unrestricted access handles. Since we need to wait on the
* child process, we'll reopen the process with limited access before doing
* away with the process handle returned by CreateProcess.
*/
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hThread));
+ supR3HardNtChildCloseFullAccessHandles(&This);
- PROCESS_BASIC_INFORMATION BasicInfo;
- HANDLE hProcWait;
- ULONG fRights = SYNCHRONIZE;
- if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
- fRights |= PROCESS_QUERY_LIMITED_INFORMATION;
- else
- fRights |= PROCESS_QUERY_INFORMATION;
- rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
- NtCurrentProcess(), &hProcWait,
- fRights, 0 /*HandleAttributes*/, 0);
- if (rcNt == STATUS_ACCESS_DENIED)
- rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
- NtCurrentProcess(), &hProcWait,
- SYNCHRONIZE, 0 /*HandleAttributes*/, 0);
+ /*
+ * Signal the child that we've closed the unrestricted handles and it can
+ * safely try open the driver.
+ */
+ rcNt = NtSetEvent(This.hEvtChild, NULL);
if (!NT_SUCCESS(rcNt))
- {
- /* Failure is unacceptable, kill the process. */
- NtTerminateProcess(hProcess, RTEXITCODE_FAILURE);
- supR3HardenedError(rcNt, false /*fFatal*/, "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
-
- NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
- bool fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
- if (!fExitOk)
- {
- NTSTATUS rcNtWait;
- DWORD dwStartTick = GetTickCount();
- do
- {
- NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
-
- LARGE_INTEGER Timeout;
- Timeout.QuadPart = -20000000; /* 2 second */
- rcNtWait = NtWaitForSingleObject(hProcess, TRUE /*Alertable*/, &Timeout);
-
- rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
- fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
- } while ( !fExitOk
- && ( rcNtWait == STATUS_TIMEOUT
- || rcNtWait == STATUS_USER_APC
- || rcNtWait == STATUS_ALERTED)
- && GetTickCount() - dwStartTick < 60 * 1000);
- if (fExitOk)
- supR3HardenedError(rcNt, false /*fFatal*/,
- "NtDuplicateObject failed and we failed to kill child: rcNt=%u rcNtWait=%u hProcess=%p\n",
- rcNt, rcNtWait, hProcess);
- }
- supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
- "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
- }
-
- SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hProcess));
- hProcess = NULL;
+ supR3HardenedWinKillChild(&This, "supR3HardenedWinReSpawn", VERR_INVALID_NAME,
+ "NtSetEvent failed on child process handle: %#x\n", rcNt);
/*
* Ditch the loader cache so we don't sit on too much memory while waiting.
*/
supR3HardenedWinFlushLoaderCache();
- HeapCompact(GetProcessHeap(), 0 /*dwFlags*/);
+ supR3HardenedWinCompactHeaps();
/*
- * If this is the middle process, wait for both parent and child to quit.
+ * Enable thread creation at this point so Ctrl-C and Ctrl-Break can be processed.
*/
- HANDLE hParent = NULL;
- if (iWhich > 1)
- {
- rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
- if (NT_SUCCESS(rcNt))
- {
- OBJECT_ATTRIBUTES ObjAttr;
- InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ supR3HardenedWinEnableThreadCreation();
- CLIENT_ID ClientId;
- ClientId.UniqueProcess = (HANDLE)BasicInfo.InheritedFromUniqueProcessId;
- ClientId.UniqueThread = NULL;
+ /*
+ * Wait for the child to get to suplibHardenedWindowsMain so we can close the handles.
+ */
+ supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_CloseEvents, 60000 /*ms*/, "CloseEvents");
- rcNt = NtOpenProcess(&hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
- }
-#ifdef DEBUG
- SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
-#endif
+ NtClose(This.hEvtChild);
+ NtClose(This.hEvtParent);
+ This.hEvtChild = NULL;
+ This.hEvtParent = NULL;
+
+ /*
+ * Wait for the process to terminate.
+ */
+ supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_End, RT_INDEFINITE_WAIT, "the end");
+ SUPR3HARDENED_ASSERT(false); /* We're not supposed to get here! */
+}
+
+
+/**
+ * Logs the content of the given object directory.
+ *
+ * @returns true if it exists, false if not.
+ * @param pszDir The path of the directory to log (ASCII).
+ */
+static void supR3HardenedWinLogObjDir(const char *pszDir)
+{
+ /*
+ * Open the driver object directory.
+ */
+ RTUTF16 wszDir[128];
+ int rc = RTUtf16CopyAscii(wszDir, RT_ELEMENTS(wszDir), pszDir);
+ if (RT_FAILURE(rc))
+ {
+ SUP_DPRINTF(("supR3HardenedWinLogObjDir: RTUtf16CopyAscii -> %Rrc on '%s'\n", rc, pszDir));
+ return;
}
- if (hParent != NULL)
+ UNICODE_STRING NtDirName;
+ NtDirName.Buffer = (WCHAR *)wszDir;
+ NtDirName.Length = (USHORT)(RTUtf16Len(wszDir) * sizeof(WCHAR));
+ NtDirName.MaximumLength = NtDirName.Length + sizeof(WCHAR);
+
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+ HANDLE hDir;
+ NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
+ SUP_DPRINTF(("supR3HardenedWinLogObjDir: %ls => %#x\n", wszDir, rcNt));
+ if (!NT_SUCCESS(rcNt))
+ return;
+
+ /*
+ * Enumerate it, looking for the driver.
+ */
+ ULONG uObjDirCtx = 0;
+ for (;;)
{
- for (;;)
+ uint32_t abBuffer[_64K + _1K];
+ ULONG cbActual;
+ rcNt = NtQueryDirectoryObject(hDir,
+ abBuffer,
+ sizeof(abBuffer) - 4, /* minus four for string terminator space. */
+ FALSE /*ReturnSingleEntry */,
+ FALSE /*RestartScan*/,
+ &uObjDirCtx,
+ &cbActual);
+ if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
{
- HANDLE ahHandles[2] = { hProcWait, hParent };
- rcNt = NtWaitForMultipleObjects(2, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*pTimeout*/);
- if ( rcNt == STATUS_WAIT_0
- || rcNt == STATUS_WAIT_0 + 1
- || rcNt == STATUS_ABANDONED_WAIT_0
- || rcNt == STATUS_ABANDONED_WAIT_0 + 1)
- break;
- if ( rcNt != STATUS_TIMEOUT
- && rcNt != STATUS_USER_APC
- && rcNt != STATUS_ALERTED)
- supR3HardenedFatal("NtWaitForMultipleObjects returned %#x\n", rcNt);
+ SUP_DPRINTF(("supR3HardenedWinLogObjDir: NtQueryDirectoryObject => rcNt=%#x cbActual=%#x\n", rcNt, cbActual));
+ break;
+ }
+
+ POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
+ while (pObjDir->Name.Length != 0)
+ {
+ WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
+ SUP_DPRINTF((" %.*ls %.*ls\n",
+ pObjDir->TypeName.Length / sizeof(WCHAR), pObjDir->TypeName.Buffer,
+ pObjDir->Name.Length / sizeof(WCHAR), pObjDir->Name.Buffer));
+
+ /* Next directory entry. */
+ pObjDir++;
}
- NtClose(hParent);
}
- else
+
+ /*
+ * Clean up and return.
+ */
+ NtClose(hDir);
+}
+
+
+/**
+ * Tries to open VBoxDrvErrorInfo and read extra error info from it.
+ *
+ * @returns pszErrorInfo.
+ * @param pszErrorInfo The destination buffer. Will always be
+ * terminated.
+ * @param cbErrorInfo The size of the destination buffer.
+ * @param pszPrefix What to prefix the error info with, if we got
+ * anything.
+ */
+DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix)
+{
+ RT_BZERO(pszErrorInfo, cbErrorInfo);
+
+ /*
+ * Try open the device.
+ */
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ UNICODE_STRING NtName = RTNT_CONSTANT_UNISTR(SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ NTSTATUS rcNt = NtCreateFile(&hFile,
+ GENERIC_READ, /* No SYNCHRONIZE. */
+ &ObjAttr,
+ &Ios,
+ NULL /* Allocation Size*/,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT. */
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ rcNt = Ios.Status;
+ if (NT_SUCCESS(rcNt))
{
/*
- * Wait for the process to terminate.
+ * Try read error info.
*/
- for (;;)
+ size_t cchPrefix = strlen(pszPrefix);
+ if (cchPrefix + 3 < cbErrorInfo)
{
- rcNt = NtWaitForSingleObject(hProcWait, TRUE /*Alertable*/, NULL /*pTimeout*/);
- if ( rcNt == STATUS_WAIT_0
- || rcNt == STATUS_ABANDONED_WAIT_0)
- break;
- if ( rcNt != STATUS_TIMEOUT
- && rcNt != STATUS_USER_APC
- && rcNt != STATUS_ALERTED)
- supR3HardenedFatal("NtWaitForSingleObject returned %#x\n", rcNt);
+ LARGE_INTEGER offRead;
+ offRead.QuadPart = 0;
+ rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+ &pszErrorInfo[cchPrefix], (ULONG)(cbErrorInfo - cchPrefix - 1), &offRead, NULL);
+ if (NT_SUCCESS(rcNt))
+ {
+ memcpy(pszErrorInfo, pszPrefix, cchPrefix);
+ pszErrorInfo[cbErrorInfo - 1] = '\0';
+ SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: '%s'", &pszErrorInfo[cchPrefix]));
+ }
+ else
+ {
+ *pszErrorInfo = '\0';
+ if (rcNt != STATUS_END_OF_FILE)
+ SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtReadFile -> %#x\n", rcNt));
+ }
}
+ else
+ RTStrCopy(pszErrorInfo, cbErrorInfo, "error info buffer too small");
+ NtClose(hFile);
}
+ else
+ SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtCreateFile -> %#x\n", rcNt));
- /*
- * Proxy the termination code of the child, if it exited already.
- */
- NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
- if ( !NT_SUCCESS(rcNt2)
- || BasicInfo.ExitStatus == STATUS_PENDING)
- BasicInfo.ExitStatus = RTEXITCODE_FAILURE;
-
- NtClose(hProcWait);
- SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): Quitting: ExitCode=%#x rcNt=%#x\n", iWhich, BasicInfo.ExitStatus, rcNt));
- suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
+ return pszErrorInfo;
}
+
/**
* Checks if the driver exists.
*
@@ -3989,11 +4348,14 @@ static bool supR3HardenedWinDriverExists(const char *pszDriver)
*/
static void supR3HardenedWinOpenStubDevice(void)
{
+ if (g_fSupStubOpened)
+ return;
+
/*
* Retry if we think driver might still be initializing (STATUS_NO_SUCH_DEVICE + \Drivers\VBoxDrv).
*/
- static const WCHAR s_wszName[] = L"\\Device\\VBoxDrvStub";
- DWORD const uStartTick = GetTickCount();
+ static const WCHAR s_wszName[] = SUPDRV_NT_DEVICE_NAME_STUB;
+ uint64_t const uMsTsStart = supR3HardenedWinGetMilliTS();
NTSTATUS rcNt;
uint32_t iTry;
@@ -4011,14 +4373,14 @@ static void supR3HardenedWinOpenStubDevice(void)
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
rcNt = NtCreateFile(&hFile,
- GENERIC_READ | GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
- FILE_NON_DIRECTORY_FILE,
+ FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT. */
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
@@ -4028,7 +4390,7 @@ static void supR3HardenedWinOpenStubDevice(void)
completely initialized. Delay a little bit and try again. */
if (rcNt != STATUS_NO_SUCH_DEVICE)
break;
- if (iTry > 0 && GetTickCount() - uStartTick > 5000) /* 5 sec, at least two tries */
+ if (iTry > 0 && supR3HardenedWinGetMilliTS() - uMsTsStart > 5000) /* 5 sec, at least two tries */
break;
if (!supR3HardenedWinDriverExists("VBoxDrv"))
{
@@ -4047,11 +4409,63 @@ static void supR3HardenedWinOpenStubDevice(void)
NtDelayExecution(TRUE, &Time);
}
- if (!NT_SUCCESS(rcNt))
+ if (NT_SUCCESS(rcNt))
+ g_fSupStubOpened = true;
+ else
{
+ /*
+ * Report trouble (fatal). For some errors codes we try gather some
+ * extra information that goes into VBoxStartup.log so that we stand a
+ * better chance resolving the issue.
+ */
+ char szErrorInfo[_4K];
int rc = VERR_OPEN_FAILED;
if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
+ {
rc = SUP_NT_STATUS_TO_VBOX(rcNt);
+
+ /*
+ * \Windows\ApiPort open trouble. So far only
+ * STATUS_OBJECT_TYPE_MISMATCH has been observed.
+ */
+ if (rc == VERR_SUPDRV_APIPORT_OPEN_ERROR)
+ {
+ SUP_DPRINTF(("Error opening VBoxDrvStub: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"));
+
+ uint32_t uSessionId = NtCurrentPeb()->SessionId;
+ SUP_DPRINTF((" SessionID=%#x\n", uSessionId));
+ char szDir[64];
+ if (uSessionId == 0)
+ RTStrCopy(szDir, sizeof(szDir), "\\Windows");
+ else
+ {
+ RTStrPrintf(szDir, sizeof(szDir), "\\Sessions\\%u\\Windows", uSessionId);
+ supR3HardenedWinLogObjDir(szDir);
+ }
+ supR3HardenedWinLogObjDir("\\Windows");
+ supR3HardenedWinLogObjDir("\\Sessions");
+
+ supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, rc,
+ "NtCreateFile(%ls) failed: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"
+ "\n"
+ "Error getting %s\\ApiPort in the driver from vboxdrv.\n"
+ "\n"
+ "Could be due to security software is redirecting access to it, so please include full "
+ "details of such software in a bug report. VBoxStartup.log may contain details important "
+ "to resolving the issue.%s"
+ , s_wszName, szDir,
+ supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+ "\n\nVBoxDrvStub error: "));
+ }
+
+ /*
+ * Generic VBox failure message.
+ */
+ supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
+ "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)%s", s_wszName, rc, rcNt,
+ supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+ "\nVBoxDrvStub error: "));
+ }
else
{
const char *pszDefine;
@@ -4063,11 +4477,44 @@ static void supR3HardenedWinOpenStubDevice(void)
case STATUS_TRUST_FAILURE: pszDefine = " STATUS_TRUST_FAILURE"; break;
default: pszDefine = ""; break;
}
+
+ /*
+ * Problems opening the device is generally due to driver load/
+ * unload issues. Check whether the driver is loaded and make
+ * suggestions accordingly.
+ */
+/** @todo don't fail during early init, wait till later and try load the driver if missing or at least query the service manager for additional information. */
+ if ( rcNt == STATUS_NO_SUCH_DEVICE
+ || rcNt == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ SUP_DPRINTF(("Error opening VBoxDrvStub: %s\n", pszDefine));
+ if (supR3HardenedWinDriverExists("VBoxDrv"))
+ supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
+ "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
+ "\n"
+ "Driver is probably stuck stopping/starting. Try 'sc.exe query vboxdrv' to get more "
+ "information about its state. Rebooting may actually help.%s"
+ , s_wszName, rcNt, pszDefine, iTry,
+ supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+ "\nVBoxDrvStub error: "));
+ else
+ supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
+ "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
+ "\n"
+ "Driver is does not appear to be loaded. Try 'sc.exe start vboxdrv', reinstall "
+ "VirtualBox or reboot.%s"
+ , s_wszName, rcNt, pszDefine, iTry,
+ supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+ "\nVBoxDrvStub error: "));
+ }
+
+ /* Generic NT failure message. */
supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
- "NtCreateFile(%ls) failed: %#x%s (%u retries)\n", s_wszName, rcNt, pszDefine, iTry);
+ "NtCreateFile(%ls) failed: %#x%s (%u retries)%s",
+ s_wszName, rcNt, pszDefine, iTry,
+ supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+ "\nVBoxDrvStub error: "));
}
- supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
- "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)\n", s_wszName, rc, rcNt);
}
}
@@ -4081,15 +4528,34 @@ DECLHIDDEN(int) supR3HardenedWinReSpawn(int iWhich)
{
/*
* Before the 2nd respawn we set up a child protection deal with the
- * support driver via /Devices/VBoxDrvStub.
+ * support driver via /Devices/VBoxDrvStub. (We tried to do this
+ * during the early init, but in case we had trouble accessing vboxdrv we
+ * retry it here where we have kernel32.dll and others to pull in for
+ * better diagnostics.)
*/
if (iWhich == 2)
supR3HardenedWinOpenStubDevice();
/*
+ * Make sure we're alone in the stub process before creating the VM process
+ * and that there isn't any debuggers attached.
+ */
+ if (iWhich == 2)
+ {
+ int rc = supHardNtVpDebugger(NtCurrentProcess(), RTErrInfoInitStatic(&g_ErrInfoStatic));
+ if (RT_SUCCESS(rc))
+ rc = supHardNtVpThread(NtCurrentProcess(), NtCurrentThread(), RTErrInfoInitStatic(&g_ErrInfoStatic));
+ if (RT_FAILURE(rc))
+ supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Integrity, rc, "%s", g_ErrInfoStatic.szMsg);
+ }
+
+
+ /*
* Respawn the process with kernel protection for the new process.
*/
- return supR3HardenedWinDoReSpawn(iWhich);
+ supR3HardenedWinDoReSpawn(iWhich);
+ SUPR3HARDENED_ASSERT(false); /* We're not supposed to get here! */
+ return RTEXITCODE_FAILURE;
}
@@ -4130,57 +4596,116 @@ DECLHIDDEN(bool) supR3HardenedWinIsReSpawnNeeded(int iWhich, int cArgs, char **p
}
-/**
- * Initializes the windows verficiation bits.
- * @param fFlags The main flags.
- */
-DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags)
-{
+/**
+ * Initializes the windows verficiation bits and other things we're better off
+ * doing after main() has passed on it's data.
+ *
+ * @param fFlags The main flags.
+ * @param fAvastKludge Whether to apply the avast kludge.
+ */
+DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge)
+{
+ NTSTATUS rcNt;
+
+#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
+ /*
+ * Install a anti debugging hack before we continue. This prevents most
+ * notifications from ending up in the debugger. (Also applied to the
+ * child process when respawning.)
+ */
+ rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
+ "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
+#endif
+
+ /*
+ * Init the verifier.
+ */
RTErrInfoInitStatic(&g_ErrInfoStatic);
int rc = supHardenedWinInitImageVerifier(&g_ErrInfoStatic.Core);
if (RT_FAILURE(rc))
supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rc,
"supHardenedWinInitImageVerifier failed: %s", g_ErrInfoStatic.szMsg);
+ /*
+ * Get the windows system directory from the KnownDlls dir.
+ */
+ HANDLE hSymlink = INVALID_HANDLE_VALUE;
+ UNICODE_STRING UniStr = RTNT_CONSTANT_UNISTR(L"\\KnownDlls\\KnownDllPath");
+ OBJECT_ATTRIBUTES ObjAttrs;
+ InitializeObjectAttributes(&ObjAttrs, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ rcNt = NtOpenSymbolicLinkObject(&hSymlink, SYMBOLIC_LINK_QUERY, &ObjAttrs);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error opening '%ls': %#x", UniStr.Buffer, rcNt);
+
+ g_System32WinPath.UniStr.Buffer = g_System32WinPath.awcBuffer;
+ g_System32WinPath.UniStr.Length = 0;
+ g_System32WinPath.UniStr.MaximumLength = sizeof(g_System32WinPath.awcBuffer) - sizeof(RTUTF16);
+ rcNt = NtQuerySymbolicLinkObject(hSymlink, &g_System32WinPath.UniStr, NULL);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error querying '%ls': %#x", UniStr.Buffer, rcNt);
+ g_System32WinPath.UniStr.Buffer[g_System32WinPath.UniStr.Length / sizeof(RTUTF16)] = '\0';
+
+ SUP_DPRINTF(("KnownDllPath: %ls\n", g_System32WinPath.UniStr.Buffer));
+ NtClose(hSymlink);
+
if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
{
- /*
- * Do a self purification to cure avast's weird NtOpenFile write-thru
- * change in GetBinaryTypeW change in kernel32. Unfortunately, avast
- * uses a system thread to perform the process modifications, which
- * means it's hard to make sure it had the chance to make them...
- *
- * We have to resort to kludge doing yield and sleep fudging for a
- * number of milliseconds and schedulings before we can hope that avast
- * and similar products have done what they need to do. If we do any
- * fixes, we wait for a while again and redo it until we're clean.
- *
- * This is unfortunately kind of fragile.
- */
- uint32_t iLoop = 0;
- uint32_t cFixes;
- do
+ if (fAvastKludge)
{
- uint32_t cSleeps = 0;
- DWORD dwStart = GetTickCount();
- do
+ /*
+ * Do a self purification to cure avast's weird NtOpenFile write-thru
+ * change in GetBinaryTypeW change in kernel32. Unfortunately, avast
+ * uses a system thread to perform the process modifications, which
+ * means it's hard to make sure it had the chance to make them...
+ *
+ * We have to resort to kludge doing yield and sleep fudging for a
+ * number of milliseconds and schedulings before we can hope that avast
+ * and similar products have done what they need to do. If we do any
+ * fixes, we wait for a while again and redo it until we're clean.
+ *
+ * This is unfortunately kind of fragile.
+ */
+ uint32_t cMsFudge = g_fSupAdversaries ? 512 : 128;
+ uint32_t cFixes;
+ for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
{
- NtYieldExecution();
- LARGE_INTEGER Time;
- Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
- NtDelayExecution(FALSE, &Time);
- cSleeps++;
- } while ( GetTickCount() - dwStart <= 80
- || cSleeps < 8);
- SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
- iLoop, GetTickCount() - dwStart, cSleeps));
-
- cFixes = 0;
- rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
- &cFixes, NULL /*pErrInfo*/);
- } while ( RT_SUCCESS(rc)
- && cFixes > 0
- && ++iLoop < 8);
+ uint32_t cSleeps = 0;
+ uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+ do
+ {
+ NtYieldExecution();
+ LARGE_INTEGER Time;
+ Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
+ NtDelayExecution(FALSE, &Time);
+ cSleeps++;
+ } while ( supR3HardenedWinGetMilliTS() - uMsTsStart <= cMsFudge
+ || cSleeps < 8);
+ SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
+ iLoop, supR3HardenedWinGetMilliTS() - uMsTsStart, cSleeps));
+
+ cFixes = 0;
+ rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
+ 0 /*fFlags*/, &cFixes, NULL /*pErrInfo*/);
+ if (RT_FAILURE(rc) || cFixes == 0)
+ break;
+
+ if (!g_fSupAdversaries)
+ g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
+ cMsFudge = 512;
+
+ /* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
+ ULONG cPatchCount = 0;
+ rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
+ &cPatchCount, sizeof(cPatchCount), NULL);
+ if (NT_SUCCESS(rcNt))
+ SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
+ cFixes, g_fSupAdversaries, cPatchCount));
+ else
+ SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
+ }
+ }
/*
* Install the hooks.
@@ -4223,7 +4748,7 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
*/
int cArgs = 0;
int cArgsAllocated = 4;
- char **papszArgs = (char **)suplibHardenedAllocZ(sizeof(char *) * cArgsAllocated);
+ char **papszArgs = (char **)RTMemAllocZ(sizeof(char *) * cArgsAllocated);
char *pszSrc = pszCmdLine;
for (;;)
{
@@ -4238,7 +4763,7 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
if (cArgs + 2 >= cArgsAllocated)
{
cArgsAllocated *= 2;
- papszArgs = (char **)suplibHardenedReAlloc(papszArgs, sizeof(char *) * cArgsAllocated);
+ papszArgs = (char **)RTMemRealloc(papszArgs, sizeof(char *) * cArgsAllocated);
}
papszArgs[cArgs++] = pszSrc;
papszArgs[cArgs] = NULL;
@@ -4291,6 +4816,516 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
}
+/**
+ * Logs information about a file from a protection product or from Windows.
+ *
+ * The purpose here is to better see which version of the product is installed
+ * and not needing to depend on the user supplying the correct information.
+ *
+ * @param pwszFile The NT path to the file.
+ * @param fAdversarial Set if from a protection product, false if
+ * system file.
+ */
+static void supR3HardenedLogFileInfo(PCRTUTF16 pwszFile, bool fAdversarial)
+{
+ /*
+ * Open the file.
+ */
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ UNICODE_STRING UniStrName;
+ UniStrName.Buffer = (WCHAR *)pwszFile;
+ UniStrName.Length = (USHORT)(RTUtf16Len(pwszFile) * sizeof(WCHAR));
+ UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ NTSTATUS rcNt = NtCreateFile(&hFile,
+ GENERIC_READ | SYNCHRONIZE,
+ &ObjAttr,
+ &Ios,
+ NULL /* Allocation Size*/,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL /*EaBuffer*/,
+ 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt))
+ rcNt = Ios.Status;
+ if (NT_SUCCESS(rcNt))
+ {
+ SUP_DPRINTF(("%ls:\n", pwszFile));
+ union
+ {
+ uint64_t u64AlignmentInsurance;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_STANDARD_INFORMATION StdInfo;
+ uint8_t abBuf[32768];
+ RTUTF16 awcBuf[16384];
+ IMAGE_DOS_HEADER MzHdr;
+ } u;
+ RTTIMESPEC TimeSpec;
+ char szTmp[64];
+
+ /*
+ * Print basic file information available via NtQueryInformationFile.
+ */
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ rcNt = NtQueryInformationFile(hFile, &Ios, &u.BasicInfo, sizeof(u.BasicInfo), FileBasicInformation);
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+ {
+ SUP_DPRINTF((" CreationTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.CreationTime.QuadPart), szTmp, sizeof(szTmp))));
+ /*SUP_DPRINTF((" LastAccessTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastAccessTime.QuadPart), szTmp, sizeof(szTmp))));*/
+ SUP_DPRINTF((" LastWriteTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastWriteTime.QuadPart), szTmp, sizeof(szTmp))));
+ SUP_DPRINTF((" ChangeTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.ChangeTime.QuadPart), szTmp, sizeof(szTmp))));
+ SUP_DPRINTF((" FileAttributes: %#x\n", u.BasicInfo.FileAttributes));
+ }
+ else
+ SUP_DPRINTF((" FileBasicInformation -> %#x %#x\n", rcNt, Ios.Status));
+
+ rcNt = NtQueryInformationFile(hFile, &Ios, &u.StdInfo, sizeof(u.StdInfo), FileStandardInformation);
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+ SUP_DPRINTF((" Size: %#llx\n", u.StdInfo.EndOfFile.QuadPart));
+ else
+ SUP_DPRINTF((" FileStandardInformation -> %#x %#x\n", rcNt, Ios.Status));
+
+ /*
+ * Read the image header and extract the timestamp and other useful info.
+ */
+ RT_ZERO(u);
+ LARGE_INTEGER offRead;
+ offRead.QuadPart = 0;
+ rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+ &u, (ULONG)sizeof(u), &offRead, NULL);
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+ {
+ uint32_t offNtHdrs = 0;
+ if (u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE)
+ offNtHdrs = u.MzHdr.e_lfanew;
+ if (offNtHdrs < sizeof(u) - sizeof(IMAGE_NT_HEADERS))
+ {
+ PIMAGE_NT_HEADERS64 pNtHdrs64 = (PIMAGE_NT_HEADERS64)&u.abBuf[offNtHdrs];
+ PIMAGE_NT_HEADERS32 pNtHdrs32 = (PIMAGE_NT_HEADERS32)&u.abBuf[offNtHdrs];
+ if (pNtHdrs64->Signature == IMAGE_NT_SIGNATURE)
+ {
+ SUP_DPRINTF((" NT Headers: %#x\n", offNtHdrs));
+ SUP_DPRINTF((" Timestamp: %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
+ SUP_DPRINTF((" Machine: %#x%s\n", pNtHdrs64->FileHeader.Machine,
+ pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ? " - i386"
+ : pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ? " - amd64" : ""));
+ SUP_DPRINTF((" Timestamp: %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
+ SUP_DPRINTF((" Image Version: %u.%u\n",
+ pNtHdrs64->OptionalHeader.MajorImageVersion, pNtHdrs64->OptionalHeader.MinorImageVersion));
+ SUP_DPRINTF((" SizeOfImage: %#x (%u)\n", pNtHdrs64->OptionalHeader.SizeOfImage, pNtHdrs64->OptionalHeader.SizeOfImage));
+
+ /*
+ * Very crude way to extract info from the file version resource.
+ */
+ PIMAGE_SECTION_HEADER paSectHdrs = (PIMAGE_SECTION_HEADER)( (uintptr_t)&pNtHdrs64->OptionalHeader
+ + pNtHdrs64->FileHeader.SizeOfOptionalHeader);
+ IMAGE_DATA_DIRECTORY RsrcDir = { 0, 0 };
+ if ( pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)
+ && pNtHdrs64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
+ RsrcDir = pNtHdrs64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ else if ( pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+ && pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
+ RsrcDir = pNtHdrs32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ SUP_DPRINTF((" Resource Dir: %#x LB %#x\n", RsrcDir.VirtualAddress, RsrcDir.Size));
+ if ( RsrcDir.VirtualAddress > offNtHdrs
+ && RsrcDir.Size > 0
+ && (uintptr_t)&u + sizeof(u) - (uintptr_t)paSectHdrs
+ >= pNtHdrs64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) )
+ {
+ offRead.QuadPart = 0;
+ for (uint32_t i = 0; i < pNtHdrs64->FileHeader.NumberOfSections; i++)
+ if ( paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress < paSectHdrs[i].SizeOfRawData
+ && paSectHdrs[i].PointerToRawData > offNtHdrs)
+ {
+ offRead.QuadPart = paSectHdrs[i].PointerToRawData
+ + (paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress);
+ break;
+ }
+ if (offRead.QuadPart > 0)
+ {
+ RT_ZERO(u);
+ rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+ &u, (ULONG)sizeof(u), &offRead, NULL);
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+ {
+ static const struct { PCRTUTF16 pwsz; size_t cb; } s_abFields[] =
+ {
+#define MY_WIDE_STR_TUPLE(a_sz) { L ## a_sz, sizeof(L ## a_sz) - sizeof(RTUTF16) }
+ MY_WIDE_STR_TUPLE("ProductName"),
+ MY_WIDE_STR_TUPLE("ProductVersion"),
+ MY_WIDE_STR_TUPLE("FileVersion"),
+ MY_WIDE_STR_TUPLE("SpecialBuild"),
+ MY_WIDE_STR_TUPLE("PrivateBuild"),
+ MY_WIDE_STR_TUPLE("FileDescription"),
+#undef MY_WIDE_STR_TUPLE
+ };
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_abFields); i++)
+ {
+ size_t cwcLeft = (sizeof(u) - s_abFields[i].cb - 10) / sizeof(RTUTF16);
+ PCRTUTF16 pwc = u.awcBuf;
+ RTUTF16 const wcFirst = *s_abFields[i].pwsz;
+ while (cwcLeft-- > 0)
+ {
+ if ( pwc[0] == 1 /* wType == text */
+ && pwc[1] == wcFirst)
+ {
+ if (memcmp(pwc + 1, s_abFields[i].pwsz, s_abFields[i].cb + sizeof(RTUTF16)) == 0)
+ {
+ size_t cwcField = s_abFields[i].cb / sizeof(RTUTF16);
+ pwc += cwcField + 2;
+ cwcLeft -= cwcField + 2;
+ for (uint32_t iPadding = 0; iPadding < 3; iPadding++, pwc++, cwcLeft--)
+ if (*pwc)
+ break;
+ int rc = RTUtf16ValidateEncodingEx(pwc, cwcLeft,
+ RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
+ if (RT_SUCCESS(rc))
+ SUP_DPRINTF((" %ls:%*s %ls",
+ s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", pwc));
+ else
+ SUP_DPRINTF((" %ls:%*s rc=%Rrc",
+ s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", rc));
+
+ break;
+ }
+ }
+ pwc++;
+ }
+ }
+ }
+ else
+ SUP_DPRINTF((" NtReadFile @%#llx -> %#x %#x\n", offRead.QuadPart, rcNt, Ios.Status));
+ }
+ else
+ SUP_DPRINTF((" Resource section not found.\n"));
+ }
+ }
+ else
+ SUP_DPRINTF((" Nt Headers @%#x: Invalid signature\n", offNtHdrs));
+ }
+ else
+ SUP_DPRINTF((" Nt Headers @%#x: out side buffer\n", offNtHdrs));
+ }
+ else
+ SUP_DPRINTF((" NtReadFile @0 -> %#x %#x\n", rcNt, Ios.Status));
+ NtClose(hFile);
+ }
+}
+
+
+/**
+ * Scans the Driver directory for drivers which may invade our processes.
+ *
+ * @returns Mask of SUPHARDNT_ADVERSARY_XXX flags.
+ *
+ * @remarks The enumeration of \Driver normally requires administrator
+ * privileges. So, the detection we're doing here isn't always gonna
+ * work just based on that.
+ *
+ * @todo Find drivers in \FileSystems as well, then we could detect VrNsdDrv
+ * from ViRobot APT Shield 2.0.
+ */
+static uint32_t supR3HardenedWinFindAdversaries(void)
+{
+ static const struct
+ {
+ uint32_t fAdversary;
+ const char *pszDriver;
+ } s_aDrivers[] =
+ {
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, "SRTSPX" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, "SymDS" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, "SymEvent" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, "SymIRON" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, "SymNetS" },
+
+ { SUPHARDNT_ADVERSARY_AVAST, "aswHwid" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswMonFlt" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswRdr2" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswRvrt" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswSnx" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswsp" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswStm" },
+ { SUPHARDNT_ADVERSARY_AVAST, "aswVmm" },
+
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmcomm" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmactmon" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmevtmgr" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmtdi" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmebc64" }, /* Titanium internet security, not officescan. */
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmeevw" }, /* Titanium internet security, not officescan. */
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmciesc" }, /* Titanium internet security, not officescan. */
+
+ { SUPHARDNT_ADVERSARY_MCAFEE, "cfwids" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "McPvDrv" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfeapfk" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfeavfk" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfefirek" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfehidk" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfencbdc" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, "mfewfpk" },
+
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "kl1" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "klflt" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "klif" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "KLIM6" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "klkbdflt" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "klmouflt" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "kltdi" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, "kneps" },
+
+ { SUPHARDNT_ADVERSARY_MBAM, "MBAMWebAccessControl" },
+ { SUPHARDNT_ADVERSARY_MBAM, "mbam" },
+ { SUPHARDNT_ADVERSARY_MBAM, "mbamchameleon" },
+ { SUPHARDNT_ADVERSARY_MBAM, "mwav" },
+ { SUPHARDNT_ADVERSARY_MBAM, "mbamswissarmy" },
+
+ { SUPHARDNT_ADVERSARY_AVG, "avgfwfd" },
+ { SUPHARDNT_ADVERSARY_AVG, "avgtdia" },
+
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINAflt" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINFile" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINKNC" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINProc" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINProt" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSINReg" },
+ { SUPHARDNT_ADVERSARY_PANDA, "PSKMAD" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSAlpc" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSHttp" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNShttps" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSIds" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSNAHSL" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSpicc" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSPihsw" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSPop3" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSProt" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSPrv" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSSmtp" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNSStrm" },
+ { SUPHARDNT_ADVERSARY_PANDA, "NNStlsc" },
+
+ { SUPHARDNT_ADVERSARY_MSE, "NisDrv" },
+
+ /*{ SUPHARDNT_ADVERSARY_COMODO, "cmdguard" }, file system */
+ { SUPHARDNT_ADVERSARY_COMODO, "inspect" },
+ { SUPHARDNT_ADVERSARY_COMODO, "cmdHlp" },
+
+ { SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN, "dgmaster" }, /* Not verified. */
+ };
+
+ static const struct
+ {
+ uint32_t fAdversary;
+ PCRTUTF16 pwszFile;
+ } s_aFiles[] =
+ {
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\SysPlant.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysfer.dll" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysferThunk.dll" },
+
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ccsetx64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ironx64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtsp64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtspx64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symds64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symefa64.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symelam.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symnets.sys" },
+ { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\symevent64x86.sys" },
+
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswHwid.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswMonFlt.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRdr2.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRvrt.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswSnx.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswsp.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswStm.sys" },
+ { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswVmm.sys" },
+
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmcomm.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmactmon.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmevtmgr.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmtdi.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmebc64.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmeevw.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmciesc.sys" },
+ { SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE, L"\\SystemRoot\\System32\\drivers\\sakfile.sys" }, /* Data Loss Prevention, not officescan. */
+ { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\sakcd.sys" }, /* Data Loss Prevention, not officescan. */
+
+
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\cfwids.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\McPvDrv.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeapfk.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeavfk.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfefirek.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfehidk.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfencbdc.sys" },
+ { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfewfpk.sys" },
+
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kl1.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klflt.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klif.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klim6.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klkbdflt.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klmouflt.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kltdi.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kneps.sys" },
+ { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\klfphc.dll" },
+
+ { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\MBAMSwissArmy.sys" },
+ { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mwac.sys" },
+ { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbamchameleon.sys" },
+ { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbam.sys" },
+
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgrkx64.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgmfx64.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsdrivera.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsha.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgtdia.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgloga.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgldx64.sys" },
+ { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgdiska.sys" },
+
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINAflt.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINFile.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINKNC.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProc.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProt.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINReg.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSKMAD.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSAlpc.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSHttp.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNShttps.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSIds.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSNAHSL.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSpicc.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPihsw.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPop3.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSProt.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPrv.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSSmtp.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSStrm.sys" },
+ { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNStlsc.sys" },
+
+ { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\MpFilter.sys" },
+ { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\NisDrvWFP.sys" },
+
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmdguard.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmderd.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\inspect.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmdhlp.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cfrmd.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\hmd.sys" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\guard64.dll" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdvrt64.dll" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdkbd64.dll" },
+ { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdcsr.dll" },
+
+ { SUPHARDNT_ADVERSARY_ZONE_ALARM, L"\\SystemRoot\\System32\\drivers\\vsdatant.sys" },
+ { SUPHARDNT_ADVERSARY_ZONE_ALARM, L"\\SystemRoot\\System32\\AntiTheftCredentialProvider.dll" },
+
+ { SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN, L"\\SystemRoot\\System32\\drivers\\dgmaster.sys" },
+ };
+
+ uint32_t fFound = 0;
+
+ /*
+ * Open the driver object directory.
+ */
+ UNICODE_STRING NtDirName = RTNT_CONSTANT_UNISTR(L"\\Driver");
+
+ OBJECT_ATTRIBUTES ObjAttr;
+ InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+ HANDLE hDir;
+ NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
+#ifdef VBOX_STRICT
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
+#endif
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Enumerate it, looking for the driver.
+ */
+ ULONG uObjDirCtx = 0;
+ for (;;)
+ {
+ uint32_t abBuffer[_64K + _1K];
+ ULONG cbActual;
+ rcNt = NtQueryDirectoryObject(hDir,
+ abBuffer,
+ sizeof(abBuffer) - 4, /* minus four for string terminator space. */
+ FALSE /*ReturnSingleEntry */,
+ FALSE /*RestartScan*/,
+ &uObjDirCtx,
+ &cbActual);
+ if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
+ break;
+
+ POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
+ while (pObjDir->Name.Length != 0)
+ {
+ WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
+ pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = '\0';
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aDrivers); i++)
+ if (RTUtf16ICmpAscii(pObjDir->Name.Buffer, s_aDrivers[i].pszDriver) == 0)
+ {
+ fFound |= s_aDrivers[i].fAdversary;
+ SUP_DPRINTF(("Found driver %s (%#x)\n", s_aDrivers[i].pszDriver, s_aDrivers[i].fAdversary));
+ break;
+ }
+
+ pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = wcSaved;
+
+ /* Next directory entry. */
+ pObjDir++;
+ }
+ }
+
+ NtClose(hDir);
+ }
+ else
+ SUP_DPRINTF(("NtOpenDirectoryObject failed on \\Driver: %#x\n", rcNt));
+
+ /*
+ * Look for files.
+ */
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
+ {
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+ UNICODE_STRING UniStrName;
+ UniStrName.Buffer = (WCHAR *)s_aFiles[i].pwszFile;
+ UniStrName.Length = (USHORT)(RTUtf16Len(s_aFiles[i].pwszFile) * sizeof(WCHAR));
+ UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
+ InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+ rcNt = NtCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &ObjAttr, &Ios, NULL /* Allocation Size*/,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL /*EaBuffer*/, 0 /*EaLength*/);
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+ {
+ fFound |= s_aFiles[i].fAdversary;
+ NtClose(hFile);
+ }
+ }
+
+ /*
+ * Log details.
+ */
+ SUP_DPRINTF(("supR3HardenedWinFindAdversaries: %#x\n", fFound));
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
+ if (fFound & s_aFiles[i].fAdversary)
+ supR3HardenedLogFileInfo(s_aFiles[i].pwszFile, true /* fAdversarial */);
+
+ return fFound;
+}
+
+
extern "C" int main(int argc, char **argv, char **envp);
/**
@@ -4305,12 +5340,33 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
RTEXITCODE rcExit = RTEXITCODE_FAILURE;
g_cSuplibHardenedWindowsMainCalls++;
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED;
/*
* Initialize the NTDLL API wrappers. This aims at bypassing patched NTDLL
* in all the processes leading up the VM process.
*/
supR3HardenedWinInitImports();
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED;
+
+ /*
+ * Notify the parent process that we're probably capable of reporting our
+ * own errors.
+ */
+ if (g_ProcParams.hEvtParent || g_ProcParams.hEvtChild)
+ {
+ SUPR3HARDENED_ASSERT(g_fSupEarlyProcessInit);
+
+ g_ProcParams.enmRequest = kSupR3WinChildReq_CloseEvents;
+ NtSetEvent(g_ProcParams.hEvtParent, NULL);
+
+ NtClose(g_ProcParams.hEvtParent);
+ NtClose(g_ProcParams.hEvtChild);
+ g_ProcParams.hEvtParent = NULL;
+ g_ProcParams.hEvtChild = NULL;
+ }
+ else
+ SUPR3HARDENED_ASSERT(!g_fSupEarlyProcessInit);
/*
* After having resolved imports we patch the LdrInitializeThunk code so
@@ -4324,6 +5380,7 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
* SUPHardenedVerfiyImage-win.cpp.)
*/
supR3HardenedWinInitVersion();
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERSION_INITIALIZED;
/*
* Convert the arguments to UTF-8 and open the log file if specified.
@@ -4336,6 +5393,19 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
supR3HardenedOpenLog(&cArgs, papszArgs);
/*
+ * Log information about important system files.
+ */
+ supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\ntdll.dll", false /* fAdversarial */);
+ supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\kernel32.dll", false /* fAdversarial */);
+ supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\KernelBase.dll", false /* fAdversarial */);
+ supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\apisetschema.dll", false /* fAdversarial */);
+
+ /*
+ * Scan the system for adversaries, logging information about them.
+ */
+ g_fSupAdversaries = supR3HardenedWinFindAdversaries();
+
+ /*
* Get the executable name.
*/
DWORD cwcExecName = GetModuleFileNameW(GetModuleHandleW(NULL), g_wszSupLibHardenedExePath,
@@ -4348,8 +5418,8 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
- supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(GetLastError()),
- "Error opening the executable: %u (%ls).", GetLastError());
+ supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+ "Error opening the executable: %u (%ls).", RtlGetLastWin32Error());
RT_ZERO(g_SupLibHardenedExeNtPath);
ULONG cbIgn;
NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &g_SupLibHardenedExeNtPath,
@@ -4366,6 +5436,16 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
g_offSupLibHardenedExeNtName--;
/*
+ * If we've done early init already, register the DLL load notification
+ * callback and reinstall the NtDll patches.
+ */
+ if (g_fSupEarlyProcessInit)
+ {
+ supR3HardenedWinRegisterDllNotificationCallback();
+ supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+ }
+
+ /*
* Call the C/C++ main function.
*/
SUP_DPRINTF(("Calling main()\n"));
@@ -4378,3 +5458,231 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
suplibHardenedExit(rcExit);
}
+
+/**
+ * Reports an error to the parent process via the process parameter structure.
+ *
+ * @param pszWhere Where this error occured, if fatal message. NULL
+ * if not message.
+ * @param enmWhat Which init operation went wrong if fatal
+ * message. kSupInitOp_Invalid if not message.
+ * @param rc The status code to report.
+ * @param pszFormat The format string.
+ * @param va The format arguments.
+ */
+DECLHIDDEN(void) supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
+ const char *pszFormat, va_list va)
+{
+ if (pszWhere)
+ RTStrCopy(g_ProcParams.szWhere, sizeof(g_ProcParams.szWhere), pszWhere);
+ else
+ g_ProcParams.szWhere[0] = '\0';
+ RTStrPrintfV(g_ProcParams.szErrorMsg, sizeof(g_ProcParams.szErrorMsg), pszFormat, va);
+ g_ProcParams.enmWhat = enmWhat;
+ g_ProcParams.rc = RT_SUCCESS(rc) ? VERR_INTERNAL_ERROR_2 : rc;
+ g_ProcParams.enmRequest = kSupR3WinChildReq_Error;
+
+ NtClearEvent(g_ProcParams.hEvtChild);
+ NTSTATUS rcNt = NtSetEvent(g_ProcParams.hEvtParent, NULL);
+ if (NT_SUCCESS(rcNt))
+ {
+ LARGE_INTEGER Timeout;
+ Timeout.QuadPart = -300000000; /* 30 second */
+ NTSTATUS rcNt = NtWaitForSingleObject(g_ProcParams.hEvtChild, FALSE /*Alertable*/, &Timeout);
+ }
+}
+
+
+/**
+ * Routine called by the supR3HardenedEarlyProcessInitThunk assembly routine
+ * when LdrInitializeThunk is executed in during process initialization.
+ *
+ * This initializes the Stub and VM processes, hooking NTDLL APIs and opening
+ * the device driver before any other DLLs gets loaded into the process. This
+ * greately reduces and controls the trusted code base of the process compared
+ * to opening the driver from SUPR3HardenedMain. It also avoids issues with so
+ * call protection software that is in the habit of patching half of the ntdll
+ * and kernel32 APIs in the process, making it almost indistinguishable from
+ * software that is up to no good. Once we've opened vboxdrv, the process
+ * should be locked down so thighly that only kernel software and csrss can mess
+ * with the process.
+ */
+DECLASM(uintptr_t) supR3HardenedEarlyProcessInit(void)
+{
+ /*
+ * When the first thread gets here we wait for the parent to continue with
+ * the process purifications. The primary thread must execute for image
+ * load notifications to trigger, at least in more recent windows versions.
+ * The old trick of starting a different thread that terminates immediately
+ * thus doesn't work.
+ *
+ * We are not allowed to modify any data at this point because it will be
+ * reset by the child process purification the parent does when we stop. To
+ * sabotage thread creation during purification, and to avoid unnecessary
+ * work for the parent, we reset g_ProcParams before signalling the parent
+ * here.
+ */
+ if (g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+ {
+ NtTerminateThread(0, 0);
+ return 0x22; /* crash */
+ }
+
+ /* Retrieve the data we need. */
+ uintptr_t uNtDllAddr = ASMAtomicXchgPtrT(&g_ProcParams.uNtDllAddr, 0, uintptr_t);
+ if (!RT_VALID_PTR(uNtDllAddr))
+ {
+ NtTerminateThread(0, 0);
+ return 0x23; /* crash */
+ }
+
+ HANDLE hEvtChild = g_ProcParams.hEvtChild;
+ HANDLE hEvtParent = g_ProcParams.hEvtParent;
+ if ( hEvtChild == NULL
+ || hEvtChild == RTNT_INVALID_HANDLE_VALUE
+ || hEvtParent == NULL
+ || hEvtParent == RTNT_INVALID_HANDLE_VALUE)
+ {
+ NtTerminateThread(0, 0);
+ return 0x24; /* crash */
+ }
+
+ /* Resolve the APIs we need. */
+ PFNNTWAITFORSINGLEOBJECT pfnNtWaitForSingleObject;
+ PFNNTSETEVENT pfnNtSetEvent;
+ supR3HardenedWinGetVeryEarlyImports(uNtDllAddr, &pfnNtWaitForSingleObject, &pfnNtSetEvent);
+
+ /* Signal the parent that we're ready for purification. */
+ RT_ZERO(g_ProcParams);
+ g_ProcParams.enmRequest = kSupR3WinChildReq_PurifyChildAndCloseHandles;
+ NTSTATUS rcNt = pfnNtSetEvent(hEvtParent, NULL);
+ if (rcNt != STATUS_SUCCESS)
+ return 0x33; /* crash */
+
+ /* Wait up to 2 mins for the parent to exorcise evil. */
+ LARGE_INTEGER Timeout;
+ Timeout.QuadPart = -1200000000; /* 120 second */
+ rcNt = pfnNtWaitForSingleObject(hEvtChild, FALSE /*Alertable*/, &Timeout);
+ if (rcNt != STATUS_SUCCESS)
+ return 0x34; /* crash */
+
+ /*
+ * We're good to go, work global state and restore process parameters.
+ * Note that we will not restore uNtDllAddr since that is our first defence
+ * against unwanted threads (see above).
+ */
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_INIT_CALLED;
+ g_fSupEarlyProcessInit = true;
+
+ g_ProcParams.hEvtChild = hEvtChild;
+ g_ProcParams.hEvtParent = hEvtParent;
+ g_ProcParams.enmRequest = kSupR3WinChildReq_Error;
+ g_ProcParams.rc = VINF_SUCCESS;
+
+ /*
+ * Initialize the NTDLL imports that we consider usable before the
+ * process has been initialized.
+ */
+ supR3HardenedWinInitImportsEarly(uNtDllAddr);
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED;
+
+ /*
+ * Init g_uNtVerCombined as well as we can at this point.
+ */
+ supR3HardenedWinInitVersion();
+
+ /*
+ * Convert the arguments to UTF-8 so we can open the log file if specified.
+ * We may have to normalize the pointer on older windows version (not w7/64 +).
+ * Note! This leaks memory at present.
+ */
+ PRTL_USER_PROCESS_PARAMETERS pUserProcParams = NtCurrentPeb()->ProcessParameters;
+ UNICODE_STRING CmdLineStr = pUserProcParams->CommandLine;
+ if ( CmdLineStr.Buffer != NULL
+ && !(pUserProcParams->Flags & RTL_USER_PROCESS_PARAMS_FLAG_NORMALIZED) )
+ CmdLineStr.Buffer = (WCHAR *)((uintptr_t)CmdLineStr.Buffer + (uintptr_t)pUserProcParams);
+ int cArgs;
+ char **papszArgs = suplibCommandLineToArgvWStub(CmdLineStr.Buffer, CmdLineStr.Length / sizeof(WCHAR), &cArgs);
+ supR3HardenedOpenLog(&cArgs, papszArgs);
+ SUP_DPRINTF(("supR3HardenedVmProcessInit: uNtDllAddr=%p\n", uNtDllAddr));
+
+ /*
+ * Set up the direct system calls so we can more easily hook NtCreateSection.
+ */
+ supR3HardenedWinInitSyscalls(true /*fReportErrors*/);
+
+ /*
+ * Determine the executable path and name. Will NOT determine the windows style
+ * executable path here as we don't need it.
+ */
+ SIZE_T cbActual = 0;
+ rcNt = NtQueryVirtualMemory(NtCurrentProcess(), &g_ProcParams, MemorySectionName, &g_SupLibHardenedExeNtPath,
+ sizeof(g_SupLibHardenedExeNtPath) - sizeof(WCHAR), &cbActual);
+ if ( !NT_SUCCESS(rcNt)
+ || g_SupLibHardenedExeNtPath.UniStr.Length == 0
+ || g_SupLibHardenedExeNtPath.UniStr.Length & 1)
+ supR3HardenedFatal("NtQueryVirtualMemory/MemorySectionName failed in supR3HardenedVmProcessInit: %#x\n", rcNt);
+
+ /* The NT executable name offset / dir path length. */
+ g_offSupLibHardenedExeNtName = g_SupLibHardenedExeNtPath.UniStr.Length / sizeof(WCHAR);
+ while ( g_offSupLibHardenedExeNtName > 1
+ && g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] != '\\' )
+ g_offSupLibHardenedExeNtName--;
+
+ /*
+ * Initialize the image verification stuff (hooks LdrLoadDll and NtCreateSection).
+ */
+ supR3HardenedWinInit(0, false /*fAvastKludge*/);
+
+ /*
+ * Open the driver.
+ */
+ if (cArgs >= 1 && suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_1_ARG0) == 0)
+ {
+ SUP_DPRINTF(("supR3HardenedVmProcessInit: Opening vboxdrv stub...\n"));
+ supR3HardenedWinOpenStubDevice();
+ }
+ else if (cArgs >= 1 && suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_2_ARG0) == 0)
+ {
+ SUP_DPRINTF(("supR3HardenedVmProcessInit: Opening vboxdrv...\n"));
+ supR3HardenedMainOpenDevice();
+ }
+ else
+ supR3HardenedFatal("Unexpected first argument '%s'!\n", papszArgs[0]);
+ g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED;
+
+ /*
+ * Reinstall the NtDll patches since there is a slight possibility that
+ * someone undid them while we where busy opening the device.
+ */
+ supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+
+ /*
+ * Restore the LdrInitializeThunk code so we can initialize the process
+ * normally when we return.
+ */
+ SUP_DPRINTF(("supR3HardenedVmProcessInit: Restoring LdrInitializeThunk...\n"));
+ PSUPHNTLDRCACHEENTRY pLdrEntry;
+ int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
+ if (RT_FAILURE(rc))
+ supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
+
+ uint8_t *pbBits;
+ rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
+ if (RT_FAILURE(rc))
+ supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
+
+ RTLDRADDR uValue;
+ rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, uNtDllAddr, UINT32_MAX, "LdrInitializeThunk", &uValue);
+ if (RT_FAILURE(rc))
+ supR3HardenedFatal("supR3HardenedVmProcessInit: Failed to find LdrInitializeThunk (%Rrc).\n", rc);
+
+ PVOID pvLdrInitThunk = (PVOID)(uintptr_t)uValue;
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READWRITE));
+ memcpy(pvLdrInitThunk, pbBits + ((uintptr_t)uValue - uNtDllAddr), 16);
+ SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READ));
+
+ SUP_DPRINTF(("supR3HardenedVmProcessInit: Returning to LdrInitializeThunk...\n"));
+ return (uintptr_t)pvLdrInitThunk;
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
index 0b9c996..d6440e5 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
@@ -31,50 +31,82 @@
%include "iprt/asmdefs.mac"
-; External data.
-extern NAME(g_pfnNtCreateSectionJmpBack)
+; External code.
+extern NAME(supR3HardenedEarlyProcessInit)
BEGINCODE
+
+;;
+; Alternative code for LdrInitializeThunk that performs the early process startup
+; for the Stub and VM processes.
;
-; 64-bit
+; This does not concern itself with any arguments on stack or in registers that
+; may be passed to the LdrIntializeThunk routine as we just save and restore
+; them all before we restart the restored LdrInitializeThunk routine.
;
-%ifdef RT_ARCH_AMD64
- %macro supR3HardenedJmpBack_NtCreateSection_Xxx 1
- BEGINPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
- SEH64_END_PROLOGUE
- ; The code we replaced.
- mov r10, rcx
- mov eax, %1
+; @sa supR3HardenedEarlyProcessInit
+;
+BEGINPROC supR3HardenedEarlyProcessInitThunk
+ ;
+ ; Prologue.
+ ;
- ; Jump back to the original code.
- jmp [NAME(g_pfnNtCreateSectionJmpBack) wrt RIP]
- ENDPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
- %endm
- %define SYSCALL(a_Num) supR3HardenedJmpBack_NtCreateSection_Xxx a_Num
- %include "NtCreateSection-template-amd64-syscall-type-1.h"
+ ; Reserve space for the "return" address.
+ push 0
+ ; Create a stack frame, saving xBP.
+ push xBP
+ SEH64_PUSH_xBP
+ mov xBP, xSP
+ SEH64_SET_FRAME_xBP 0 ; probably wrong...
+
+ ; Save all volatile registers.
+ push xAX
+ push xCX
+ push xDX
+%ifdef RT_ARCH_AMD64
+ push r8
+ push r9
+ push r10
+ push r11
%endif
+ ; Reserve spill space and align the stack.
+ sub xSP, 20h
+ and xSP, ~0fh
+ SEH64_END_PROLOGUE
-;
-; 32-bit.
-;
-%ifdef RT_ARCH_X86
- %macro supR3HardenedJmpBack_NtCreateSection_Xxx 1
- BEGINPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
- ; The code we replaced.
- mov eax, %1
-
- ; Jump back to the original code.
- jmp [NAME(g_pfnNtCreateSectionJmpBack)]
- ENDPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
- %endm
- %define SYSCALL(a_Num) supR3HardenedJmpBack_NtCreateSection_Xxx a_Num
- %include "NtCreateSection-template-x86-syscall-type-1.h"
+ ;
+ ; Call the C/C++ code that does the actual work. This returns the
+ ; resume address in xAX, which we put in the "return" stack position.
+ ;
+ call NAME(supR3HardenedEarlyProcessInit)
+ mov [xBP + xCB], xAX
+ ;
+ ; Restore volatile registers.
+ ;
+ mov xAX, [xBP - xCB*1]
+ mov xCX, [xBP - xCB*2]
+ mov xDX, [xBP - xCB*3]
+%ifdef RT_ARCH_AMD64
+ mov r8, [xBP - xCB*4]
+ mov r9, [xBP - xCB*5]
+ mov r10, [xBP - xCB*6]
+ mov r11, [xBP - xCB*7]
%endif
+ ;
+ ; Use the leave instruction to restore xBP and set up xSP to point at
+ ; the resume address. Then use the 'ret' instruction to resume process
+ ; initializaton.
+ ;
+ leave
+ ret
+ENDPROC supR3HardenedEarlyProcessInitThunk
+
+
;;
; Composes a standard call name.
@@ -84,6 +116,9 @@ BEGINCODE
%define SUPHNTIMP_STDCALL_NAME(a,b) NAME(a)
%endif
+;; Concats two litterals.
+%define SUPHNTIMP_CONCAT(a,b) a %+ b
+
;;
; Import data and code for an API call.
@@ -91,9 +126,10 @@ BEGINCODE
; @param 1 The plain API name.
; @param 2 The parameter frame size on x86. Multiple of dword.
; @param 3 Non-zero expression if system call.
+; @param 4 Non-zero expression if early available call
;
%define SUPHNTIMP_SYSCALL 1
-%macro SupHardNtImport 3
+%macro SupHardNtImport 4
;
; The data.
;
@@ -145,11 +181,24 @@ BEGINPROC %1 %+ _SyscallType2
ENDPROC %1 %+ _SyscallType2
%endif
%endif
+
+%if %4 == 0
+global NAME(SUPHNTIMP_CONCAT(%1,_Early))
+NAME(SUPHNTIMP_CONCAT(%1,_Early)):
+ int3
+ %ifdef RT_ARCH_AMD64
+ ret
+ %else
+ ret %2
+ %endif
+%endif
%endmacro
%define SUPHARNT_COMMENT(a_Comment)
-%define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, SUPHNTIMP_SYSCALL
-%define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, 0
+%define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, SUPHNTIMP_SYSCALL, 1
+%define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, 0, 0
+%define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, 0, 1
+%define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)
%include "import-template-ntdll.h"
%include "import-template-kernel32.h"
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
index 0d979b3..99a1751 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
@@ -47,10 +47,13 @@
#define VBOX_HARDENED_STUB_WITHOUT_IMPORTS
#ifdef VBOX_HARDENED_STUB_WITHOUT_IMPORTS
-# define SUPHNTIMP_ERROR(a_id, a_szWhere, a_enmOp, a_rc, ...) \
- do { static const char s_szWhere[] = a_szWhere; *(char *)(uintptr_t)(a_id) += 1; __debugbreak(); } while (0)
+# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
+ do { \
+ if (a_fReportErrors) supR3HardenedFatalMsg(a_szWhere, a_enmOp, a_rc, __VA_ARGS__); \
+ else { static const char s_szWhere[] = a_szWhere; *(char *)(uintptr_t)(a_id) += 1; __debugbreak(); } \
+ } while (0)
#else
-# define SUPHNTIMP_ERROR(a_id, a_szWhere, a_enmOp, a_rc, ...) \
+# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
supR3HardenedFatalMsg(a_szWhere, a_enmOp, a_rc, __VA_ARGS__)
#endif
@@ -68,6 +71,12 @@ typedef struct SUPHNTIMPFUNC
const char *pszName;
/** Where to store the function address (think __imp_ApiName). */
PFNRT *ppfnImport;
+ /** Pointer to an early dummy function for imports that aren't available
+ * during early process initialization. */
+ PFNRT pfnEarlyDummy;
+ /** Indicates whether this is an optional import and failure to locate it
+ * should set it to NULL instead of freaking out. */
+ bool fOptional;
} SUPHNTIMPFUNC;
/** Pointer to an import table entry. */
typedef SUPHNTIMPFUNC const *PCSUPHNTIMPFUNC;
@@ -138,6 +147,9 @@ typedef struct SUPHNTIMPDLL
* (indexes into paoffExports). */
uint16_t const *pau16NameOrdinals;
+ /** Number of patched export table entries. */
+ uint32_t cPatchedExports;
+
} SUPHNTIMPDLL;
/** Pointer to an import DLL entry. */
typedef SUPHNTIMPDLL *PSUPHNTIMPDLL;
@@ -147,13 +159,17 @@ typedef SUPHNTIMPDLL *PSUPHNTIMPDLL;
/*
* Declare assembly symbols.
*/
-#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
extern PFNRT RT_CONCAT(g_pfn, a_Name);
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)
#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
- SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+ SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
extern uint32_t RT_CONCAT(g_uApiNo, a_Name); \
extern FNRT RT_CONCAT(a_Name, _SyscallType1); \
extern FNRT RT_CONCAT(a_Name, _SyscallType2);
+#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+ extern PFNRT RT_CONCAT(g_pfn, a_Name); \
+ extern FNRT RT_CONCAT(a_Name, _Early);
RT_C_DECLS_BEGIN
#include "import-template-ntdll.h"
@@ -164,9 +180,17 @@ RT_C_DECLS_END
* Import functions.
*/
#undef SUPHARNT_IMPORT_SYSCALL
+#undef SUPHARNT_IMPORT_STDCALL_EARLY
+#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
#undef SUPHARNT_IMPORT_STDCALL
-#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) { #a_Name, &RT_CONCAT(g_pfn, a_Name) },
-#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) { #a_Name, &RT_CONCAT(g_pfn, a_Name) },
+#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
+ { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
+ { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) \
+ { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, true },
+#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+ { #a_Name, &RT_CONCAT(g_pfn, a_Name), RT_CONCAT(a_Name,_Early), false },
static const SUPHNTIMPFUNC g_aSupNtImpNtDllFunctions[] =
{
#include "import-template-ntdll.h"
@@ -184,6 +208,8 @@ static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
*/
#undef SUPHARNT_IMPORT_SYSCALL
#undef SUPHARNT_IMPORT_STDCALL
+#undef SUPHARNT_IMPORT_STDCALL_EARLY
+#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
#ifdef RT_ARCH_AMD64
# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
{ NULL, NULL },
@@ -195,6 +221,8 @@ static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
{ &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name,_SyscallType1), &RT_CONCAT(a_Name, _SyscallType2), a_cbParamsX86 },
#endif
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
static const SUPHNTIMPSYSCALL g_aSupNtImpNtDllSyscalls[] =
{
#include "import-template-ntdll.h"
@@ -203,6 +231,7 @@ static const SUPHNTIMPSYSCALL g_aSupNtImpNtDllSyscalls[] =
/**
* All the DLLs we import from.
+ * @remarks Code ASSUMES that ntdll is the first entry.
*/
static SUPHNTIMPDLL g_aSupNtImpDlls[] =
{
@@ -241,12 +270,12 @@ static void supR3HardenedFindOrLoadModule(PSUPHNTIMPDLL pDll)
if (!pDll->cImports)
pDll->pbImageBase = NULL; /* optional */
else
- SUPHNTIMP_ERROR(1, "supR3HardenedFindOrLoadModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ SUPHNTIMP_ERROR(false, 1, "supR3HardenedFindOrLoadModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
"Failed to locate %ls", pDll->pwszName);
#else
HMODULE hmod = GetModuleHandleW(pDll->pwszName);
if (RT_UNLIKELY(!hmod && pDll->cImports))
- SUPHNTIMP_ERROR(1, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ SUPHNTIMP_ERROR(true, 1, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
"Failed to locate %ls", pDll->pwszName);
pDll->pbImageBase = (uint8_t *)hmod;
#endif
@@ -265,22 +294,22 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
{
offNtHdrs = pMzHdr->e_lfanew;
if (offNtHdrs > _2K)
- SUPHNTIMP_ERROR(2, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ SUPHNTIMP_ERROR(false, 2, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
"%ls: e_lfanew=%#x, expected a lower value", pDll->pwszName, offNtHdrs);
}
pDll->pNtHdrs = pNtHdrs = (PIMAGE_NT_HEADERS)&pDll->pbImageBase[offNtHdrs];
if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
- SUPHNTIMP_ERROR(3, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 3, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Invalid PE signature: %#x", pDll->pwszName, pNtHdrs->Signature);
if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(pNtHdrs->OptionalHeader))
- SUPHNTIMP_ERROR(4, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 4, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Unexpected optional header size: %#x", pDll->pwszName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
if (pNtHdrs->OptionalHeader.Magic != RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
- SUPHNTIMP_ERROR(5, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 5, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Unexpected optional header magic: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.Magic);
if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
- SUPHNTIMP_ERROR(6, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 6, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Unexpected number of RVA and sizes: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
pDll->offNtHdrs = offNtHdrs;
@@ -297,7 +326,7 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
|| ExpDir.VirtualAddress < pDll->offEndSectHdrs
|| ExpDir.VirtualAddress >= pNtHdrs->OptionalHeader.SizeOfImage
|| ExpDir.VirtualAddress + ExpDir.Size > pNtHdrs->OptionalHeader.SizeOfImage)
- SUPHNTIMP_ERROR(7, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 7, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Missing or invalid export directory: %#lx LB %#x", pDll->pwszName, ExpDir.VirtualAddress, ExpDir.Size);
pDll->offExportDir = ExpDir.VirtualAddress;
pDll->cbExportDir = ExpDir.Size;
@@ -308,7 +337,7 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
|| pExpDir->NumberOfFunctions < 1
|| pExpDir->NumberOfNames >= _1M
|| pExpDir->NumberOfNames < 1)
- SUPHNTIMP_ERROR(8, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 8, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
pDll->pwszName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
pDll->cNamedExports = pExpDir->NumberOfNames;
@@ -317,27 +346,27 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
if ( pExpDir->AddressOfFunctions < pDll->offEndSectHdrs
|| pExpDir->AddressOfFunctions >= pNtHdrs->OptionalHeader.SizeOfImage
|| pExpDir->AddressOfFunctions + pDll->cExports * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
- SUPHNTIMP_ERROR(9, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 9, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Bad AddressOfFunctions: %#x\n", pDll->pwszName, pExpDir->AddressOfFunctions);
pDll->paoffExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfFunctions];
if ( pExpDir->AddressOfNames < pDll->offEndSectHdrs
|| pExpDir->AddressOfNames >= pNtHdrs->OptionalHeader.SizeOfImage
|| pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
- SUPHNTIMP_ERROR(10, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 10, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Bad AddressOfNames: %#x\n", pDll->pwszName, pExpDir->AddressOfNames);
pDll->paoffNamedExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfNames];
if ( pExpDir->AddressOfNameOrdinals < pDll->offEndSectHdrs
|| pExpDir->AddressOfNameOrdinals >= pNtHdrs->OptionalHeader.SizeOfImage
|| pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
- SUPHNTIMP_ERROR(11, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+ SUPHNTIMP_ERROR(false, 11, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
"%ls: Bad AddressOfNameOrdinals: %#x\n", pDll->pwszName, pExpDir->AddressOfNameOrdinals);
pDll->pau16NameOrdinals = (uint16_t const *)&pDll->pbImageBase[pExpDir->AddressOfNameOrdinals];
}
-static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport)
+static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, bool fReportErrors)
{
/*
* Binary search.
@@ -349,7 +378,7 @@ static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUN
uint32_t iCur = iStart + (iEnd - iStart) / 2;
uint32_t offExpName = pDll->paoffNamedExports[iCur];
if (RT_UNLIKELY(offExpName < pDll->offEndSectHdrs || offExpName >= pDll->cbImage))
- SUPHNTIMP_ERROR(12, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
+ SUPHNTIMP_ERROR(fReportErrors, 12, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
"%ls: Bad export name entry: %#x (iCur=%#x)", pDll->pwszName, offExpName, iCur);
const char *pszExpName = (const char *)&pDll->pbImageBase[offExpName];
@@ -364,36 +393,37 @@ static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUN
if (iExpOrdinal < pDll->cExports)
{
uint32_t offExport = pDll->paoffExports[iExpOrdinal];
- if (offExport < pDll->cbImage)
- {
- if (offExport - pDll->offExportDir >= pDll->cbExportDir)
- {
- *pImport->ppfnImport = (PFNRT)&pDll->pbImageBase[offExport];
- return NULL;
- }
- /* Forwarder. */
- return (const char *)&pDll->pbImageBase[offExport];
+ /* detect export table patching. */
+ if (offExport >= pDll->cbImage)
+ pDll->cPatchedExports++;
+
+ if (offExport - pDll->offExportDir >= pDll->cbExportDir)
+ {
+ *pImport->ppfnImport = (PFNRT)&pDll->pbImageBase[offExport];
+ return NULL;
}
- SUPHNTIMP_ERROR(13, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
- "%ls: The export RVA for '%s' is out of bounds: %#x (SizeOfImage %#x)",
- pDll->pwszName, offExport, pDll->cbImage);
+
+ /* Forwarder. */
+ return (const char *)&pDll->pbImageBase[offExport];
}
- SUPHNTIMP_ERROR(14, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
+ SUPHNTIMP_ERROR(fReportErrors, 14, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
"%ls: Name ordinal for '%s' is out of bounds: %#x (max %#x)",
pDll->pwszName, iExpOrdinal, pDll->cExports);
return NULL;
}
}
- SUPHNTIMP_ERROR(15, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
- "%ls: Failed to resolve '%s'.", pDll->pwszName, pImport->pszName);
+ if (!pImport->fOptional)
+ SUPHNTIMP_ERROR(fReportErrors, 15, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
+ "%ls: Failed to resolve '%s'.", pDll->pwszName, pImport->pszName);
+ *pImport->ppfnImport = NULL;
return NULL;
}
static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, PCSUPHNTIMPSYSCALL pSyscall,
- PSUPHNTLDRCACHEENTRY pLdrEntry, uint8_t *pbBits)
+ PSUPHNTLDRCACHEENTRY pLdrEntry, uint8_t *pbBits, bool fReportErrors)
{
/*
* Skip non-syscall entries.
@@ -408,7 +438,7 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
int rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)pDll->pbImageBase, UINT32_MAX, pImport->pszName, &uValue);
if (RT_FAILURE(rc))
{
- SUPHNTIMP_ERROR(16, "supR3HardenedDirectSyscall", kSupInitOp_Misc, rc,
+ SUPHNTIMP_ERROR(fReportErrors, 16, "supR3HardenedDirectSyscall", kSupInitOp_Misc, rc,
"%s: RTLdrGetSymbolEx failed on %s: %Rrc", pDll->pszName, pImport->pszName, rc);
return;
}
@@ -513,12 +543,127 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
*/
volatile uint8_t abCopy[16];
memcpy((void *)&abCopy[0], pbFunction, sizeof(abCopy));
- SUPHNTIMP_ERROR(17, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+ SUPHNTIMP_ERROR(fReportErrors, 17, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
"%ls: supHardNtLdrCacheOpen failed: '%s': %.16Rhxs",
- g_aSupNtImpDlls[iDll].pwszName, pImport->pszName, &abCopy[0]);
+ pDll->pwszName, pImport->pszName, &abCopy[0]);
+}
+
+
+/**
+ * Check out system calls and do the directly instead of via NtDll.
+ *
+ * We need to have access to the on disk NTDLL.DLL file as we do not trust the
+ * stuff we find in memory. Too early to verify signatures though.
+ *
+ * @param fReportErrors Whether we've got the machinery for reporting
+ * errors going already.
+ */
+DECLHIDDEN(void) supR3HardenedWinInitSyscalls(bool fReportErrors)
+{
+ for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+ if (g_aSupNtImpDlls[iDll].paSyscalls)
+ {
+ PSUPHNTLDRCACHEENTRY pLdrEntry;
+ int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
+ if (RT_SUCCESS(rc))
+ {
+ uint8_t *pbBits;
+ rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+ NULL /*pErrInfo*/);
+ if (RT_SUCCESS(rc))
+ {
+ for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+ supR3HardenedDirectSyscall(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
+ &g_aSupNtImpDlls[iDll].paSyscalls[i], pLdrEntry, pbBits, fReportErrors);
+ }
+ else
+ SUPHNTIMP_ERROR(fReportErrors, 20, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+ "%ls: supHardNtLdrCacheEntryGetBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+ }
+ else
+ SUPHNTIMP_ERROR(fReportErrors, 21, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+ "%ls: supHardNtLdrCacheOpen failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+ }
+}
+
+
+/**
+ * Resolves a few NtDll functions we need before child purification is executed.
+ *
+ * We must not permanently modify any global data here.
+ *
+ * @param uNtDllAddr The address of the NTDLL.
+ */
+DECLHIDDEN(void) supR3HardenedWinGetVeryEarlyImports(uintptr_t uNtDllAddr,
+ PFNNTWAITFORSINGLEOBJECT *ppfnNtWaitForSingleObject,
+ PFNNTSETEVENT *ppfnNtSetEvent)
+{
+ /*
+ * NTDLL is the first entry in the list. Save it and do the parsing.
+ */
+ SUPHNTIMPDLL SavedDllEntry = g_aSupNtImpDlls[0];
+
+ g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
+ supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
+
+ /*
+ * Create a temporary import table for the requested APIs and resolve them.
+ */
+ SUPHNTIMPFUNC aImports[] =
+ {
+ { "NtWaitForSingleObject", (PFNRT *)ppfnNtWaitForSingleObject, NULL, false },
+ { "NtSetEvent", (PFNRT *)ppfnNtSetEvent, NULL, false },
+ };
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(aImports); i++)
+ {
+ const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &aImports[i], false);
+ if (pszForwarder)
+ SUPHNTIMP_ERROR(false, 31, "supR3HardenedWinGetVeryEarlyImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
+ }
+
+ /*
+ * Restore the NtDll entry.
+ */
+ g_aSupNtImpDlls[0] = SavedDllEntry;
}
+/**
+ * Resolves NtDll functions we can trust calling before process init.
+ *
+ * @param uNtDllAddr The address of the NTDLL.
+ */
+DECLHIDDEN(void) supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr)
+{
+ /*
+ * NTDLL is the first entry in the list.
+ */
+ g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
+ supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
+ for (uint32_t i = 0; i < g_aSupNtImpDlls[0].cImports; i++)
+ if (!g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy)
+ {
+ const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &g_aSupNtImpDlls[0].paImports[i], false);
+ if (pszForwarder)
+ SUPHNTIMP_ERROR(false, 32, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
+ }
+ else
+ *g_aSupNtImpDlls[0].paImports[i].ppfnImport = g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy;
+
+ /*
+ * Pointer the other imports at the early init stubs.
+ */
+ for (uint32_t iDll = 1; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+ for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+ if (!g_aSupNtImpDlls[iDll].paImports[i].fOptional)
+ *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = g_aSupNtImpDlls[iDll].paImports[i].pfnEarlyDummy;
+ else
+ *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = NULL;
+}
+
/**
* Resolves imported functions, esp. system calls from NTDLL.
@@ -547,7 +692,8 @@ DECLHIDDEN(void) supR3HardenedWinInitImports(void)
for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
{
- const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i]);
+ const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
+ false);
if (pszForwarder)
{
const char *pszDot = strchr(pszForwarder, '.');
@@ -555,53 +701,103 @@ DECLHIDDEN(void) supR3HardenedWinInitImports(void)
SUPHNTIMPFUNC Tmp = g_aSupNtImpDlls[iDll].paImports[i];
Tmp.pszName = pszDot + 1;
if (cchDllName == sizeof("ntdll") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("ntdll")) == 0)
- supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &Tmp);
+ supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &Tmp, false);
else if (cchDllName == sizeof("kernelbase") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("kernelbase")) == 0)
- supR3HardenedResolveImport(&g_aSupNtImpDlls[1], &Tmp);
+ supR3HardenedResolveImport(&g_aSupNtImpDlls[1], &Tmp, false);
else
- SUPHNTIMP_ERROR(18, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+ SUPHNTIMP_ERROR(false, 18, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
"%ls: Failed to resolve forwarder '%s'.", g_aSupNtImpDlls[iDll].pwszName, pszForwarder);
}
}
/*
- * Check out system calls and try do them directly if we can.
- * In order to do this though, we need to access the DLL on disk as we
- * cannot trust the memory content to be unpatched.
- *
- * Note! It's too early to validate any signatures.
+ * Do system calls directly.
+ */
+ supR3HardenedWinInitSyscalls(false);
+
+ /*
+ * Use the on disk image to avoid export table patching. Currently
+ * ignoring errors here as can live normally without this step.
*/
for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
- if (g_aSupNtImpDlls[iDll].paSyscalls)
+ if (g_aSupNtImpDlls[iDll].cPatchedExports > 0)
+ {
+ PSUPHNTLDRCACHEENTRY pLdrEntry;
+ int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
+ if (RT_SUCCESS(rc))
+ {
+ uint8_t *pbBits;
+ rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+ NULL /*pErrInfo*/);
+ if (RT_SUCCESS(rc))
+ for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+ {
+ RTLDRADDR uValue;
+ rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
+ UINT32_MAX, g_aSupNtImpDlls[iDll].paImports[i].pszName, &uValue);
+ if (RT_SUCCESS(rc))
+ *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = (PFNRT)(uintptr_t)uValue;
+ }
+ }
+ }
+
+
+#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
+ *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
+#endif
+}
+
+
+/**
+ * Gets the address of a procedure in a DLL, ignoring our own syscall
+ * implementations.
+ *
+ * Currently restricted to NTDLL and KERNEL32
+ *
+ * @returns The procedure address.
+ * @param pszDll The DLL name.
+ * @param pszProcedure The procedure name.
+ */
+DECLHIDDEN(PFNRT) supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure)
+{
+ /*
+ * Look the DLL up in the import DLL table.
+ */
+ for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+ if (RTStrICmp(g_aSupNtImpDlls[iDll].pszName, pszDll) == 0)
{
+
PSUPHNTLDRCACHEENTRY pLdrEntry;
int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
if (RT_SUCCESS(rc))
{
uint8_t *pbBits;
- rc = supHardNtLdrCacheEntryAllocBits(pLdrEntry, &pbBits, NULL);
+ rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+ NULL /*pErrInfo*/);
if (RT_SUCCESS(rc))
{
- rc = RTLdrGetBits(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL);
+ RTLDRADDR uValue;
+ rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
+ UINT32_MAX, pszProcedure, &uValue);
if (RT_SUCCESS(rc))
- for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
- supR3HardenedDirectSyscall(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
- &g_aSupNtImpDlls[iDll].paSyscalls[i], pLdrEntry, pbBits);
- else
- SUPHNTIMP_ERROR(19, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
- "%ls: RTLdrGetBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+ return (PFNRT)(uintptr_t)uValue;
+ SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: Error getting %s in %s -> %Rrc\n", pszProcedure, pszDll, rc));
}
else
- SUPHNTIMP_ERROR(20, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
- "%ls: supHardNtLdrCacheEntryAllocBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+ SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheEntryAllocBits failed on %s: %Rrc\n",
+ pszDll, rc));
}
else
- SUPHNTIMP_ERROR(21, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
- "%ls: supHardNtLdrCacheOpen failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+ SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheOpen failed on %s: %Rrc\n",
+ pszDll, rc));
+
+ /* Complications, just call GetProcAddress. */
+ if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ return (PFNRT)GetProcAddress(GetModuleHandleW(g_aSupNtImpDlls[iDll].pwszName), pszProcedure);
+ return NULL;
}
-#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
- *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
-#endif
+ supR3HardenedFatal("supR3HardenedWinGetRealDllSymbol: Unknown DLL %s (proc: %s)\n", pszDll, pszProcedure);
+ return NULL;
}
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
index 93f034e..b19a9bc 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
@@ -38,9 +38,11 @@
#include <VBox/err.h>
#include <iprt/assert.h>
#include <iprt/ctype.h>
+#include <iprt/heap.h>
#include <iprt/string.h>
#include <iprt/initterm.h>
#include <iprt/param.h>
+#include <iprt/path.h>
#include <iprt/mem.h>
#include "SUPLibInternal.h"
@@ -96,6 +98,153 @@ RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
* Memory allocator.
*/
+/** The handle of the heap we're using. */
+static HANDLE g_hSupR3HardenedHeap = NULL;
+/** Number of heaps used during early process init. */
+static uint32_t g_cSupR3HardenedEarlyHeaps = 0;
+/** Early process init heaps. */
+static struct
+{
+ /** The heap handle. */
+ RTHEAPSIMPLE hHeap;
+ /** The heap block pointer. */
+ void *pvBlock;
+ /** The size of the heap block. */
+ size_t cbBlock;
+ /** Number of active allocations on this heap. */
+ size_t cAllocations;
+} g_aSupR3HardenedEarlyHeaps[8];
+
+
+static uint32_t supR3HardenedEarlyFind(void *pv)
+{
+ uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
+ while (iHeap-- > 0)
+ if ((uintptr_t)pv - (uintptr_t)g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock < g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock)
+ return iHeap;
+ return UINT32_MAX;
+}
+
+
+static void supR3HardenedEarlyCompact(void)
+{
+ uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
+ while (iHeap-- > 0)
+ if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations == 0)
+ {
+ PVOID pvMem = g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock;
+ SIZE_T cbMem = g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock;
+ if (iHeap + 1 < g_cSupR3HardenedEarlyHeaps)
+ g_aSupR3HardenedEarlyHeaps[iHeap] = g_aSupR3HardenedEarlyHeaps[g_cSupR3HardenedEarlyHeaps - 1];
+ g_cSupR3HardenedEarlyHeaps--;
+
+ NTSTATUS rcNt = NtFreeVirtualMemory(NtCurrentProcess(), &pvMem, &cbMem, MEM_RELEASE);
+ Assert(NT_SUCCESS(rcNt));
+ SUP_DPRINTF(("supR3HardenedEarlyCompact: Removed heap %#u (%#p LB %#zx)\n", iHeap, pvMem, cbMem));
+ }
+}
+
+
+static void *supR3HardenedEarlyAlloc(size_t cb, bool fZero)
+{
+ /*
+ * Try allocate on existing heaps.
+ */
+ void *pv;
+ uint32_t iHeap = 0;
+ while (iHeap < g_cSupR3HardenedEarlyHeaps)
+ {
+ if (fZero)
+ pv = RTHeapSimpleAllocZ(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
+ else
+ pv = RTHeapSimpleAlloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
+ if (pv)
+ {
+ g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations++;
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+ SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
+#endif
+ return pv;
+ }
+ iHeap++;
+ }
+
+ /*
+ * Add another heap.
+ */
+ if (iHeap == RT_ELEMENTS(g_aSupR3HardenedEarlyHeaps))
+ supR3HardenedFatal("Early heap table is full (cb=%#zx).\n", cb);
+ SIZE_T cbBlock = iHeap == 0 ? _1M : g_aSupR3HardenedEarlyHeaps[iHeap - 1].cbBlock * 2;
+ while (cbBlock <= cb * 2)
+ cbBlock *= 2;
+
+ PVOID pvBlock = NULL;
+ NTSTATUS rcNt = NtAllocateVirtualMemory(NtCurrentProcess(), &pvBlock, 0 /*ZeroBits*/, &cbBlock, MEM_COMMIT, PAGE_READWRITE);
+ if (!NT_SUCCESS(rcNt))
+ supR3HardenedFatal("NtAllocateVirtualMemory(,,,%#zx,,) failed: rcNt=%#x\n", cbBlock, rcNt);
+ SUP_DPRINTF(("New simple heap: #%u %p LB %#zx (for %zu allocation)\n", iHeap, pvBlock, cbBlock, cb));
+
+ RTHEAPSIMPLE hHeap;
+ int rc = RTHeapSimpleInit(&hHeap, pvBlock, cbBlock);
+ if (RT_FAILURE(rc))
+ supR3HardenedFatal("RTHeapSimpleInit(,%p,%#zx) failed: rc=%#x\n", pvBlock, cbBlock, rc);
+
+ if (fZero)
+ pv = RTHeapSimpleAllocZ(hHeap, cb, 0);
+ else
+ pv = RTHeapSimpleAlloc(hHeap, cb, 0);
+ if (!pv)
+ supR3HardenedFatal("RTHeapSimpleAlloc[Z] failed allocating %#zx bytes on a %#zu heap.\n", cb, cbBlock);
+
+ g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock = pvBlock;
+ g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock = cbBlock;
+ g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations = 1;
+ g_aSupR3HardenedEarlyHeaps[iHeap].hHeap = hHeap;
+
+ Assert(g_cSupR3HardenedEarlyHeaps == iHeap);
+ g_cSupR3HardenedEarlyHeaps = iHeap + 1;
+
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+ SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
+#endif
+ return pv;
+}
+
+
+/**
+ * Lazy heap initialization function.
+ *
+ * @returns Heap handle.
+ */
+static HANDLE supR3HardenedHeapInit(void)
+{
+ Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED);
+ HANDLE hHeap = RtlCreateHeap(HEAP_GROWABLE | HEAP_CLASS_PRIVATE, NULL /*HeapBase*/,
+ 0 /*ReserveSize*/, 0 /*CommitSize*/, NULL /*Lock*/, NULL /*Parameters*/);
+ if (hHeap)
+ {
+ g_hSupR3HardenedHeap = hHeap;
+ return hHeap;
+ }
+
+ supR3HardenedFatal("RtlCreateHeap failed.\n");
+ return NULL;
+}
+
+
+/**
+ * Compacts the heaps before enter wait for parent/child.
+ */
+DECLHIDDEN(void) supR3HardenedWinCompactHeaps(void)
+{
+ if (g_hSupR3HardenedHeap)
+ RtlCompactHeap(g_hSupR3HardenedHeap, 0 /*dwFlags*/);
+ RtlCompactHeap(GetProcessHeap(), 0 /*dwFlags*/);
+ supR3HardenedEarlyCompact();
+}
+
+
+
RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
{
return RTMemAllocTag(cb, pszTag);
@@ -116,13 +265,37 @@ RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW
RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
{
- return suplibHardenedAllocZ(cb);
+ HANDLE hHeap = g_hSupR3HardenedHeap;
+ if (!hHeap)
+ {
+ if ( g_fSupEarlyProcessInit
+ && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
+ return supR3HardenedEarlyAlloc(cb, false /*fZero*/);
+ hHeap = supR3HardenedHeapInit();
+ }
+
+ void *pv = RtlAllocateHeap(hHeap, 0 /*fFlags*/, cb);
+ if (!pv)
+ supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
+ return pv;
}
RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
{
- return suplibHardenedAllocZ(cb);
+ HANDLE hHeap = g_hSupR3HardenedHeap;
+ if (!hHeap)
+ {
+ if ( g_fSupEarlyProcessInit
+ && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
+ return supR3HardenedEarlyAlloc(cb, true /*fZero*/);
+ hHeap = supR3HardenedHeapInit();
+ }
+
+ void *pv = RtlAllocateHeap(hHeap, HEAP_ZERO_MEMORY, cb);
+ if (!pv)
+ supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
+ return pv;
}
@@ -150,13 +323,92 @@ RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_T
RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW
{
- return suplibHardenedReAlloc(pvOld, cbNew);
+ if (!pvOld)
+ return RTMemAllocZTag(cbNew, pszTag);
+
+ void *pv;
+ if (g_fSupEarlyProcessInit)
+ {
+ uint32_t iHeap = supR3HardenedEarlyFind(pvOld);
+ if (iHeap != UINT32_MAX)
+ {
+#if 0 /* RTHeapSimpleRealloc is not implemented */
+ /* If this is before we can use a regular heap, we try resize
+ within the simple heap. (There are a lot of array growing in
+ the ASN.1 code.) */
+ if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ {
+ pv = RTHeapSimpleRealloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld, cbNew, 0);
+ if (pv)
+ {
+# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+ SUP_DPRINTF(("Early heap: %p LB %#zx, was %p - realloc\n", pvNew, cbNew, pvOld));
+# endif
+ return pv;
+ }
+ }
+#endif
+
+ /* Either we can't reallocate it on the same simple heap, or we're
+ past hardened main and wish to migrate everything over on the
+ real heap. */
+ size_t cbOld = RTHeapSimpleSize(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
+ pv = RTMemAllocTag(cbNew, pszTag);
+ if (pv)
+ {
+ memcpy(pv, pvOld, RT_MIN(cbOld, cbNew));
+ RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
+ if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
+ g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
+ if ( !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
+ && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ supR3HardenedEarlyCompact();
+ }
+# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+ SUP_DPRINTF(("Early heap: %p LB %#zx, was %p %LB %#zx - realloc\n", pv, cbNew, pvOld, cbOld));
+# endif
+ return pv;
+ }
+ Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
+ }
+
+ /* Allocate from the regular heap. */
+ HANDLE hHeap = g_hSupR3HardenedHeap;
+ Assert(hHeap != NULL);
+ pv = RtlReAllocateHeap(hHeap, 0 /*dwFlags*/, pvOld, cbNew);
+ if (!pv)
+ supR3HardenedFatal("RtlReAllocateHeap failed to allocate %zu bytes.\n", cbNew);
+ return pv;
}
RTDECL(void) RTMemFree(void *pv) RT_NO_THROW
{
- suplibHardenedFree(pv);
+ if (pv)
+ {
+ if (g_fSupEarlyProcessInit)
+ {
+ uint32_t iHeap = supR3HardenedEarlyFind(pv);
+ if (iHeap != UINT32_MAX)
+ {
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+ SUP_DPRINTF(("Early heap: %p - free\n", pv));
+#endif
+ RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pv);
+ if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
+ g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
+ if ( !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
+ && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+ supR3HardenedEarlyCompact();
+ return;
+ }
+ Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
+ }
+
+ HANDLE hHeap = g_hSupR3HardenedHeap;
+ Assert(hHeap != NULL);
+ RtlFreeHeap(hHeap, 0 /* dwFlags*/, pv);
+ }
}
@@ -189,3 +441,37 @@ RTDECL(void) RTMemWipeThoroughly(void *pv, size_t cb, size_t cMinPasses) RT_NO_T
ASMMemoryFence();
}
+
+
+/*
+ * path-win.cpp
+ */
+
+RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cbPath)
+{
+ int rc;
+ if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+/** @todo Rainy day: improve this by checking the process parameter block
+ * (needs to be normalized). */
+ rc = RTStrCopy(pszPath, cbPath, "C:\\");
+ else
+ {
+ /*
+ * GetCurrentDirectory may in some cases omit the drive letter, according
+ * to MSDN, thus the GetFullPathName call.
+ */
+ RTUTF16 wszCurPath[RTPATH_MAX];
+ if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath))
+ {
+ RTUTF16 wszFullPath[RTPATH_MAX];
+ if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL))
+ rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
+ else
+ rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
+ }
+ else
+ rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
+ }
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
index cafe8ea..4768aff 100644
--- a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
@@ -51,7 +51,7 @@ BOOL __stdcall DllMainEntrypoint(HANDLE hModule, DWORD dwReason, PVOID pvReserve
WCHAR wszName[RTPATH_MAX];
SetLastError(NO_ERROR);
if ( GetModuleFileNameW((HMODULE)hModule, wszName, RT_ELEMENTS(wszName)) > 0
- && GetLastError() == NO_ERROR)
+ && RtlGetLastWin32Error() == NO_ERROR)
{
int cExtraLoads = 2;
while (cExtraLoads-- > 0)
diff --git a/src/VBox/HostDrivers/Support/win/import-template-kernel32.h b/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
index 331a780..1466d94 100644
--- a/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
+++ b/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
@@ -1,10 +1,9 @@
-SUPHARNT_IMPORT_STDCALL(CloseHandle, 4)
SUPHARNT_IMPORT_STDCALL(CreateFileW, 28)
SUPHARNT_IMPORT_STDCALL(CreateProcessW, 40)
SUPHARNT_IMPORT_STDCALL(ExitProcess, 4)
-SUPHARNT_IMPORT_STDCALL(GetCurrentThreadId, 0)
SUPHARNT_IMPORT_STDCALL(GetFullPathNameA, 16)
-SUPHARNT_IMPORT_STDCALL(GetLastError, 0)
+SUPHARNT_IMPORT_STDCALL(GetFullPathNameW, 16)
+SUPHARNT_IMPORT_STDCALL(GetCurrentDirectoryW, 8)
SUPHARNT_IMPORT_STDCALL(GetModuleFileNameW, 12)
SUPHARNT_IMPORT_STDCALL(GetModuleHandleA, 4)
SUPHARNT_IMPORT_STDCALL(GetModuleHandleW, 4)
@@ -12,17 +11,10 @@ SUPHARNT_IMPORT_STDCALL(GetProcAddress, 8)
SUPHARNT_IMPORT_STDCALL(GetProcessHeap, 0)
SUPHARNT_IMPORT_STDCALL(GetSystemDirectoryW, 8)
SUPHARNT_IMPORT_STDCALL(GetTickCount, 0)
-SUPHARNT_IMPORT_STDCALL(HeapAlloc, 12)
-SUPHARNT_IMPORT_STDCALL(HeapCompact, 8)
-SUPHARNT_IMPORT_STDCALL(HeapFree, 8)
-SUPHARNT_IMPORT_STDCALL(HeapReAlloc, 16)
SUPHARNT_IMPORT_STDCALL(LoadLibraryExW, 12)
SUPHARNT_IMPORT_STDCALL(OutputDebugStringA, 4)
-SUPHARNT_IMPORT_STDCALL(SetLastError, 4)
-SUPHARNT_IMPORT_STDCALL(Sleep, 4)
SUPHARNT_IMPORT_STDCALL(TlsAlloc, 0)
SUPHARNT_IMPORT_STDCALL(TlsGetValue, 4)
SUPHARNT_IMPORT_STDCALL(TlsSetValue, 8)
-SUPHARNT_IMPORT_STDCALL(VirtualProtectEx, 20)
SUPHARNT_IMPORT_STDCALL(WriteFile, 20)
diff --git a/src/VBox/HostDrivers/Support/win/import-template-ntdll.h b/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
index 1f7b917..a9318c4 100644
--- a/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
+++ b/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
@@ -1,6 +1,9 @@
SUPHARNT_IMPORT_SYSCALL(NtAllocateVirtualMemory, 24)
+SUPHARNT_IMPORT_SYSCALL(NtClearEvent, 4)
SUPHARNT_IMPORT_SYSCALL(NtClose, 4)
+SUPHARNT_IMPORT_SYSCALL(NtCreateEvent, 20)
SUPHARNT_IMPORT_SYSCALL(NtCreateFile, 44)
+SUPHARNT_IMPORT_SYSCALL(NtCreateSymbolicLinkObject, 16)
SUPHARNT_IMPORT_SYSCALL(NtDelayExecution, 8)
SUPHARNT_IMPORT_SYSCALL(NtDeviceIoControlFile, 40)
SUPHARNT_IMPORT_SYSCALL(NtDuplicateObject, 28)
@@ -8,28 +11,35 @@ SUPHARNT_IMPORT_SYSCALL(NtFreeVirtualMemory, 16)
SUPHARNT_IMPORT_SYSCALL(NtGetContextThread, 8)
SUPHARNT_IMPORT_SYSCALL(NtMapViewOfSection, 40)
SUPHARNT_IMPORT_SYSCALL(NtOpenDirectoryObject, 12)
+SUPHARNT_IMPORT_SYSCALL(NtOpenEvent, 12)
SUPHARNT_IMPORT_SYSCALL(NtOpenKey, 12)
SUPHARNT_IMPORT_SYSCALL(NtOpenProcess, 16)
SUPHARNT_IMPORT_SYSCALL(NtOpenProcessToken, 12)
+SUPHARNT_IMPORT_SYSCALL(NtOpenSymbolicLinkObject, 12)
SUPHARNT_IMPORT_SYSCALL(NtOpenThread, 16)
SUPHARNT_IMPORT_SYSCALL(NtOpenThreadToken, 16)
SUPHARNT_IMPORT_SYSCALL(NtProtectVirtualMemory, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryFile, 44)
SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryObject, 28)
+SUPHARNT_IMPORT_SYSCALL(NtQueryEvent, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryInformationFile, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryInformationProcess, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryInformationThread, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryInformationToken, 20)
SUPHARNT_IMPORT_SYSCALL(NtQueryObject, 20)
SUPHARNT_IMPORT_SYSCALL(NtQuerySecurityObject, 20)
+SUPHARNT_IMPORT_SYSCALL(NtQuerySymbolicLinkObject, 12)
+SUPHARNT_IMPORT_SYSCALL(NtQuerySystemInformation, 16)
SUPHARNT_IMPORT_SYSCALL(NtQueryTimerResolution, 12)
SUPHARNT_IMPORT_SYSCALL(NtQueryValueKey, 24)
SUPHARNT_IMPORT_SYSCALL(NtQueryVirtualMemory, 24)
SUPHARNT_IMPORT_SYSCALL(NtReadFile, 36)
SUPHARNT_IMPORT_SYSCALL(NtReadVirtualMemory, 20)
+SUPHARNT_IMPORT_SYSCALL(NtResetEvent, 8)
SUPHARNT_IMPORT_SYSCALL(NtResumeProcess, 4)
SUPHARNT_IMPORT_SYSCALL(NtResumeThread, 8)
SUPHARNT_IMPORT_SYSCALL(NtSetContextThread, 8)
+SUPHARNT_IMPORT_SYSCALL(NtSetEvent, 8)
SUPHARNT_IMPORT_SYSCALL(NtSetInformationFile, 20)
SUPHARNT_IMPORT_SYSCALL(NtSetInformationObject, 16)
SUPHARNT_IMPORT_SYSCALL(NtSetInformationProcess, 16)
@@ -40,32 +50,46 @@ SUPHARNT_IMPORT_SYSCALL(NtSuspendThread, 8)
SUPHARNT_IMPORT_SYSCALL(NtTerminateProcess, 8)
SUPHARNT_IMPORT_SYSCALL(NtTerminateThread, 8)
SUPHARNT_IMPORT_SYSCALL(NtUnmapViewOfSection, 8)
-SUPHARNT_IMPORT_SYSCALL(NtWaitForSingleObject, 12)
SUPHARNT_IMPORT_SYSCALL(NtWaitForMultipleObjects, 20)
+SUPHARNT_IMPORT_SYSCALL(NtWaitForSingleObject, 12)
SUPHARNT_IMPORT_SYSCALL(NtWriteFile, 36)
SUPHARNT_IMPORT_SYSCALL(NtWriteVirtualMemory, 20)
SUPHARNT_IMPORT_SYSCALL(NtYieldExecution, 0)
+SUPHARNT_IMPORT_SYSCALL(NtCreateSection, 28)
+SUPHARNT_IMPORT_SYSCALL(NtQueryVolumeInformationFile, 20)
+SUPHARNT_IMPORT_STDCALL_EARLY(LdrInitializeThunk, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(LdrRegisterDllNotification, 16)
-SUPHARNT_IMPORT_STDCALL(NtCreateSection, 28)
-SUPHARNT_IMPORT_STDCALL(NtQueryVolumeInformationFile, 20)
-SUPHARNT_IMPORT_STDCALL(LdrInitializeThunk, 12)
SUPHARNT_IMPORT_STDCALL(RtlAddAccessAllowedAce, 16)
SUPHARNT_IMPORT_STDCALL(RtlAddAccessDeniedAce, 16)
+SUPHARNT_IMPORT_STDCALL(RtlAllocateHeap, 12)
+SUPHARNT_IMPORT_STDCALL(RtlCompactHeap, 8)
SUPHARNT_IMPORT_STDCALL(RtlCopySid, 12)
SUPHARNT_IMPORT_STDCALL(RtlCreateAcl, 12)
+SUPHARNT_IMPORT_STDCALL(RtlCreateHeap, 24)
SUPHARNT_IMPORT_STDCALL(RtlCreateProcessParameters, 40)
SUPHARNT_IMPORT_STDCALL(RtlCreateSecurityDescriptor, 8)
SUPHARNT_IMPORT_STDCALL(RtlCreateUserProcess, 40)
SUPHARNT_IMPORT_STDCALL(RtlCreateUserThread, 40)
SUPHARNT_IMPORT_STDCALL(RtlDestroyProcessParameters, 4)
-SUPHARNT_IMPORT_STDCALL(RtlDosApplyFileIsolationRedirection_Ustr, 36)
-SUPHARNT_IMPORT_STDCALL(RtlEqualSid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlDosApplyFileIsolationRedirection_Ustr, 36)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlEqualSid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(RtlExitUserProcess, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlExitUserThread, 4)
SUPHARNT_IMPORT_STDCALL(RtlExpandEnvironmentStrings_U, 16)
-SUPHARNT_IMPORT_STDCALL(RtlFreeUnicodeString, 4)
-SUPHARNT_IMPORT_STDCALL(RtlGetVersion, 4)
-SUPHARNT_IMPORT_STDCALL(RtlInitializeSid, 12)
-SUPHARNT_IMPORT_STDCALL(RtlNtStatusToDosError, 4)
+SUPHARNT_IMPORT_STDCALL(RtlFreeHeap, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlFreeUnicodeString, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetLastNtStatus, 0)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetLastWin32Error, 0)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetVersion, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlInitializeSid, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlNtStatusToDosError, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlReAllocateHeap, 16)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlRestoreLastWin32Error, 4)
SUPHARNT_IMPORT_STDCALL(RtlSetDaclSecurityDescriptor, 16)
-SUPHARNT_IMPORT_STDCALL(RtlSubAuthoritySid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSetLastWin32Error, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSetLastWin32ErrorAndNtStatusFromNtStatus, 4)
+SUPHARNT_IMPORT_STDCALL(RtlSizeHeap, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSubAuthoritySid, 8)
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
index 93a99d6..c8f2e5f 100644
--- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
@@ -89,7 +89,7 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedShaders(GLuint program,
GLsizei i;
GLuint *ids=(GLuint*)&pLocal[1];
- for (i=0; i<*pLocal; ++i);
+ for (i=0; i<*pLocal; ++i)
ids[i] = crStateGLSLShaderHWIDtoID(ids[i]);
}
diff --git a/src/VBox/Installer/win/Makefile.kmk b/src/VBox/Installer/win/Makefile.kmk
index c856af6..c731135 100644
--- a/src/VBox/Installer/win/Makefile.kmk
+++ b/src/VBox/Installer/win/Makefile.kmk
@@ -49,23 +49,9 @@ include $(PATH_SUB_CURRENT)/Resources/Makefile.kmk
# Globals and targets.
# Note: en_US *must* come first for the dependency file generation.
#
-VBOX_INSTALLER_LANGUAGES = en_US de_DE fr_FR it_IT zh_TW
-VBOX_INSTALLER_LANGUAGES += $(VBOX_INSTALLER_ADD_LANGUAGES)
-
-#
-# Use merge modules if we're not doing an official release.
-# This will increase the overall installer size significantly because
-# merge modules are not able to use a common .cab file to reduce their
-# size.
-#
-ifneq ($(int-mod $(VBOX_VERSION_BUILD),2),0)
- VBOX_WITH_MSM_INSTALL := 1
- VBOX_INSTALLER_LANGUAGES = en_US
-endif
-
-ifeq ($(USERNAME),andy)
- VBOX_WITH_MSM_INSTALL := 1
- VBOX_INSTALLER_LANGUAGES = en_US
+ifndef VBOX_INSTALLER_LANGUAGES
+ VBOX_INSTALLER_LANGUAGES = en_US de_DE fr_FR it_IT zh_TW
+ VBOX_INSTALLER_LANGUAGES += $(VBOX_INSTALLER_ADD_LANGUAGES)
endif
#
@@ -77,19 +63,32 @@ ifeq ($(KBUILD_TARGET_ARCH),amd64)
endif
# We only ship the merge modules in locale en_US for the moment.
-VBOX_INSTALLER_MERGE_LANGUAGES = $(VBOX_INSTALLER_LANGUAGES)
+ifdef VBOX_WITH_MSM_INSTALL
+ VBOX_INSTALLER_LANGUAGES := en_US
+ VBOX_INSTALLER_MERGE_LANGUAGES = $(VBOX_INSTALLER_LANGUAGES)
+endif
#
# We don't have the license text in another language than English yet,
# so just define the branding targets to use the English one for now.
+# The installer generation assumes that there is a translation for each
+# of VBOX_INSTALLER_LANGUAGES.
#
$(foreach lang,$(VBOX_INSTALLER_LANGUAGES), \
- $(eval VBOX_BRAND_$(lang)_LICENSE_RTF := $(VBOX_BRAND_LICENSE_RTF)) \
+ $(eval VBOX_BRAND_$(lang)_LICENSE_RTF := $(VBOX_BRAND_LICENSE_RTF)))
+
+# Set the codepage for all languages to 1252, covers most cases.
+$(foreach lang,$(sort $(VBOX_INSTALLER_LANGUAGES) $(VBOX_LICENSE_ADD_LANGUAGES) $(VBOX_MANUAL_ADD_LANGUAGES)), \
$(eval VBOX_BRAND_$(lang)_LANGUAGE_CODEPAGE := 1252))
# Some languages need another codepage than 1252. Override them here.
VBOX_BRAND_zh_TW_LANGUAGE_CODEPAGE := 950
+# Standard language names (in the native language), to be extended as we go.
+# VBOX_BRAND_$(lang)_LANG_NAME must be defined for each language which occurs
+# in either # VBOX_LICENSE_ADD_LANGUAGES or VBOX_MANUAL_ADD_LANGUAGES.
+VBOX_BRAND_fr_FR_LANG_NAME := Français
+
VBOX_PATH_WIN_INST_SRC := $(PATH_SUB_CURRENT)
VBOX_WIN_INST_OUT_DIR := $(PATH_TARGET)/Installer/win
@@ -300,7 +299,7 @@ $(VBOX_WIN_INST_OUT_DIR)/Files_License.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@)
$(APPEND) $@ '<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">'
$(APPEND) $@ ' <File Id="file_License_en_US.rtf" Name="License_en_US.rtf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(VBOX_BRAND_LICENSE_RTF)">' \
' </File>'
- $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
+ $(APPEND) -n $@ $(foreach lang,$(VBOX_LICENSE_ADD_LANGUAGES), \
' <File Id="file_License_$(lang).rtf" Name="License_$(lang).rtf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(VBOX_BRAND_$(lang)_LICENSE_RTF)">' \
' </File>')
$(APPEND) $@ '</Include>'
@@ -316,22 +315,22 @@ ifdef VBOX_WITH_DOCS_PACKING
$(APPEND) $@ ' <Shortcut Id="sc_StartMenu_ManualCHM_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (CHM, English)" Description="!(loc.StartMenu_UserManual)"' \
' Target="[INSTALLDIR]\VirtualBox.chm" WorkingDirectory="dir_Documents" Advertise="no"/>'
$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
- ' <Shortcut Id="sc_StartMenu_ManualCHM_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_UserManual) (CHM, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
- ' Description="$!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\VirtualBox_$(lang).chm" WorkingDirectory="dir_Documents"/>')
+ ' <Shortcut Id="sc_StartMenu_ManualCHM_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (CHM, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+ ' Description="!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\VirtualBox_$(lang).chm" WorkingDirectory="dir_Documents"/>')
endif
$(APPEND) $@ ' <Shortcut Id="sc_StartMenu_ManualPDF_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (PDF, English)" Description="!(loc.StartMenu_UserManual)"' \
' Target="[INSTALLDIR]\doc\UserManual.pdf" WorkingDirectory="dir_Documents" Advertise="no"/>'
$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
- ' <Shortcut Id="sc_StartMenu_ManualPDF_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_UserManual) (PDF, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
- ' Description="$!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\doc\UserManual_$(lang).pdf" WorkingDirectory="dir_Documents"/>')
+ ' <Shortcut Id="sc_StartMenu_ManualPDF_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (PDF, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+ ' Description="!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\doc\UserManual_$(lang).pdf" WorkingDirectory="dir_Documents"/>')
#
# License(s) (RTF)
#
$(APPEND) $@ ' <Shortcut Id="sc_StartMenu_License_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_License) (English)" Description="!(loc.StartMenu_License)"' \
' Target="[INSTALLDIR]License_en_US.rtf" WorkingDirectory="INSTALLDIR" Advertise="no"/>'
- $(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
- ' <Shortcut Id="sc_StartMenu_License_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))"' \
- ' Description="$!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="License_$(lang).rtf" WorkingDirectory="INSTALLDIR"/>')
+ $(APPEND) -n $@ $(foreach lang,$(VBOX_LICENSE_ADD_LANGUAGES), \
+ ' <Shortcut Id="sc_StartMenu_License_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+ ' Description="!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="License_$(lang).rtf" WorkingDirectory="INSTALLDIR"/>')
$(APPEND) $@ '</Include>'
#
diff --git a/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi b/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
index 58ee600..c9a11db 100644
--- a/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
+++ b/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
@@ -19,28 +19,28 @@
<?if $(env.VBOX_WITH_NETFLT) = "yes" ?>
<Custom Action="ca_RollbackInstallNetFltArgs" Before="ca_RollbackInstallNetFlt" >
<?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
- <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+ <![CDATA[NOT Installed]]>
<?else ?>
<![CDATA[&VBoxNetworkFlt=3]]>
<?endif ?>
</Custom>
<Custom Action="ca_RollbackInstallNetFlt" Before="ca_InstallNetFlt" >
<?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
- <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+ <![CDATA[NOT Installed]]>
<?else ?>
<![CDATA[&VBoxNetworkFlt=3]]>
<?endif ?>
</Custom>
<Custom Action="ca_InstallNetFltArgs" Before="ca_InstallNetFlt" >
<?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
- <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+ <![CDATA[NOT Installed]]>
<?else ?>
<![CDATA[&VBoxNetworkFlt=3]]>
<?endif ?>
</Custom>
<Custom Action="ca_InstallNetFlt" Before="InstallFinalize" >
<?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
- <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+ <![CDATA[NOT Installed]]>
<?else ?>
<![CDATA[&VBoxNetworkFlt=3]]>
<?endif ?>
diff --git a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
index 3a5e698..73db613 100644
--- a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
+++ b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 91907 $ */
+/* $Revision: 96259 $ */
/** @file VBoxXPCOMCGlue.c
* Glue code for dynamically linking to VBoxCAPI, LEGACY VARIANT.
*/
@@ -266,7 +266,7 @@ int VBoxCGlueInit(void)
if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0)
return 0;
#elif defined(__APPLE__)
- if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0)
+ if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0)
return 0;
#elif defined(__FreeBSD__)
if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0)
diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.c b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
index d229a6b..500cb38 100644
--- a/src/VBox/Main/cbinding/VBoxCAPIGlue.c
+++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 91907 $ */
+/* $Revision: 96259 $ */
/** @file
* Glue code for dynamically linking to VBoxCAPI.
*/
@@ -266,7 +266,7 @@ int VBoxCGlueInit(void)
if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0)
return 0;
#elif defined(__APPLE__)
- if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0)
+ if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0)
return 0;
#elif defined(__FreeBSD__)
if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0)
diff --git a/src/VBox/Main/cbinding/capiidl.xsl b/src/VBox/Main/cbinding/capiidl.xsl
index 7c3635f..a450a19 100644
--- a/src/VBox/Main/cbinding/capiidl.xsl
+++ b/src/VBox/Main/cbinding/capiidl.xsl
@@ -197,6 +197,7 @@ typedef const BSTR CBSTR;
#define ComSafeArrayAsInParam(f) (f)
#define ComSafeArrayAsOutParam(f) (&(f))
+#define ComSafeArrayAsOutTypeParam(f,t) (&(f))
#define ComSafeArrayAsOutIfaceParam(f,t) (&(f))
#else /* !WIN32 */
@@ -867,6 +868,7 @@ typedef struct SAFEARRAY
#define ComSafeArrayAsInParam(f) ((f)->c), ((f)->pv)
#define ComSafeArrayAsOutParam(f) (&((f)->c)), (&((f)->pv))
+#define ComSafeArrayAsOutTypeParam(f,t) (&((f)->c)), (t**)(&((f)->pv))
#define ComSafeArrayAsOutIfaceParam(f,t) (&((f)->c)), (t**)(&((f)->pv))
/* Glossing over differences between COM and XPCOM */
@@ -2096,7 +2098,7 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
<xsl:if test="not(@readonly='yes')">
<!-- setter (COM compatible) -->
<xsl:text>#define </xsl:text>
- <xsl:value-of select="concat($iface, '_set_')"/>
+ <xsl:value-of select="concat($iface, '_put_')"/>
<xsl:call-template name="capitalize">
<xsl:with-param name="str" select="@name"/>
</xsl:call-template>
@@ -2285,7 +2287,7 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
<xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,33,2)"/>
<xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,35,2)"/>
<xsl:text> } \
}
</xsl:text>
- <xsl:text>enum </xsl:text>
+ <xsl:text>typedef enum </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>
{
</xsl:text>
<xsl:variable name="this" select="."/>
@@ -2299,7 +2301,9 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:for-each>
- <xsl:text>};
</xsl:text>
+ <xsl:text>} </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>;
</xsl:text>
<xsl:text>/* End of enum </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text> declaration */
diff --git a/src/VBox/Main/cbinding/tstCAPIGlue.c b/src/VBox/Main/cbinding/tstCAPIGlue.c
index c05ec30..2396a09 100644
--- a/src/VBox/Main/cbinding/tstCAPIGlue.c
+++ b/src/VBox/Main/cbinding/tstCAPIGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 93190 $ */
+/* $Revision: 96185 $ */
/** @file tstCAPIGlue.c
* Demonstrator program to illustrate use of C bindings of Main API.
*
@@ -748,7 +748,7 @@ static void startVM(const char *argv0, IVirtualBox *virtualBox, ISession *sessio
return;
}
- rc = IMachine_get_Groups(machine, ComSafeArrayAsOutParam(groupsSA));
+ rc = IMachine_get_Groups(machine, ComSafeArrayAsOutTypeParam(groupsSA, BSTR));
if (SUCCEEDED(rc))
{
BSTR *groups = NULL;
diff --git a/src/VBox/Main/include/ConsoleEvents.h b/src/VBox/Main/include/ConsoleEvents.h
deleted file mode 100644
index a4718ac..0000000
--- a/src/VBox/Main/include/ConsoleEvents.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/** @file
- *
- * VirtualBox console event handling
- */
-
-/*
- * Copyright (C) 2006-2010 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef ____H_CONSOLEEVENTS
-#define ____H_CONSOLEEVENTS
-
-#include <iprt/semaphore.h>
-
-template<class C> class ConsoleEventBuffer
-{
-public:
- /**
- * Constructor
- *
- * @param size FIFO size in elements.
- */
- ConsoleEventBuffer(size_t size) :
- sz(size), buf(new C[size]), curg(0), curp(0), full(false)
- {
- RTSemMutexCreate(&mutex);
- }
-
- /**
- * Destructor
- *
- */
- virtual ~ConsoleEventBuffer()
- {
- RTSemMutexDestroy(mutex);
- delete buf;
- }
-
- /**
- * Opens the buffer for extraction of elements. Must be called before #get().
- */
- void open()
- {
- lock();
- }
-
- /**
- * Closes the buffer previously opened by #open(). Must be called after #get().
- */
- void close()
- {
- unlock();
- }
-
- /**
- * Gets the element from the buffer. Requires #open() before and #close()
- * after. Returns the first element and removes it from the buffer. If
- * the buffer is empty, returns an empty element (constructed with the
- * default constructor).
- */
- C get()
- {
- C c;
- if (full || curg != curp)
- {
- c = buf[curg];
- ++curg %= sz;
- full = false;
- }
- return c;
- }
-
- /**
- * Puts the element to the end of the buffer. #open()/#close() must not
- * be used. Returns 1 if successful, or 0 if the buffer is full, or 2
- * if the element is invalid.
- */
- size_t put(C c)
- {
- if (!c.isValid())
- return 2; // invalid element
- lock();
- size_t i = 0;
- if (!full)
- {
- buf[curp] = c;
- ++curp %= sz;
- i++;
- full = curg == curp;
- }
- unlock();
- return i;
- }
-
- /**
- * Puts the number of elements to the buffer. #open()/#close() must not
- * be used. Returns the count of elements placed. If it is less than
- * the count passed as an argument then the buffer is full. If it is
- * greater (special case) then the invalid element is encountered and
- * its index is return value munis count minus 1.
- */
- size_t put(C *codes, size_t count)
- {
- lock();
- size_t i = 0;
- while (i < count && !full)
- {
- if (!codes[i].isValid())
- {
- i += count + 1; // invalid code
- break;
- }
- buf[curp] = codes[i++];
- ++curp %= sz;
- full = curg == curp;
- }
- unlock();
- return i;
- }
-
-private:
- /**
- * Acquire the local mutex
- */
- void lock()
- {
- RTSemMutexRequest(mutex, RT_INDEFINITE_WAIT);
- }
- /**
- * Release the local mutex
- */
- void unlock()
- {
- RTSemMutexRelease(mutex);
- }
-
-private:
- size_t sz;
- C *buf;
- size_t curg, curp;
- bool full;
- RTSEMMUTEX mutex;
-};
-
-#endif // ____H_CONSOLEEVENTS
-/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/include/KeyboardImpl.h b/src/VBox/Main/include/KeyboardImpl.h
index a94e67b..71cee23 100644
--- a/src/VBox/Main/include/KeyboardImpl.h
+++ b/src/VBox/Main/include/KeyboardImpl.h
@@ -19,7 +19,6 @@
#define ____H_KEYBOARDIMPL
#include "VirtualBoxBase.h"
-#include "ConsoleEvents.h"
#include "EventImpl.h"
#include <VBox/vmm/pdmdrv.h>
@@ -39,9 +38,6 @@ public:
}
int scan;
};
-// template instantiation
-typedef ConsoleEventBuffer<KeyboardEvent> KeyboardEventBuffer;
-
class Console;
class ATL_NO_VTABLE Keyboard :
diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h
index bb91290..d3c6d85 100644
--- a/src/VBox/Main/include/MachineImpl.h
+++ b/src/VBox/Main/include/MachineImpl.h
@@ -1213,7 +1213,7 @@ private:
HRESULT setMachineState(MachineState_T aMachineState);
HRESULT updateMachineStateOnClient();
- HRESULT mRemoveSavedState;
+ bool mRemoveSavedState;
ConsoleTaskData mConsoleTaskData;
diff --git a/src/VBox/Main/include/MouseImpl.h b/src/VBox/Main/include/MouseImpl.h
index 404c759..21dde0e 100644
--- a/src/VBox/Main/include/MouseImpl.h
+++ b/src/VBox/Main/include/MouseImpl.h
@@ -19,7 +19,6 @@
#define ____H_MOUSEIMPL
#include "VirtualBoxBase.h"
-#include "ConsoleEvents.h"
#include "ConsoleImpl.h"
#include "EventImpl.h"
#include <VBox/vmm/pdmdrv.h>
diff --git a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
index 1b0fb66..3c1e233 100644
--- a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
+++ b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
@@ -1268,6 +1268,11 @@ GuestWaitEventBase::GuestWaitEventBase(void)
GuestWaitEventBase::~GuestWaitEventBase(void)
{
+ if (mEventSem != NIL_RTSEMEVENT)
+ {
+ RTSemEventDestroy(mEventSem);
+ mEventSem = NIL_RTSEMEVENT;
+ }
}
int GuestWaitEventBase::Init(uint32_t uCID)
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp
index c8c5718..a814909 100644
--- a/src/VBox/Main/src-server/ApplianceImplExport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp
@@ -1057,21 +1057,17 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmVirtualSystem->setAttribute("ovf:id", strVMName);
// product info
- std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
+ std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
std::list<VirtualSystemDescriptionEntry*> llProductUrl = vsdescThis->findByType(VirtualSystemDescriptionType_ProductUrl);
- std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
- std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
- std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
- bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty();
+ std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
+ std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
+ std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
+ bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty();
bool fProductUrl = llProductUrl.size() && !llProductUrl.back()->strVBoxCurrent.isEmpty();
- bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty();
- bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty();
- bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty();
- if (fProduct ||
- fProductUrl ||
- fVersion ||
- fVendorUrl ||
- fVersion)
+ bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty();
+ bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty();
+ bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty();
+ if (fProduct || fProductUrl || fVendor || fVendorUrl || fVersion)
{
/* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
<Info>Meta-information about the installed software</Info>
diff --git a/src/VBox/Main/src-server/ApplianceImplImport.cpp b/src/VBox/Main/src-server/ApplianceImplImport.cpp
index 1eada73..6077aea 100644
--- a/src/VBox/Main/src-server/ApplianceImplImport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplImport.cpp
@@ -389,8 +389,9 @@ STDMETHODIMP Appliance::Interpret()
}
}
/* else we use the ovf configuration. */
- else if (size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size() > 0)
+ else if (vsysThis.llEthernetAdapters.size() > 0)
{
+ size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size();
uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(ChipsetType_PIIX3);
/* Check for the constrains */
@@ -3820,10 +3821,8 @@ void Appliance::importMachines(ImportStack &stack,
list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
/* Iterate through all virtual systems of that appliance */
size_t i = 0;
- for (it = reader.m_llVirtualSystems.begin(),
- it1 = m->virtualSystemDescriptions.begin();
- it != reader.m_llVirtualSystems.end(),
- it1 != m->virtualSystemDescriptions.end();
+ for (it = reader.m_llVirtualSystems.begin(), it1 = m->virtualSystemDescriptions.begin();
+ it != reader.m_llVirtualSystems.end() && it1 != m->virtualSystemDescriptions.end();
++it, ++it1, ++i)
{
const ovf::VirtualSystem &vsysThis = *it;
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index 3889a01..2eb2947 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2004-2013 Oracle Corporation
+ * Copyright (C) 2004-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -5346,7 +5346,10 @@ STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue)
// creates a new key if needed
bool fNeedsGlobalSaveSettings = false;
- saveSettings(&fNeedsGlobalSaveSettings);
+ // This saving of settings is tricky: there is no "old state" for the
+ // extradata items at all (unlike all other settings), so the old/new
+ // settings comparison would give a wrong result!
+ saveSettings(&fNeedsGlobalSaveSettings, SaveS_Force);
if (fNeedsGlobalSaveSettings)
{
@@ -5797,6 +5800,11 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task)
logFolder.c_str(), RTPATH_DELIMITER, i);
RTFileDelete(log.c_str());
}
+#if defined(RT_OS_WINDOWS)
+ log = Utf8StrFmt("%s%cVBoxStartup.log",
+ logFolder.c_str(), RTPATH_DELIMITER);
+ RTFileDelete(log.c_str());
+#endif
RTDirRemove(logFolder.c_str());
}
diff --git a/src/VBox/Main/src-server/MediumImpl.cpp b/src/VBox/Main/src-server/MediumImpl.cpp
index c61ea6f..3a935b5 100644
--- a/src/VBox/Main/src-server/MediumImpl.cpp
+++ b/src/VBox/Main/src-server/MediumImpl.cpp
@@ -2398,7 +2398,8 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue)
Utf8Str strName(aName);
Utf8Str strValue(aValue);
settings::StringsMap::iterator it = m->mapProperties.find(strName);
- if (!strName.startsWith("Special/"))
+ if ( !strName.startsWith("Special/")
+ && !isPropertyForFilter(strName))
{
if (it == m->mapProperties.end())
return setError(VBOX_E_OBJECT_NOT_FOUND,
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index 3520c9c..e988800 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -54,7 +54,7 @@
*/
/*
- * Copyright (C) 2007-2013 Oracle Corporation
+ * Copyright (C) 2007-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -2188,7 +2188,7 @@ bool MachineConfigFile::operator==(const MachineConfigFile &c) const
&& (hardwareMachine == c.hardwareMachine) // this one's deep
&& (storageMachine == c.storageMachine) // this one's deep
&& (mediaRegistry == c.mediaRegistry) // this one's deep
- && (mapExtraDataItems == c.mapExtraDataItems) // this one's deep
+ // skip mapExtraDataItems! there is no old state available as it's always forced
&& (llFirstSnapshot == c.llFirstSnapshot) // this one's deep
)
);
@@ -5386,7 +5386,7 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
if (ctrl.strName != "OHCI")
fNonStdName = true;
break;
- case USBControllerType_EHCI:
+ case USBControllerType_EHCI:
cEhciCtrls++;
if (ctrl.strName != "EHCI")
fNonStdName = true;
diff --git a/src/VBox/NetworkServices/NAT/proxy.c b/src/VBox/NetworkServices/NAT/proxy.c
index 51f29b4..ade529f 100644
--- a/src/VBox/NetworkServices/NAT/proxy.c
+++ b/src/VBox/NetworkServices/NAT/proxy.c
@@ -635,7 +635,7 @@ proxy_lwip_strerr(err_t error)
static char buf[32];
int e = -error;
- if (0 < e || e < (int)__arraycount(lwiperr)) {
+ if (0 <= e && e < (int)__arraycount(lwiperr)) {
return lwiperr[e];
}
else {
diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
index c533302..fe63353 100644
--- a/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
+++ b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
@@ -281,9 +281,9 @@ int netPfStrToPf(const char *pcszStrPortForward, int fIPv6, PPORTFORWARDRULE pPf
cbRaw--;
- if ( (( fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0)
- || (RTStrNICmp(pszRaw, "udp", 3) == 0))
- && (pszRaw[3] == PF_FIELD_SEPARATOR)))
+ if ( ( (fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0))
+ || RTStrNICmp(pszRaw, "udp", 3) == 0)
+ && pszRaw[3] == PF_FIELD_SEPARATOR)
{
proto = (fTcpProto ? IPPROTO_TCP : IPPROTO_UDP);
idxRaw = 3;
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk
index b015047..f6e234c 100644
--- a/src/VBox/Runtime/Makefile.kmk
+++ b/src/VBox/Runtime/Makefile.kmk
@@ -272,6 +272,7 @@ RuntimeR3_SOURCES = \
common/asn1/asn1-basics.cpp \
common/asn1/asn1-cursor.cpp \
common/asn1/asn1-default-allocator.cpp \
+ common/asn1/asn1-efence-allocator.cpp \
common/asn1/asn1-dump.cpp \
common/asn1/asn1-encode.cpp \
common/asn1/asn1-ut-bitstring.cpp \
@@ -581,6 +582,7 @@ RuntimeR3_SOURCES = \
generic/RTLogWriteStdErr-generic.cpp \
generic/RTLogWriteStdOut-generic.cpp \
generic/RTLogWriteUser-generic.cpp \
+ generic/RTPathGetCurrentDrive-generic.cpp \
generic/RTPathIsSame-generic.cpp \
generic/RTProcessQueryUsernameA-generic.cpp \
generic/RTTimerLRCreate-generic.cpp \
@@ -691,6 +693,7 @@ RuntimeR3_SOURCES.win = \
generic/RTFileExists-generic.cpp \
generic/RTMpGetCurFrequency-generic.cpp \
generic/RTMpGetMaxFrequency-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
generic/RTRandAdvCreateSystemFaster-generic.cpp \
generic/RTRandAdvCreateSystemTruer-generic.cpp \
generic/RTSemEventWait-generic.cpp \
@@ -758,6 +761,8 @@ RuntimeR3_SOURCES.linux = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTSemEventMultiWait-2-ex-generic.cpp \
generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
@@ -843,6 +848,8 @@ RuntimeR3_SOURCES.os2 = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTRandAdvCreateSystemFaster-generic.cpp \
generic/RTRandAdvCreateSystemTruer-generic.cpp \
@@ -915,6 +922,8 @@ RuntimeR3_SOURCES.darwin = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTThreadGetAffinity-stub-generic.cpp \
generic/RTThreadSetAffinity-stub-generic.cpp \
@@ -983,6 +992,8 @@ RuntimeR3_SOURCES.freebsd = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTSemEventMultiWait-2-ex-generic.cpp \
generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
generic/RTSystemQueryDmiString-generic.cpp \
@@ -1053,6 +1064,8 @@ RuntimeR3_SOURCES.solaris = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTProcIsRunningByName-generic.cpp \
generic/RTSemEventMultiWait-2-ex-generic.cpp \
@@ -1126,6 +1139,8 @@ RuntimeR3_SOURCES.haiku = \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
+ generic/RTPathAbs-generic.cpp \
+ generic/RTPathGetCurrentOnDrive-generic.cpp \
generic/RTProcDaemonize-generic.cpp \
generic/RTTimeLocalNow-generic.cpp \
generic/RTTimerCreate-generic.cpp \
diff --git a/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp b/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp
new file mode 100644
index 0000000..efdac71
--- /dev/null
+++ b/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp
@@ -0,0 +1,85 @@
+/* $Id: asn1-efence-allocator.cpp $ */
+/** @file
+ * IPRT - ASN.1, Electric Fense Allocator.
+ */
+
+/*
+ * Copyright (C) 2006-2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/asn1.h>
+
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnFree} */
+static DECLCALLBACK(void) rtAsn1EFenceAllocator_Free(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation, void *pv)
+{
+ RTMemEfFreeNP(pv);
+ pAllocation->cbAllocated = 0;
+}
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnAlloc} */
+static DECLCALLBACK(int) rtAsn1EFenceAllocator_Alloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation,
+ void **ppv, size_t cb)
+{
+ void *pv = RTMemEfAllocZNP(cb, RTMEM_TAG);
+ if (pv)
+ {
+ *ppv = pv;
+ pAllocation->cbAllocated = (uint32_t)cb;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnRealloc} */
+static DECLCALLBACK(int) rtAsn1EFenceAllocator_Realloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation,
+ void *pvOld, void **ppvNew, size_t cbNew)
+{
+ Assert(pvOld);
+ Assert(cbNew);
+ void *pv = RTMemEfReallocNP(pvOld, cbNew, RTMEM_TAG);
+ if (pv)
+ {
+ *ppvNew = pv;
+ pAllocation->cbAllocated = (uint32_t)cbNew;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+/** The Electric Fence ASN.1 allocator. */
+RT_DECL_DATA_CONST(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator =
+{
+ rtAsn1EFenceAllocator_Free,
+ rtAsn1EFenceAllocator_Alloc,
+ rtAsn1EFenceAllocator_Realloc
+};
+
diff --git a/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp b/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
index f11a8ba..dc0750a 100644
--- a/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
+++ b/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
@@ -1439,7 +1439,7 @@ RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *psz
iDiff = cch < cchString ? - 1 : 1;
break;
- /** @todo Implement compating ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
+ /** @todo Implement comparing ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
* ASN1_TAG_T61_STRING with UTF-8 strings without conversion. */
default:
@@ -1527,7 +1527,7 @@ RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size
{
char *pszDst = psz;
size_t cchSrc = pThis->Asn1Core.cb;
- uint8_t const *pbSrc = (uint8_t const *)psz;
+ uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
while (cchSrc > 0)
{
RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[3], pbSrc[2], pbSrc[1], pbSrc[0]); /* big endian */
@@ -1546,7 +1546,7 @@ RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size
{
char *pszDst = psz;
size_t cchSrc = pThis->Asn1Core.cb;
- uint8_t const *pbSrc = (uint8_t const *)psz;
+ uint8_t const *pbSrc = pThis->Asn1Core.uData.pu8;
while (cchSrc > 0)
{
RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[1], pbSrc[0], 0, 0); /* big endian */
diff --git a/src/VBox/Runtime/common/crypto/store-inmem.cpp b/src/VBox/Runtime/common/crypto/store-inmem.cpp
index 59015b1..53d0e15 100644
--- a/src/VBox/Runtime/common/crypto/store-inmem.cpp
+++ b/src/VBox/Runtime/common/crypto/store-inmem.cpp
@@ -31,6 +31,7 @@
#include "internal/iprt.h"
#include <iprt/crypto/store.h>
+#include <iprt/asm.h>
#include <iprt/err.h>
#include <iprt/mem.h>
#include <iprt/string.h>
@@ -253,8 +254,9 @@ static DECLCALLBACK(PCRTCRCERTCTX) rtCrStoreInMem_CertSearchNext(void *pvProvide
if (i < pThis->cCerts)
{
pSearch->auOpaque[1] = i + 1;
- pThis->papCerts[i]->Core.cRefs++;
- return &pThis->papCerts[i]->Core.Public;
+ PRTCRCERTCTXINT pCertCtx = &pThis->papCerts[i]->Core;
+ ASMAtomicIncU32(&pCertCtx->cRefs);
+ return &pCertCtx->Public;
}
return NULL;
}
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
index 6e11da2..1091465 100644
--- a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
@@ -2938,6 +2938,7 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
if ( pRet != NULL
&& uCurCode >= pThis->cCachedAbbrevsAlloced)
break;
+ uPrevCode = uCurCode;
}
}
else
diff --git a/src/VBox/Runtime/common/ldr/ldrMemory.cpp b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
index c402949..944b3a2 100644
--- a/src/VBox/Runtime/common/ldr/ldrMemory.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
@@ -314,7 +314,7 @@ RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH en
pReader->pfnDestroy(pReader);
}
else
- pfnDtor(pvUser),
+ pfnDtor(pvUser);
*phLdrMod = NIL_RTLDRMOD;
LogFlow(("RTLdrOpen: return %Rrc\n", rc));
diff --git a/src/VBox/Runtime/common/ldr/ldrPE.cpp b/src/VBox/Runtime/common/ldr/ldrPE.cpp
index e470136..c460d15 100644
--- a/src/VBox/Runtime/common/ldr/ldrPE.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrPE.cpp
@@ -1595,7 +1595,7 @@ static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDREN
if (SegInfo.cchName >= sizeof(pSh->Name))
{
memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
- szName[sizeof(sizeof(pSh->Name))] = '\0';
+ szName[sizeof(pSh->Name)] = '\0';
SegInfo.pszName = szName;
}
else if (SegInfo.cchName == 0)
diff --git a/src/VBox/Runtime/common/string/strformat.cpp b/src/VBox/Runtime/common/string/strformat.cpp
index 335d303..61fd186 100644
--- a/src/VBox/Runtime/common/string/strformat.cpp
+++ b/src/VBox/Runtime/common/string/strformat.cpp
@@ -181,7 +181,7 @@ static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, s
/*
* Validate and adjust input...
*/
- Assert(uiBase >= 2 || uiBase <= 16);
+ Assert(uiBase >= 2 && uiBase <= 16);
if (fFlags & RTSTR_F_CAPITAL)
pachDigits = "0123456789ABCDEF";
if (fFlags & RTSTR_F_LEFT)
diff --git a/src/VBox/Runtime/common/string/utf-16.cpp b/src/VBox/Runtime/common/string/utf-16.cpp
index 63c9931..d684bc9 100644
--- a/src/VBox/Runtime/common/string/utf-16.cpp
+++ b/src/VBox/Runtime/common/string/utf-16.cpp
@@ -99,6 +99,20 @@ static int rtUtf16Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcuc, size_t *pcwcA
}
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag)
+{
+ if (cb > sizeof(RTUTF16))
+ cb = RT_ALIGN_Z(cb, sizeof(RTUTF16));
+ else
+ cb = sizeof(RTUTF16);
+ PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag(cb, pszTag);
+ if (pwsz)
+ *pwsz = '\0';
+ return pwsz;
+}
+RT_EXPORT_SYMBOL(RTUtf16AllocTag);
+
+
RTDECL(void) RTUtf16Free(PRTUTF16 pwszString)
{
if (pwszString)
diff --git a/src/VBox/Runtime/common/time/time.cpp b/src/VBox/Runtime/common/time/time.cpp
index f16911a..c47caca 100644
--- a/src/VBox/Runtime/common/time/time.cpp
+++ b/src/VBox/Runtime/common/time/time.cpp
@@ -452,7 +452,7 @@ static PRTTIME rtTimeNormalizeInternal(PRTTIME pTime)
{
unsigned cDaysInMonth = fLeapYear
? g_acDaysInMonthsLeap[pTime->u8Month - 1]
- : g_acDaysInMonthsLeap[pTime->u8Month - 1];
+ : g_acDaysInMonths[pTime->u8Month - 1];
if (pTime->u8MonthDay <= cDaysInMonth)
break;
pTime->u8MonthDay -= cDaysInMonth;
diff --git a/src/VBox/Runtime/generic/RTPathAbs-generic.cpp b/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
new file mode 100644
index 0000000..72ea7bb
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
@@ -0,0 +1,358 @@
+/* $Id: RTPathAbs-generic.cpp $ */
+/** @file
+ * IPRT - RTPathAbs, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+#include "internal/fs.h"
+
+
+static char *rtPathSkipRootSpec(char *pszCur)
+{
+#ifdef HAVE_DRIVE
+ if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == RTPATH_SLASH)
+ pszCur += 3;
+# ifdef HAVE_UNC
+ else if (pszCur[0] == RTPATH_SLASH && pszCur[1] == RTPATH_SLASH)
+ {
+ pszCur += 2;
+ while (*pszCur == RTPATH_SLASH)
+ pszCur++;
+ if (*pszCur)
+ {
+ while (*pszCur != RTPATH_SLASH && *pszCur)
+ pszCur++;
+ if (*pszCur == RTPATH_SLASH)
+ {
+ pszCur++;
+ while (*pszCur != RTPATH_SLASH && *pszCur)
+ pszCur++;
+ if (*pszCur == RTPATH_SLASH)
+ pszCur++;
+ }
+ }
+ }
+# endif
+#else
+ if (pszCur[0] == RTPATH_SLASH)
+ pszCur += 1;
+#endif
+ return pszCur;
+}
+
+
+/**
+ * Cleans up a path specifier a little bit.
+ *
+ * This includes removing duplicate slashes, unnecessary single dots, and
+ * trailing slashes. Also, replaces all slash characters with RTPATH_SLASH.
+ *
+ * @returns Length of the cleaned path (in chars).
+ * @param pszPath The path to cleanup.
+ */
+static int fsCleanPath(char *pszPath)
+{
+ char *pszSrc = pszPath;
+ char *pszTrg = pszPath;
+
+ /*
+ * On windows, you either use on or two slashes at the head of a path,
+ * seems like it treats additional slashes as part of the UNC server name.
+ * Just change slashes to RTPATH_SLASH and skip them.
+ */
+ /** @todo check how OS/2 treats unnecessary leading slashes */
+ int cchIgnoreLeading = 0;
+#ifdef HAVE_UNC
+ if ( RTPATH_IS_SLASH(pszSrc[0])
+ && RTPATH_IS_SLASH(pszSrc[1]))
+ {
+ pszTrg[0] = RTPATH_SLASH;
+ pszTrg[1] = RTPATH_SLASH;
+ pszTrg += 2;
+ pszSrc += 2;
+ cchIgnoreLeading = 1;
+ while (RTPATH_IS_SLASH(*pszSrc))
+ {
+ cchIgnoreLeading++;
+ pszSrc++;
+ *pszTrg++ = RTPATH_SLASH;
+ }
+ }
+#endif
+
+ /*
+ * Change slashes to RTPATH_SLASH and remove duplicates.
+ */
+ for (;;)
+ {
+ char ch = *pszSrc++;
+ if (RTPATH_IS_SLASH(ch))
+ {
+ *pszTrg++ = RTPATH_SLASH;
+ for (;;)
+ {
+ do
+ ch = *pszSrc++;
+ while (RTPATH_IS_SLASH(ch));
+
+ /* Remove '/./' and '/.'. */
+ if ( ch != '.'
+ || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
+ break;
+ }
+ }
+ *pszTrg = ch;
+ if (!ch)
+ break;
+ pszTrg++;
+ }
+
+ return pszTrg - pszPath;
+}
+
+
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+{
+ int rc;
+
+ /*
+ * Validation.
+ */
+ AssertPtr(pszAbsPath);
+ AssertPtr(pszPath);
+ if (RT_UNLIKELY(!*pszPath))
+ return VERR_INVALID_PARAMETER; //VERR_INVALID_NAME;
+
+ /*
+ * Make a clean working copy of the input.
+ */
+ size_t cchPath = strlen(pszPath);
+ if (cchPath >= RTPATH_MAX)
+ {
+ LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
+ return VERR_FILENAME_TOO_LONG;
+ }
+
+ char szTmpPath[RTPATH_MAX];
+ memcpy(szTmpPath, pszPath, cchPath + 1);
+ size_t cchTmpPath = fsCleanPath(szTmpPath);
+
+ /*
+ * Handle "." specially (fsCleanPath does).
+ */
+ if (szTmpPath[0] == '.')
+ {
+ if ( cchTmpPath == 1
+ || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
+ {
+ rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cch = fsCleanPath(pszAbsPath);
+ char *pszTop = rtPathSkipRootSpec(pszAbsPath);
+#if 1
+ if ((uintptr_t)&pszAbsPath[cch] > (uintptr_t)pszTop && pszAbsPath[cch - 1] == RTPATH_SLASH)
+ pszAbsPath[cch - 1] = '\0';
+#else
+ if ( cchTmpPath == 2
+ && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
+ {
+ if (cch + 1 < cchAbsPath)
+ {
+ pszAbsPath[cch++] = RTPATH_SLASH;
+ pszAbsPath[cch] = '\0';
+ }
+ else
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+#endif
+ }
+ return rc;
+ }
+ }
+
+ /*
+ * Do we have an incomplete root spec? Supply the missing bits.
+ */
+#ifdef HAVE_DRIVE
+ if ( !(szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] == RTPATH_SLASH)
+# ifdef HAVE_UNC
+ && !(szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] == RTPATH_SLASH)
+# endif
+ )
+#else
+ if (szTmpPath[0] != RTPATH_SLASH)
+#endif
+ {
+ char szCurDir[RTPATH_MAX];
+ size_t cchCurDir;
+ int offApplyAt;
+ bool fNeedSlash;
+#ifdef HAVE_DRIVE
+ if (szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] != RTPATH_SLASH)
+ {
+ /*
+ * Relative to drive specific current directory.
+ */
+ rc = RTPathGetCurrentOnDrive(szTmpPath[0], szCurDir, sizeof(szCurDir));
+ fNeedSlash = true;
+ offApplyAt = 2;
+ }
+# ifdef HAVE_UNC
+ else if (szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] != RTPATH_SLASH)
+# else
+ else if (szTmpPath[0] == RTPATH_SLASH)
+# endif
+ {
+ /*
+ * Root of current drive. This may return a UNC root if we're not
+ * standing on a drive but on a UNC share.
+ */
+ rc = RTPathGetCurrentDrive(szCurDir, sizeof(szCurDir));
+ fNeedSlash = false;
+ offApplyAt = 0;
+ }
+ else
+#endif
+ {
+ /*
+ * Relative to current directory.
+ */
+ rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
+ fNeedSlash = true;
+ offApplyAt = 0;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ cchCurDir = fsCleanPath(szCurDir);
+ if (fNeedSlash && cchCurDir > 0 && szCurDir[cchCurDir - 1] == RTPATH_SLASH)
+ fNeedSlash = false;
+
+ if (cchCurDir + fNeedSlash + cchTmpPath - offApplyAt <= RTPATH_MAX)
+ {
+ memmove(szTmpPath + cchCurDir + fNeedSlash, szTmpPath + offApplyAt, cchTmpPath + 1 - offApplyAt);
+ memcpy(szTmpPath, szCurDir, cchCurDir);
+ if (fNeedSlash)
+ szTmpPath[cchCurDir] = RTPATH_SLASH;
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+ }
+ if (RT_FAILURE(rc))
+ {
+ LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
+ return rc;
+ }
+ }
+
+ /*
+ * Skip past the root spec.
+ */
+ char *pszCur = rtPathSkipRootSpec(szTmpPath);
+ AssertMsgReturn(pszCur != &szTmpPath[0], ("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
+ char * const pszTop = pszCur;
+
+ /*
+ * Get rid of double dot path components by evaluating them.
+ */
+ for (;;)
+ {
+ if ( pszCur[0] == '.'
+ && pszCur[1] == '.'
+ && (!pszCur[2] || pszCur[2] == RTPATH_SLASH))
+ {
+ /* rewind to the previous component if any */
+ char *pszPrev = pszCur;
+ if ((uintptr_t)pszPrev > (uintptr_t)pszTop)
+ {
+ pszPrev--;
+ while ( (uintptr_t)pszPrev > (uintptr_t)pszTop
+ && pszPrev[-1] != RTPATH_SLASH)
+ pszPrev--;
+ }
+ if (!pszCur[2])
+ {
+ if (pszPrev != pszTop)
+ pszPrev[-1] = '\0';
+ else
+ *pszPrev = '\0';
+ break;
+ }
+ Assert(pszPrev[-1] == RTPATH_SLASH);
+ memmove(pszPrev, pszCur + 3, strlen(pszCur + 3) + 1);
+ pszCur = pszPrev - 1;
+ }
+ else
+ {
+ /* advance to end of component. */
+ while (*pszCur && *pszCur != RTPATH_SLASH)
+ pszCur++;
+ }
+
+ if (!*pszCur)
+ break;
+
+ /* skip the slash */
+ ++pszCur;
+ }
+
+ cchTmpPath = pszCur - szTmpPath;
+
+#if 1
+ /*
+ * Strip trailing slash if that's what's desired.
+ */
+
+ if ((uintptr_t)&szTmpPath[cchTmpPath] > (uintptr_t)pszTop && szTmpPath[cchTmpPath - 1] == RTPATH_SLASH)
+ szTmpPath[--cchTmpPath] = '\0';
+#endif
+
+ /*
+ * Copy the result to the user buffer.
+ */
+ if (cchTmpPath < cchAbsPath)
+ {
+ memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_BUFFER_OVERFLOW;
+
+ LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
+ RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp b/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
new file mode 100644
index 0000000..f5706b2
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
@@ -0,0 +1,106 @@
+/* $Id: RTPathGetCurrentDrive-generic.cpp $ */
+/** @file
+ * IPRT - RTPathGetCurrentDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+ /*
+ * Query the current directroy and extract the wanted information from it.
+ */
+ int rc = RTPathGetCurrent(pszPath, cbPath);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Drive letter? Chop off at root slash.
+ */
+ if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
+ {
+ pszPath[2] = '\0';
+ return rc;
+ }
+
+ /*
+ * UNC? Chop off after share.
+ */
+ if ( RTPATH_IS_SLASH(pszPath[0])
+ && RTPATH_IS_SLASH(pszPath[1])
+ && !RTPATH_IS_SLASH(pszPath[2])
+ && pszPath[2])
+ {
+ /* Work thru the server name. */
+ size_t off = 3;
+ while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+ off++;
+ size_t offServerSlash = off;
+
+ /* Is there a share name? */
+ if (RTPATH_IS_SLASH(pszPath[off]))
+ {
+ while (RTPATH_IS_SLASH(pszPath[off]))
+ off++;
+ if (pszPath[off])
+ {
+ /* Work thru the share name. */
+ while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+ off++;
+ }
+ /* No share name, chop at server name. */
+ else
+ off = offServerSlash;
+ }
+ }
+ return VERR_INTERNAL_ERROR_4;
+ }
+ return rc;
+
+#else /* !HAVE_DRIVE */
+ /*
+ * No drive letters on this system, return empty string.
+ */
+ if (cbPath > 0)
+ {
+ *pszPath = '\0';
+ return VINF_SUCCESS;
+ }
+ return VERR_BUFFER_OVERFLOW;
+#endif /* !HAVE_DRIVE */
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentDrive);
+
diff --git a/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp b/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp
new file mode 100644
index 0000000..09a8eb2
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp
@@ -0,0 +1,84 @@
+/* $Id: RTPathGetCurrentOnDrive-generic.cpp $ */
+/** @file
+ * IPRT - RTPathGetCurrentOnDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+ /*
+ * Check if it's the same drive as the current directory.
+ */
+ int rc = RTPathGetCurrent(pszPath, cbPath);
+ if (RT_SUCCESS(rc))
+ {
+ if ( ( chDrive == *pszPath
+ || RT_C_TO_LOWER(chDrive) == RT_C_TO_LOWER(*pszPath))
+ && RTPATH_IS_VOLSEP(pszPath[1]))
+ return rc;
+
+ /*
+ * Different drive, indicate root.
+ */
+ if (cbPath >= 4)
+ {
+ pszPath[0] = RT_C_TO_UPPER(chDrive);
+ pszPath[1] = ':';
+ pszPath[2] = RTPATH_SLASH;
+ pszPath[3] = '\0';
+ return VINF_SUCCESS;
+ }
+ }
+ return rc;
+
+#else
+ /*
+ * No driver letters, just return root slash on whatever we're asked.
+ */
+ NOREF(chDrive);
+ if (cbPath >= 2)
+ {
+ pszPath[0] = RTPATH_SLASH;
+ pszPath[1] = '\0';
+ return VINF_SUCCESS;
+ }
+ return VERR_BUFFER_OVERFLOW;
+#endif
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentOnDrive);
+
diff --git a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
index dc1f7a8..7c6064a 100644
--- a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
@@ -164,7 +164,7 @@ static PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
pVmArea->nr_pages = 0; /* paranoia? */
pVmArea->pages = NULL; /* paranoia? */
- papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL);
+ papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL | __GFP_NOWARN);
if (!papPages)
{
vunmap(pVmArea->addr);
@@ -254,11 +254,11 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
# else /* !RTMEMALLOC_EXEC_HEAP */
# error "you don not want to go here..."
- pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
+ pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
# endif /* !RTMEMALLOC_EXEC_HEAP */
#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
- pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
+ pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
#else
pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
#endif
@@ -276,7 +276,8 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
{
fFlags |= RTMEMHDR_FLAG_KMALLOC;
pHdr = kmalloc(cb + sizeof(*pHdr),
- (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? GFP_ATOMIC : GFP_KERNEL);
+ (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? (GFP_ATOMIC | __GFP_NOWARN)
+ : (GFP_KERNEL | __GFP_NOWARN));
if (RT_UNLIKELY( !pHdr
&& cb > PAGE_SIZE
&& !(fFlags & RTMEMHDR_FLAG_ANY_CTX) ))
diff --git a/src/VBox/Runtime/r3/memsafer-r3.cpp b/src/VBox/Runtime/r3/memsafer-r3.cpp
index fc07a06..63b86dd 100644
--- a/src/VBox/Runtime/r3/memsafer-r3.cpp
+++ b/src/VBox/Runtime/r3/memsafer-r3.cpp
@@ -285,6 +285,15 @@ static int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
rtMemSaferInitializePages(pThis, pvPages);
/*
+ * On darwin we cannot allocate pages without an R0 mapping and
+ * SUPR3PageAllocEx falls back to another method which is incompatible with
+ * the way SUPR3PageProtect works. Ignore changing the protection of the guard
+ * pages.
+ */
+#ifdef RT_OS_DARWIN
+ return VINF_SUCCESS;
+#else
+ /*
* Configure the guard pages.
* SUPR3PageProtect isn't supported on all hosts, we ignore that.
*/
@@ -301,6 +310,7 @@ static int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
/* failed. */
int rc2 = SUPR3PageFreeEx(pvPages, pThis->cPages); AssertRC(rc2);
+#endif
}
return rc;
#else /* !IN_SUP_R3 */
diff --git a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
index f93f6e4..ea2d1e3 100644
--- a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
@@ -104,7 +104,7 @@ int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
bool fObjDir;
#endif
- rc = rtNtPathOpenDir(pszPathBuf,
+ rc = RTNtPathOpenDir(pszPathBuf,
FILE_READ_DATA | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
@@ -148,11 +148,11 @@ RTDECL(int) RTDirClose(PRTDIR pDir)
* Close the handle.
*/
pDir->u32Magic = ~RTDIR_MAGIC;
- if (pDir->hDir != MY_INVALID_HANDLE_VALUE)
+ if (pDir->hDir != RTNT_INVALID_HANDLE_VALUE)
{
- int rc = rtNtPathClose(pDir->hDir);
+ int rc = RTNtPathClose(pDir->hDir);
AssertRC(rc);
- pDir->hDir = MY_INVALID_HANDLE_VALUE;
+ pDir->hDir = RTNT_INVALID_HANDLE_VALUE;
}
RTStrFree(pDir->pszName);
pDir->pszName = NULL;
@@ -280,7 +280,7 @@ static int rtDirNtFetchMore(PRTDIR pThis)
* Read more.
*/
NTSTATUS rcNt;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
{
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
diff --git a/src/VBox/Runtime/r3/nt/fs-nt.cpp b/src/VBox/Runtime/r3/nt/fs-nt.cpp
index 314059d..e89b55b 100644
--- a/src/VBox/Runtime/r3/nt/fs-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/fs-nt.cpp
@@ -52,7 +52,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
* Open the file/dir/whatever.
*/
HANDLE hFile;
- int rc = rtNtPathOpen(pszFsPath,
+ int rc = RTNtPathOpen(pszFsPath,
GENERIC_READ,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -67,7 +67,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
* Get the volume information.
*/
FILE_FS_SIZE_INFORMATION FsSizeInfo;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsSizeInfo, sizeof(FsSizeInfo), FileFsSizeInformation);
if (NT_SUCCESS(rcNt))
{
@@ -107,7 +107,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
else
rc = RTErrConvertFromNtStatus(rcNt);
- rtNtPathClose(hFile);
+ RTNtPathClose(hFile);
}
return rc;
}
@@ -125,7 +125,7 @@ RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
* Open the file/dir/whatever.
*/
HANDLE hFile;
- int rc = rtNtPathOpen(pszFsPath,
+ int rc = RTNtPathOpen(pszFsPath,
GENERIC_READ,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -144,14 +144,14 @@ RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
FILE_FS_VOLUME_INFORMATION FsVolInfo;
uint8_t abBuf[sizeof(FILE_FS_VOLUME_INFORMATION) + 4096];
} u;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsVolumeInformation);
if (NT_SUCCESS(rcNt))
*pu32Serial = u.FsVolInfo.VolumeSerialNumber;
else
rc = RTErrConvertFromNtStatus(rcNt);
- rtNtPathClose(hFile);
+ RTNtPathClose(hFile);
}
return rc;
}
@@ -169,7 +169,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
* Open the file/dir/whatever.
*/
HANDLE hFile;
- int rc = rtNtPathOpen(pszFsPath,
+ int rc = RTNtPathOpen(pszFsPath,
GENERIC_READ,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -188,7 +188,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
} u;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
if (NT_SUCCESS(rcNt))
{
@@ -219,7 +219,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
else
rc = RTErrConvertFromNtStatus(rcNt);
- rtNtPathClose(hFile);
+ RTNtPathClose(hFile);
}
return rc;
}
@@ -239,7 +239,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
* Open the file/dir/whatever.
*/
HANDLE hFile;
- int rc = rtNtPathOpen(pszFsPath,
+ int rc = RTNtPathOpen(pszFsPath,
GENERIC_READ,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -258,7 +258,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
} u;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
if (NT_SUCCESS(rcNt))
{
@@ -277,7 +277,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
else
rc = RTErrConvertFromNtStatus(rcNt);
- rtNtPathClose(hFile);
+ RTNtPathClose(hFile);
}
return rc;
}
diff --git a/src/VBox/Runtime/r3/nt/internal-r3-nt.h b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
index 0a97096..f2d33ca 100644
--- a/src/VBox/Runtime/r3/nt/internal-r3-nt.h
+++ b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,38 +28,14 @@
#ifndef ___internal_r3_nt_h___
#define ___internal_r3_nt_h___
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <ntstatus.h>
-#ifdef IPRT_NT_USE_WINTERNL
-# define WIN32_NO_STATUS
-# include <windef.h>
-# include <winnt.h>
-# include <winternl.h>
-# define IPRT_NT_NEED_API_GROUP_1
-
-#elif defined(IPRT_NT_USE_WDM)
-# include <wdm.h>
-# define IPRT_NT_NEED_API_GROUP_1
-
+#ifdef IN_SUP_HARDENED_R3
+# include <iprt/nt/nt-and-windows.h>
#else
-# include <ntifs.h>
+# include <iprt/nt/nt.h>
#endif
#include "internal/iprt.h"
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
-/** Indicates that we're targetting native NT in the current source. */
-#define RT_USE_NATIVE_NT 1
-/** Initializes a IO_STATUS_BLOCK. */
-#define MY_IO_STATUS_BLOCK_INITIALIZER { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 }
-/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */
-#define MY_INVALID_HANDLE_VALUE ( (HANDLE)~(uintptr_t)0 )
-
#ifdef DEBUG_bird
/** Enables the "\\!\" NT path pass thru as well as hacks for listing NT object
* directories. */
@@ -67,17 +43,6 @@
#endif
-/*******************************************************************************
-* Internal Functions *
-*******************************************************************************/
-int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
- ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
- PHANDLE phHandle, PULONG_PTR puDisposition);
-int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
- ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
-int rtNtPathClose(HANDLE hHandle);
-
-
/**
* Internal helper for comparing a WCHAR string with a char string.
*
@@ -101,40 +66,5 @@ DECLINLINE(bool) rtNtCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const
return true;
}
-
-/*******************************************************************************
-* NT APIs *
-*******************************************************************************/
-
-RT_C_DECLS_BEGIN
-
-#ifdef IPRT_NT_NEED_API_GROUP_1
-
-typedef struct _FILE_FS_ATTRIBUTE_INFORMATION
-{
- ULONG FileSystemAttributes;
- LONG MaximumComponentNameLength;
- ULONG FileSystemNameLength;
- WCHAR FileSystemName[1];
-} FILE_FS_ATTRIBUTE_INFORMATION;
-typedef FILE_FS_ATTRIBUTE_INFORMATION *PFILE_FS_ATTRIBUTE_INFORMATION;
-extern "C" NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS);
-
-#endif
-
-NTSTATUS NTAPI NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
-
-typedef struct _OBJECT_DIRECTORY_INFORMATION
-{
- UNICODE_STRING Name;
- UNICODE_STRING TypeName;
-} OBJECT_DIRECTORY_INFORMATION;
-typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION;
-
-NTSTATUS NTAPI NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
-
-
-RT_C_DECLS_END
-
#endif
diff --git a/src/VBox/Runtime/r3/nt/pathint-nt.cpp b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
index a68f059..aedbc0d 100644
--- a/src/VBox/Runtime/r3/nt/pathint-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
@@ -37,16 +37,22 @@
#include <iprt/assert.h>
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+static char const g_szPrefixUnc[] = "\\??\\UNC\\";
+static char const g_szPrefix[] = "\\??\\";
+
/**
- * Handles the pass thru case.
+ * Handles the pass thru case for UTF-8 input.
*
* @returns IPRT status code.
* @param pNtName Where to return the NT name.
* @param phRootDir Where to return the root handle, if applicable.
* @param pszPath The UTF-8 path.
*/
-static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
{
PRTUTF16 pwszPath = NULL;
size_t cwcLen;
@@ -60,7 +66,8 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
pwszPath[2] = '\\';
pNtName->Buffer = pwszPath;
- pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+ pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+ pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
*phRootDir = NULL;
return VINF_SUCCESS;
}
@@ -73,6 +80,56 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
/**
+ * Handles the pass thru case for UTF-16 input.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name.
+ * @param phRootDir Stores NULL here, as we don't use it.
+ * @param pwszWinPath The UTF-16 windows-style path.
+ * @param cwcWinPath The length of the windows-style input path.
+ */
+static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
+ PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+ /* Drop a character because: \\?\ -> \.\ */
+ pwszWinPath++;
+ cwcWinPath--;
+
+ /* Check length and allocate memory for it. */
+ int rc;
+ if (cwcWinPath < _32K - 1)
+ {
+ PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+ if (pwszNtPath)
+ {
+ /* Intialize the path. */
+ pwszNtPath[0] = '\\';
+ pwszNtPath[1] = '.';
+ pwszNtPath[2] = '\\';
+ memcpy(pwszNtPath + 3, pwszWinPath + 3, (cwcWinPath - 3) * sizeof(RTUTF16));
+ pwszNtPath[cwcWinPath] = '\0';
+
+ /* Initialize the return values. */
+ pNtName->Buffer = pwszNtPath;
+ pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+ pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+ *phRootDir = NULL;
+
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_NO_UTF16_MEMORY;
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+ return rc;
+}
+
+
+
+
+
+/**
* Converts the path to UTF-16 and sets all the return values.
*
* @returns IPRT status code.
@@ -80,7 +137,7 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
* @param phRootDir Where to return the root handle, if applicable.
* @param pszPath The UTF-8 path.
*/
-static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathUtf8ToUniStr(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
{
PRTUTF16 pwszPath = NULL;
size_t cwcLen;
@@ -90,7 +147,8 @@ static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRo
if (cwcLen < _32K - 1)
{
pNtName->Buffer = pwszPath;
- pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+ pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+ pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
*phRootDir = NULL;
return VINF_SUCCESS;
}
@@ -112,14 +170,11 @@ static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRo
*/
static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
{
- static char const s_szPrefixUnc[] = "\\??\\UNC\\";
- static char const s_szPrefix[] = "\\??\\";
-
/*
* Very simple conversion of a win32-like path into an NT path.
*/
- const char *pszPrefix = s_szPrefix;
- size_t cchPrefix = sizeof(s_szPrefix) - 1;
+ const char *pszPrefix = g_szPrefix;
+ size_t cchPrefix = sizeof(g_szPrefix) - 1;
size_t cchSkip = 0;
if ( RTPATH_IS_SLASH(pszPath[0])
@@ -129,13 +184,13 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
{
if ( pszPath[2] == '?'
&& RTPATH_IS_SLASH(pszPath[3]))
- return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
+ return rtNtPathFromWinUtf8PassThru(pNtName, phRootDir, pszPath);
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
/* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
if ( pszPath[2] == '!'
&& RTPATH_IS_SLASH(pszPath[3]))
- return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
+ return rtNtPathUtf8ToUniStr(pNtName, phRootDir, pszPath + 3);
#endif
if ( pszPath[2] == '.'
@@ -150,8 +205,8 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
else
{
/* UNC */
- pszPrefix = s_szPrefixUnc;
- cchPrefix = sizeof(s_szPrefixUnc) - 1;
+ pszPrefix = g_szPrefixUnc;
+ cchPrefix = sizeof(g_szPrefixUnc) - 1;
cchSkip = 2;
}
}
@@ -168,7 +223,119 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
* Add prefix and convert it to UTF16.
*/
memcpy(szPath, pszPrefix, cchPrefix);
- return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
+ return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
+}
+
+
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param pNtName Where to return the NT name. Free using
+ * RTNtPathFree.
+ * @param phRootDir Where to return the root handle, if applicable.
+ * @param pwszWinPath The UTF-16 windows-style path.
+ * @param cwcWinPath The max length of the windows-style path in
+ * RTUTF16 units. Use RTSTR_MAX if unknown and @a
+ * pwszWinPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+ /*
+ * Validate the input, calculating the correct length.
+ */
+ if (cwcWinPath == 0 || *pwszWinPath == '\0')
+ return VERR_INVALID_NAME;
+
+ RTUtf16NLenEx(pwszWinPath, cwcWinPath, &cwcWinPath);
+ int rc = RTUtf16ValidateEncodingEx(pwszWinPath, cwcWinPath, 0);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Very simple conversion of a win32-like path into an NT path.
+ */
+ const char *pszPrefix = g_szPrefix;
+ size_t cchPrefix = sizeof(g_szPrefix) - 1;
+ size_t cchSkip = 0;
+
+ if ( RTPATH_IS_SLASH(pwszWinPath[0])
+ && cwcWinPath >= 3
+ && RTPATH_IS_SLASH(pwszWinPath[1])
+ && !RTPATH_IS_SLASH(pwszWinPath[2]) )
+ {
+ if ( pwszWinPath[2] == '?'
+ && cwcWinPath >= 4
+ && RTPATH_IS_SLASH(pwszWinPath[3]))
+ return rtNtPathFromWinUtf16PassThru(pNtName, phRootDir, pwszWinPath, cwcWinPath);
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+ /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
+ if ( pwszWinPath[2] == '!'
+ && cwcWinPath >= 4
+ && RTPATH_IS_SLASH(pwszWinPath[3]))
+ {
+ pwszWinPath += 3;
+ cwcWinPath -= 3;
+ if (cwcWinPath < _32K - 1)
+ {
+ PRTUTF16 pwszNtPath = RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+ if (pwszNtPath)
+ {
+ memcpy(pwszNtPath, pwszWinPath, cwcWinPath * sizeof(RTUTF16));
+ pwszNtPath[cwcWinPath] = '\0';
+ pNtName->Buffer = pwszNtPath;
+ pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+ pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+ *phRootDir = NULL;
+ return VINF_SUCCESS;
+ }
+ rc = VERR_NO_UTF16_MEMORY;
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+ return rc;
+ }
+#endif
+
+ if ( pwszWinPath[2] == '.'
+ && cwcWinPath >= 4
+ && RTPATH_IS_SLASH(pwszWinPath[3]))
+ {
+ /*
+ * Device path.
+ * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
+ */
+ cchSkip = 4;
+ }
+ else
+ {
+ /* UNC */
+ pszPrefix = g_szPrefixUnc;
+ cchPrefix = sizeof(g_szPrefixUnc) - 1;
+ cchSkip = 2;
+ }
+ }
+
+ /*
+ * Straighten out all .. and unnecessary . references and convert slashes.
+ */
+ char szAbsPath[RTPATH_MAX];
+ char szRelPath[RTPATH_MAX];
+ char *pszRelPath = szRelPath;
+ size_t cchRelPath;
+ rc = RTUtf16ToUtf8Ex(pwszWinPath, cwcWinPath, &pszRelPath, sizeof(szRelPath), &cchRelPath);
+ if (RT_SUCCESS(rc))
+ rc = RTPathAbs(szRelPath, &szAbsPath[cchPrefix - cchSkip], sizeof(szAbsPath) - (cchPrefix - cchSkip));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add prefix and convert it to UTF16.
+ */
+ memcpy(szAbsPath, pszPrefix, cchPrefix);
+ return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szAbsPath);
+ }
+ return rc;
}
@@ -180,7 +347,7 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
* @param phRootDir The root handle variable after a
* rtNtPathToNative.
*/
-void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
+static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
{
RTUtf16Free(pNtName->Buffer);
pNtName->Buffer = NULL;
@@ -188,6 +355,20 @@ void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
/**
+ * Frees the native path and root handle.
+ *
+ * @param pNtName The NT path after a successful
+ * RTNtPathFromWinUtf16Ex call.
+ * @param phRootDir The root handle variable after a successfull
+ * RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
+{
+ rtNtPathFreeNative(pNtName, phRootDir);
+}
+
+
+/**
* Wrapper around NtCreateFile.
*
* @returns IPRT status code.
@@ -202,19 +383,19 @@ void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
* @param phHandle Where to return the handle.
* @param puAction Where to return the action taken. Optional.
*/
-int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
- ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
- PHANDLE phHandle, PULONG_PTR puAction)
+RTDECL(int) RTNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+ ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+ PHANDLE phHandle, PULONG_PTR puAction)
{
- *phHandle = MY_INVALID_HANDLE_VALUE;
+ *phHandle = RTNT_INVALID_HANDLE_VALUE;
HANDLE hRootDir;
UNICODE_STRING NtName;
int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
if (RT_SUCCESS(rc))
{
- HANDLE hFile = MY_INVALID_HANDLE_VALUE;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
@@ -262,18 +443,18 @@ int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAt
* @c false if we opened an directory file (normal
* directory).
*/
-int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
- ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
+RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
+ ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
{
- *phHandle = MY_INVALID_HANDLE_VALUE;
+ *phHandle = RTNT_INVALID_HANDLE_VALUE;
HANDLE hRootDir;
UNICODE_STRING NtName;
int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
if (RT_SUCCESS(rc))
{
- HANDLE hFile = MY_INVALID_HANDLE_VALUE;
- IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
+ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
@@ -346,7 +527,7 @@ int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fSha
* @returns IPRT status code
* @param hHandle The handle value.
*/
-int rtNtPathClose(HANDLE hHandle)
+RTDECL(int) RTNtPathClose(HANDLE hHandle)
{
NTSTATUS rcNt = NtClose(hHandle);
if (NT_SUCCESS(rcNt))
diff --git a/src/VBox/Runtime/r3/posix/path-posix.cpp b/src/VBox/Runtime/r3/posix/path-posix.cpp
index 2b7adf9..6467d07 100644
--- a/src/VBox/Runtime/r3/posix/path-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/path-posix.cpp
@@ -79,224 +79,6 @@ RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPat
}
-/**
- * Cleans up a path specifier a little bit.
- * This includes removing duplicate slashes, unnecessary single dots, and
- * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
- *
- * @returns Number of bytes in the clean path.
- * @param pszPath The path to cleanup.
- */
-static int fsCleanPath(char *pszPath)
-{
- /*
- * Change to '/' and remove duplicates.
- */
- char *pszSrc = pszPath;
- char *pszTrg = pszPath;
-#ifdef HAVE_UNC
- int fUnc = 0;
- if ( RTPATH_IS_SLASH(pszPath[0])
- && RTPATH_IS_SLASH(pszPath[1]))
- { /* Skip first slash in a unc path. */
- pszSrc++;
- *pszTrg++ = '/';
- fUnc = 1;
- }
-#endif
-
- for (;;)
- {
- char ch = *pszSrc++;
- if (RTPATH_IS_SLASH(ch))
- {
- *pszTrg++ = '/';
- for (;;)
- {
- do ch = *pszSrc++;
- while (RTPATH_IS_SLASH(ch));
-
- /* Remove '/./' and '/.'. */
- if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
- break;
- }
- }
- *pszTrg = ch;
- if (!ch)
- break;
- pszTrg++;
- }
-
- /*
- * Remove trailing slash if the path may be pointing to a directory.
- */
- int cch = pszTrg - pszPath;
- if ( cch > 1
- && RTPATH_IS_SLASH(pszTrg[-1])
-#ifdef HAVE_DRIVE
- && !RTPATH_IS_VOLSEP(pszTrg[-2])
-#endif
- && !RTPATH_IS_SLASH(pszTrg[-2]))
- pszPath[--cch] = '\0';
-
- return cch;
-}
-
-
-RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
-{
- int rc;
-
- /*
- * Validation.
- */
- AssertPtr(pszAbsPath);
- AssertPtr(pszPath);
- if (RT_UNLIKELY(!*pszPath))
- return VERR_INVALID_PARAMETER;
-
- /*
- * Make a clean working copy of the input.
- */
- size_t cchPath = strlen(pszPath);
- if (cchPath > PATH_MAX)
- {
- LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
- return VERR_FILENAME_TOO_LONG;
- }
-
- char szTmpPath[PATH_MAX + 1];
- memcpy(szTmpPath, pszPath, cchPath + 1);
- size_t cchTmpPath = fsCleanPath(szTmpPath);
-
- /*
- * Handle "." specially (fsCleanPath does).
- */
- if (szTmpPath[0] == '.' && !szTmpPath[1])
- return RTPathGetCurrent(pszAbsPath, cchAbsPath);
-
- /*
- * Do we have a root slash?
- */
- char *pszCur = szTmpPath;
-#ifdef HAVE_DRIVE
- if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
- pszCur += 3;
-# ifdef HAVE_UNC
- else if (pszCur[0] == '/' && pszCur[1] == '/')
- pszCur += 2;
-# endif
-#else /* !HAVE_DRIVE */
- if (pszCur[0] == '/')
- pszCur += 1;
-#endif /* !HAVE_DRIVE */
- else
- {
- /*
- * No, prepend the current directory to the relative path.
- */
- char szCurDir[RTPATH_MAX];
- rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
- AssertRCReturn(rc, rc);
-
- size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
- if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
- {
- LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
- return VERR_FILENAME_TOO_LONG;
- }
-
- memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
- memcpy(szTmpPath, szCurDir, cchCurDir);
- szTmpPath[cchCurDir] = '/';
-
-
-#ifdef HAVE_DRIVE
- if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
- pszCur += 3;
-# ifdef HAVE_UNC
- else if (pszCur[0] == '/' && pszCur[1] == '/')
- pszCur += 2;
-# endif
-#else
- if (pszCur[0] == '/')
- pszCur += 1;
-#endif
- else
- AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
- }
-
- char *pszTop = pszCur;
-
- /*
- * Get rid of double dot path components by evaluating them.
- */
- for (;;)
- {
- if ( pszCur[0] == '.'
- && pszCur[1] == '.'
- && (!pszCur[2] || pszCur[2] == '/'))
- {
- /* rewind to the previous component if any */
- char *pszPrev = pszCur - 1;
- if (pszPrev > pszTop)
- while (*--pszPrev != '/')
- ;
-
- AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
- memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
-
- pszCur = pszPrev;
- }
- else
- {
- /* advance to end of component. */
- while (*pszCur && *pszCur != '/')
- pszCur++;
- }
-
- if (!*pszCur)
- break;
-
- /* skip the slash */
- ++pszCur;
- }
-
- if (pszCur < pszTop)
- {
- /*
- * We overwrote the root slash with '\0', restore it.
- */
- *pszCur++ = '/';
- *pszCur = '\0';
- }
- else if (pszCur > pszTop && pszCur[-1] == '/')
- {
- /*
- * Extra trailing slash in a non-root path, remove it.
- * (A bit questionable...)
- */
- *--pszCur = '\0';
- }
-
- /*
- * Copy the result to the user buffer.
- */
- cchTmpPath = pszCur - szTmpPath;
- if (cchTmpPath < cchAbsPath)
- {
- memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_BUFFER_OVERFLOW;
-
- LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
- RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
- return rc;
-}
-
-
RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode)
{
AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
index 0a08ea9..4a2503a 100644
--- a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
@@ -216,6 +216,7 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
case kRTWinOSType_7: strcpy(szTmp, "Windows 7"); break;
case kRTWinOSType_8: strcpy(szTmp, "Windows 8"); break;
case kRTWinOSType_81: strcpy(szTmp, "Windows 8.1"); break;
+ case kRTWinOSType_10: strcpy(szTmp, "Windows 10"); break;
case kRTWinOSType_NT_UNKNOWN:
RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u",
diff --git a/src/VBox/Runtime/r3/win/init-win.cpp b/src/VBox/Runtime/r3/win/init-win.cpp
index 0f00d9b..f58a45f 100644
--- a/src/VBox/Runtime/r3/win/init-win.cpp
+++ b/src/VBox/Runtime/r3/win/init-win.cpp
@@ -160,6 +160,9 @@ static RTWINOSTYPE rtR3InitWinSimplifiedVersion(OSVERSIONINFOEXW const *pOSInfoE
else if ( dwMajorVersion == 6
&& dwMinorVersion == 3)
enmVer = kRTWinOSType_81;
+ else if ( dwMajorVersion == 6
+ && dwMinorVersion == 4)
+ enmVer = kRTWinOSType_10;
else
enmVer = kRTWinOSType_NT_UNKNOWN;
}
diff --git a/src/VBox/Runtime/r3/win/internal-r3-win.h b/src/VBox/Runtime/r3/win/internal-r3-win.h
index fdbd932..cc73b58 100644
--- a/src/VBox/Runtime/r3/win/internal-r3-win.h
+++ b/src/VBox/Runtime/r3/win/internal-r3-win.h
@@ -40,6 +40,7 @@ typedef enum RTWINOSTYPE
kRTWinOSType_7,
kRTWinOSType_8,
kRTWinOSType_81,
+ kRTWinOSType_10,
kRTWinOSType_NT_UNKNOWN = 199,
kRTWinOSType_NT_LAST = kRTWinOSType_UNKNOWN
} RTWINOSTYPE;
diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
index 1f6c654..dc78228 100644
--- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
+++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
@@ -32,9 +32,12 @@ EXPORTS
CsrClientCallServer ;;= _CsrClientCallServer at 16
NtAllocateVirtualMemory ;;= _NtAllocateVirtualMemory at 24
+ NtClearEvent ;;= _NtClearEvent at 4
NtClose ;;= _NtClose at 4
+ NtCreateEvent ;;= _NtCreateEvent at 20
NtCreateFile ;;= _NtCreateFile at 44
NtCreateSection ;;= _NtCreateSection at 28
+ NtCreateSymbolicLinkObject ;;= _NtCreateSymbolicLinkObject at 16
NtDelayExecution ;;= _NtDelayExecution at 8
NtDeviceIoControlFile ;;= _NtDeviceIoControlFile at 40
NtDuplicateObject ;;= _NtDuplicateObject at 28
@@ -42,29 +45,36 @@ EXPORTS
NtGetContextThread ;;= _NtGetContextThread at 8
NtMapViewOfSection ;;= _NtMapViewOfSection at 40
NtOpenDirectoryObject ;;= _NtOpenDirectoryObject at 12
+ NtOpenEvent ;;= _NtOpenEvent at 12
NtOpenKey ;;= _NtOpenKey at 12
NtOpenProcess ;;= _NtOpenProcess at 16
NtOpenProcessToken ;;= _NtOpenProcessToken at 12
+ NtOpenSymbolicLinkObject ;;= _NtOpenSymbolicLinkObject at 12
NtOpenThread ;;= _NtOpenThread at 16
NtOpenThreadToken ;;= _NtOpenThreadToken at 16
NtProtectVirtualMemory ;;= _NtProtectVirtualMemory at 20
NtQueryDirectoryFile ;;= _NtQueryDirectoryFile at 44
NtQueryDirectoryObject ;;= _NtQueryDirectoryObject at 28
+ NtQueryEvent ;;= _NtQueryEvent at 20
NtQueryInformationFile ;;= _NtQueryInformationFile at 20
NtQueryInformationProcess ;;= _NtQueryInformationProcess at 20
NtQueryInformationThread ;;= _NtQueryInformationThread at 20
NtQueryInformationToken ;;= _NtQueryInformationToken at 20
NtQueryObject ;;= _NtQueryObject at 20
NtQuerySecurityObject ;;= _NtQuerySecurityObject at 20
+ NtQuerySymbolicLinkObject ;;= _NtQuerySymbolicLinkObject at 12
+ NtQuerySystemInformation ;;= _NtQuerySystemInformation at 16
NtQueryTimerResolution ;;= _NtQueryTimerResolution at 12
NtQueryValueKey ;;= _NtQueryValueKey at 24
NtQueryVirtualMemory ;;= _NtQueryVirtualMemory at 24
NtQueryVolumeInformationFile ;;= _NtQueryVolumeInformationFile at 20
NtReadFile ;;= _NtReadFile at 36
NtReadVirtualMemory ;;= _NtReadVirtualMemory at 20
+ NtResetEvent ;;= _NtResetEvent at 8
NtResumeProcess ;;= _NtResumeProcess at 4
NtResumeThread ;;= _NtResumeThread at 8
NtSetContextThread ;;= _NtSetContextThread at 8
+ NtSetEvent ;;= _NtSetEvent at 8
NtSetInformationFile ;;= _NtSetInformationFile at 20
NtSetInformationObject ;;= _NtSetInformationObject at 16
NtSetInformationProcess ;;= _NtSetInformationProcess at 16
@@ -75,18 +85,22 @@ EXPORTS
NtTerminateProcess ;;= _NtTerminateProcess at 8
NtTerminateThread ;;= _NtTerminateThread at 8
NtUnmapViewOfSection ;;= _NtUnmapViewOfSection at 8
- NtWaitForSingleObject ;;= _NtWaitForSingleObject at 12
NtWaitForMultipleObjects ;;= _NtWaitForMultipleObjects at 20
+ NtWaitForSingleObject ;;= _NtWaitForSingleObject at 12
NtWriteFile ;;= _NtWriteFile at 36
NtWriteVirtualMemory ;;= _NtWriteVirtualMemory at 20
NtYieldExecution ;;= _NtYieldExecution at 0
LdrInitializeThunk ;;= _LdrInitializeThunk at 12
+ LdrRegisterDllNotification ;;= _LdrRegisterDllNotification at 16
RtlAddAccessAllowedAce ;;= _RtlAddAccessAllowedAce at 16
RtlAddAccessDeniedAce ;;= _RtlAddAccessDeniedAce at 16
+ RtlAllocateHeap ;;= _RtlAllocateHeap at 12
+ RtlCompactHeap ;;= _RtlCompactHeap at 8
RtlCopySid ;;= _RtlCopySid at 12
RtlCreateAcl ;;= _RtlCreateAcl at 12
+ RtlCreateHeap ;;= _RtlCreateHeap at 24
RtlCreateProcessParameters ;;= _RtlCreateProcessParameters at 40
RtlCreateSecurityDescriptor ;;= _RtlCreateSecurityDescriptor at 8
RtlCreateUserProcess ;;= _RtlCreateUserProcess at 40
@@ -94,12 +108,21 @@ EXPORTS
RtlDestroyProcessParameters ;;= _RtlDestroyProcessParameters at 4
RtlDosApplyFileIsolationRedirection_Ustr ;;= _RtlDosApplyFileIsolationRedirection_Ustr at 36
RtlEqualSid ;;= _RtlEqualSid at 8
+ RtlExitUserProcess ;;= _RtlExitUserProcess at 4
+ RtlExitUserThread ;;= _RtlExitUserThread at 4
RtlExpandEnvironmentStrings_U ;;= _RtlExpandEnvironmentStrings_U at 16
+ RtlFreeHeap ;;= _RtlFreeHeap at 12
RtlFreeUnicodeString ;;= _RtlFreeUnicodeString at 4
+ RtlGetLastNtStatus ;;= _RtlGetLastNtStatus at 0
+ RtlGetLastWin32Error ;;= _RtlGetLastWin32Error at 0
RtlGetVersion ;;= _RtlGetVersion at 4
RtlInitializeSid ;;= _RtlInitializeSid at 12
RtlNtStatusToDosError ;;= _RtlNtStatusToDosError at 4
+ RtlReAllocateHeap ;;= _RtlReAllocateHeap at 16
+ RtlRestoreLastWin32Error ;;= _RtlRestoreLastWin32Error at 4
RtlSetDaclSecurityDescriptor ;;= _RtlSetDaclSecurityDescriptor at 16
+ RtlSetLastWin32Error ;;= _RtlSetLastWin32Error at 4
+ RtlSetLastWin32ErrorAndNtStatusFromNtStatus ;;= _RtlSetLastWin32ErrorAndNtStatusFromNtStatus at 4
+ RtlSizeHeap ;;= _RtlSizeHeap at 12
RtlSubAuthoritySid ;;= _RtlSubAuthoritySid at 8
-
diff --git a/src/VBox/Runtime/r3/win/path-win.cpp b/src/VBox/Runtime/r3/win/path-win.cpp
index 0245b77..7d5b055 100644
--- a/src/VBox/Runtime/r3/win/path-win.cpp
+++ b/src/VBox/Runtime/r3/win/path-win.cpp
@@ -88,7 +88,7 @@ RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPat
return rc;
}
-
+#if 0
/**
* Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
*
@@ -124,6 +124,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
rc = RTUtf16ToUtf8Ex(&wsz[0], RTSTR_MAX, &pszAbsPath, cchAbsPath, &cch);
if (RT_SUCCESS(rc))
{
+# if 1 /** @todo This code is completely bonkers. */
/*
* Remove trailing slash if the path may be pointing to a directory.
* (See posix variant.)
@@ -133,6 +134,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
&& !RTPATH_IS_VOLSEP(pszAbsPath[cch - 2])
&& !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
pszAbsPath[cch - 1] = '\0';
+# endif
}
}
else if (rc <= 0)
@@ -143,6 +145,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
RTUtf16Free(pwszPath);
return rc;
}
+#endif
/**
@@ -683,3 +686,20 @@ RTDECL(int) RTPathSetCurrent(const char *pszPath)
return rc;
}
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+ WCHAR wszInput[4];
+ wszInput[0] = chDrive;
+ wszInput[1] = ':';
+ wszInput[2] = '\0';
+
+ int rc;
+ RTUTF16 wszFullPath[RTPATH_MAX];
+ if (GetFullPathNameW(wszInput, RTPATH_MAX, wszFullPath, NULL))
+ rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
+ else
+ rc = RTErrConvertFromWin32(GetLastError());
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTPath.cpp b/src/VBox/Runtime/testcase/tstRTPath.cpp
index 131466a..5986708 100644
--- a/src/VBox/Runtime/testcase/tstRTPath.cpp
+++ b/src/VBox/Runtime/testcase/tstRTPath.cpp
@@ -314,7 +314,7 @@ int main()
{ "C:\\MustDie", "\\from_root/dir/..", VINF_SUCCESS, "C:\\from_root" },
{ "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" },
{ NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ },
- { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server" },
+ { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" },
{ NULL, "\\\\", VINF_SUCCESS, "\\\\" },
{ NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ },
{ "\\\\server\\share_as_base", "/from_root", VINF_SUCCESS, "\\\\server\\from_root" },
diff --git a/src/VBox/Storage/VHD.cpp b/src/VBox/Storage/VHD.cpp
index 229498b..1f9db9f 100644
--- a/src/VBox/Storage/VHD.cpp
+++ b/src/VBox/Storage/VHD.cpp
@@ -2694,7 +2694,7 @@ static int vhdResize(void *pBackendData, uint64_t cbSize,
{
if (pImage->pBlockAllocationTable[idxBlock] != ~0U)
{
- uint64_t offStartBlock = pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE;
+ uint64_t offStartBlock = (uint64_t)pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE;
if (offStartBlock < offStartDataOld)
offStartDataOld = offStartBlock;
cBlocksAllocated++;
diff --git a/src/VBox/Storage/testcase/BuiltinTests.h b/src/VBox/Storage/testcase/BuiltinTests.h
new file mode 100644
index 0000000..072ff41
--- /dev/null
+++ b/src/VBox/Storage/testcase/BuiltinTests.h
@@ -0,0 +1,41 @@
+/** @file
+ *
+ * tstVDIo testing utility - builtin tests.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#ifndef _BuiltinTests_h__
+#define _BuiltinTests_h__
+
+/**
+ * Builtin Tests (in generated BuiltinTests.cpp)
+ */
+typedef struct TSTVDIOTESTENTRY
+{
+ /** Pointer to the raw bytes. */
+ const unsigned char *pch;
+ /** Number of bytes. */
+ unsigned cb;
+} TSTVDIOTESTENTRY;
+/** Pointer to a trust anchor table entry. */
+typedef TSTVDIOTESTENTRY const *PCTSTVDIOTESTENTRY;
+
+/** Macro for simplifying generating the trust anchor tables. */
+#define TSTVDIOTESTENTRY_GEN(a_abTest) { &a_abTest[0], sizeof(a_abTest) }
+
+/** All tests we know. */
+extern TSTVDIOTESTENTRY const g_aVDIoTests[];
+/** Number of entries in g_aVDIoTests. */
+extern unsigned const g_cVDIoTests;
+
+#endif /* _BuiltinTests_h__ */
diff --git a/src/VBox/Storage/testcase/Makefile.kmk b/src/VBox/Storage/testcase/Makefile.kmk
index 9d44e45..5098ee5 100644
--- a/src/VBox/Storage/testcase/Makefile.kmk
+++ b/src/VBox/Storage/testcase/Makefile.kmk
@@ -47,21 +47,71 @@ ifdef VBOX_WITH_TESTCASES
tstVDCopy_SOURCES = tstVDCopy.cpp
tstVDCopy_LIBS = $(LIB_DDU)
- ifn1of ($(KBUILD_TARGET),win)
- PROGRAMS += tstVDIo
-
- tstVDIo_TEMPLATE = VBOXR3TSTEXE
- tstVDIo_SOURCES = tstVDIo.cpp \
- VDIoBackend.cpp \
- VDIoBackendMem.cpp \
- VDMemDisk.cpp \
- VDIoRnd.cpp \
- VDScript.cpp \
- VDScriptAst.cpp \
- VDScriptChecker.cpp \
- VDScriptInterp.cpp
- tstVDIo_LIBS = \
- $(LIB_DDU) \
+ PROGRAMS += tstVDIo
+
+ #
+ # VD I/O test scripts to built in -> .cpp
+ #
+ TSTVDIO_BUILTIN_TESTS_FILE = $(tstVDIo_0_OUTDIR)/BuiltinTests.cpp
+ TSTVDIO_BUILTIN_TESTS := \
+ tstVDIo=tstVDIo.vd \
+ tstVDResize=tstVDResize.vd \
+ tstVDCompact=tstVDCompact.vd \
+ tstVDCopy=tstVDCopy.vd \
+ tstVDDiscard=tstVDDiscard.vd \
+ tstVDShareable=tstVDShareable.vd
+ TSTVDIO_BUILTIN_TEST_NAMES := $(foreach test,$(TSTVDIO_BUILTIN_TESTS),$(firstword $(subst =,$(SPACE) ,$(test))))
+ TSTVDIO_PATH_TESTS := $(PATH_SUB_CURRENT)
+
+ # 1=name, 2=filter
+ TSTVDIO_GEN_TEST_MACRO = 'TSTVDIOTESTENTRY const g_a$(1)[] =' '{' \
+ $(foreach testnm,$(filter $(2),$(TSTVDIO_BUILTIN_TEST_NAMES)), ' TSTVDIOTESTENTRY_GEN(g_ab$(testnm)),') \
+ '};' 'unsigned const g_c$(1) = RT_ELEMENTS(g_a$(1));' '' ''
+
+ $$(TSTVDIO_BUILTIN_TESTS_FILE): $(MAKEFILE_CURRENT) \
+ $(foreach test,$(TSTVDIO_BUILTIN_TESTS),$(TSTVDIO_PATH_TESTS)/$(lastword $(subst =,$(SPACE) ,$(test)))) \
+ $(VBOX_BIN2C) \
+ | $$(dir $$@)
+ $(QUIET)$(RM) -f -- $@ $@.vd
+ $(QUIET)$(APPEND) -n "$@" \
+ '' \
+ '#include "BuiltinTests.h"' \
+ ''
+ $(foreach test,$(TSTVDIO_BUILTIN_TESTS), $(NLTAB)$(VBOX_BIN2C) -ascii --append \
+ "$(firstword $(subst =,$(SP) ,$(test)))" \
+ "$(TSTVDIO_PATH_TESTS)/$(lastword $(subst =,$(SP) ,$(test)))" \
+ "$@")
+
+# Generate test lists.
+ $(QUIET)$(APPEND) -n "$@" '' \
+ $(call TSTVDIO_GEN_TEST_MACRO,VDIoTests,%) \
+
+ ifn1of ($(KBUILD_TARGET), win)
+ VBOX_TSTVDIO_WITH_LOG_REPLAY = 1
+ endif
+
+ tstVDIo_TEMPLATE = VBOXR3TSTEXE
+ tstVDIo_INCS := $(PATH_SUB_CURRENT)
+
+ ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+ tstVDIo_DEFS += VBOX_TSTVDIO_WITH_LOG_REPLAY
+ endif
+
+ tstVDIo_SOURCES = tstVDIo.cpp \
+ VDIoBackend.cpp \
+ VDIoBackendMem.cpp \
+ VDMemDisk.cpp \
+ VDIoRnd.cpp \
+ VDScript.cpp \
+ VDScriptAst.cpp \
+ VDScriptChecker.cpp \
+ VDScriptInterp.cpp \
+ $(TSTVDIO_BUILTIN_TESTS_FILE)
+ tstVDIo_LIBS = \
+ $(LIB_DDU)
+
+ ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+ tstVDIo_LIBS += \
$(PATH_STAGE_LIB)/StorageDbgLib$(VBOX_SUFF_LIB)
endif
diff --git a/src/VBox/Storage/testcase/VDMemDisk.cpp b/src/VBox/Storage/testcase/VDMemDisk.cpp
index a921250..e953657 100644
--- a/src/VBox/Storage/testcase/VDMemDisk.cpp
+++ b/src/VBox/Storage/testcase/VDMemDisk.cpp
@@ -89,6 +89,7 @@ void VDMemDiskDestroy(PVDMEMDISK pMemDisk)
AssertPtrReturnVoid(pMemDisk);
RTAvlrU64Destroy(pMemDisk->pTreeSegments, vdMemDiskDestroy, NULL);
+ RTMemFree(pMemDisk->pTreeSegments);
RTMemFree(pMemDisk);
}
diff --git a/src/VBox/Storage/testcase/VDScript.cpp b/src/VBox/Storage/testcase/VDScript.cpp
index 6378631..9b6ef83 100644
--- a/src/VBox/Storage/testcase/VDScript.cpp
+++ b/src/VBox/Storage/testcase/VDScript.cpp
@@ -88,15 +88,24 @@ typedef enum VDSCRIPTTOKENKEYWORD
{
VDSCRIPTTOKENKEYWORD_INVALID = 0,
VDSCRIPTTOKENKEYWORD_CONTINUE,
+ VDSCRIPTTOKENKEYWORD_REGISTER,
+ VDSCRIPTTOKENKEYWORD_RESTRICT,
+ VDSCRIPTTOKENKEYWORD_VOLATILE,
+ VDSCRIPTTOKENKEYWORD_TYPEDEF,
VDSCRIPTTOKENKEYWORD_DEFAULT,
+ VDSCRIPTTOKENKEYWORD_EXTERN,
+ VDSCRIPTTOKENKEYWORD_STATIC,
VDSCRIPTTOKENKEYWORD_RETURN,
VDSCRIPTTOKENKEYWORD_SWITCH,
+ VDSCRIPTTOKENKEYWORD_STRUCT,
VDSCRIPTTOKENKEYWORD_WHILE,
VDSCRIPTTOKENKEYWORD_BREAK,
+ VDSCRIPTTOKENKEYWORD_CONST,
VDSCRIPTTOKENKEYWORD_FALSE,
VDSCRIPTTOKENKEYWORD_TRUE,
VDSCRIPTTOKENKEYWORD_ELSE,
VDSCRIPTTOKENKEYWORD_CASE,
+ VDSCRIPTTOKENKEYWORD_AUTO,
VDSCRIPTTOKENKEYWORD_FOR,
VDSCRIPTTOKENKEYWORD_IF,
VDSCRIPTTOKENKEYWORD_DO,
@@ -219,6 +228,7 @@ static VDSCRIPTOP g_aScriptOps[] =
{"!=", 2},
{">=", 2},
{"<=", 2},
+ {"->", 2},
{"=", 1},
{"+", 1},
{"-", 1},
@@ -231,7 +241,8 @@ static VDSCRIPTOP g_aScriptOps[] =
{"<", 1},
{">", 1},
{"!", 1},
- {"~", 1}
+ {"~", 1},
+ {".", 1}
};
/**
@@ -268,15 +279,24 @@ typedef VDSCRIPTKEYWORD *PVDSCRIPTKEYWORD;
static VDSCRIPTKEYWORD g_aKeywords[] =
{
{"continue", 8, VDSCRIPTTOKENKEYWORD_CONTINUE},
+ {"register", 8, VDSCRIPTTOKENKEYWORD_REGISTER},
+ {"restrict", 8, VDSCRIPTTOKENKEYWORD_RESTRICT},
+ {"voaltile", 8, VDSCRIPTTOKENKEYWORD_VOLATILE},
+ {"typedef", 7, VDSCRIPTTOKENKEYWORD_TYPEDEF},
{"default", 7, VDSCRIPTTOKENKEYWORD_DEFAULT},
+ {"extern", 6, VDSCRIPTTOKENKEYWORD_EXTERN},
+ {"static", 6, VDSCRIPTTOKENKEYWORD_STATIC},
{"return", 6, VDSCRIPTTOKENKEYWORD_RETURN},
{"switch", 6, VDSCRIPTTOKENKEYWORD_SWITCH},
+ {"struct", 6, VDSCRIPTTOKENKEYWORD_STRUCT},
{"while", 5, VDSCRIPTTOKENKEYWORD_WHILE},
{"break", 5, VDSCRIPTTOKENKEYWORD_BREAK},
+ {"const", 5, VDSCRIPTTOKENKEYWORD_CONST},
{"false", 5, VDSCRIPTTOKENKEYWORD_FALSE},
{"true", 4, VDSCRIPTTOKENKEYWORD_TRUE},
{"else", 4, VDSCRIPTTOKENKEYWORD_ELSE},
{"case", 4, VDSCRIPTTOKENKEYWORD_CASE},
+ {"auto", 4, VDSCRIPTTOKENKEYWORD_AUTO},
{"for", 3, VDSCRIPTTOKENKEYWORD_FOR},
{"if", 2, VDSCRIPTTOKENKEYWORD_IF},
{"do", 2, VDSCRIPTTOKENKEYWORD_DO}
@@ -286,6 +306,8 @@ static int vdScriptParseCompoundStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTM
static int vdScriptParseStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeStmt);
static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
+static int vdScriptParseCastExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
+static int vdScriptParseConstExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
/**
* Returns whether the tokenizer reached the end of the stream.
@@ -521,6 +543,11 @@ static void vdScriptTokenizerGetNumberConst(PVDTOKENIZER pTokenizer, PVDSCRIPTTO
pToken->Class.NumConst.u64 *= _1G;
vdScriptTokenizerSkipCh(pTokenizer);
}
+ else if (vdScriptTokenizerGetCh(pTokenizer) == 'T')
+ {
+ pToken->Class.NumConst.u64 *= _1T;
+ vdScriptTokenizerSkipCh(pTokenizer);
+ }
}
/**
@@ -1031,6 +1058,11 @@ static int vdScriptParseFnCallArgumentList(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEX
* postfix-expression ( argument-expression )
* postfix-expression ++
* postfix-expression --
+ * postfix-expression . identifier
+ * postfix-expression -> identifier
+ * @note: Not supported so far are:
+ * ( type-name ) { initializer-list }
+ * ( type-name ) { initializer-list , }
*/
static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
{
@@ -1070,6 +1102,46 @@ static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXP
else
rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
}
+ else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "->"))
+ {
+ pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+ if (pExprNew)
+ {
+ PVDSCRIPTASTIDE pIde = NULL;
+ rc = vdScriptParseIde(pThis, &pIde);
+ if (RT_SUCCESS(rc))
+ {
+ pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE;
+ pExprNew->Deref.pIde = pIde;
+ pExprNew->Deref.pExpr = pExpr;
+ pExpr = pExprNew;
+ }
+ else
+ vdScriptAstNodeFree(&pExprNew->Core);
+ }
+ else
+ rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+ }
+ else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "."))
+ {
+ pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+ if (pExprNew)
+ {
+ PVDSCRIPTASTIDE pIde = NULL;
+ rc = vdScriptParseIde(pThis, &pIde);
+ if (RT_SUCCESS(rc))
+ {
+ pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DOT;
+ pExprNew->Deref.pIde = pIde;
+ pExprNew->Deref.pExpr = pExpr;
+ pExpr = pExprNew;
+ }
+ else
+ vdScriptAstNodeFree(&pExprNew->Core);
+ }
+ else
+ rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+ }
else if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
{
pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
@@ -1114,10 +1186,12 @@ static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXP
* postfix-expression
* ++ unary-expression
* -- unary-expression
- * + unary-expression
- * - unary-expression
- * ~ unary-expression
- * ! unary-expression
+ * + cast-expression
+ * - cast-expression
+ * ~ cast-expression
+ * ! cast-expression
+ * & cast-expression
+ * * cast-expression
*/
static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
{
@@ -1127,58 +1201,69 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
+ /** @todo: Think about a more beautiful way of parsing this. */
while (true)
{
bool fQuit = false;
+ bool fCastExprFollows = false;
PVDSCRIPTASTEXPR pExprNew = NULL;
+ VDSCRIPTEXPRTYPE enmType = VDSCRIPTEXPRTYPE_INVALID;
if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
- {
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
- }
+ enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
- {
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
- }
+ enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
{
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+ enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
+ fCastExprFollows = true;
}
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
{
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+ enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
+ fCastExprFollows = true;
}
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "~"))
{
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+ enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
+ fCastExprFollows = true;
}
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!"))
{
+ enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
+ fCastExprFollows = true;
+ }
+ else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&"))
+ {
+ enmType = VDSCRIPTEXPRTYPE_UNARY_REFERENCE;
+ fCastExprFollows = true;
+ }
+ else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
+ {
+ enmType = VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE;
+ fCastExprFollows = true;
+ }
+
+ if (enmType != VDSCRIPTEXPRTYPE_INVALID)
+ {
pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
+ pExprNew->enmType = enmType;
else
rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+
+ if ( RT_SUCCESS(rc)
+ && fCastExprFollows)
+ {
+ PVDSCRIPTASTEXPR pCastExpr = NULL;
+
+ rc = vdScriptParseCastExpression(pThis, &pCastExpr);
+ if (RT_SUCCESS(rc))
+ pExprNew->pExpr = pCastExpr;
+ else
+ vdScriptAstNodeFree(&pExprNew->Core);
+ fQuit = true;
+ }
}
else
{
@@ -1216,6 +1301,168 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
}
/**
+ * Parse a storage class specifier.
+ *
+ * @returns nothing.
+ * @param pThis The script context.
+ * @param penmStorageClass Where to return the parsed storage classe.
+ * Contains VDSCRIPTASTSTORAGECLASS_INVALID if no
+ * valid storage class specifier was found.
+ *
+ * @note Syntax:
+ * typedef
+ * extern
+ * static
+ * auto
+ * register
+ */
+static void vdScriptParseStorageClassSpecifier(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTORAGECLASS penmStorageClass)
+{
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_INVALID;
+
+ if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_TYPEDEF))
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_TYPEDEF;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_EXTERN))
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_EXTERN;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_STATIC))
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_STATIC;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_AUTO))
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_AUTO;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_REGISTER))
+ *penmStorageClass = VDSCRIPTASTSTORAGECLASS_REGISTER;
+}
+
+/**
+ * Parse a type qualifier.
+ *
+ * @returns nothing.
+ * @param pThis The script context.
+ * @param penmTypeQualifier Where to return the parsed type qualifier.
+ * Contains VDSCRIPTASTTYPEQUALIFIER_INVALID if no
+ * valid type qualifier was found.
+ *
+ * @note Syntax:
+ * const
+ * restrict
+ * volatile
+ */
+static void vdScriptParseTypeQualifier(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTTYPEQUALIFIER penmTypeQualifier)
+{
+ *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_INVALID;
+
+ if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_CONST))
+ *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_CONST;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_RESTRICT))
+ *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_RESTRICT;
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_VOLATILE))
+ *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_VOLATILE;
+}
+
+#if 0
+/**
+ * Parse a struct or union specifier.
+ *
+ * @returns VBox status code.
+ * @param pThis The script context.
+ * @param ppAstTypeSpec Where to store the type specifier AST node on success.
+ * @param enmTypeSpecifier The type specifier to identify whete this is a struct or a union.
+ */
+static int vdScriptParseStructOrUnionSpecifier(PVDSCRIPTCTXINT pThis, , enmTypeSpecifier)
+{
+ int rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+/**
+ * Parse a type specifier.
+ *
+ * @returns VBox status code.
+ * @param pThis The script context.
+ * @param ppAstTypeSpec Where to store the type specifier AST node on success.
+ *
+ * @note Syntax:
+ * struct-or-union-specifier
+ * enum-specifier
+ * typedef-name (identifier: includes void, bool, uint8_t, int8_t, ... for basic integer types)
+ */
+static int vdScriptParseTypeSpecifier(PVDSCRIPTCTXINT pThis, )
+{
+ int rc = VINF_SUCCESS;
+
+ if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_STRUCT))
+ rc = vdScriptParseStructOrUnionSpecifier(pThis, , VDSCRIPTASTTYPESPECIFIER_STRUCT);
+ else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_UNION))
+ rc = vdScriptParseStructOrUnionSpecifier(pThis, , VDSCRIPTASTTYPESPECIFIER_UNION);
+ else
+ {
+ PVDSCRIPTASTIDE pIde = NULL;
+
+ rc = vdScriptParseIde(pThis, &pIde);
+ if (RT_SUCCESS(rc))
+ {
+ AssertMsgFailed(("TODO\n")); /* Parse identifier. */
+ }
+ }
+
+ return rc;
+}
+#endif
+
+/**
+ * Parse a cast expression.
+ *
+ * @returns VBox status code.
+ * @param pThis The script context.
+ * @param ppAstNodeExpr Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ * cast-expression:
+ * unary-expression
+ * ( type-name ) cast-expression
+ */
+static int vdScriptParseCastExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+ int rc = VINF_SUCCESS;
+ PVDSCRIPTASTEXPR pExpr = NULL;
+
+ LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
+
+#if 0
+ if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
+ {
+ PVDSCRIPTASTTYPE pTypeName = NULL;
+ rc = vdScriptParseTypeName(pThis, &pTypeName);
+ if ( RT_SUCCESS(rc)
+ && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
+ {
+ PVDSCRIPTASTEXPR pExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+ if (pExpr)
+ {
+ pExpr->enmType = VDSCRIPTEXPRTYPE_CAST;
+ rc = vdScriptParseCastExpression(pThis, &pExpr->Cast.pExpr); /** @todo: Kill recursion. */
+ if (RT_SUCCESS(rc))
+ pExpr->Cast.pTypeName = pTypeName;
+ else
+ vdScriptAstNodeFree(&pExpr->Core);
+ }
+ else
+ rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+
+ if (RT_FAILURE(rc))
+ vdScriptAstNodeFree(&pTypeName->Core);
+ }
+ else if (RT_SUCCESS(rc))
+ rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
+ }
+ else
+#endif
+ rc = vdScriptParseUnaryExpression(pThis, ppAstNodeExpr);
+
+ return rc;
+}
+
+/**
* Parse a multiplicative expression.
*
* @returns VBox status code.
@@ -1224,10 +1471,10 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
*
* @note Syntax:
* multiplicative-expression:
- * unary-expression
- * multiplicative-expression * unary-expression
- * multiplicative-expression / unary-expression
- * multiplicative-expression % unary-expression
+ * cast-expression
+ * multiplicative-expression * cast-expression
+ * multiplicative-expression / cast-expression
+ * multiplicative-expression % cast-expression
*/
static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
{
@@ -1236,42 +1483,35 @@ static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIP
LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
- rc = vdScriptParseUnaryExpression(pThis, &pExpr);
+ rc = vdScriptParseCastExpression(pThis, &pExpr);
if (RT_SUCCESS(rc))
{
- PVDSCRIPTASTEXPR pExprNew = NULL;
while (RT_SUCCESS(rc))
{
+ VDSCRIPTEXPRTYPE enmType = VDSCRIPTEXPRTYPE_INVALID;
+ PVDSCRIPTASTEXPR pExprNew = NULL;
+
if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
- {
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
- }
+ enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/"))
- {
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_DIVISION;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
- }
+ enmType = VDSCRIPTEXPRTYPE_DIVISION;
else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%"))
- {
- pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
- if (pExprNew)
- pExprNew->enmType = VDSCRIPTEXPRTYPE_MODULUS;
- else
- rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
- }
+ enmType = VDSCRIPTEXPRTYPE_MODULUS;
+ else
+ break;
+
+ pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+ if (pExprNew)
+ pExprNew->enmType = enmType;
else
+ {
+ rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
break;
+ }
pExprNew->BinaryOp.pLeftExpr = pExpr;
pExpr = pExprNew;
- rc = vdScriptParseUnaryExpression(pThis, &pExprNew);
+ rc = vdScriptParseCastExpression(pThis, &pExprNew);
if (RT_SUCCESS(rc))
pExpr->BinaryOp.pRightExpr = pExprNew;
}
@@ -1818,6 +2058,22 @@ static int vdScriptParseCondExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *
}
/**
+ * Parse a constant expression.
+ *
+ * @returns VBox status code.
+ * @param pThis The script context.
+ * @param ppAstNodeExpr Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ * constant-expression:
+ * conditional-expression
+ */
+static int vdScriptParseConstExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+ return vdScriptParseCondExpression(pThis, ppAstNodeExpr);
+}
+
+/**
* Parse an assignment expression.
*
* @returns VBox status code.
@@ -2644,7 +2900,16 @@ DECLHIDDEN(void) VDScriptCtxDestroy(VDSCRIPTCTX hScriptCtx)
RTStrSpaceDestroy(&pThis->hStrSpaceFn, vdScriptCtxDestroyFnSpace, NULL);
- /** @todo: Go through the list and destroy all ASTs. */
+ /* Go through list of function ASTs and destroy them. */
+ PVDSCRIPTASTCORE pIter;
+ PVDSCRIPTASTCORE pIterNext;
+ RTListForEachSafe(&pThis->ListAst, pIter, pIterNext, VDSCRIPTASTCORE, ListNode)
+ {
+ RTListNodeRemove(&pIter->ListNode);
+ RTListInit(&pIter->ListNode);
+ vdScriptAstNodeFree(pIter);
+ }
+
RTMemFree(pThis);
}
diff --git a/src/VBox/Storage/testcase/VDScript.h b/src/VBox/Storage/testcase/VDScript.h
index f1731df..93d6455 100644
--- a/src/VBox/Storage/testcase/VDScript.h
+++ b/src/VBox/Storage/testcase/VDScript.h
@@ -42,6 +42,7 @@ typedef enum VDSCRIPTTYPE
VDSCRIPTTYPE_INT64,
VDSCRIPTTYPE_STRING,
VDSCRIPTTYPE_BOOL,
+ VDSCRIPTTYPE_POINTER,
/** As usual, the 32bit blowup hack. */
VDSCRIPTTYPE_32BIT_HACK = 0x7fffffff
} VDSCRIPTTYPE;
@@ -70,6 +71,7 @@ typedef struct VDSCRIPTARG
int64_t i64;
const char *psz;
bool f;
+ void *p;
};
} VDSCRIPTARG;
/** Pointer to an argument. */
@@ -102,6 +104,43 @@ typedef VDSCRIPTCALLBACK *PVDSCRIPTCALLBACK;
typedef const VDSCRIPTCALLBACK *PCVDSCRIPTCALLBACK;
/**
+ * @{
+ */
+/** The address space stays assigned to a variable
+ * even if the pointer is casted to another type.
+ */
+#define VDSCRIPT_AS_FLAGS_TRANSITIVE RT_BIT(0)
+/** @} */
+
+/**
+ * Address space read callback
+ *
+ * @returns VBox status code.
+ * @param pvUser Opaque user data given on registration.
+ * @param Address The address to read from, address is stored in the member for
+ * base type given on registration.
+ * @param pvBuf Where to store the read bits.
+ * @param cbRead How much to read.
+ */
+typedef DECLCALLBACK(int) FNVDSCRIPTASREAD(void *pvUser, VDSCRIPTARG Address, void *pvBuf, size_t cbRead);
+/** Pointer to a read callback. */
+typedef FNVDSCRIPTASREAD *PFNVDSCRIPTASREAD;
+
+/**
+ * Address space write callback
+ *
+ * @returns VBox status code.
+ * @param pvUser Opaque user data given on registration.
+ * @param Address The address to write to, address is stored in the member for
+ * base type given on registration.
+ * @param pvBuf Data to write.
+ * @param cbWrite How much to write.
+ */
+typedef DECLCALLBACK(int) FNVDSCRIPTASWRITE(void *pvUser, VDSCRIPTARG Address, const void *pvBuf, size_t cbWrite);
+/** Pointer to a write callback. */
+typedef FNVDSCRIPTASWRITE *PFNVDSCRIPTASWRITE;
+
+/**
* Create a new scripting context.
*
* @returns VBox status code.
@@ -150,4 +189,34 @@ DECLHIDDEN(int) VDScriptCtxLoadScript(VDSCRIPTCTX hScriptCtx, const char *pszScr
DECLHIDDEN(int) VDScriptCtxCallFn(VDSCRIPTCTX hScriptCtx, const char *pszFnCall,
PVDSCRIPTARG paArgs, unsigned cArgs);
+/**
+ * Registers a new address space provider.
+ *
+ * @returns VBox status code.
+ * @param hScriptCtx The script context handle.
+ * @param pszType The type string.
+ * @param enmBaseType The base integer type to use for the address space.
+ * Bool and String are not supported of course.
+ * @param pfnRead The read callback for the registered address space.
+ * @param pfnWrite The write callback for the registered address space.
+ * @param pvUser Opaque user data to pass to the read and write callbacks.
+ * @param fFlags Flags, see VDSCRIPT_AS_FLAGS_*.
+ *
+ * @note This will automatically register a new type with the identifier given in pszType
+ * used for the pointer. Every variable with this type is automatically treated as a pointer.
+ *
+ * @note If the transitive flag is set the address space stays assigned even if the pointer value
+ * is casted to another pointer type.
+ * In the following example the pointer pStruct will use the registered address space for RTGCPHYS
+ * and dereferencing the pointer causes the read/write callbacks to be triggered.
+ *
+ * ...
+ * Struct *pStruct = (Struct *)(RTGCPHYS)0x12345678;
+ * pStruct->count++;
+ * ...
+ */
+DECLHIDDEN(int) VDScriptCtxAsRegister(VDSCRIPTCTX hScriptCtx, const char *pszType, VDSCRIPTTYPE enmBaseType,
+ PFNVDSCRIPTASREAD pfnRead, PFNVDSCRIPTASWRITE pfnWrite, void *pvUser,
+ uint32_t fFlags);
+
#endif /* _VDScript_h__ */
diff --git a/src/VBox/Storage/testcase/VDScriptAst.cpp b/src/VBox/Storage/testcase/VDScriptAst.cpp
index 8b3d001..b7774c9 100644
--- a/src/VBox/Storage/testcase/VDScriptAst.cpp
+++ b/src/VBox/Storage/testcase/VDScriptAst.cpp
@@ -72,6 +72,13 @@ static void vdScriptAstNodeExpressionPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIP
}
break;
}
+ case VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE:
+ case VDSCRIPTEXPRTYPE_POSTFIX_DOT:
+ {
+ RTListAppend(pList, &pExpr->Deref.pIde->Core.ListNode);
+ RTListAppend(pList, &pExpr->Deref.pExpr->Core.ListNode);
+ break;
+ }
case VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT:
case VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT:
case VDSCRIPTEXPRTYPE_UNARY_INCREMENT:
@@ -80,6 +87,8 @@ static void vdScriptAstNodeExpressionPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIP
case VDSCRIPTEXPRTYPE_UNARY_NEGSIGN:
case VDSCRIPTEXPRTYPE_UNARY_INVERT:
case VDSCRIPTEXPRTYPE_UNARY_NEGATE:
+ case VDSCRIPTEXPRTYPE_UNARY_REFERENCE:
+ case VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE:
{
RTListAppend(pList, &pExpr->pExpr->Core.ListNode);
break;
@@ -153,7 +162,7 @@ static void vdScriptAstNodeStatmentPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIPTA
/* Put all statements on the to free list. */
while (!RTListIsEmpty(&pStmt->Compound.ListStmts))
{
- PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListDecls, VDSCRIPTASTCORE, ListNode);
+ PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListStmts, VDSCRIPTASTCORE, ListNode);
RTListNodeRemove(&pNode->ListNode);
RTListAppend(pList, &pNode->ListNode);
}
@@ -272,7 +281,11 @@ DECLHIDDEN(void) vdScriptAstNodeFree(PVDSCRIPTASTCORE pAstNode)
case VDSCRIPTASTCLASS_IDENTIFIER:
break;
case VDSCRIPTASTCLASS_DECLARATION:
+ case VDSCRIPTASTCLASS_TYPENAME:
+ {
+ AssertMsgFailed(("TODO\n"));
break;
+ }
case VDSCRIPTASTCLASS_STATEMENT:
{
vdScriptAstNodeStatmentPutOnFreeList(&ListFree, pAstNode);
@@ -314,6 +327,9 @@ DECLHIDDEN(PVDSCRIPTASTCORE) vdScriptAstNodeAlloc(VDSCRIPTASTCLASS enmClass)
case VDSCRIPTASTCLASS_EXPRESSION:
cbAlloc = sizeof(VDSCRIPTASTEXPR);
break;
+ case VDSCRIPTASTCLASS_TYPENAME:
+ cbAlloc = sizeof(VDSCRIPTASTTYPENAME);
+ break;
case VDSCRIPTASTCLASS_IDENTIFIER:
case VDSCRIPTASTCLASS_INVALID:
default:
diff --git a/src/VBox/Storage/testcase/VDScriptAst.h b/src/VBox/Storage/testcase/VDScriptAst.h
index 3f32409..ae6b1ef 100644
--- a/src/VBox/Storage/testcase/VDScriptAst.h
+++ b/src/VBox/Storage/testcase/VDScriptAst.h
@@ -53,6 +53,10 @@ typedef enum VDSCRIPTASTCLASS
VDSCRIPTASTCLASS_STATEMENT,
/** Expression node. */
VDSCRIPTASTCLASS_EXPRESSION,
+ /** Type name node. */
+ VDSCRIPTASTCLASS_TYPENAME,
+ /** Type specifier node. */
+ VDSCRIPTASTCLASS_TYPESPECIFIER,
/** 32bit blowup. */
VDSCRIPTASTCLASS_32BIT_HACK = 0x7fffffff
} VDSCRIPTASTCLASS;
@@ -95,6 +99,105 @@ typedef struct VDSCRIPTASTIDE
typedef VDSCRIPTASTIDE *PVDSCRIPTASTIDE;
/**
+ * Type specifier.
+ */
+typedef enum VDSCRIPTASTTYPESPECIFIER
+{
+ /** Invalid type specifier. */
+ VDSCRIPTASTTYPESPECIFIER_INVALID = 0,
+ /** Union type specifier. */
+ VDSCRIPTASTTYPESPECIFIER_UNION,
+ /** Struct type specifier. */
+ VDSCRIPTASTTYPESPECIFIER_STRUCT,
+ /** Identifier of a typedefed type. */
+ VDSCRIPTASTTYPESPECIFIER_IDE,
+ /** 32bit hack. */
+ VDSCRIPTASTTYPESPECIFIER_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTTYPESPECIFIER;
+/** Pointer to a typespecifier. */
+typedef VDSCRIPTASTTYPESPECIFIER *PVDSCRIPTASTTYPESPECIFIER;
+
+/**
+ * AST type specifier.
+ */
+typedef struct VDSCRIPTASTTYPESPEC
+{
+ /** Core structure. */
+ VDSCRIPTASTCORE Core;
+ /** Specifier type. */
+ VDSCRIPTASTTYPESPECIFIER enmType;
+ /** Type dependent data .*/
+ union
+ {
+ /** Pointer to an identifier for typedefed types. */
+ PVDSCRIPTASTIDE pIde;
+ /** struct or union specifier. */
+ struct
+ {
+ /** Pointer to the identifier, optional. */
+ PVDSCRIPTASTIDE pIde;
+ /** Declaration list - VDSCRIPTAST. */
+ RTLISTANCHOR ListDecl;
+ } StructUnion;
+ };
+} VDSCRIPTASTTYPESPEC;
+/** Pointer to an AST type specifier. */
+typedef VDSCRIPTASTTYPESPEC *PVDSCRIPTASTTYPESPEC;
+
+/**
+ * Storage clase specifier.
+ */
+typedef enum VDSCRIPTASTSTORAGECLASS
+{
+ /** Invalid storage class sepcifier. */
+ VDSCRIPTASTSTORAGECLASS_INVALID = 0,
+ /** A typedef type. */
+ VDSCRIPTASTSTORAGECLASS_TYPEDEF,
+ /** An external declared object. */
+ VDSCRIPTASTSTORAGECLASS_EXTERN,
+ /** A static declared object. */
+ VDSCRIPTASTSTORAGECLASS_STATIC,
+ /** Auto object. */
+ VDSCRIPTASTSTORAGECLASS_AUTO,
+ /** Object should be stored in a register. */
+ VDSCRIPTASTSTORAGECLASS_REGISTER,
+ /** 32bit hack. */
+ VDSCRIPTASTSTORAGECLASS_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTSTORAGECLASS;
+/** Pointer to a storage class. */
+typedef VDSCRIPTASTSTORAGECLASS *PVDSCRIPTASTSTORAGECLASS;
+
+/**
+ * Type qualifier.
+ */
+typedef enum VDSCRIPTASTTYPEQUALIFIER
+{
+ /** Invalid type qualifier. */
+ VDSCRIPTASTTYPEQUALIFIER_INVALID = 0,
+ /** Const type qualifier. */
+ VDSCRIPTASTTYPEQUALIFIER_CONST,
+ /** Restrict type qualifier. */
+ VDSCRIPTASTTYPEQUALIFIER_RESTRICT,
+ /** Volatile type qualifier. */
+ VDSCRIPTASTTYPEQUALIFIER_VOLATILE,
+ /** 32bit hack. */
+ VDSCRIPTASTTYPEQUALIFIER_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTTYPEQUALIFIER;
+/** Pointer to a type qualifier. */
+typedef VDSCRIPTASTTYPEQUALIFIER *PVDSCRIPTASTTYPEQUALIFIER;
+
+/**
+ * AST type name node.
+ */
+typedef struct VDSCRIPTASTTYPENAME
+{
+ /** Core structure. */
+ VDSCRIPTASTCORE Core;
+} VDSCRIPTASTTYPENAME;
+/** Pointer to a type name node. */
+typedef VDSCRIPTASTTYPENAME *PVDSCRIPTASTTYPENAME;
+
+/**
* AST declaration node.
*/
typedef struct VDSCRIPTASTDECL
@@ -129,6 +232,10 @@ typedef enum VDSCRIPTEXPRTYPE
VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT,
/** Postfix function call expression. */
VDSCRIPTEXPRTYPE_POSTFIX_FNCALL,
+ /** Postfix dereference expression. */
+ VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE,
+ /** Dot operator (@todo: Is there a better name for it?). */
+ VDSCRIPTEXPRTYPE_POSTFIX_DOT,
/** Unary increment expression. */
VDSCRIPTEXPRTYPE_UNARY_INCREMENT,
/** Unary decrement expression. */
@@ -141,6 +248,12 @@ typedef enum VDSCRIPTEXPRTYPE
VDSCRIPTEXPRTYPE_UNARY_INVERT,
/** Unary negate expression. */
VDSCRIPTEXPRTYPE_UNARY_NEGATE,
+ /** Unary reference expression. */
+ VDSCRIPTEXPRTYPE_UNARY_REFERENCE,
+ /** Unary dereference expression. */
+ VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE,
+ /** Cast expression. */
+ VDSCRIPTEXPRTYPE_CAST,
/** Multiplicative expression. */
VDSCRIPTEXPRTYPE_MULTIPLICATION,
/** Division expression. */
@@ -245,6 +358,22 @@ typedef struct VDSCRIPTASTEXPR
/** Right operator. */
PVDSCRIPTASTEXPR pRightExpr;
} BinaryOp;
+ /** Dereference or dot operation. */
+ struct
+ {
+ /** The identifier to access. */
+ PVDSCRIPTASTIDE pIde;
+ /** Postfix expression coming after this. */
+ PVDSCRIPTASTEXPR pExpr;
+ } Deref;
+ /** Cast expression. */
+ struct
+ {
+ /** Type name. */
+ PVDSCRIPTASTTYPENAME pTypeName;
+ /** Following cast expression. */
+ PVDSCRIPTASTEXPR pExpr;
+ } Cast;
};
} VDSCRIPTASTEXPR;
diff --git a/src/VBox/Storage/testcase/tstVDCompact.vd b/src/VBox/Storage/testcase/tstVDCompact.vd
index 95532d2..0289978 100644
--- a/src/VBox/Storage/testcase/tstVDCompact.vd
+++ b/src/VBox/Storage/testcase/tstVDCompact.vd
@@ -21,7 +21,7 @@ void tstCompact(string strMsg, string strBackend)
/* Create disk containers, read verification is on. */
createdisk("disk", true);
- create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false);
+ create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false, false);
/* Fill the disk with random data. */
io("disk", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
@@ -45,6 +45,31 @@ void tstCompact(string strMsg, string strBackend)
destroydisk("disk");
}
+void tstSnapshotCompact(string strMsg, string strBackend)
+{
+ print(strMsg);
+
+ /* Create disk containers, read verification is on. */
+ createdisk("disk", true);
+ create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false, false);
+
+ /* Fill the disk with random data. */
+ io("disk", false, 1, "seq", 64K, 0, 100M, 100M, 100, "none");
+
+ create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, true /* fHonorSame */);
+
+ io("disk", false, 1, "seq", 64K, 100M, 200M, 100M, 100, "none");
+ io("disk", false, 1, "seq", 64K, 100M, 150M, 50M, 100, "zero");
+
+ create("disk", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, true /* fHonorSame */);
+ merge("disk", 1, 2);
+
+ compact("disk", 1);
+
+ close("disk", "single", true);
+ destroydisk("disk");
+}
+
void main()
{
/* Init I/O RNG for generating random data for writes. */
@@ -56,6 +81,9 @@ void main()
tstCompact("Testing VDI", "VDI");
tstCompact("Testing VHD", "VHD");
+ tstSnapshotCompact("Testing Snapshot VDI", "VDI");
+ tstSnapshotCompact("Testing Snapshot VHD", "VHD");
+
/* Destroy RNG and pattern */
iopatterndestroy("zero");
iorngdestroy();
diff --git a/src/VBox/Storage/testcase/tstVDCopy.vd b/src/VBox/Storage/testcase/tstVDCopy.vd
index 9cd4e03..d34f27d 100644
--- a/src/VBox/Storage/testcase/tstVDCopy.vd
+++ b/src/VBox/Storage/testcase/tstVDCopy.vd
@@ -23,23 +23,23 @@ void main()
/* Create source disk and fill data. */
print("Creating Source Disk");
createdisk("source", false);
- create("source", "base", "source_base.vdi", "dynamic", "VDI", 1G, false);
+ create("source", "base", "source_base.vdi", "dynamic", "VDI", 1G, false, false);
io("source", false, 1, "rnd", 64K, 0, 512M, 256M, 100, "none");
print("Creating first diff");
- create("source", "diff", "source_diff1.vdi", "dynamic", "VDI", 1G, false);
+ create("source", "diff", "source_diff1.vdi", "dynamic", "VDI", 1G, false, false);
io("source", false, 1, "rnd", 64K, 512M, 1G, 256M, 50, "none");
print("Creating second diff");
- create("source", "diff", "source_diff2.vdi", "dynamic", "VDI", 1G, false);
+ create("source", "diff", "source_diff2.vdi", "dynamic", "VDI", 1G, false, false);
io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
print("Creating third diff");
- create("source", "diff", "source_diff3.vdi", "dynamic", "VDI", 1G, false);
+ create("source", "diff", "source_diff3.vdi", "dynamic", "VDI", 1G, false, false);
io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
print("Creating fourth diff");
- create("source", "diff", "source_diff4.vdi", "dynamic", "VDI", 1G, false);
+ create("source", "diff", "source_diff4.vdi", "dynamic", "VDI", 1G, false, false);
io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
print("Creating destination disk");
@@ -52,11 +52,11 @@ void main()
copy("source", "dest", 1, "VDI", "dest_diff1.vdi", false, 0, 0, 0);
print("Copying other diffs optimized");
- copy("source", "dest", 2, "VDI", "dest_diff1.vdi", false, 0, 1, 1);
- copy("source", "dest", 3, "VDI", "dest_diff1.vdi", false, 0, 2, 2);
- copy("source", "dest", 4, "VDI", "dest_diff1.vdi", false, 0, 3, 3);
+ copy("source", "dest", 2, "VDI", "dest_diff2.vdi", false, 0, 1, 1);
+ copy("source", "dest", 3, "VDI", "dest_diff3.vdi", false, 0, 2, 2);
+ copy("source", "dest", 4, "VDI", "dest_diff4.vdi", false, 0, 3, 3);
- print("Comparing_Disks");
+ print("Comparing disks");
comparedisks("source", "dest");
printfilesize("source", 0);
diff --git a/src/VBox/Storage/testcase/tstVDDiscard.vd b/src/VBox/Storage/testcase/tstVDDiscard.vd
index 56fadf5..3af7c10 100644
--- a/src/VBox/Storage/testcase/tstVDDiscard.vd
+++ b/src/VBox/Storage/testcase/tstVDDiscard.vd
@@ -25,14 +25,14 @@ void main()
/* Create disk containers, read verification is on. */
createdisk("disk", true /* fVerify */);
/* Create the disk. */
- create("disk", "base", "tstCompact.vdi", "dynamic", "VDI", 2G, false /* fIgnoreFlush */);
+ create("disk", "base", "tstCompact.vdi", "dynamic", "VDI", 2G, false /* fIgnoreFlush */, false);
/* Fill the disk with random data */
- io("disk", false, 1, "seq", 64K, 0, 2G, 2G, 100, "none");
+ io("disk", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
/* Read the data to verify it once. */
- io("disk", false, 1, "seq", 64K, 0, 2G, 2G, 0, "none");
+ io("disk", false, 1, "seq", 64K, 0, 200M, 200M, 0, "none");
close("disk", "single", false);
- open("disk", "tstCompact.vdi", "VDI", true, false, false, true, false);
+ open("disk", "tstCompact.vdi", "VDI", true, false, false, true, false, false);
printfilesize("disk", 0);
discard("disk", true, "6,0M,512K,1M,512K,2M,512K,3M,512K,4M,512K,5M,512K");
discard("disk", true, "6,6M,512K,7M,512K,8M,512K,9M,512K,10M,512K,11M,512K");
diff --git a/src/VBox/Storage/testcase/tstVDIo.cpp b/src/VBox/Storage/testcase/tstVDIo.cpp
index 7ab76ea..a8fdad1 100644
--- a/src/VBox/Storage/testcase/tstVDIo.cpp
+++ b/src/VBox/Storage/testcase/tstVDIo.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2011-2013 Oracle Corporation
+ * Copyright (C) 2011-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -17,7 +17,6 @@
*/
#define LOGGROUP LOGGROUP_DEFAULT
#include <VBox/vd.h>
-#include <VBox/vddbg.h>
#include <VBox/err.h>
#include <VBox/log.h>
#include <iprt/asm.h>
@@ -32,12 +31,22 @@
#include <iprt/thread.h>
#include <iprt/rand.h>
#include <iprt/critsect.h>
+#include <iprt/test.h>
+#include <iprt/system.h>
+
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+# include <VBox/vddbg.h>
+#endif
#include "VDMemDisk.h"
#include "VDIoBackend.h"
#include "VDIoRnd.h"
#include "VDScript.h"
+#include "BuiltinTests.h"
+
+/** forward declaration for the global test data pointer. */
+typedef struct VDTESTGLOB *PVDTESTGLOB;
/**
* A virtual file backed by memory.
@@ -98,6 +107,8 @@ typedef struct VDDISK
VDGEOMETRY PhysGeom;
/** Logical CHS geometry. */
VDGEOMETRY LogicalGeom;
+ /** Global test data. */
+ PVDTESTGLOB pTestGlob;
} VDDISK, *PVDDISK;
/**
@@ -140,7 +151,9 @@ typedef struct VDTESTGLOB
PVDIORND pIoRnd;
/** Current storage backend to use. */
char *pszIoBackend;
-} VDTESTGLOB, *PVDTESTGLOB;
+ /** Testcase handle. */
+ RTTEST hTest;
+} VDTESTGLOB;
/**
* Transfer direction.
@@ -227,7 +240,6 @@ static DECLCALLBACK(int) vdScriptHandlerDiscard(PVDSCRIPTARG paScriptArgs, void
static DECLCALLBACK(int) vdScriptHandlerCopy(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerClose(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerPrintFileSize(PVDSCRIPTARG paScriptArgs, void *pvUser);
-static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerIoRngDestroy(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromNumber(PVDSCRIPTARG paScriptArgs, void *pvUser);
@@ -245,6 +257,10 @@ static DECLCALLBACK(int) vdScriptHandlerResetStatistics(PVDSCRIPTARG paScriptArg
static DECLCALLBACK(int) vdScriptHandlerResize(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerSetFileBackend(PVDSCRIPTARG paScriptArgs, void *pvUser);
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser);
+#endif
+
/* create action */
const VDSCRIPTTYPE g_aArgCreate[] =
{
@@ -254,6 +270,7 @@ const VDSCRIPTTYPE g_aArgCreate[] =
VDSCRIPTTYPE_STRING,
VDSCRIPTTYPE_STRING,
VDSCRIPTTYPE_UINT64,
+ VDSCRIPTTYPE_BOOL,
VDSCRIPTTYPE_BOOL
};
@@ -267,7 +284,8 @@ const VDSCRIPTTYPE g_aArgOpen[] =
VDSCRIPTTYPE_BOOL, /* shareable */
VDSCRIPTTYPE_BOOL, /* readonly */
VDSCRIPTTYPE_BOOL, /* discard */
- VDSCRIPTTYPE_BOOL /* ignoreflush */
+ VDSCRIPTTYPE_BOOL, /* ignoreflush */
+ VDSCRIPTTYPE_BOOL, /* honorsame */
};
/* I/O action */
@@ -344,12 +362,14 @@ const VDSCRIPTTYPE g_aArgPrintFileSize[] =
VDSCRIPTTYPE_UINT32 /* image */
};
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
/* print file size action */
const VDSCRIPTTYPE g_aArgIoLogReplay[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_STRING /* iolog */
};
+#endif
/* I/O RNG create action */
const VDSCRIPTTYPE g_aArgIoRngCreate[] =
@@ -459,7 +479,9 @@ const VDSCRIPTCALLBACK g_aScriptActions[] =
{"flush", VDSCRIPTTYPE_VOID, g_aArgFlush, RT_ELEMENTS(g_aArgFlush), vdScriptHandlerFlush},
{"close", VDSCRIPTTYPE_VOID, g_aArgClose, RT_ELEMENTS(g_aArgClose), vdScriptHandlerClose},
{"printfilesize", VDSCRIPTTYPE_VOID, g_aArgPrintFileSize, RT_ELEMENTS(g_aArgPrintFileSize), vdScriptHandlerPrintFileSize},
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
{"ioreplay", VDSCRIPTTYPE_VOID, g_aArgIoLogReplay, RT_ELEMENTS(g_aArgIoLogReplay), vdScriptHandlerIoLogReplay},
+#endif
{"merge", VDSCRIPTTYPE_VOID, g_aArgMerge, RT_ELEMENTS(g_aArgMerge), vdScriptHandlerMerge},
{"compact", VDSCRIPTTYPE_VOID, g_aArgCompact, RT_ELEMENTS(g_aArgCompact), vdScriptHandlerCompact},
{"discard", VDSCRIPTTYPE_VOID, g_aArgDiscard, RT_ELEMENTS(g_aArgDiscard), vdScriptHandlerDiscard},
@@ -531,6 +553,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
bool fBase = false;
bool fDynamic = true;
bool fIgnoreFlush = false;
+ bool fHonorSame = false;
PVDIOBACKEND pIoBackend = NULL;
pcszDisk = paScriptArgs[0].psz;
@@ -556,6 +579,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
pcszBackend = paScriptArgs[4].psz;
cbSize = paScriptArgs[5].u64;
fIgnoreFlush = paScriptArgs[6].f;
+ fHonorSame = paScriptArgs[7].f;
if (RT_SUCCESS(rc))
{
@@ -571,6 +595,9 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
if (fIgnoreFlush)
fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
+ if (fHonorSame)
+ fOpenFlags |= VD_OPEN_FLAGS_HONOR_SAME;
+
if (fBase)
rc = VDCreateBase(pDisk->pVD, pcszBackend, pcszImage, cbSize, fImageFlags, NULL,
&pDisk->PhysGeom, &pDisk->LogicalGeom,
@@ -599,6 +626,7 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
bool fAsyncIo = true;
bool fDiscard = false;
bool fIgnoreFlush = false;
+ bool fHonorSame = false;
pcszDisk = paScriptArgs[0].psz;
pcszImage = paScriptArgs[1].psz;
@@ -607,6 +635,8 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
fReadonly = paScriptArgs[4].f;
fAsyncIo = paScriptArgs[5].f;
fDiscard = paScriptArgs[6].f;
+ fIgnoreFlush = paScriptArgs[7].f;
+ fHonorSame = paScriptArgs[8].f;
if (RT_SUCCESS(rc))
{
@@ -625,6 +655,8 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
fOpenFlags |= VD_OPEN_FLAGS_DISCARD;
if (fIgnoreFlush)
fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
+ if (fHonorSame)
+ fOpenFlags |= VD_OPEN_FLAGS_HONOR_SAME;
rc = VDOpen(pDisk->pVD, pcszBackend, pcszImage, fOpenFlags, pGlob->pInterfacesImages);
}
@@ -711,6 +743,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
{
VDIOTEST IoTest;
+ RTTestSub(pGlob->hTest, "Basic I/O");
rc = tstVDIoTestInit(&IoTest, pGlob, fRandomAcc, cbIo, cbBlkSize, offStart, offEnd, uWriteChance, pPattern);
if (RT_SUCCESS(rc))
{
@@ -769,7 +802,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
if (VDMemDiskCmp(pDisk->pMemDiskVerify, paIoReq[idx].off, paIoReq[idx].cbReq, &SgBuf))
{
- RTPrintf("Corrupted disk at offset %llu!\n", paIoReq[idx].off);
+ RTTestFailed(pGlob->hTest, "Corrupted disk at offset %llu!\n", paIoReq[idx].off);
rc = VERR_INVALID_STATE;
}
}
@@ -848,7 +881,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
if (VDMemDiskCmp(pDisk->pMemDiskVerify, paIoReq[idx].off, paIoReq[idx].cbReq,
&paIoReq[idx].SgBuf))
{
- RTPrintf("Corrupted disk at offset %llu!\n", paIoReq[idx].off);
+ RTTestFailed(pGlob->hTest, "Corrupted disk at offset %llu!\n", paIoReq[idx].off);
rc = VERR_INVALID_STATE;
}
RTCritSectLeave(&pDisk->CritSectVerify);
@@ -922,7 +955,13 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
NanoTS = RTTimeNanoTS() - NanoTS;
uint64_t SpeedKBs = (uint64_t)(cbIo / (NanoTS / 1000000000.0) / 1024);
- RTPrintf("I/O Test: Throughput %lld kb/s\n", SpeedKBs);
+ RTTestValue(pGlob->hTest, "Throughput", SpeedKBs, RTTESTUNIT_KILOBYTES_PER_SEC);
+
+ for (unsigned i = 0; i < cMaxTasksOutstanding; i++)
+ {
+ if (paIoReq[i].pvBufRead)
+ RTMemFree(paIoReq[i].pvBufRead);
+ }
RTSemEventDestroy(EventSem);
RTMemFree(paIoReq);
@@ -1363,6 +1402,7 @@ static DECLCALLBACK(int) vdScriptHandlerPrintFileSize(PVDSCRIPTARG paScriptArgs,
}
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser)
{
int rc = VINF_SUCCESS;
@@ -1513,6 +1553,7 @@ static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, v
return rc;
}
+#endif
static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDSCRIPTARG paScriptArgs, void *pvUser)
@@ -1744,6 +1785,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreateDisk(PVDSCRIPTARG paScriptArgs, vo
pDisk = (PVDDISK)RTMemAllocZ(sizeof(VDDISK));
if (pDisk)
{
+ pDisk->pTestGlob = pGlob;
pDisk->pszName = RTStrDup(pcszDisk);
if (pDisk->pszName)
{
@@ -1844,8 +1886,9 @@ static DECLCALLBACK(int) vdScriptHandlerCompareDisks(PVDSCRIPTARG paScriptArgs,
cbDisk1 = VDGetSize(pDisk1->pVD, VD_LAST_IMAGE);
cbDisk2 = VDGetSize(pDisk2->pVD, VD_LAST_IMAGE);
+ RTTestSub(pGlob->hTest, "Comparing two disks for equal content");
if (cbDisk1 != cbDisk2)
- RTPrintf("Disks differ in size %llu vs %llu\n", cbDisk1, cbDisk2);
+ RTTestFailed(pGlob->hTest, "Disks differ in size %llu vs %llu\n", cbDisk1, cbDisk2);
else
{
while (uOffCur < cbDisk1)
@@ -1860,14 +1903,14 @@ static DECLCALLBACK(int) vdScriptHandlerCompareDisks(PVDSCRIPTARG paScriptArgs,
{
if (memcmp(pbBuf1, pbBuf2, cbRead))
{
- RTPrintf("Disks differ at offset %llu\n", uOffCur);
+ RTTestFailed(pGlob->hTest, "Disks differ at offset %llu\n", uOffCur);
rc = VERR_DEV_IO_ERROR;
break;
}
}
else
{
- RTPrintf("Reading one disk at offset %llu failed\n", uOffCur);
+ RTTestFailed(pGlob->hTest, "Reading one disk at offset %llu failed\n", uOffCur);
break;
}
@@ -1990,7 +2033,7 @@ static DECLCALLBACK(int) vdScriptHandlerResize(PVDSCRIPTARG paScriptArgs, void *
int rc = VINF_SUCCESS;
PVDTESTGLOB pGlob = (PVDTESTGLOB)pvUser;
const char *pcszDisk = paScriptArgs[0].psz;
- uint64_t cbDiskNew = 0;
+ uint64_t cbDiskNew = paScriptArgs[1].u64;
PVDDISK pDisk = NULL;
pDisk = tstVDIoGetDiskByName(pGlob, pcszDisk);
@@ -2515,7 +2558,7 @@ static void tstVDIoTestReqComplete(void *pvUser1, void *pvUser2, int rcReq)
if (VDMemDiskCmp(pDisk->pMemDiskVerify, pIoReq->off, pIoReq->cbReq,
&pIoReq->SgBuf))
- RTPrintf("Corrupted disk at offset %llu!\n", pIoReq->off);
+ RTTestFailed(pDisk->pTestGlob->hTest, "Corrupted disk at offset %llu!\n", pIoReq->off);
RTCritSectLeave(&pDisk->CritSectVerify);
}
case VDIOREQTXDIR_WRITE:
@@ -2647,18 +2690,15 @@ static int tstVDIoPatternGetBuffer(PVDPATTERN pPattern, void **ppv, size_t cb)
}
/**
- * Executes the given I/O script using the new scripting engine.
+ * Executes the given script.
*
* @returns nothing.
- *
- * @param pcszFilename The script to execute.
+ * @param pszScript The script to execute.
*/
-static void tstVDIoScriptRun(const char *pcszFilename)
+static void tstVDIoScriptExec(const char *pszScript)
{
int rc = VINF_SUCCESS;
VDTESTGLOB GlobTest; /**< Global test data. */
- void *pvFile = NULL;
- size_t cbFile = 0;
memset(&GlobTest, 0, sizeof(VDTESTGLOB));
RTListInit(&GlobTest.ListFiles);
@@ -2671,40 +2711,36 @@ static void tstVDIoScriptRun(const char *pcszFilename)
return;
}
- rc = RTFileReadAll(pcszFilename, &pvFile, &cbFile);
+ /* Init global test data. */
+ GlobTest.VDIfError.pfnError = tstVDError;
+ GlobTest.VDIfError.pfnMessage = tstVDMessage;
+
+ rc = VDInterfaceAdd(&GlobTest.VDIfError.Core, "tstVDIo_VDIError", VDINTERFACETYPE_ERROR,
+ NULL, sizeof(VDINTERFACEERROR), &GlobTest.pInterfacesDisk);
+ AssertRC(rc);
+
+ GlobTest.VDIfIo.pfnOpen = tstVDIoFileOpen;
+ GlobTest.VDIfIo.pfnClose = tstVDIoFileClose;
+ GlobTest.VDIfIo.pfnDelete = tstVDIoFileDelete;
+ GlobTest.VDIfIo.pfnMove = tstVDIoFileMove;
+ GlobTest.VDIfIo.pfnGetFreeSpace = tstVDIoFileGetFreeSpace;
+ GlobTest.VDIfIo.pfnGetModificationTime = tstVDIoFileGetModificationTime;
+ GlobTest.VDIfIo.pfnGetSize = tstVDIoFileGetSize;
+ GlobTest.VDIfIo.pfnSetSize = tstVDIoFileSetSize;
+ GlobTest.VDIfIo.pfnWriteSync = tstVDIoFileWriteSync;
+ GlobTest.VDIfIo.pfnReadSync = tstVDIoFileReadSync;
+ GlobTest.VDIfIo.pfnFlushSync = tstVDIoFileFlushSync;
+ GlobTest.VDIfIo.pfnReadAsync = tstVDIoFileReadAsync;
+ GlobTest.VDIfIo.pfnWriteAsync = tstVDIoFileWriteAsync;
+ GlobTest.VDIfIo.pfnFlushAsync = tstVDIoFileFlushAsync;
+
+ rc = VDInterfaceAdd(&GlobTest.VDIfIo.Core, "tstVDIo_VDIIo", VDINTERFACETYPE_IO,
+ &GlobTest, sizeof(VDINTERFACEIO), &GlobTest.pInterfacesImages);
+ AssertRC(rc);
+
+ rc = RTTestCreate("tstVDIo", &GlobTest.hTest);
if (RT_SUCCESS(rc))
{
- char *pszScript = RTStrDupN((char *)pvFile, cbFile);
- RTFileReadAllFree(pvFile, cbFile);
-
- AssertPtr(pszScript);
- /* Init global test data. */
- GlobTest.VDIfError.pfnError = tstVDError;
- GlobTest.VDIfError.pfnMessage = tstVDMessage;
-
- rc = VDInterfaceAdd(&GlobTest.VDIfError.Core, "tstVDIo_VDIError", VDINTERFACETYPE_ERROR,
- NULL, sizeof(VDINTERFACEERROR), &GlobTest.pInterfacesDisk);
- AssertRC(rc);
-
- GlobTest.VDIfIo.pfnOpen = tstVDIoFileOpen;
- GlobTest.VDIfIo.pfnClose = tstVDIoFileClose;
- GlobTest.VDIfIo.pfnDelete = tstVDIoFileDelete;
- GlobTest.VDIfIo.pfnMove = tstVDIoFileMove;
- GlobTest.VDIfIo.pfnGetFreeSpace = tstVDIoFileGetFreeSpace;
- GlobTest.VDIfIo.pfnGetModificationTime = tstVDIoFileGetModificationTime;
- GlobTest.VDIfIo.pfnGetSize = tstVDIoFileGetSize;
- GlobTest.VDIfIo.pfnSetSize = tstVDIoFileSetSize;
- GlobTest.VDIfIo.pfnWriteSync = tstVDIoFileWriteSync;
- GlobTest.VDIfIo.pfnReadSync = tstVDIoFileReadSync;
- GlobTest.VDIfIo.pfnFlushSync = tstVDIoFileFlushSync;
- GlobTest.VDIfIo.pfnReadAsync = tstVDIoFileReadAsync;
- GlobTest.VDIfIo.pfnWriteAsync = tstVDIoFileWriteAsync;
- GlobTest.VDIfIo.pfnFlushAsync = tstVDIoFileFlushAsync;
-
- rc = VDInterfaceAdd(&GlobTest.VDIfIo.Core, "tstVDIo_VDIIo", VDINTERFACETYPE_IO,
- &GlobTest, sizeof(VDINTERFACEIO), &GlobTest.pInterfacesImages);
- AssertRC(rc);
-
/* Init I/O backend. */
rc = VDIoBackendCreate(&GlobTest.pIoBackend);
if (RT_SUCCESS(rc))
@@ -2713,9 +2749,10 @@ static void tstVDIoScriptRun(const char *pcszFilename)
rc = VDScriptCtxCreate(&hScriptCtx);
if (RT_SUCCESS(rc))
{
- rc = VDScriptCtxCallbacksRegister(hScriptCtx, g_aScriptActions, g_cScriptActions, &GlobTest);
- AssertRC(rc);
+ RTTEST_CHECK_RC_OK(GlobTest.hTest,
+ VDScriptCtxCallbacksRegister(hScriptCtx, g_aScriptActions, g_cScriptActions, &GlobTest));
+ RTTestBanner(GlobTest.hTest);
rc = VDScriptCtxLoadScript(hScriptCtx, pszScript);
if (RT_FAILURE(rc))
{
@@ -2729,14 +2766,80 @@ static void tstVDIoScriptRun(const char *pcszFilename)
}
else
RTPrintf("Creating the I/O backend failed rc=%Rrc\n");
+
+ RTTestSummaryAndDestroy(GlobTest.hTest);
}
else
- RTPrintf("Opening script failed rc=%Rrc\n", rc);
+ RTStrmPrintf(g_pStdErr, "tstVDIo: fatal error: RTTestCreate failed with rc=%Rrc\n", rc);
RTStrFree(GlobTest.pszIoBackend);
}
/**
+ * Executes the given I/O script using the new scripting engine.
+ *
+ * @returns nothing.
+ *
+ * @param pcszFilename The script to execute.
+ */
+static void tstVDIoScriptRun(const char *pcszFilename)
+{
+ int rc = VINF_SUCCESS;
+ void *pvFile = NULL;
+ size_t cbFile = 0;
+
+ rc = RTFileReadAll(pcszFilename, &pvFile, &cbFile);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszScript = RTStrDupN((char *)pvFile, cbFile);
+ RTFileReadAllFree(pvFile, cbFile);
+
+ AssertPtr(pszScript);
+ tstVDIoScriptExec(pszScript);
+ RTStrFree(pszScript);
+ }
+ else
+ RTPrintf("Opening the script failed: %Rrc\n", rc);
+
+}
+
+/**
+ * Run builtin tests.
+ *
+ * @returns nothing.
+ */
+static void tstVDIoRunBuiltinTests(void)
+{
+ /* 32bit hosts are excluded because of the 4GB address space. */
+#if HC_ARCH_BITS == 32
+ RTStrmPrintf(g_pStdErr, "tstVDIo: Running on a 32bit host is not supported for the builtin tests, skipping\n");
+ return;
+#else
+ /*
+ * We need quite a bit of RAM for the builtin tests. Skip it if there
+ * is not enough free RAM available.
+ */
+ uint64_t cbFree = 0;
+ int rc = RTSystemQueryAvailableRam(&cbFree);
+ if ( RT_FAILURE(rc)
+ || cbFree < (UINT64_C(6) * _1G))
+ {
+ RTStrmPrintf(g_pStdErr, "tstVDIo: fatal error: Failed to query available RAM or not enough available, skipping (rc=%Rrc cbFree=%llu)\n",
+ rc, cbFree);
+ return;
+ }
+
+ for (unsigned i = 0; i < g_cVDIoTests; i++)
+ {
+ char *pszScript = RTStrDupN((const char *)g_aVDIoTests[i].pch, g_aVDIoTests[i].cb);
+
+ AssertPtr(pszScript);
+ tstVDIoScriptExec(pszScript);
+ }
+#endif
+}
+
+/**
* Shows help message.
*/
static void printUsage(void)
@@ -2747,28 +2850,28 @@ static void printUsage(void)
static const RTGETOPTDEF g_aOptions[] =
{
- { "--script", 's', RTGETOPT_REQ_STRING }
+ { "--script", 's', RTGETOPT_REQ_STRING },
+ { "--help", 'h', RTGETOPT_REQ_NOTHING }
};
int main(int argc, char *argv[])
{
-#if 0 /** @todo: Enable when the testcase was fixed. */
RTR3InitExe(argc, &argv, 0);
int rc;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
char c;
- if (argc != 3)
- {
- printUsage();
- return RTEXITCODE_FAILURE;
- }
-
rc = VDInit();
if (RT_FAILURE(rc))
return RTEXITCODE_FAILURE;
+ if (argc == 1)
+ {
+ tstVDIoRunBuiltinTests();
+ return RTEXITCODE_SUCCESS;
+ }
+
RTGetOptInit(&GetState, argc, argv, g_aOptions,
RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
@@ -2780,15 +2883,17 @@ int main(int argc, char *argv[])
case 's':
tstVDIoScriptRun(ValueUnion.psz);
break;
- default:
+ case 'h':
printUsage();
+ break;
+ default: /* Default is to run built in tests if no arguments are given (automated testing). */
+ tstVDIoRunBuiltinTests();
}
}
rc = VDShutdown();
if (RT_FAILURE(rc))
RTPrintf("tstVDIo: unloading backends failed! rc=%Rrc\n", rc);
-#endif
return RTEXITCODE_SUCCESS;
}
diff --git a/src/VBox/Storage/testcase/tstVDIo.vd b/src/VBox/Storage/testcase/tstVDIo.vd
index 0074be6..3eae4f6 100644
--- a/src/VBox/Storage/testcase/tstVDIo.vd
+++ b/src/VBox/Storage/testcase/tstVDIo.vd
@@ -19,15 +19,15 @@ void tstIo(string strMessage, string strBackend)
{
print(strMessage);
createdisk("test", true /* fVerify */);
- create("test", "base", "tst.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+ create("test", "base", "tst.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
io("test", true, 32, "seq", 64K, 0, 200M, 200M, 100, "none");
io("test", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
io("test", true, 32, "seq", 64K, 0, 200M, 200M, 0, "none");
io("test", false, 1, "seq", 64K, 0, 200M, 200M, 0, "none");
- create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+ create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
io("test", true, 32, "rnd", 64K, 0, 200M, 200M, 50, "none");
io("test", false, 1, "rnd", 64K, 0, 200M, 200M, 50, "none");
- create("test", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+ create("test", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
io("test", true, 32, "rnd", 64K, 0, 200M, 200M, 50, "none");
io("test", false, 1, "rnd", 64K, 0, 200M, 200M, 50, "none");
close("test", "single", true /* fDelete */);
@@ -36,6 +36,16 @@ void tstIo(string strMessage, string strBackend)
destroydisk("test");
}
+void tstIoUnaligned(string strMessage, string strBackend)
+{
+ print(strMessage);
+ createdisk("test", true);
+ create("test", "base", "tst.disk", "dynamic", strBackend, 2G, false);
+ io("test", false, 1, "seq", 512, 3584, 4096, 512, 100, "none");
+ io("test", false, 1, "seq", 512, 3584, 4096, 512, 0, "none");
+ destroydisk("test");
+}
+
void main()
{
/* Init I/O RNG for generating random data for writes */
diff --git a/src/VBox/Storage/testcase/tstVDMultBackends.vd b/src/VBox/Storage/testcase/tstVDMultBackends.vd
new file mode 100644
index 0000000..fa3f9c3
--- /dev/null
+++ b/src/VBox/Storage/testcase/tstVDMultBackends.vd
@@ -0,0 +1,60 @@
+/* $Id: tstVDMultBackends.vd $ */
+/**
+ * Storage: Simple I/O test with different backends in one chain.
+ */
+
+/*
+ * Copyright (C) 2011-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+void tstIo(string strMessage, string strBackend)
+{
+ print(strMessage);
+ createdisk("test", true /* fVerify */);
+ create("test", "base", "tst.disk", "dynamic", strBackend, 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "seq", 64K, 0, 2G, 200M, 100, "none");
+ io("test", false, 1, "seq", 64K, 0, 2G, 200M, 100, "none");
+ io("test", true, 32, "seq", 64K, 0, 2G, 200M, 0, "none");
+ io("test", false, 1, "seq", 64K, 0, 2G, 200M, 0, "none");
+ create("test", "diff", "tst2.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ io("test", false, 1, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ create("test", "diff", "tst3.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ io("test", false, 1, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ create("test", "diff", "tst4.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 0, "none");
+
+ create("test", "diff", "tst5.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 0, "none");
+
+ create("test", "diff", "tst6.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 50, "none");
+ io("test", true, 32, "rnd", 64K, 0, 2G, 200M, 0, "none");
+
+ close("test", "single", true /* fDelete */);
+ close("test", "single", true /* fDelete */);
+ close("test", "single", true /* fDelete */);
+ destroydisk("test");
+}
+
+void main()
+{
+ /* Init I/O RNG for generating random data for writes */
+ iorngcreate(10M, "manual", 1234567890);
+
+ tstIo("Testing VDI", "VDI");
+
+ iorngdestroy();
+}
+
diff --git a/src/VBox/Storage/testcase/tstVDResize.vd b/src/VBox/Storage/testcase/tstVDResize.vd
index 0a3dcf4..8e74d35 100644
--- a/src/VBox/Storage/testcase/tstVDResize.vd
+++ b/src/VBox/Storage/testcase/tstVDResize.vd
@@ -17,16 +17,17 @@
void main()
{
- /* Init I/O RNG for generating random data for writes. */
- iorngcreate(10M, "manual", 1234567890);
+ /* Init I/O RNG for generating random data for writes. */
+ iorngcreate(10M, "manual", 1234567890);
- print("Testing VDI");
- createdisk("test", true);
- create("test", "base", "tst.vdi", "dynamic", "VDI", 1T, false);
- io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 100, "none");
- resize("test", 1331200M);
- io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 0, "none");
- destroydisk("test");
+ print("Testing VDI");
+ createdisk("test", true);
+ create("test", "base", "tst.vdi", "dynamic", "VDI", 1T, false, false);
+ io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 100, "none");
+ resize("test", 1331200M);
+ io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 0, "none");
+ destroydisk("test");
- iorngdestroy();
+ iorngdestroy();
}
+
diff --git a/src/VBox/Storage/testcase/tstVDShareable.vd b/src/VBox/Storage/testcase/tstVDShareable.vd
index 7cbe4e2..6fdf032 100644
--- a/src/VBox/Storage/testcase/tstVDShareable.vd
+++ b/src/VBox/Storage/testcase/tstVDShareable.vd
@@ -25,12 +25,12 @@ void main()
createdisk("shared2", false);
/* Create the disk and close it. */
- create("shared1", "base", "tstShared.vdi", "fixed", "VDI", 20M, false);
+ create("shared1", "base", "tstShared.vdi", "fixed", "VDI", 20M, false, false);
close("shared1", "all", false);
/* Open the disk with sharing enabled. */
- open("shared1", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false);
- open("shared2", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false);
+ open("shared1", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false, false);
+ open("shared2", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false, false);
/* Write to one disk and verify that the other disk can see the content. */
io("shared1", true, 32, "seq", 64K, 0, 20M, 20M, 100, "none");
@@ -45,7 +45,7 @@ void main()
close("shared2", "all", false);
/* Open and delete. */
- open("shared1", "tstShared.vdi", "VDI", false /* fAsync */, false /* fShareable */, false, false, false);
+ open("shared1", "tstShared.vdi", "VDI", false /* fAsync */, false /* fShareable */, false, false, false, false);
close("shared1", "single", true);
/* Cleanup */
@@ -53,3 +53,4 @@ void main()
destroydisk("shared2");
iorngdestroy();
}
+
diff --git a/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp b/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
index 32cc236..88d2358 100644
--- a/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
+++ b/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
@@ -93,7 +93,7 @@ static const unsigned g_aSize2Shift[] =
static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void const *pvValue, unsigned cbValue)
{
AssertReturn( (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
- || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
+ && (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
VERR_IOM_MMIO_IPE_1);
AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
RTGCPHYS const GCPhysStart = GCPhys; NOREF(GCPhysStart);
diff --git a/src/VBox/VMM/VMMR0/HMSVMR0.cpp b/src/VBox/VMM/VMMR0/HMSVMR0.cpp
index 8738755..26d876f 100644
--- a/src/VBox/VMM/VMMR0/HMSVMR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMSVMR0.cpp
@@ -4923,9 +4923,20 @@ HMSVM_EXIT_DECL hmR0SvmExitXcptMF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSv
if (!(pCtx->cr0 & X86_CR0_NE))
{
- /* Old-style FPU error reporting needs some extra work. */
- /** @todo don't fall back to the recompiler, but do it manually. */
- return VERR_EM_INTERPRETER;
+ PVM pVM = pVCpu->CTX_SUFF(pVM);
+ PDISSTATE pDis = &pVCpu->hm.s.DisState;
+ unsigned cbOp;
+ int rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
+ if (RT_SUCCESS(rc))
+ {
+ /* Convert a #MF into a FERR -> IRQ 13. */
+ rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /*uTagSrc*/);
+ if (RT_SUCCESS(rc))
+ pCtx->rip += cbOp;
+ }
+ else
+ Log4(("hmR0SvmExitXcptMF: EMInterpretDisasCurrent returned %Rrc uOpCode=%#x\n", rc, pDis->pCurInstr->uOpcode));
+ return rc;
}
hmR0SvmSetPendingXcptMF(pVCpu);
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index 92ff4db..cced81e 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -8724,17 +8724,17 @@ static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
for (unsigned i = 0; i < 8; i++)
{
- uint8_t u8Val = (u64Val & 0x7);
+ uint8_t u8Val = (u64Val & 0xff);
if ( u8Val != 0 /* UC */
- || u8Val != 1 /* WC */
- || u8Val != 4 /* WT */
- || u8Val != 5 /* WP */
- || u8Val != 6 /* WB */
- || u8Val != 7 /* UC- */)
+ && u8Val != 1 /* WC */
+ && u8Val != 4 /* WT */
+ && u8Val != 5 /* WP */
+ && u8Val != 6 /* WB */
+ && u8Val != 7 /* UC- */)
{
HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
}
- u64Val >>= 3;
+ u64Val >>= 8;
}
}
@@ -10749,9 +10749,11 @@ static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVm
if (!(pMixedCtx->cr0 & X86_CR0_NE))
{
- /* Old-style FPU error reporting needs some extra work. */
- /** @todo don't fall back to the recompiler, but do it manually. */
- return VERR_EM_INTERPRETER;
+ /* Convert a #MF into a FERR -> IRQ 13. */
+ rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /*uTagSrc*/);
+ int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
+ AssertRCReturn(rc2, rc2);
+ return rc;
}
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
diff --git a/src/VBox/VMM/VMMR3/MMPagePool.cpp b/src/VBox/VMM/VMMR3/MMPagePool.cpp
index e40bb3d..6716e75 100644
--- a/src/VBox/VMM/VMMR3/MMPagePool.cpp
+++ b/src/VBox/VMM/VMMR3/MMPagePool.cpp
@@ -231,7 +231,7 @@ DECLINLINE(void *) mmR3PagePoolAlloc(PMMPAGEPOOL pPool)
unsigned cPages = !pPool->fLow ? 128 : 32;
PMMPAGESUBPOOL pSub;
int rc = MMHyperAlloc(pPool->pVM,
- RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0] * 8))])
+ RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)])
+ (sizeof(SUPPAGE) + sizeof(MMPPLOOKUPHCPHYS)) * cPages
+ sizeof(MMPPLOOKUPHCPTR),
0,
diff --git a/src/VBox/VMM/VMMR3/PGMPhys.cpp b/src/VBox/VMM/VMMR3/PGMPhys.cpp
index 9a21f28..80b10ec 100644
--- a/src/VBox/VMM/VMMR3/PGMPhys.cpp
+++ b/src/VBox/VMM/VMMR3/PGMPhys.cpp
@@ -3852,7 +3852,7 @@ VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
if (pVCpu->pgm.s.fA20Enabled != fEnable)
{
pVCpu->pgm.s.fA20Enabled = fEnable;
- pVCpu->pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!fEnable << 20);
+ pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!fEnable << 20);
#ifdef VBOX_WITH_REM
REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
#endif
diff --git a/src/VBox/VMM/VMMR3/PGMPool.cpp b/src/VBox/VMM/VMMR3/PGMPool.cpp
index 97a8bab..6afc27e 100644
--- a/src/VBox/VMM/VMMR3/PGMPool.cpp
+++ b/src/VBox/VMM/VMMR3/PGMPool.cpp
@@ -298,7 +298,7 @@ int pgmR3PoolInit(PVM pVM)
pPool->aPages[NIL_PGMPOOL_IDX].iModifiedNext = NIL_PGMPOOL_IDX;
pPool->aPages[NIL_PGMPOOL_IDX].iModifiedPrev = NIL_PGMPOOL_IDX;
pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredNext = NIL_PGMPOOL_IDX;
- pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredNext = NIL_PGMPOOL_IDX;
+ pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredPrev = NIL_PGMPOOL_IDX;
pPool->aPages[NIL_PGMPOOL_IDX].iAgeNext = NIL_PGMPOOL_IDX;
pPool->aPages[NIL_PGMPOOL_IDX].iAgePrev = NIL_PGMPOOL_IDX;
@@ -480,7 +480,7 @@ VMMR3DECL(int) PGMR3PoolGrow(PVM pVM)
pPage->iModifiedNext = NIL_PGMPOOL_IDX;
pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
- pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
+ pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
pPage->iAgeNext = NIL_PGMPOOL_IDX;
pPage->iAgePrev = NIL_PGMPOOL_IDX;
/* commit it */
diff --git a/src/VBox/VMM/VMMR3/PGMSavedState.cpp b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
index fbd01bb..0d0d30e 100644
--- a/src/VBox/VMM/VMMR3/PGMSavedState.cpp
+++ b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
@@ -3074,7 +3074,11 @@ static int pgmR3LoadFinalLocked(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion)
* Fix the A20 mask.
*/
for (VMCPUID i = 0; i < pVM->cCpus; i++)
- pVM->aCpus[i].pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!pVM->aCpus[i].pgm.s.fA20Enabled << 20);
+ {
+ PVMCPU pVCpu = &pVM->aCpus[i];
+ pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!pVCpu->pgm.s.fA20Enabled << 20);
+ pgmR3RefreshShadowModeAfterA20Change(pVCpu);
+ }
/*
* The guest mappings - skipped now, see re-fixation in the caller.
diff --git a/src/VBox/VMM/VMMR3/STAM.cpp b/src/VBox/VMM/VMMR3/STAM.cpp
index 6b47ef6..68f7224 100644
--- a/src/VBox/VMM/VMMR3/STAM.cpp
+++ b/src/VBox/VMM/VMMR3/STAM.cpp
@@ -1129,7 +1129,7 @@ static void stamR3LookupMaybeFree(PSTAMLOOKUP pLookup)
if (pCur->cDescsInTree > 0)
return;
PSTAMLOOKUP pParent = pCur->pParent;
- if (pParent)
+ if (!pParent)
return;
if (pParent->cDescsInTree == 0 && pParent->pParent)
@@ -1150,6 +1150,7 @@ static void stamR3LookupMaybeFree(PSTAMLOOKUP pLookup)
papChildren[i] = pChild;
}
pCur->pParent = NULL;
+ pCur->iParent = UINT16_MAX;
/*
* Destroy pCur.
diff --git a/src/VBox/VMM/testcase/tstAnimate.cpp b/src/VBox/VMM/testcase/tstAnimate.cpp
index 1efb09f..ba8eea1 100644
--- a/src/VBox/VMM/testcase/tstAnimate.cpp
+++ b/src/VBox/VMM/testcase/tstAnimate.cpp
@@ -309,7 +309,7 @@ static DECLCALLBACK(int) loadMem(PVM pVM, RTFILE File, uint64_t *poff)
}
/* Write that page to the guest - skip known rom areas for now. */
- if (GCPhys < 0xa0000 || GCPhys >= 0x10000) /* ASSUME size of a8Page is a power of 2. */
+ if (GCPhys < 0xa0000 || GCPhys >= 0x100000) /* ASSUME size of a8Page is a power of 2. */
PGMPhysWrite(pVM, GCPhys, &au8Page, cbRead);
GCPhys += cbRead;
}
diff --git a/src/bldprogs/VBoxCPP.cpp b/src/bldprogs/VBoxCPP.cpp
index 7cc0817..5e0a567 100644
--- a/src/bldprogs/VBoxCPP.cpp
+++ b/src/bldprogs/VBoxCPP.cpp
@@ -1132,7 +1132,7 @@ static void vbcppProcessSkipWhiteAndEscapedEol(PSCMSTREAM pStrmInput)
}
else if (RT_C_IS_SPACE(ch))
{
- ch = chPrev;
+ chPrev = ch;
ch = ScmStreamGetCh(pStrmInput);
Assert(ch == chPrev);
}
@@ -5359,7 +5359,7 @@ static RTEXITCODE vbcppParseOptions(PVBCPP pThis, int argc, char **argv, bool *p
case 'V':
{
/* The following is assuming that svn does it's job here. */
- static const char s_szRev[] = "$Revision: 79724 $";
+ static const char s_szRev[] = "$Revision: 96257 $";
const char *psz = RTStrStripL(strchr(s_szRev, ' '));
RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz);
*pfExit = true;
diff --git a/src/bldprogs/scmdiff.cpp b/src/bldprogs/scmdiff.cpp
index 28463ad..f2d28e8 100644
--- a/src/bldprogs/scmdiff.cpp
+++ b/src/bldprogs/scmdiff.cpp
@@ -236,7 +236,7 @@ DECLINLINE(bool) scmDiffCompare(PSCMDIFFSTATE pState,
|| memcmp(pchLeft, pchRight, cchLeft))
{
if ( pState->fIgnoreTrailingWhite
- || pState->fIgnoreTrailingWhite)
+ || pState->fIgnoreLeadingWhite)
return scmDiffCompareSlow(pState,
pchLeft, cchLeft, enmEolLeft,
pchRight, cchRight, enmEolRight);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/virtualbox.git
More information about the Pkg-virtualbox-commits
mailing list