Re: [RFC PATCH v3 12/24] x86/mm: Modify ptep_set_wrprotect and pmdp_set_wrprotect for _PAGE_DIRTY_SW

From: Dave Hansen
Date: Thu Aug 30 2018 - 13:24:22 EST


On 08/30/2018 09:23 AM, Jann Horn wrote:
> Three threads (A, B, C) run with the same CR3.
>
> 1. a dirty+writable PTE is placed directly in front of B's shadow stack.
> (this can happen, right? or is there a guard page?)
> 2. C's TLB caches the dirty+writable PTE.
> 3. A performs some syscall that triggers ptep_set_wrprotect().
> 4. A's syscall calls clear_bit().
> 5. B's TLB caches the transient shadow stack.
> [now C has write access to B's transiently-extended shadow stack]
> 6. B recurses into the transiently-extended shadow stack
> 7. C overwrites the transiently-extended shadow stack area.
> 8. B returns through the transiently-extended shadow stack, giving
> the attacker instruction pointer control in B.
> 9. A's syscall broadcasts a TLB flush.

Heh, that's a good point. The shadow stack permissions are *not*
strictly reduced because a page getting marked as shadow-stack has
*increased* permissions when being used as a shadow stack. Fun.

For general hardening, it seems like we want to ensure that there's a
guard page at the bottom of the shadow stack. Yu-cheng, do we have a
guard page?

But, to keep B's TLB from picking up the entry, I think we can just make
it !Present for a moment. No TLB can cache it, and I believe the same
"don't set Dirty on a !Writable entry" logic also holds for !Present
(modulo a weird erratum or two).

If we do that, we just need to make sure that the fault handler knows it
can get spurious faults from it, and might even run into the !Present
PTE for a moment. It might be a bit confusing because it won't be a
PROT_NONE, migration, or swap PTE, but will be !Present. We'll also
have to make sure that we're doing this in a way which is friendly to
the L1TF PTE handling.