diff mbox series

[5/7] tcg/i386: add support for IBT

Message ID 20190313124042.12855-6-pbonzini@redhat.com
State New
Headers show
Series CET support | expand

Commit Message

Paolo Bonzini March 13, 2019, 12:40 p.m. UTC
Add endbr annotations before indirect branch targets.  This lets QEMU enable
IBT even for TCG-enabled builds.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.target           |  2 ++
 configure                 |  9 +++++++++
 tcg/i386/tcg-target.inc.c | 14 ++++++++++++++
 3 files changed, 25 insertions(+)

Comments

Richard Henderson March 13, 2019, 11:46 p.m. UTC | #1
On 3/13/19 5:40 AM, Paolo Bonzini wrote:
> Add endbr annotations before indirect branch targets.  This lets QEMU enable
> IBT even for TCG-enabled builds.

> @@ -3514,6 +3526,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>                    CPU_TEMP_BUF_NLONGS * sizeof(long));
>  
>      /* Save all callee saved registers.  */
> +    tcg_out_endbr(s);
>      for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
>          tcg_out_push(s, tcg_target_callee_save_regs[i]);
>      }

Nit: Keep the comment with the code to which it applies.

I'll note that there's one latent but currently unused indirect branch:

>         } else {
>             /* indirect jump method */
>             tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
>                                  (intptr_t)(s->tb_jmp_target_addr + a0));
>         }
>         set_jmp_reset_offset(s, a0);

We can probably just delete that condition, and assert it instead.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~
Richard Henderson March 14, 2019, 1:05 a.m. UTC | #2
On 3/13/19 5:40 AM, Paolo Bonzini wrote:
> +static void tcg_out_endbr(TCGContext *s)
> +{
> +#if defined __CET__ && (__CET__ & 1)
> +#ifdef __x86_64__
> +    tcg_out32(s, 0xfa1e0ff3);
> +#else
> +    tcg_out32(s, 0xfb1e0ff3);
> +#endif
> +#endif
> +}

Normally we'd use a runtime test for the feature.

Just because we compiled with CET does not mean we're running on CET-enabled
hardware, since IIRC this is a nop otherwise.  I assume there's a cpuid/xgetbv
bit that indicates when IBT is present and/or active?


r~
Paolo Bonzini March 14, 2019, 10:50 a.m. UTC | #3
On 14/03/19 02:05, Richard Henderson wrote:
> On 3/13/19 5:40 AM, Paolo Bonzini wrote:
>> +static void tcg_out_endbr(TCGContext *s)
>> +{
>> +#if defined __CET__ && (__CET__ & 1)
>> +#ifdef __x86_64__
>> +    tcg_out32(s, 0xfa1e0ff3);
>> +#else
>> +    tcg_out32(s, 0xfb1e0ff3);
>> +#endif
>> +#endif
>> +}
> 
> Normally we'd use a runtime test for the feature.
> 
> Just because we compiled with CET does not mean we're running on CET-enabled
> hardware, since IIRC this is a nop otherwise.  I assume there's a cpuid/xgetbv
> bit that indicates when IBT is present and/or active?

No, there is a way to deduce whether shadow stack is active, but IBT is
only detectable by SIGSEGV'ing.  It is enabled through an MSR which of
course is not available from user space.

There is a prctl to query the state, ARCH_X86_CET_STATUS, but I'm a bit
wary of adding support for it before it hits the kernel; IBT only needs
compiler support because the instructions/prefixes are a nop if
disabled, unlike SHSTK which needs the "allocate shadow stack" prctl.
It's a small fixed cost per TB, it seemed not a big deal to me.

Paolo
Richard Henderson March 14, 2019, 3:15 p.m. UTC | #4
On 3/14/19 3:50 AM, Paolo Bonzini wrote:
> There is a prctl to query the state, ARCH_X86_CET_STATUS, but I'm a bit
> wary of adding support for it before it hits the kernel; IBT only needs
> compiler support because the instructions/prefixes are a nop if
> disabled, unlike SHSTK which needs the "allocate shadow stack" prctl.
> It's a small fixed cost per TB, it seemed not a big deal to me.

There's a cpuid bit though, leaf 7, ebx bit 20.  If that's not set...

It's a small fixed cost, and it's possible that it's lost in the padding
between TB's.  But per 256k TB's it's 1MB "wasted", worst case.


