Driver compatibility with Device Guard in Windows 10
Published Mar 12 2019 07:11 AM 30.3K Views
Copper Contributor
First published on MSDN on May 22, 2015
Note: This post was last updated on February 8, 2018

Windows 10 has a new feature called Device Guard that gives organizations the ability to lock down devices in a way that provides advanced malware protection against new and unknown malware variants as well as Advanced Persistent Threats (APTs). Device Guard can use hardware technology and virtualization to isolate the Code Integrity (CI) decision-making function from the rest of the Windows operating system. When using virtualization-based security to isolate Code Integrity, the only way kernel memory can become executable is through a Code Integrity verification. This means that kernel memory pages can never be Writable and Executable (W+X) and executable code cannot be directly modified.

How to build compatible drivers

Since memory pages and sections can never be writable and executable, the first step is to ensure a clear separation of data and code and not to attempt to directly modify code pages.

  • Opt-in to NX by default

  • Use NX APIs/flags for memory allocation - NonPagedPoolNx

  • Don’t use sections that are both writable and executable

  • Don’t attempt to directly modify executable system memory

  • Don’t use dynamic code in kernel

  • Don’t load data files as executable

  • Section Alignment must be a multiple of 0x1000 (PAGE_SIZE). E.g. DRIVER_ALIGNMENT=0x1000


Use the latest version of the WDK and Visual Studio 2015 to produce compatible drivers when using default settings. Visual Studio 2013 currently marks the INIT section as RWX. This will be patched soon, but is still compatible as Windows 10 will automatically strip the write permission (W) from the INIT section.

How to verify driver compatibility

There are four steps to verify driver compatibility:

1. Use Driver Verifier with the new Code Integrity compatibility checks enabled
2. Test the driver on a system with virtualization-based isolation of Code Integrity enabled.
3. Run the HyperVisor Code Integrity Readiness Test in the Windows HLK.
4. Use the Device Guard Readiness Tool .


Driver Verifier compatibility checks

Driver Verifier has a new Code Integrity option flag (0x02000000) to enable extra checks that validate compliance with this feature. To enable this from the command line, use the following command:

verifier.exe /flags 0x02000000 /driver <driver.sys>

To choose this option if using the verifier GUI, choose Create custom settings (for code developers) , choose Next , and then choose Code integrity checks .

Drivers built with older versions of Visual Studio will fail on the INIT section being WRX.  However, if this is the only issue you can ignore this issue and hit go past this in the kernel debugger as this will not cause any compatibility issues with this feature.  Forthcoming updates to driver verifier will not flag the INIT section.

Enable virtualization-based isolation for Code Integrity

Virtualization-based security is supported on Enterprise and Server editions of Windows. To enable virtualization-based protection of Code Integrity, the simplest method is to use gpedit as described below. This will turn on Hyper-V and Isolated User Mode and enable the feature:

1. Run gpedit to edit local Group Policy
2. Under Computer Configuration -> Administrative Templates -> System -> Device Guard , choose Turn On Virtualization Based Security



3. In the detailed configuration dialog that appears, choose Enabled , and then select Enable Virtualization Based Protection of Code Integrity



4. Reboot


Virtualization-based protection of Code Integrity is now enabled.

HLK testing (Desktop and Server)

A new HLK test, the HyperVisor Code Integrity Readiness Test , needs to pass for HVCI drivers to be approved for Microsoft signing. HVCI-compatible drivers are required for both Desktop and Server SKUs. The HLK test is a basic test written to make sure that HVCI-compatible drivers are correctly loaded and run by the OS.

Although simply passing the HLK test is sufficient for a Microsoft signature for the driver, we strongly recommend thorough functional testing with Device Guard enabled. For example, there might be incorrectly-coded memory allocation violating NX protections causing failures that won't be caught by the test. The driver author should thoroughly test the driver while keeping Device Guard enabled.

During driver development and during HLK testing, Device Guard should be disabled, as Device Guard might prevent the driver from loading.

Device Guard Readiness Tool

