Joerg Roedel
2020-Jun-23 13:40 UTC
Should SEV-ES #VC use IST? (Re: [PATCH] Allow RDTSC and RDTSCP from userspace)
On Tue, Jun 23, 2020 at 02:52:01PM +0200, Peter Zijlstra wrote:> On Tue, Jun 23, 2020 at 02:04:33PM +0200, Joerg Roedel wrote: > > No, the recursion check is fine, because overwriting an already used IST > > stack doesn't matter (as long as it can be detected) if we are going to > > panic anyway. It doesn't matter because the kernel will not leave the > > currently running handler anymore. > > You only have that guarantee when any SNP #VC from kernel is an > automatic panic. But in that case, what's the point of having the > recursion count?It is not a recursion count, it is a stack-recursion check. Basically walk down the stack and look if your current stack is already in use. Yes, this can be optimized, but that is what is needed. IIRC the current prototype code for SNP just pre-validates all memory in the VM and doesn't support moving pages around on the host. So any #VC SNP exception would be fatal, yes. In a scenario with on-demand validation of guest pages and support for guest-assisted page-moving on the HV side it would be more complicated. Basically all memory that is accessed during #VC exception handling must stay validated at all times, including the IST stack. So saying this, I don't understand why _all_ SNP #VC exceptions from kernel space must be fatal? Regards, Joerg
Peter Zijlstra
2020-Jun-23 13:59 UTC
Should SEV-ES #VC use IST? (Re: [PATCH] Allow RDTSC and RDTSCP from userspace)
On Tue, Jun 23, 2020 at 03:40:03PM +0200, Joerg Roedel wrote:> On Tue, Jun 23, 2020 at 02:52:01PM +0200, Peter Zijlstra wrote:> > You only have that guarantee when any SNP #VC from kernel is an > > automatic panic. But in that case, what's the point of having the > > recursion count? > > It is not a recursion count, it is a stack-recursion check. Basically > walk down the stack and look if your current stack is already in use. > Yes, this can be optimized, but that is what is needed. > > IIRC the current prototype code for SNP just pre-validates all memory in > the VM and doesn't support moving pages around on the host. So any #VC > SNP exception would be fatal, yes. > > In a scenario with on-demand validation of guest pages and support for > guest-assisted page-moving on the HV side it would be more complicated. > Basically all memory that is accessed during #VC exception handling must > stay validated at all times, including the IST stack. > > So saying this, I don't understand why _all_ SNP #VC exceptions from > kernel space must be fatal?Ah, because I hadn't thought of the stack-recursion check. So basically when your exception frame points to your own IST, you die. That sounds like something we should have in generic IST code.
Peter Zijlstra
2020-Jun-23 14:53 UTC
Should SEV-ES #VC use IST? (Re: [PATCH] Allow RDTSC and RDTSCP from userspace)
On Tue, Jun 23, 2020 at 03:59:16PM +0200, Peter Zijlstra wrote:> So basically when your exception frame points to your own IST, you die. > That sounds like something we should have in generic IST code.Something like this... #DF already dies and NMI is 'magic' --- arch/x86/entry/common.c | 7 +++++++ arch/x86/include/asm/idtentry.h | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index af0d57ed5e69..e38e4f34c90c 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -742,6 +742,13 @@ noinstr void idtentry_exit_nmi(struct pt_regs *regs, bool restore) __nmi_exit(); } +noinstr void idtentry_validate_ist(struct pt_regs *regs) +{ + if ((regs->sp & ~(EXCEPTION_STKSZ-1)) =+ (_RET_IP_ & ~(EXCEPTION_STKSZ-1))) + die("IST stack recursion", regs, 0); +} + #ifdef CONFIG_XEN_PV #ifndef CONFIG_PREEMPTION /* diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 4e399f120ff8..974c1a4eacbb 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -19,6 +19,8 @@ void idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit); bool idtentry_enter_nmi(struct pt_regs *regs); void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state); +void idtentry_validate_ist(struct pt_regs *regs); + /** * DECLARE_IDTENTRY - Declare functions for simple IDT entry points * No error code pushed by hardware @@ -322,7 +324,15 @@ static __always_inline void __##func(struct pt_regs *regs) * Maps to DEFINE_IDTENTRY_RAW */ #define DEFINE_IDTENTRY_IST(func) \ - DEFINE_IDTENTRY_RAW(func) +static __always_inline void __##func(struct pt_regs *regs); \ + \ +__visible noinstr void func(struct pt_regs *regs) \ +{ \ + idtentry_validate_ist(regs); \ + __##func(regs); \ +} \ + \ +static __always_inline void __##func(struct pt_regs *regs) /** * DEFINE_IDTENTRY_NOIST - Emit code for NOIST entry points which