|
[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.
Signed-off-by: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
---
include/xen.h | 8 --
src/xen/amd64/hypercall_thunk.asm | 101 +++++++++++-----
src/xen/driver.c | 33 +++---
src/xen/hypercall.c | 191 +++++++++++++++++-------------
src/xen/hypercall.h | 2 +-
src/xen/i386/hypercall_thunk.asm | 69 ++++++++---
src/xenbus/fdo.c | 2 -
src/xenbus/suspend.c | 2 -
8 files changed, 254 insertions(+), 154 deletions(-)
diff --git a/include/xen.h b/include/xen.h
index 8691a0f..0c3e8a4 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -76,14 +76,6 @@ XenTouch(
_In_ ULONG BuildNumber
);
-// HYPERCALL
-
-XEN_API
-VOID
-HypercallPopulate(
- VOID
- );
-
// HVM
_Check_return_
diff --git a/src/xen/amd64/hypercall_thunk.asm
b/src/xen/amd64/hypercall_thunk.asm
index af045bb..b32ee2e 100644
--- a/src/xen/amd64/hypercall_thunk.asm
+++ b/src/xen/amd64/hypercall_thunk.asm
@@ -3,39 +3,76 @@
.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 hypercall2(uint32_t ord,
uintptr_t arg1, uintptr_t arg2);
- public hypercall2
-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
-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 hypercall3(uint32_t ord,
uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
- public hypercall3
-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
-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
+
+ ; 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/xen/driver.c b/src/xen/driver.c
index 7b2621b..0bed6d1 100644
--- a/src/xen/driver.c
+++ b/src/xen/driver.c
@@ -621,31 +621,33 @@ DllInitialize(
__DriverSetMemoryKey(MemoryKey);
- HypercallInitialize();
+ status = HypercallInitialize();
+ if (!NT_SUCCESS(status))
+ goto fail8;
status = AcpiInitialize();
if (!NT_SUCCESS(status))
- goto fail8;
+ goto fail9;
status = SystemInitialize();
if (!NT_SUCCESS(status))
- goto fail9;
+ goto fail10;
status = BugCheckInitialize();
if (!NT_SUCCESS(status))
- goto fail10;
+ goto fail11;
status = ModuleInitialize();
if (!NT_SUCCESS(status))
- goto fail11;
+ goto fail12;
status = ProcessInitialize();
if (!NT_SUCCESS(status))
- goto fail12;
+ goto fail13;
status = UnplugInitialize();
if (!NT_SUCCESS(status))
- goto fail13;
+ goto fail14;
RegistryCloseKey(ServiceKey);
@@ -653,36 +655,39 @@ DllInitialize(
return STATUS_SUCCESS;
+fail14:
+ Error("fail14\n");
+
+ ProcessTeardown();
+
fail13:
Error("fail13\n");
- ProcessTeardown();
+ ModuleTeardown();
fail12:
Error("fail12\n");
- ModuleTeardown();
+ BugCheckTeardown();
fail11:
Error("fail11\n");
- BugCheckTeardown();
+ SystemTeardown();
fail10:
Error("fail10\n");
- SystemTeardown();
+ AcpiTeardown();
fail9:
Error("fail9\n");
- AcpiTeardown();
+ HypercallTeardown();
fail8:
Error("fail8\n");
- HypercallTeardown();
-
RegistryCloseKey(MemoryKey);
__DriverSetMemoryKey(NULL);
diff --git a/src/xen/hypercall.c b/src/xen/hypercall.c
index 911ae4f..3c68709 100644
--- a/src/xen/hypercall.c
+++ b/src/xen/hypercall.c
@@ -30,9 +30,6 @@
* SUCH DAMAGE.
*/
-#undef XEN_API
-#define XEN_API __declspec(dllexport)
-
#include <ntddk.h>
#include <xen.h>
#include <intrin.h>
@@ -42,55 +39,63 @@
#include "assert.h"
#include "util.h"
-#define MAXIMUM_HYPERCALL_PAGE_COUNT 2
-
-#pragma code_seg("hypercall")
-__declspec(allocate("hypercall"))
-static UCHAR __Section[(MAXIMUM_HYPERCALL_PAGE_COUNT + 1) * PAGE_SIZE];
-
-static ULONG XenBaseLeaf = 0x40000000;
-
-static PHYSICAL_ADDRESS HypercallPage[MAXIMUM_HYPERCALL_PAGE_COUNT];
-static ULONG HypercallPageCount;
-static BOOLEAN HypercallPageInitialized;
-
-typedef UCHAR HYPERCALL_GATE[32];
-typedef HYPERCALL_GATE *PHYPERCALL_GATE;
-
-PHYPERCALL_GATE Hypercall;
-ULONG HypercallMsr;
-
-XEN_API
-VOID
-HypercallPopulate(
- VOID
- )
-{
- ULONG Index;
-
- for (Index = 0; Index < HypercallPageCount; Index++) {
- LogPrintf(LOG_LEVEL_INFO,
- "XEN: HYPERCALL PAGE %d @ %08x.%08x\n",
- Index,
- HypercallPage[Index].HighPart,
- HypercallPage[Index].LowPart);
-
- __writemsr(HypercallMsr, HypercallPage[Index].QuadPart);
- }
-
- HypercallPageInitialized = TRUE;
-}
-
-VOID
+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;
+
+NTSTATUS
HypercallInitialize(
VOID
)
{
- ULONG EAX = 'DEAD';
- ULONG EBX = 'DEAD';
- ULONG ECX = 'DEAD';
- ULONG EDX = 'DEAD';
- ULONG_PTR Index;
+ 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};
@@ -103,13 +108,13 @@ HypercallInitialize(
if (strcmp(Signature, "XenVMMXenVMM") == 0 &&
EAX >= XenBaseLeaf + 2)
break;
-
+
XenBaseLeaf += 0x100;
-
+
if (XenBaseLeaf > 0x40000100) {
LogPrintf(LOG_LEVEL_INFO,
"XEN: BASE CPUID LEAF NOT FOUND\n");
- return;
+ return STATUS_NOT_SUPPORTED;
}
}
@@ -117,27 +122,46 @@ HypercallInitialize(
"XEN: BASE CPUID LEAF @ %08x\n",
XenBaseLeaf);
- if ((ULONG_PTR)__Section & (PAGE_SIZE - 1))
- Hypercall = (PVOID)(((ULONG_PTR)__Section + PAGE_SIZE - 1) &
~(PAGE_SIZE - 1));
- else
- Hypercall = (PVOID)__Section;
-
- ASSERT3U(((ULONG_PTR)Hypercall & (PAGE_SIZE - 1)), ==, 0);
+ __CpuId(0, &EAX, &EBX, &ECX, &EDX);
+ for (Index = 0; Index < ARRAYSIZE(HypercallVendorData); Index++) {
+ const CPU_VENDOR_DATA *CurrentData = &HypercallVendorData[Index];
- for (Index = 0; Index < MAXIMUM_HYPERCALL_PAGE_COUNT; Index++)
- HypercallPage[Index] = MmGetPhysicalAddress((PUCHAR)Hypercall +
- (Index << PAGE_SHIFT));
+ if (EBX == CurrentData->EBX &&
+ ECX == CurrentData->ECX &&
+ EDX == CurrentData->EDX) {
+ Instruction = CurrentData->Instruction;
+ break;
+ }
+ }
- __CpuId(XenBaseLeaf + 2, &EAX, &EBX, NULL, NULL);
- HypercallPageCount = EAX;
- ASSERT(HypercallPageCount <= MAXIMUM_HYPERCALL_PAGE_COUNT);
- HypercallMsr = EBX;
+ if (Instruction == HYPERCALL_INSTRUCTION_UNKNOWN) {
+ LogPrintf(LOG_LEVEL_INFO,
+ "XEN: CANNOT DETECT HYPERCALL INSTRUCTION\n");
+ return STATUS_NOT_SUPPORTED;
+ }
- HypercallPopulate();
+ HypercallInstruction = Instruction;
+ return STATUS_SUCCESS;
}
-extern uintptr_t __stdcall hypercall2(uint32_t ord, uintptr_t arg1, uintptr_t
arg2);
-extern uintptr_t __stdcall hypercall3(uint32_t ord, uintptr_t arg1, uintptr_t
arg2, uintptr_t arg3);
+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);
LONG_PTR
__Hypercall(
@@ -149,9 +173,6 @@ __Hypercall(
va_list Arguments;
ULONG_PTR Value;
- if (!HypercallPageInitialized)
- return -ENOSYS;
-
va_start(Arguments, Count);
switch (Count) {
case 2: {
@@ -159,7 +180,16 @@ __Hypercall(
uintptr_t arg1 = va_arg(Arguments, ULONG_PTR);
uintptr_t arg2 = va_arg(Arguments, ULONG_PTR);
- Value = hypercall2(ord, arg1, arg2);
+ switch (HypercallInstruction) {
+ case HYPERCALL_INSTRUCTION_VMCALL:
+ Value = hypercall2_vmcall(ord, arg1, arg2);
+ break;
+ case HYPERCALL_INSTRUCTION_VMMCALL:
+ Value = hypercall2_vmmcall(ord, arg1, arg2);
+ break;
+ default:
+ BUG("NO HYPERCALL INSTRUCTION");
+ }
break;
}
case 3: {
@@ -168,7 +198,16 @@ __Hypercall(
uintptr_t arg2 = va_arg(Arguments, ULONG_PTR);
uintptr_t arg3 = va_arg(Arguments, ULONG_PTR);
- Value = hypercall3(ord, arg1, arg2, arg3);
+ switch (HypercallInstruction) {
+ case HYPERCALL_INSTRUCTION_VMCALL:
+ Value = hypercall3_vmcall(ord, arg1, arg2, arg3);
+ break;
+ case HYPERCALL_INSTRUCTION_VMMCALL:
+ Value = hypercall3_vmmcall(ord, arg1, arg2, arg3);
+ break;
+ default:
+ BUG("NO HYPERCALL INSTRUCTION");
+ }
break;
}
default:
@@ -185,12 +224,4 @@ HypercallTeardown(
VOID
)
{
- ULONG Index;
-
- Hypercall = NULL;
-
- for (Index = 0; Index < MAXIMUM_HYPERCALL_PAGE_COUNT; Index++)
- HypercallPage[Index].QuadPart = 0;
-
- HypercallPageCount = 0;
}
diff --git a/src/xen/hypercall.h b/src/xen/hypercall.h
index 306d9ab..6f4c7e0 100644
--- a/src/xen/hypercall.h
+++ b/src/xen/hypercall.h
@@ -40,7 +40,7 @@
#include <public/xen.h>
-extern VOID
+extern NTSTATUS
HypercallInitialize(
VOID
);
diff --git a/src/xen/i386/hypercall_thunk.asm b/src/xen/i386/hypercall_thunk.asm
index a15ae27..be68db3 100644
--- a/src/xen/i386/hypercall_thunk.asm
+++ b/src/xen/i386/hypercall_thunk.asm
@@ -5,28 +5,69 @@
.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 hypercall2(uint32_t ord,
uintptr_t arg1, uintptr_t arg2);
- public _hypercall2@12
-_hypercall2@12 proc
+ ; 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
- shl eax, 5
- add eax, dword ptr [_Hypercall]
- call eax
+ vmmcall
pop ebx
leave
ret 0Ch
-_hypercall2@12 endp
+_hypercall2_vmmcall@12 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
- ; uintptr_t __stdcall hypercall3(uint32_t ord,
uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
- public _hypercall3@16
-_hypercall3@16 proc
+ ; 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
@@ -34,12 +75,10 @@ _hypercall3@16 proc
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
+ vmmcall
pop ebx
leave
ret 10h
-_hypercall3@16 endp
+_hypercall3_vmmcall@16 endp
end
diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index 8695a56..a5a0ca1 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -3831,8 +3831,6 @@ FdoS4ToS3(
LogResume();
- HypercallPopulate();
-
UnplugDevices();
not_active:
diff --git a/src/xenbus/suspend.c b/src/xenbus/suspend.c
index cd292c0..687f86c 100644
--- a/src/xenbus/suspend.c
+++ b/src/xenbus/suspend.c
@@ -205,8 +205,6 @@ SuspendEarly(
if (Cpu != 0)
return;
- HypercallPopulate();
-
UnplugDevices();
for (ListEntry = Context->EarlyList.Flink;
--
2.51.2.windows.1
--
Ngoc Tu Dinh | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |