From 2e4e5d5be7c381f94df95df84e663b10de8a074c Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Tue, 16 Dec 2014 23:57:51 +0000 Subject: [PATCH] Fix 197259 Unsupported arch_prtctl PR_SET_GS option On amd64, We handle GS similar to FS, i.e. consider it is constant. Note that FS is not always 0 on linux. It looks rather to be constant in all threads, and is zero in the main thread. As values for FS and/or GS differs between platforms (linux or darwin), FS_CONST and GS_CONST are used. Note that we cannot easily test that the value of GS or FS is the expected one, as the value might not be set at the begin of execution but only set after prctl has been executed. So, we just hope that effectively GS and FS are constant. Some trials to set GS to other values that the expected constant value on linux was causing a SEGV. So, it looks like this is all effectively protected. In summary: we were counting somewhat on the luck for FS, we now similarly count on luch for GS git-svn-id: svn://svn.valgrind.org/vex/trunk@3043 --- VEX/priv/guest_amd64_helpers.c | 11 ++++++----- VEX/priv/guest_amd64_toIR.c | 28 ++++++++++++++-------------- VEX/priv/main_main.c | 4 ++-- VEX/pub/libvex.h | 14 +++++++------- VEX/pub/libvex_guest_amd64.h | 20 +++++++++++--------- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/VEX/priv/guest_amd64_helpers.c b/VEX/priv/guest_amd64_helpers.c index 629e11a2b1..15dc8bcb11 100644 --- a/VEX/priv/guest_amd64_helpers.c +++ b/VEX/priv/guest_amd64_helpers.c @@ -3901,9 +3901,10 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state ) vex_state->guest_IDFLAG = 0; vex_state->guest_ACFLAG = 0; - /* HACK: represent the offset associated with %fs==0. This - assumes that %fs is only ever zero. */ - vex_state->guest_FS_ZERO = 0; + /* HACK: represent the offset associated with a constant %fs. + Typically, on linux, this assumes that %fs is only ever zero (main + thread) or 0x63. */ + vex_state->guest_FS_CONST = 0; vex_state->guest_RIP = 0; @@ -3945,7 +3946,7 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state ) vex_state->guest_NRADDR = 0; vex_state->guest_SC_CLASS = 0; - vex_state->guest_GS_0x60 = 0; + vex_state->guest_GS_CONST = 0; vex_state->guest_IP_AT_SYSCALL = 0; vex_state->pad1 = 0; @@ -4031,7 +4032,7 @@ VexGuestLayout /* 2 */ ALWAYSDEFD(guest_DFLAG), /* 3 */ ALWAYSDEFD(guest_IDFLAG), /* 4 */ ALWAYSDEFD(guest_RIP), - /* 5 */ ALWAYSDEFD(guest_FS_ZERO), + /* 5 */ ALWAYSDEFD(guest_FS_CONST), /* 6 */ ALWAYSDEFD(guest_FTOP), /* 7 */ ALWAYSDEFD(guest_FPTAG), /* 8 */ ALWAYSDEFD(guest_FPROUND), diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index 2d8bd923b3..2df860a0dd 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -395,8 +395,8 @@ static void unimplemented ( const HChar* str ) #define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP) -#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO) -#define OFFB_GS_0x60 offsetof(VexGuestAMD64State,guest_GS_0x60) +#define OFFB_FS_CONST offsetof(VexGuestAMD64State,guest_FS_CONST) +#define OFFB_GS_CONST offsetof(VexGuestAMD64State,guest_GS_CONST) #define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP) #define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1) @@ -2323,26 +2323,26 @@ static IRExpr* handleAddrOverrides ( const VexAbiInfo* vbi, Prefix pfx, IRExpr* virtual ) { + /* Note that the below are hacks that relies on the assumption + that %fs or %gs are constant. + Typically, %fs is always 0x63 on linux (in the main thread, it + stays at value 0), %gs always 0x60 on Darwin, ... */ /* --- segment overrides --- */ if (pfx & PFX_FS) { - if (vbi->guest_amd64_assume_fs_is_zero) { - /* Note that this is a linux-kernel specific hack that relies - on the assumption that %fs is always zero. */ - /* return virtual + guest_FS_ZERO. */ + if (vbi->guest_amd64_assume_fs_is_const) { + /* return virtual + guest_FS_CONST. */ virtual = binop(Iop_Add64, virtual, - IRExpr_Get(OFFB_FS_ZERO, Ity_I64)); + IRExpr_Get(OFFB_FS_CONST, Ity_I64)); } else { unimplemented("amd64 %fs segment override"); } } if (pfx & PFX_GS) { - if (vbi->guest_amd64_assume_gs_is_0x60) { - /* Note that this is a darwin-kernel specific hack that relies - on the assumption that %gs is always 0x60. */ - /* return virtual + guest_GS_0x60. */ + if (vbi->guest_amd64_assume_gs_is_const) { + /* return virtual + guest_GS_CONST. */ virtual = binop(Iop_Add64, virtual, - IRExpr_Get(OFFB_GS_0x60, Ity_I64)); + IRExpr_Get(OFFB_GS_CONST, Ity_I64)); } else { unimplemented("amd64 %gs segment override"); } @@ -31388,11 +31388,11 @@ DisResult disInstr_AMD64_WRK ( /* We have a %fs prefix. Reject it if there's no evidence in 'vbi' that we should accept it. */ - if ((pfx & PFX_FS) && !vbi->guest_amd64_assume_fs_is_zero) + if ((pfx & PFX_FS) && !vbi->guest_amd64_assume_fs_is_const) goto decode_failure; /* Ditto for %gs prefixes. */ - if ((pfx & PFX_GS) && !vbi->guest_amd64_assume_gs_is_0x60) + if ((pfx & PFX_GS) && !vbi->guest_amd64_assume_gs_is_const) goto decode_failure; /* Set up sz. */ diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index f52a68f23f..b007fa1c8f 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -1264,8 +1264,8 @@ void LibVEX_default_VexAbiInfo ( /*OUT*/VexAbiInfo* vbi ) { vex_bzero(vbi, sizeof(*vbi)); vbi->guest_stack_redzone_size = 0; - vbi->guest_amd64_assume_fs_is_zero = False; - vbi->guest_amd64_assume_gs_is_0x60 = False; + vbi->guest_amd64_assume_fs_is_const = False; + vbi->guest_amd64_assume_gs_is_const = False; vbi->guest_ppc_zap_RZ_at_blr = False; vbi->guest_ppc_zap_RZ_at_bl = NULL; vbi->host_ppc_calls_use_fndescrs = False; diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 6da02daf23..1f09de5a0d 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -316,14 +316,14 @@ void LibVEX_default_VexArchInfo ( /*OUT*/VexArchInfo* vai ); guest is amd64-linux ==> 128 guest is other ==> inapplicable - guest_amd64_assume_fs_is_zero + guest_amd64_assume_fs_is_const guest is amd64-linux ==> True guest is amd64-darwin ==> False guest is other ==> inapplicable - guest_amd64_assume_gs_is_0x60 + guest_amd64_assume_gs_is_const guest is amd64-darwin ==> True - guest is amd64-linux ==> False + guest is amd64-linux ==> True guest is other ==> inapplicable guest_ppc_zap_RZ_at_blr @@ -350,13 +350,13 @@ typedef /* AMD64 GUESTS only: should we translate %fs-prefixed instructions using the assumption that %fs always contains - zero? */ - Bool guest_amd64_assume_fs_is_zero; + the same value? (typically zero on linux) */ + Bool guest_amd64_assume_fs_is_const; /* AMD64 GUESTS only: should we translate %gs-prefixed instructions using the assumption that %gs always contains - 0x60? */ - Bool guest_amd64_assume_gs_is_0x60; + the same value? (typically 0x60 on darwin)? */ + Bool guest_amd64_assume_gs_is_const; /* PPC GUESTS only: should we zap the stack red zone at a 'blr' (function return) ? */ diff --git a/VEX/pub/libvex_guest_amd64.h b/VEX/pub/libvex_guest_amd64.h index 5920672bf6..787510ee7d 100644 --- a/VEX/pub/libvex_guest_amd64.h +++ b/VEX/pub/libvex_guest_amd64.h @@ -90,10 +90,11 @@ typedef all the old x87 FPU gunk segment registers */ - /* HACK to make tls on amd64-linux work. %fs only ever seems to - hold zero, and so guest_FS_ZERO holds the 64-bit offset - associated with a %fs value of zero. */ - /* 200 */ ULong guest_FS_ZERO; + /* HACK to e.g. make tls on amd64-linux work. %fs only ever seems to + hold a constant value (zero on linux main thread, 0x63 in other + threads), and so guest_FS_CONST holds + the 64-bit offset associated with this constant %fs value. */ + /* 200 */ ULong guest_FS_CONST; /* YMM registers. Note that these must be allocated consecutively in order that the SSE4.2 PCMP{E,I}STR{I,M} @@ -152,11 +153,12 @@ typedef /* Used for Darwin syscall dispatching. */ ULong guest_SC_CLASS; - /* HACK to make tls on darwin work. %gs only ever seems to - hold 0x60, and so guest_GS_0x60 holds the 64-bit offset - associated with a %gs value of 0x60. (A direct analogue - of the %fs-zero hack for amd64-linux). */ - ULong guest_GS_0x60; + /* HACK to make e.g. tls on darwin work, wine on linux work, ... + %gs only ever seems to hold a constant value (e.g. 0x60 on darwin, + 0x6b on linux), and so guest_GS_CONST holds the 64-bit offset + associated with this constant %gs value. (A direct analogue + of the %fs-const hack for amd64-linux). */ + ULong guest_GS_CONST; /* Needed for Darwin (but mandated for all guest architectures): RIP at the last syscall insn (int 0x80/81/82, sysenter, -- 2.47.2