The Device Guard and Credential Guard hardware readiness tool can also be used to check for HVCI compatibility of all installed drivers on the device. The download includes a readme file that contains usage information. Note that while running the Readiness Tool, Device Guard must be disabled, as Device Guard might prevent the driver from loading, and the driver won’t be available for the Readiness Tool to test. For more information about the Readiness Tool, see Use the Device Guard Readiness Tool to evaluate HVCI driver compatibility

Windows 10 Creators Update: Enabling Device Guard Virtualization Based Protection of Code Integrity may result in a system crash during boot

We are aware of an issue introduced with the Windows 10 Creators Update that may cause a failure during boot for systems that have enabled the Device Guard Virtualization Based Protection of Code Integrity feature and are running certain 3rd party drivers that were previously working. We have addressed the issue, and the fix is scheduled for release on May 23, 2017. We recommend that you disable the Device Guard Virtualization Based Protection of Code Integrity feature prior to upgrade or delay upgrade until the fix is released, and do not enable the feature on Windows 10 Creators Update until after the fix has been released.

FAQs:

What about existing drivers?  Do I need to re-build these drivers to get them to work with Windows 10?

It depends. Many drivers will already be compatible. If using standard settings with the old versions of the WDK and Visual Studio, a known issue is that the INIT section is marked as RWX. In Windows 10, however, the W will automatically be stripped, so if this is the only issue then the driver will be compatible.

How do I verify that Virtualization Based Protection of Code Integrity is enabled?

The simplest mechanism is to run the System Information app (msinfo32). Look for the following line: “Device Guard Security Services Running”. It should report: “Hypervisor enforced Code Integrity”. There is also a WMI interface for checking using management tools.

Can I verify that Virtualization Based Protection of Code Integrity is enabled programmatically from kernel in order to alter driver behavior?

Yes, you can use NtQuerySystemInformation: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx

The SYSTEM_CODEINTEGRITY_INFORMATION structure has a new 0x400 value exposed, indicating that virtualization based protection of Code Integrity is on.

How do I fix compatibility issues?

In addition to double checking that there are no W+X pages and the driver sections are aligned correctly as mentioned above, the most likely issue will be improper memory allocation. Information about the Code Analysis warnings related to memory allocation issued is available on MSDN on the following page:

Code Analysis for Drivers Warnings


The following MSDN links show some examples of commonly-used APIs that cause executable memory to be allocated, along with some example fixes:

C30029
C30030
C30031
C30032
C30033
C30034
C30035

Use the following table to interpret the output to determine what driver code changes are needed to resolve the different types of HVCI incompatibilities.
WarningResolution
Execute Pool Type The caller specified an executable pool type. Calling a memory allocating function that requests executable memory.
Be sure that all pool types contain a non executable NX flag.
Execute Page Protection The caller specified an executable page protection.
Specify a "no execute" page protection mask.
Execute Page Mapping The caller specified an executable memory descriptor list (MDL) mapping.
Make sure that the mask that is used contains MdlMappingNoExecute. For more information, see MmGetSystemAddressForMdlSafe
Execute-Write Section The image contains an executable and writable section.
Section Alignment Failures The image contains a section that is not page aligned.
Section Alignment must be a multiple of 0x1000 (PAGE_SIZE). E.g. DRIVER_ALIGNMENT=0x1000
Unsupported Relocs In Windows 10 version 1507 through version 1607, because of the use of Address Space Layout Randomization (ASLR) an issue can arise with address alignment and memory relocation. The operating system needs to relocate the address from where the linker set its default base address to the actual location that ASLR assigned. This relocation cannot straddle a page boundary. For example, consider a 64-bit address value that starts at offset 0x3FFC in a page. It’s address value overlaps over to the next page at offset 0x0003. This type of overlapping relocs is not supported prior to Windows 10 version 1703.

This situation can occur when a global struct type variable initializer has a misaligned pointer to another global, laid out in such a way that the linker cannot move the variable to avoid the straddling relocation. The linker will attempt to move the variable, but there are situations where it may not be able to do so, for example with large misaligned structs or large arrays of misaligned structs. Where appropriate, modules should be assembled using the [/Gy (COMDAT)](https://docs.microsoft.com/en-us/cpp/build/reference/gy-enable-function-level-linking) option to allow the linker to align module code as much as possible.
#include <pshpack1.h>

typedef struct _BAD_STRUCT {
USHORT Value;
CONST CHAR *String;
} BAD_STRUCT, * PBAD_STRUCT;

#include <poppack.h>

#define BAD_INITIALIZER0 { 0, "BAD_STRING" },
#define BAD_INITIALIZER1 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0 \
BAD_INITIALIZER0

#define BAD_INITIALIZER2 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1 \
BAD_INITIALIZER1

#define BAD_INITIALIZER3 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2 \
BAD_INITIALIZER2

#define BAD_INITIALIZER4 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3 \
BAD_INITIALIZER3

BAD_STRUCT MayHaveStraddleRelocations[4096] = { // as a global variable
BAD_INITIALIZER4
};
There are other situations involving the use of assembler code, where this issue can also occur.
IAT in Executable Section The import address table (IAT), should not be an executable section of memory.

This issue occurs when the IAT, is located in a Read and Execute (RX) only section of memory. This means that the OS will not be able to write to the IAT to set the correct addresses for where the referenced DLL.

One way that this can occur is when using the /MERGE (Combine Sections) option in code linking. For example if .rdata (Read-only initialized data) is merged with .text data (Executable code), it is possible that the IAT may end up in an executable section of memory.

Which APIs are potentially affected?

The following list of APIs that are not reserved for system use may be impacted:
API name Description
ExAllocatePool https://msdn.microsoft.com/en-us/library/windows/hardware/ff544501(v=vs.85).aspx
ExAllocatePoolWithQuota https://msdn.microsoft.com/en-us/library/windows/hardware/ff544506(v=vs.85).aspx
ExAllocatePoolWithQuotaTag https://msdn.microsoft.com/en-us/library/windows/hardware/ff544513(v=vs.85).aspx
ExAllocatePoolWithTag https://msdn.microsoft.com/en-us/library/windows/hardware/ff544520(v=vs.85).aspx
ExAllocatePoolWithTagPriority https://msdn.microsoft.com/en-us/library/windows/hardware/ff544523(v=vs.85).aspx
ExInitializeNPagedLookasideList https://msdn.microsoft.com/en-us/library/windows/hardware/ff545301(v=vs.85).aspx
ExInitializeLookasideListEx https://msdn.microsoft.com/en-us/library/windows/hardware/ff545298(v=vs.85).aspx
MmAllocateContiguousMemory https://msdn.microsoft.com/en-us/library/windows/hardware/ff554460(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCache https://msdn.microsoft.com/en-us/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousMemorySpecifyCacheNode https://msdn.microsoft.com/en-us/library/windows/hardware/ff554464(v=vs.85).aspx
MmAllocateContiguousNodeMemory https://msdn.microsoft.com/en-us/library/windows/hardware/jj602795(v=vs.85).aspx
MmCopyMemory https://msdn.microsoft.com/en-us/library/windows/hardware/dn342884(v=vs.85).aspx
MmMapIoSpace https://msdn.microsoft.com/en-us/library/windows/hardware/ff554618(v=vs.85).aspx
MmMapLockedPages https://msdn.microsoft.com/en-us/library/windows/hardware/ff554622(v=vs.85).aspx
MmMapLockedPagesSpecifyCache https://msdn.microsoft.com/en-us/library/windows/hardware/ff554629(v=vs.85).aspx
MmProtectMdlSystemAddress https://msdn.microsoft.com/en-us/library/windows/hardware/ff554670(v=vs.85).aspx
ZwAllocateVirtualMemory https://msdn.microsoft.com/en-us/library/windows/hardware/ff566416(v=vs.85).aspx
ZwCreateSection https://msdn.microsoft.com/en-us/library/windows/hardware/ff566428(v=vs.85).aspx
ZwMapViewOfSection https://msdn.microsoft.com/en-us/library/windows/hardware/ff566481(v=vs.85).aspx
NtCreateSection https://msdn.microsoft.com/en-us/library/windows/hardware/ff556473(v=vs.85).aspx
NtMapViewOfSection https://msdn.microsoft.com/en-us/library/windows/hardware/ff556551(v=vs.85).aspx
StorPortGetDataInBufferSystemAddress https://msdn.microsoft.com/en-us/library/windows/hardware/jj553720(v=vs.85).aspx
StorPortGetSystemAddress https://msdn.microsoft.com/en-us/library/windows/hardware/ff567100(v=vs.85).aspx
DxgkCbMapMemory https://msdn.microsoft.com/en-us/library/windows/hardware/ff559533(v=vs.85).aspx
IMiniportDMus::NewStream https://msdn.microsoft.com/en-us/library/windows/hardware/ff536701(v=vs.85).aspx
FltAllocatePoolAlignedWithTag https://msdn.microsoft.com/en-us/library/windows/hardware/ff541762(v=vs.85).aspx
FltAllocateContext https://msdn.microsoft.com/en-us/library/windows/hardware/ff541710(v=vs.85).aspx
ChangerClassAllocatePool https://msdn.microsoft.com/en-us/library/windows/hardware/ff551402(v=vs.85).aspx
IMiniportMidi::NewStream https://msdn.microsoft.com/en-us/library/windows/hardware/ff536710(v=vs.85).aspx
IMiniportWaveCyclic::NewStream https://msdn.microsoft.com/en-us/library/windows/hardware/ff536723(v=vs.85).aspx
IPortWavePci::NewMasterDmaChannel https://msdn.microsoft.com/en-us/library/windows/hardware/ff536916(v=vs.85).aspx
IMiniportWavePci::NewStream https://msdn.microsoft.com/en-us/library/windows/hardware/ff536735(v=vs.85).aspx
PcNewDmaChannel https://msdn.microsoft.com/en-us/library/windows/hardware/ff537712(v=vs.85).aspx
PcNewResourceList https://msdn.microsoft.com/en-us/library/windows/hardware/ff537717(v=vs.85).aspx
PcNewResourceSublist https://msdn.microsoft.com/en-us/library/windows/hardware/ff537718(v=vs.85).aspx
VideoPortAllocatePool https://msdn.microsoft.com/en-us/library/windows/hardware/ff570180(v=vs.85).aspx
ClfsCreateMarshallingArea https://msdn.microsoft.com/en-us/library/windows/hardware/ff541520(v=vs.85).aspx
WdfLookasideListCreate https://msdn.microsoft.com/en-us/library/windows/hardware/ff548694(v=vs.85).aspx
WdfMemoryCreate https://msdn.microsoft.com/en-us/library/windows/hardware/ff548706(v=vs.85).aspx
WdfDeviceAllocAndQueryProperty https://msdn.microsoft.com/en-us/library/windows/hardware/ff545882(v=vs.85).aspx
WdfDeviceAllocAndQueryPropertyEx https://msdn.microsoft.com/en-us/library/windows/hardware/dn265599(v=vs.85).aspx
WdfFdoInitAllocAndQueryProperty https://msdn.microsoft.com/en-us/library/windows/hardware/ff547239(v=vs.85).aspx
WdfFdoInitAllocAndQueryPropertyEx https://msdn.microsoft.com/en-us/library/windows/hardware/dn265612(v=vs.85).aspx
WdfIoTargetAllocAndQueryTargetProperty https://msdn.microsoft.com/en-us/library/windows/hardware/ff548585(v=vs.85).aspx
WdfRegistryQueryMemory https://msdn.microsoft.com/en-us/library/windows/hardware/ff549920(v=vs.85).aspx
NdisAllocateMemory https://msdn.microsoft.com/en-us/library/windows/hardware/ff550762(v=vs.85).aspx

Version history
Last update:
‎Mar 12 2019 07:11 AM
Updated by: