diff --git a/src/macros.S b/src/macros.S index 9e98481..4edc759 100644 --- a/src/macros.S +++ b/src/macros.S @@ -64,6 +64,52 @@ m1632: endbr64 .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__ .macro GET_TEB_HOST reg diff --git a/src/macros.h b/src/macros.h index 1a76a5c..1d4062f 100644 --- a/src/macros.h +++ b/src/macros.h @@ -12,11 +12,12 @@ #ifdef __x86_64__ -#define TEB_CS_SEL 0xf9c // CodeSelector -#define TEB_DS_SEL 0xf9e // DataSelector -#define TEB_SP 0xfa0 // CurrentStackPointer -#define TEB_FSBASE 0xfa8 // HostFsBase -#define TEB_GSBASE 0xfb0 // HostGsBase +#define TEB_CS_SEL 0xf9c // CodeSelector +#define TEB_DS_SEL 0xf9e // DataSelector +#define TEB_SP 0xfa0 // CurrentStackPointer +#define TEB_FSBASE 0xfa8 // HostFsBase +#define TEB_GSBASE 0xfb0 // HostGsBase +#define TEB_HAS_FSGSBASE 0xfb8 // HasFsGsBase #ifdef __linux__ #define CS_32 0x23 // 32-bit code segment (Linux) diff --git a/src/setup_linux.cpp b/src/setup_linux.cpp index 1826b32..4f0f514 100644 --- a/src/setup_linux.cpp +++ b/src/setup_linux.cpp @@ -11,14 +11,16 @@ namespace { std::mutex g_tebSetupMutex; int g_entryNumber = -1; -} // namespace - constexpr uint16_t createSelector(int entryNumber) { return static_cast((entryNumber << 3) | USER_PRIVILEGE); } +} // namespace + #if defined(__x86_64__) +#include + // Implemented in setup.S extern "C" int tebThreadSetup64(int entryNumber, TEB *teb); @@ -37,6 +39,15 @@ bool tebThreadSetup(TEB *teb) { teb->CurrentFsSelector = createSelector(ret); 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, ®s[0], ®s[1], ®s[2], ®s[3])) { + teb->HasFsGsBase = !!(regs[1] & 1); + } + DEBUG_LOG("setup_linux: FSBASE/GSBASE instruction support: %s\n", teb->HasFsGsBase ? "yes" : "no"); + return true; } diff --git a/src/types.h b/src/types.h index 04203d7..68a7379 100644 --- a/src/types.h +++ b/src/types.h @@ -549,6 +549,7 @@ typedef struct _TEB { #ifdef __x86_64__ void *HostFsBase; void *HostGsBase; + bool HasFsGsBase; #endif } TEB; typedef GUEST_PTR PTEB; @@ -575,6 +576,9 @@ static_assert(offsetof(TEB, HostFsBase) == TEB_FSBASE); #ifdef TEB_GSBASE static_assert(offsetof(TEB, HostGsBase) == TEB_GSBASE); #endif +#ifdef TEB_HAS_FSGSBASE +static_assert(offsetof(TEB, HasFsGsBase) == TEB_HAS_FSGSBASE); +#endif typedef struct _MEMORY_BASIC_INFORMATION { GUEST_PTR BaseAddress; diff --git a/tools/gen_trampolines.py b/tools/gen_trampolines.py index b853a86..8f4c854 100644 --- a/tools/gen_trampolines.py +++ b/tools/gen_trampolines.py @@ -721,7 +721,7 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]): if sys.platform != "darwin": # Save FS base - lines.append("\trdfsbase r9") + lines.append("\tREAD_FSBASE r9, rbx") lines.append("\tmov qword ptr [rbx+TEB_FSBASE], r9") # Save RSP and load guest stack @@ -782,7 +782,7 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]): if sys.platform != "darwin": # Restore FS base lines.append("\tmov r9, qword ptr [rbx+TEB_FSBASE]") - lines.append("\twrfsbase r9") + lines.append("\tWRITE_FSBASE r9, rbx") # Restore host stack lines.append("\tmov rsp, qword ptr [rbx+TEB_SP]")