r~
Paolo Bonzini March 14, 2019, 3:35 p.m. UTC | #5
On 14/03/19 16:15, Richard Henderson wrote:
> There's a cpuid bit though, leaf 7, ebx bit 20.  If that's not set...

Yes, I can definitely test CPUID.

Paolo
Stefan Hajnoczi March 15, 2019, 10:56 a.m. UTC | #6
On Wed, Mar 13, 2019 at 01:40:40PM +0100, Paolo Bonzini wrote:
> +static void tcg_out_endbr(TCGContext *s)
> +{
> +#if defined __CET__ && (__CET__ & 1)

Please include a comment explaining why __CET__ & 1 is necessary.  Is
bit 0 of __CET__ the Indirect Branch Tracking feature flag?
diff mbox series

Patch

diff --git a/Makefile.target b/Makefile.target
index fa143d7b4b..df413c9b7f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -114,8 +114,10 @@  obj-y += accel/
 obj-$(CONFIG_TCG) += tcg/tcg.o tcg/tcg-op.o tcg/tcg-op-vec.o tcg/tcg-op-gvec.o
 obj-$(CONFIG_TCG) += tcg/tcg-common.o tcg/optimize.o
 ifeq ($(CONFIG_CET),y)
+ifneq ($(CONFIG_CET_TCG),y)
 tcg/tcg.o-cflags := -fcf-protection=return
 endif
+endif
 obj-$(CONFIG_TCG_INTERPRETER) += tcg/tci.o
 obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
 obj-$(CONFIG_TCG) += fpu/softfloat.o
diff --git a/configure b/configure
index 4470fe8e74..4e553e521b 100755
--- a/configure
+++ b/configure
@@ -5096,6 +5096,11 @@  if test "$cet" = ""; then
   cet=yes
   QEMU_CFLAGS="-fcf-protection $QEMU_CFLAGS"
 fi
+if test "$cpu" = "x86_64"; then
+  cet_tcg=yes
+else
+  cet_tcg=no
+fi
 
 ##########################################
 # check and set a backend for coroutine
@@ -6290,6 +6295,7 @@  echo "TCG support       $tcg"
 if test "$tcg" = "yes" ; then
     echo "TCG debug enabled $debug_tcg"
     echo "TCG interpreter   $tcg_interpreter"
+    echo "TCG CET support   $cet_tcg"
 fi
 echo "malloc trim support $malloc_trim"
 echo "RDMA support      $rdma"
@@ -6495,6 +6501,9 @@  fi
 if test "$cet" = "yes" ; then
   echo "CONFIG_CET=y" >> $config_host_mak
 fi
+if test "$cet_tcg" = "yes" ; then
+  echo "CONFIG_CET_TCG=y" >> $config_host_mak
+fi
 if test "$slirp" != "no"; then
   echo "CONFIG_SLIRP=y" >> $config_host_mak
   echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index 781b1faec2..4d1f80c1b2 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -808,6 +808,17 @@  static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
     tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3) + ext, dest, src);
 }
 
+static void tcg_out_endbr(TCGContext *s)
+{
+#if defined __CET__ && (__CET__ & 1)
+#ifdef __x86_64__
+    tcg_out32(s, 0xfa1e0ff3);
+#else
+    tcg_out32(s, 0xfb1e0ff3);
+#endif
+#endif
+}
+
 static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
 {
     int rexw = 0;
@@ -3499,6 +3510,7 @@  static const int tcg_target_callee_save_regs[] = {
 
 static inline void tcg_out_start(TCGContext *s)
 {
+    tcg_out_endbr(s);
 }
 
 /* Generate global QEMU prologue and epilogue code */
@@ -3514,6 +3526,7 @@  static void tcg_target_qemu_prologue(TCGContext *s)
                   CPU_TEMP_BUF_NLONGS * sizeof(long));
 
     /* Save all callee saved registers.  */
+    tcg_out_endbr(s);
     for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
         tcg_out_push(s, tcg_target_callee_save_regs[i]);
     }
@@ -3553,6 +3566,7 @@  static void tcg_target_qemu_prologue(TCGContext *s)
      * and fall through to the rest of the epilogue.
      */
     s->code_gen_epilogue = s->code_ptr;
+    tcg_out_endbr(s);
     tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_EAX, 0);
 
     /* TB epilogue */