x86_64 Linux: Add fallback for CPUs without RDFSBASE/WRFSBASE

This commit is contained in:
2025-11-10 00:22:56 -07:00
parent 76f97efe07
commit 2494b541b7
5 changed files with 71 additions and 9 deletions

View File

@@ -64,6 +64,52 @@ m1632:
endbr64 endbr64
.endm .endm
.macro READ_FSBASE out_reg teb_reg
push rax
movzx rax, byte ptr [\teb_reg+TEB_HAS_FSGSBASE]
test rax, rax
jz 1f
rdfsbase \out_reg
jmp 2f
1:
push rdi
push rsi
push rcx
sub rsp, 8
mov rsi, rsp # addr
mov rdi, 0x1003 # ARCH_GET_FS
mov rax, 158 # SYS_arch_prctl
syscall
pop \out_reg
pop rcx
pop rsi
pop rdi
2:
pop rax
.endm
.macro WRITE_FSBASE in_reg teb_reg
push rax
movzx rax, byte ptr [\teb_reg+TEB_HAS_FSGSBASE]
test rax, rax
jz 1f
wrfsbase \in_reg
jmp 2f
1:
push rdi
push rsi
push rcx
mov rsi, \in_reg # addr
mov rdi, 0x1002 # ARCH_SET_FS
mov rax, 158 # SYS_arch_prctl
syscall
pop rcx
pop rsi
pop rdi
2:
pop rax
.endm
#endif // __x86_64__ #endif // __x86_64__
.macro GET_TEB_HOST reg .macro GET_TEB_HOST reg

View File

@@ -12,11 +12,12 @@
#ifdef __x86_64__ #ifdef __x86_64__
#define TEB_CS_SEL 0xf9c // CodeSelector #define TEB_CS_SEL 0xf9c // CodeSelector
#define TEB_DS_SEL 0xf9e // DataSelector #define TEB_DS_SEL 0xf9e // DataSelector
#define TEB_SP 0xfa0 // CurrentStackPointer #define TEB_SP 0xfa0 // CurrentStackPointer
#define TEB_FSBASE 0xfa8 // HostFsBase #define TEB_FSBASE 0xfa8 // HostFsBase
#define TEB_GSBASE 0xfb0 // HostGsBase #define TEB_GSBASE 0xfb0 // HostGsBase
#define TEB_HAS_FSGSBASE 0xfb8 // HasFsGsBase
#ifdef __linux__ #ifdef __linux__
#define CS_32 0x23 // 32-bit code segment (Linux) #define CS_32 0x23 // 32-bit code segment (Linux)

View File

@@ -11,14 +11,16 @@ namespace {
std::mutex g_tebSetupMutex; std::mutex g_tebSetupMutex;
int g_entryNumber = -1; int g_entryNumber = -1;
} // namespace
constexpr uint16_t createSelector(int entryNumber) { constexpr uint16_t createSelector(int entryNumber) {
return static_cast<uint16_t>((entryNumber << 3) | USER_PRIVILEGE); return static_cast<uint16_t>((entryNumber << 3) | USER_PRIVILEGE);
} }
} // namespace
#if defined(__x86_64__) #if defined(__x86_64__)
#include <cpuid.h>
// Implemented in setup.S // Implemented in setup.S
extern "C" int tebThreadSetup64(int entryNumber, TEB *teb); extern "C" int tebThreadSetup64(int entryNumber, TEB *teb);
@@ -37,6 +39,15 @@ bool tebThreadSetup(TEB *teb) {
teb->CurrentFsSelector = createSelector(ret); teb->CurrentFsSelector = createSelector(ret);
teb->CurrentGsSelector = 0; teb->CurrentGsSelector = 0;
// Check for FSBASE/GSBASE instruction support
unsigned int regs[4];
int cpuidMax = __get_cpuid_max(0, nullptr);
if (cpuidMax >= 0x7 && __get_cpuid_count(0x7, 0, &regs[0], &regs[1], &regs[2], &regs[3])) {
teb->HasFsGsBase = !!(regs[1] & 1);
}
DEBUG_LOG("setup_linux: FSBASE/GSBASE instruction support: %s\n", teb->HasFsGsBase ? "yes" : "no");
return true; return true;
} }

View File

@@ -549,6 +549,7 @@ typedef struct _TEB {
#ifdef __x86_64__ #ifdef __x86_64__
void *HostFsBase; void *HostFsBase;
void *HostGsBase; void *HostGsBase;
bool HasFsGsBase;
#endif #endif
} TEB; } TEB;
typedef GUEST_PTR PTEB; typedef GUEST_PTR PTEB;
@@ -575,6 +576,9 @@ static_assert(offsetof(TEB, HostFsBase) == TEB_FSBASE);
#ifdef TEB_GSBASE #ifdef TEB_GSBASE
static_assert(offsetof(TEB, HostGsBase) == TEB_GSBASE); static_assert(offsetof(TEB, HostGsBase) == TEB_GSBASE);
#endif #endif
#ifdef TEB_HAS_FSGSBASE
static_assert(offsetof(TEB, HasFsGsBase) == TEB_HAS_FSGSBASE);
#endif
typedef struct _MEMORY_BASIC_INFORMATION { typedef struct _MEMORY_BASIC_INFORMATION {
GUEST_PTR BaseAddress; GUEST_PTR BaseAddress;

View File

@@ -721,7 +721,7 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
if sys.platform != "darwin": if sys.platform != "darwin":
# Save FS base # Save FS base
lines.append("\trdfsbase r9") lines.append("\tREAD_FSBASE r9, rbx")
lines.append("\tmov qword ptr [rbx+TEB_FSBASE], r9") lines.append("\tmov qword ptr [rbx+TEB_FSBASE], r9")
# Save RSP and load guest stack # Save RSP and load guest stack
@@ -782,7 +782,7 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
if sys.platform != "darwin": if sys.platform != "darwin":
# Restore FS base # Restore FS base
lines.append("\tmov r9, qword ptr [rbx+TEB_FSBASE]") lines.append("\tmov r9, qword ptr [rbx+TEB_FSBASE]")
lines.append("\twrfsbase r9") lines.append("\tWRITE_FSBASE r9, rbx")
# Restore host stack # Restore host stack
lines.append("\tmov rsp, qword ptr [rbx+TEB_SP]") lines.append("\tmov rsp, qword ptr [rbx+TEB_SP]")