|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] Use direct hypercall instead of hypercall page
XSA-466 "Xen hypercall page unsafe against speculative attacks"
recommends that OSes avoid using the hypercall page, since that breaks
the use of return thunks and CET IBT.
While Windows doesn't support return thunks or CET IBT, the current
hypercall code uses a naked indirect call to call into the hypercall
page. This call is not protected by Windows CFG, and cannot be patched
by Windows's Retpoline implementation.
Convert the hypercall code to detect CPU vendor and use the appropriate
hypercall instructions.
Ported from xenbus 2635e7c08ee8df3e3c1be427926a53fe1b345c96
by Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
src/xencrsh/amd64/hypercall.asm | 109 ++++++++++++------
src/xencrsh/hvm.c | 120 +-------------------
src/xencrsh/hypercall.h | 6 +-
src/xencrsh/hypercall_stub.c | 189 +++++++++++++++++++++++++++++++-
src/xencrsh/i386/hypercall.asm | 119 +++++++++++++-------
5 files changed, 341 insertions(+), 202 deletions(-)
diff --git a/src/xencrsh/amd64/hypercall.asm b/src/xencrsh/amd64/hypercall.asm
index 1ceda85..de430e7 100644
--- a/src/xencrsh/amd64/hypercall.asm
+++ b/src/xencrsh/amd64/hypercall.asm
@@ -1,41 +1,78 @@
- page ,132
- title Hypercall Gates
+ page ,132
+ title Hypercall Thunks
- .code
+ .code
- extrn Hypercall:qword
+ ; uintptr_t __stdcall hypercall2_vmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2);
+ public hypercall2_vmcall
+hypercall2_vmcall proc
+ push rdi
+ push rsi
+ mov eax, ecx ; ord
+ mov rdi, rdx ; arg1
+ mov rsi, r8 ; arg2
+ vmcall
+ pop rsi
+ pop rdi
+ ret
+hypercall2_vmcall endp
- ; uintptr_t __stdcall asm___hypercall2(uint32_t ord, uintptr_t
arg1, uintptr_t arg2);
- public asm___hypercall2
-asm___hypercall2 proc
- push rdi
- push rsi
- mov rdi, rdx ; arg1
- mov rax, qword ptr [Hypercall]
- shl rcx, 5 ; ord
- add rax, rcx
- mov rsi, r8 ; arg2
- call rax
- pop rsi
- pop rdi
- ret
-asm___hypercall2 endp
+ ; uintptr_t __stdcall hypercall2_vmmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2);
+ public hypercall2_vmmcall
+hypercall2_vmmcall proc
+ push rdi
+ push rsi
+ mov eax, ecx ; ord
+ mov rdi, rdx ; arg1
+ mov rsi, r8 ; arg2
+ vmmcall
+ pop rsi
+ pop rdi
+ ret
+hypercall2_vmmcall endp
- ; uintptr_t __stdcall asm___hypercall3(uint32_t ord, uintptr_t
arg1, uintptr_t arg2, uintptr_t arg3);
- public asm___hypercall3
-asm___hypercall3 proc
- push rdi
- push rsi
- mov rdi, rdx ; arg1
- mov rax, qword ptr [Hypercall]
- shl rcx, 5 ; ord
- add rax, rcx
- mov rsi, r8 ; arg2
- mov rdx, r9 ; arg3
- call rax
- pop rsi
- pop rdi
- ret
-asm___hypercall3 endp
+ ; uintptr_t __stdcall hypercall3_vmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2,
+ ; uintptr_t arg3);
+ public hypercall3_vmcall
+hypercall3_vmcall proc
+ push rdi
+ push rsi
+ mov eax, ecx ; ord
+ mov rdi, rdx ; arg1
+ mov rsi, r8 ; arg2
+ mov rdx, r9 ; arg3
+ vmcall
+ pop rsi
+ pop rdi
+ ret
+hypercall3_vmcall endp
- end
+ ; uintptr_t __stdcall hypercall3_vmmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2,
+ ; uintptr_t arg3);
+ public hypercall3_vmmcall
+hypercall3_vmmcall proc
+ push rdi
+ push rsi
+ mov eax, ecx ; ord
+ mov rdi, rdx ; arg1
+ mov rsi, r8 ; arg2
+ mov rdx, r9 ; arg3
+ vmmcall
+ pop rsi
+ pop rdi
+ ret
+hypercall3_vmmcall endp
+
+ end
diff --git a/src/xencrsh/hvm.c b/src/xencrsh/hvm.c
index 04da4e3..82230ef 100644
--- a/src/xencrsh/hvm.c
+++ b/src/xencrsh/hvm.c
@@ -50,22 +50,6 @@
#include "log.h"
#include "assert.h"
-#define MAXIMUM_HYPERCALL_PFN_COUNT 2
-
-#pragma code_seg("hypercall")
-__declspec(allocate("hypercall"))
-static UCHAR __HypercallSection[(MAXIMUM_HYPERCALL_PFN_COUNT + 1) *
PAGE_SIZE];
-
-#define XEN_SIGNATURE "XenVMMXenVMM"
-
-static ULONG __BaseLeaf = 0x40000000;
-static USHORT __MajorVersion;
-static USHORT __MinorVersion;
-static PFN_NUMBER __Pfn[MAXIMUM_HYPERCALL_PFN_COUNT];
-static ULONG __PfnCount;
-
-PHYPERCALL_GATE Hypercall;
-
//#pragma code_seg("sharedinfo")
//__declspec(allocate("sharedinfo"))
//static UCHAR __SharedInfoSection[(1 + 1) * PAGE_SIZE];
@@ -95,102 +79,6 @@ fail:
return Status;
}
-static FORCEINLINE VOID
-CpuId(
- IN ULONG Leaf,
- OUT PULONG EAX OPTIONAL,
- OUT PULONG EBX OPTIONAL,
- OUT PULONG ECX OPTIONAL,
- OUT PULONG EDX OPTIONAL
- )
-{
- int Value[4] = {0};
-
- __cpuid(Value, Leaf);
-
- if (EAX)
- *EAX = (ULONG)Value[0];
-
- if (EBX)
- *EBX = (ULONG)Value[1];
-
- if (ECX)
- *ECX = (ULONG)Value[2];
-
- if (EDX)
- *EDX = (ULONG)Value[3];
-}
-
-static FORCEINLINE NTSTATUS
-__InitHypercallPage()
-{
- ULONG eax = 'DEAD';
- ULONG ebx = 'DEAD';
- ULONG ecx = 'DEAD';
- ULONG edx = 'DEAD';
- ULONG_PTR Index;
- ULONG HypercallMsr;
-
- NTSTATUS Status;
-
- Status = STATUS_UNSUCCESSFUL;
- for (;;) {
- CHAR Signature[13] = { 0 };
-
- CpuId(__BaseLeaf, &eax, &ebx, &ecx, &edx);
- *((PULONG)(Signature + 0)) = ebx;
- *((PULONG)(Signature + 4)) = ecx;
- *((PULONG)(Signature + 8)) = edx;
-
- if (strcmp(Signature, XEN_SIGNATURE) == 0 &&
- eax >= __BaseLeaf + 2)
- break;
-
- __BaseLeaf += 0x100;
-
- if (__BaseLeaf > 0x40000100)
- goto fail1;
- }
-
- CpuId(__BaseLeaf + 1, &eax, NULL, NULL, NULL);
- __MajorVersion = (USHORT)(eax >> 16);
- __MinorVersion = (USHORT)(eax & 0xFFFF);
-
- LogVerbose("XEN %d.%d\n", __MajorVersion, __MinorVersion);
- LogVerbose("INTERFACE 0x%08x\n", __XEN_INTERFACE_VERSION__);
-
- if ((ULONG_PTR)__HypercallSection & (PAGE_SIZE - 1))
- Hypercall = (PVOID)(((ULONG_PTR)__HypercallSection + PAGE_SIZE - 1) &
~(PAGE_SIZE - 1));
- else
- Hypercall = (PVOID)__HypercallSection;
-
- ASSERT3U(((ULONG_PTR)Hypercall & (PAGE_SIZE - 1)), ==, 0);
-
- for (Index = 0; Index < MAXIMUM_HYPERCALL_PFN_COUNT; Index++) {
- PHYSICAL_ADDRESS PhysicalAddress;
-
- PhysicalAddress = MmGetPhysicalAddress((PUCHAR)Hypercall + (Index <<
PAGE_SHIFT));
- __Pfn[Index] = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
- }
-
- CpuId(__BaseLeaf + 2, &eax, &ebx, NULL, NULL);
- __PfnCount = eax;
- ASSERT(__PfnCount <= MAXIMUM_HYPERCALL_PFN_COUNT);
- HypercallMsr = ebx;
-
- for (Index = 0; Index < __PfnCount; Index++) {
- LogVerbose("HypercallPfn[%d]: %p\n", Index, (PVOID)__Pfn[Index]);
- __writemsr(HypercallMsr, (ULONG64)__Pfn[Index] << PAGE_SHIFT);
- }
-
- return STATUS_SUCCESS;
-
-fail1:
- LogError("fail1 (%08x)", Status);
-
- return Status;
-}
-
//static NTSTATUS
//__InitSharedInfo()
//{
@@ -235,7 +123,7 @@ HvmInitialize()
{
NTSTATUS Status;
- Status = __InitHypercallPage();
+ Status = HypercallInitialize();
if (!NT_SUCCESS(Status))
goto fail;
@@ -258,12 +146,6 @@ fail:
VOID
HvmTerminate()
{
- ULONG Index;
-
- Hypercall = NULL;
- for (Index = 0; Index < MAXIMUM_HYPERCALL_PFN_COUNT; ++Index) {
- __Pfn[Index] = 0;
- }
//SharedInfo = NULL;
}
diff --git a/src/xencrsh/hypercall.h b/src/xencrsh/hypercall.h
index 762ecf8..6b055fa 100644
--- a/src/xencrsh/hypercall.h
+++ b/src/xencrsh/hypercall.h
@@ -35,8 +35,10 @@
#include "driver.h"
-typedef UCHAR HYPERCALL_GATE[32];
-typedef HYPERCALL_GATE *PHYPERCALL_GATE;
+extern NTSTATUS
+HypercallInitialize(
+ VOID
+ );
extern ULONG_PTR
___Hypercall2(
diff --git a/src/xencrsh/hypercall_stub.c b/src/xencrsh/hypercall_stub.c
index 1741850..7339c88 100644
--- a/src/xencrsh/hypercall_stub.c
+++ b/src/xencrsh/hypercall_stub.c
@@ -39,9 +39,157 @@
#include <xen-types.h>
+#include "log.h"
+#include "assert.h"
+
#include "hypercall.h"
-extern uintptr_t __stdcall asm___hypercall2(uint32_t ord, uintptr_t arg1,
uintptr_t arg2);
+typedef enum _HYPERCALL_INSTRUCTION {
+ HYPERCALL_INSTRUCTION_UNKNOWN,
+ HYPERCALL_INSTRUCTION_VMCALL,
+ HYPERCALL_INSTRUCTION_VMMCALL,
+} HYPERCALL_INSTRUCTION;
+
+typedef struct _CPU_VENDOR_DATA {
+ ULONG EBX;
+ ULONG ECX;
+ ULONG EDX;
+ HYPERCALL_INSTRUCTION Instruction;
+} CPU_VENDOR_DATA;
+
+static const CPU_VENDOR_DATA HypercallVendorData[] = {
+ // Note that the vendor data goes EBX-ECX-EDX
+ {
+ // "GenuineIntel"
+ 0x756E6547, 0x6C65746E, 0x49656E69,
+ HYPERCALL_INSTRUCTION_VMCALL
+ },
+ {
+ // "AuthenticAMD"
+ 0x68747541, 0x444D4163, 0x69746E65,
+ HYPERCALL_INSTRUCTION_VMMCALL
+ },
+ {
+ // "CentaurHauls"
+ 0x746E6543, 0x736C7561, 0x48727561,
+ HYPERCALL_INSTRUCTION_VMCALL
+ },
+ {
+ // " Shanghai "
+ 0x68532020, 0x20206961, 0x68676E61,
+ HYPERCALL_INSTRUCTION_VMCALL
+ },
+ {
+ // "HygonGenuine"
+ 0x6F677948, 0x656E6975, 0x6E65476E,
+ HYPERCALL_INSTRUCTION_VMMCALL
+ },
+};
+
+static HYPERCALL_INSTRUCTION HypercallInstruction
+ = HYPERCALL_INSTRUCTION_UNKNOWN;
+
+static FORCEINLINE VOID
+__CpuId(
+ IN ULONG Leaf,
+ OUT PULONG EAX OPTIONAL,
+ OUT PULONG EBX OPTIONAL,
+ OUT PULONG ECX OPTIONAL,
+ OUT PULONG EDX OPTIONAL
+ )
+{
+ int Value[4] = {0};
+
+ __cpuid(Value, Leaf);
+
+ if (EAX)
+ *EAX = (ULONG)Value[0];
+
+ if (EBX)
+ *EBX = (ULONG)Value[1];
+
+ if (ECX)
+ *ECX = (ULONG)Value[2];
+
+ if (EDX)
+ *EDX = (ULONG)Value[3];
+}
+
+NTSTATUS
+HypercallInitialize(
+ VOID
+ )
+{
+ ULONG XenBaseLeaf = 0x40000000;
+ ULONG EAX = 'DEAD';
+ ULONG EBX = 'DEAD';
+ ULONG ECX = 'DEAD';
+ ULONG EDX = 'DEAD';
+ HYPERCALL_INSTRUCTION Instruction = HYPERCALL_INSTRUCTION_UNKNOWN;
+ ULONG Index;
+
+ for (;;) {
+ CHAR Signature[13] = {0};
+
+ __CpuId(XenBaseLeaf, &EAX, &EBX, &ECX, &EDX);
+ *((PULONG)(Signature + 0)) = EBX;
+ *((PULONG)(Signature + 4)) = ECX;
+ *((PULONG)(Signature + 8)) = EDX;
+
+ if (strcmp(Signature, "XenVMMXenVMM") == 0 &&
+ EAX >= XenBaseLeaf + 2)
+ break;
+
+ XenBaseLeaf += 0x100;
+
+ if (XenBaseLeaf > 0x40000100) {
+ LogVerbose("XEN: BASE CPUID LEAF NOT FOUND\n");
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ LogVerbose("XEN: BASE CPUID LEAF @ %08x\n",
+ XenBaseLeaf);
+
+ __CpuId(0, &EAX, &EBX, &ECX, &EDX);
+ for (Index = 0; Index < ARRAYSIZE(HypercallVendorData); Index++) {
+ const CPU_VENDOR_DATA *CurrentData = &HypercallVendorData[Index];
+
+ if (EBX == CurrentData->EBX &&
+ ECX == CurrentData->ECX &&
+ EDX == CurrentData->EDX) {
+ Instruction = CurrentData->Instruction;
+ break;
+ }
+ }
+
+ if (Instruction == HYPERCALL_INSTRUCTION_UNKNOWN) {
+ LogVerbose("XEN: CANNOT DETECT HYPERCALL INSTRUCTION\n");
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ HypercallInstruction = Instruction;
+ return STATUS_SUCCESS;
+}
+
+extern uintptr_t __stdcall hypercall2_vmcall(
+ uint32_t ord,
+ uintptr_t arg1,
+ uintptr_t arg2);
+extern uintptr_t __stdcall hypercall2_vmmcall(
+ uint32_t ord,
+ uintptr_t arg1,
+ uintptr_t arg2);
+extern uintptr_t __stdcall hypercall3_vmcall(
+ uint32_t ord,
+ uintptr_t arg1,
+ uintptr_t arg2,
+ uintptr_t arg3);
+extern uintptr_t __stdcall hypercall3_vmmcall(
+ uint32_t ord,
+ uintptr_t arg1,
+ uintptr_t arg2,
+ uintptr_t arg3);
ULONG_PTR
___Hypercall2(
@@ -50,10 +198,24 @@ ___Hypercall2(
ULONG_PTR Argument2
)
{
- return asm___hypercall2(Ordinal, Argument1, Argument2);
-}
+ ULONG_PTR Value;
-extern uintptr_t __stdcall asm___hypercall3(uint32_t ord, uintptr_t arg1,
uintptr_t arg2, uintptr_t arg3);
+ switch (HypercallInstruction) {
+ case HYPERCALL_INSTRUCTION_VMCALL:
+ Value = hypercall2_vmcall(Ordinal, Argument1, Argument2);
+ break;
+
+ case HYPERCALL_INSTRUCTION_VMMCALL:
+ Value = hypercall2_vmmcall(Ordinal, Argument1, Argument2);
+ break;
+
+ default:
+ Value = 0;
+ BUG("NO HYPERCALL INSTRUCTION");
+ }
+
+ return Value;
+}
ULONG_PTR
___Hypercall3(
@@ -63,5 +225,22 @@ ___Hypercall3(
ULONG_PTR Argument3
)
{
- return asm___hypercall3(Ordinal, Argument1, Argument2, Argument3);
+ ULONG_PTR Value;
+
+ switch (HypercallInstruction) {
+ case HYPERCALL_INSTRUCTION_VMCALL:
+ Value = hypercall3_vmcall(Ordinal, Argument1, Argument2, Argument3);
+ break;
+
+ case HYPERCALL_INSTRUCTION_VMMCALL:
+ Value = hypercall3_vmmcall(Ordinal, Argument1, Argument2, Argument3);
+ break;
+
+ default:
+ Value = 0;
+ BUG("NO HYPERCALL INSTRUCTION");
+ }
+
+ return Value;
+
}
diff --git a/src/xencrsh/i386/hypercall.asm b/src/xencrsh/i386/hypercall.asm
index 51094be..be68db3 100644
--- a/src/xencrsh/i386/hypercall.asm
+++ b/src/xencrsh/i386/hypercall.asm
@@ -1,45 +1,84 @@
- page ,132
- title Hypercall Gates
+ page ,132
+ title Hypercall Thunks
- .686p
- .model FLAT
- .code
+ .686p
+ .model FLAT
+ .code
- extrn _Hypercall:dword
+ ; uintptr_t __stdcall hypercall2_vmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2);
+ public _hypercall2_vmcall@12
+_hypercall2_vmcall@12 proc
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov eax, [ebp + 08h] ; ord
+ mov ebx, [ebp + 0ch] ; arg1
+ mov ecx, [ebp + 10h] ; arg2
+ vmcall
+ pop ebx
+ leave
+ ret 0Ch
+_hypercall2_vmcall@12 endp
- ; uintptr_t __stdcall asm___hypercall2(uint32_t ord, uintptr_t
arg1, uintptr_t arg2);
- public _asm___hypercall2@12
-_asm___hypercall2@12 proc
- push ebp
- mov ebp, esp
- push ebx
- mov eax, [ebp + 08h] ; ord
- mov ebx, [ebp + 0ch] ; arg1
- mov ecx, [ebp + 10h] ; arg2
- shl eax, 5
- add eax, dword ptr [_Hypercall]
- call eax
- pop ebx
- leave
- ret 0Ch
-_asm___hypercall2@12 endp
+ ; uintptr_t __stdcall hypercall2_vmmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2);
+ public _hypercall2_vmmcall@12
+_hypercall2_vmmcall@12 proc
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov eax, [ebp + 08h] ; ord
+ mov ebx, [ebp + 0ch] ; arg1
+ mov ecx, [ebp + 10h] ; arg2
+ vmmcall
+ pop ebx
+ leave
+ ret 0Ch
+_hypercall2_vmmcall@12 endp
- ; uintptr_t __stdcall asm___hypercall3(uint32_t ord, uintptr_t
arg1, uintptr_t arg2, uintptr_t arg3);
- public _asm___hypercall3@16
-_asm___hypercall3@16 proc
- push ebp
- mov ebp, esp
- push ebx
- mov eax, [ebp + 08h] ; ord
- mov ebx, [ebp + 0ch] ; arg1
- mov ecx, [ebp + 10h] ; arg2
- mov edx, [ebp + 14h] ; arg3
- shl eax, 5
- add eax, dword ptr [_Hypercall]
- call eax
- pop ebx
- leave
- ret 10h
-_asm___hypercall3@16 endp
+ ; uintptr_t __stdcall hypercall3_vmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2,
+ ; uintptr_t arg3);
+ public _hypercall3_vmcall@16
+_hypercall3_vmcall@16 proc
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov eax, [ebp + 08h] ; ord
+ mov ebx, [ebp + 0ch] ; arg1
+ mov ecx, [ebp + 10h] ; arg2
+ mov edx, [ebp + 14h] ; arg3
+ vmcall
+ pop ebx
+ leave
+ ret 10h
+_hypercall3_vmcall@16 endp
- end
+ ; uintptr_t __stdcall hypercall3_vmmcall(
+ ; uint32_t ord,
+ ; uintptr_t arg1,
+ ; uintptr_t arg2,
+ ; uintptr_t arg3);
+ public _hypercall3_vmmcall@16
+_hypercall3_vmmcall@16 proc
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov eax, [ebp + 08h] ; ord
+ mov ebx, [ebp + 0ch] ; arg1
+ mov ecx, [ebp + 10h] ; arg2
+ mov edx, [ebp + 14h] ; arg3
+ vmmcall
+ pop ebx
+ leave
+ ret 10h
+_hypercall3_vmmcall@16 endp
+
+ end
--
2.51.2.windows.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |