Skip to content

Commit

Permalink
Add an implementation of RestoreContext for Windows/amd64 for use w…
Browse files Browse the repository at this point in the history
…ith shadow stacks (#51887)

* Add an implementation of `RestoreContext` for Windows/amd64 for use with shadow stacks

- Added `ClrRestoreNonvolatileContext` to Windows/amd64 similar to the PAL's `RtlRestoreContext` but allowing for example continuing from exception in managed code when shadow stacks are enabled
- Updated to use the new implementation for cases that don't need the volatile register state restored. The two remaining cases that still use `RtlRestoreContext` would have to be changed later to use a different mechanism.
- For other targets, forwarded `ClrRestoreNonvolatileContext` to `RtlRestoreContext` for now
  • Loading branch information
kouvel committed Apr 27, 2021
1 parent cb48026 commit c37257f
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/coreclr/pal/src/arch/amd64/asmconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#ifdef HOST_64BIT

// The arch bit is normally set in the flag constants below. Since this is already arch-specific code and the arch bit is not
// relevant, the arch bit is excluded from the flag constants below for simpler tests.
#define CONTEXT_AMD64 0x100000

#define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/PInvokeStubs.asm
${ARCH_SOURCES_DIR}/RedirectedHandledJITCase.asm
${ARCH_SOURCES_DIR}/ThePreStubAMD64.asm
${ARCH_SOURCES_DIR}/Context.asm
${ARCH_SOURCES_DIR}/ExternalMethodFixupThunk.asm
${ARCH_SOURCES_DIR}/UMThunkStub.asm
${ARCH_SOURCES_DIR}/VirtualCallStubAMD64.asm
Expand Down
60 changes: 60 additions & 0 deletions src/coreclr/vm/amd64/Context.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
; Licensed to the .NET Foundation under one or more agreements.
; The .NET Foundation licenses this file to you under the MIT license.

;
; Some implementations of operations done on the CONTEXT structure, like capturing and restoring the thread's context.
;

include AsmMacros.inc
include AsmConstants.inc

; Some constants for CONTEXT.ContextFlags. The arch bit (CONTEXT_AMD64) is normally set in these flag constants below. Since
; this is already arch-specific code and the arch bit is not relevant, the arch bit is excluded from the flag constants below
; for simpler tests.
CONTEXT_CONTROL equ 1h
CONTEXT_INTEGER equ 2h
CONTEXT_FLOATING_POINT equ 8h

; Signature: EXTERN_C void STDCALL ClrRestoreNonvolatileContext(PCONTEXT ContextRecord);
NESTED_ENTRY ClrRestoreNonvolatileContext, _TEXT
push_nonvol_reg rbp
set_frame rbp, 0
END_PROLOGUE
test byte ptr [rcx + OFFSETOF__CONTEXT__ContextFlags], CONTEXT_FLOATING_POINT
je Done_Restore_CONTEXT_FLOATING_POINT
fxrstor [rcx + OFFSETOF__CONTEXT__FltSave]
Done_Restore_CONTEXT_FLOATING_POINT:
test byte ptr [rcx + OFFSETOF__CONTEXT__ContextFlags], CONTEXT_INTEGER
je Done_Restore_CONTEXT_INTEGER
mov rbx, [rcx + OFFSETOF__CONTEXT__Rbx]
mov rbp, [rcx + OFFSETOF__CONTEXT__Rbp]
mov rsi, [rcx + OFFSETOF__CONTEXT__Rsi]
mov rdi, [rcx + OFFSETOF__CONTEXT__Rdi]
mov r12, [rcx + OFFSETOF__CONTEXT__R12]
mov r13, [rcx + OFFSETOF__CONTEXT__R13]
mov r14, [rcx + OFFSETOF__CONTEXT__R14]
mov r15, [rcx + OFFSETOF__CONTEXT__R15]
Done_Restore_CONTEXT_INTEGER:
test byte ptr [rcx + OFFSETOF__CONTEXT__ContextFlags], CONTEXT_CONTROL
je Done_Restore_CONTEXT_CONTROL
; When user-mode shadow stacks are enabled, and for example the intent is to continue execution in managed code after
; exception handling, iret and ret can't be used because their shadow stack enforcement would not allow that transition,
; and using them would require writing to the shadow stack, which is not preferable. Instead, iret is partially
; simulated.
mov eax, [rcx + OFFSETOF__CONTEXT__EFlags]
push rax
popfq
mov rsp, [rcx + OFFSETOF__CONTEXT__Rsp]
jmp qword ptr [rcx + OFFSETOF__CONTEXT__Rip]
Done_Restore_CONTEXT_CONTROL:
; The function was not asked to restore the control registers so we return back to the caller
pop rbp
ret
NESTED_END ClrRestoreNonvolatileContext, _TEXT

end
16 changes: 16 additions & 0 deletions src/coreclr/vm/amd64/asmconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__VASigCookie__pNDirectILStub
ASMCONSTANTS_C_ASSERT(SIZEOF__CONTEXT
== sizeof(CONTEXT));

#define OFFSETOF__CONTEXT__ContextFlags (8*6)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__ContextFlags
== offsetof(CONTEXT, ContextFlags));

#define OFFSETOF__CONTEXT__EFlags (8*6 + 4*2 + 2*6)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__EFlags
== offsetof(CONTEXT, EFlags));

#define OFFSETOF__CONTEXT__Rax (8*6 + 4*2 + 2*6 + 4 + 8*6)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__Rax
== offsetof(CONTEXT, Rax));
Expand Down Expand Up @@ -382,6 +390,10 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__R15
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__Rip
== offsetof(CONTEXT, Rip));

#define OFFSETOF__CONTEXT__FltSave (8*6 + 4*2 + 2*6 + 4 + 8*6 + 8*16 + 8)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__FltSave
== offsetof(CONTEXT, FltSave));

#define OFFSETOF__CONTEXT__Xmm0 (8*6 + 4*2 + 2*6 + 4 + 8*6 + 8*16 + 8 + 2*16 + 8*16)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__Xmm0
== offsetof(CONTEXT, Xmm0));
Expand Down Expand Up @@ -446,6 +458,10 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__Xmm14
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__Xmm15
== offsetof(CONTEXT, Xmm15));

#define OFFSETOF__CONTEXT__VectorRegister (8*6 + 4*2 + 2*6 + 4 + 8*6 + 8*16 + 8 + 2*16 + 8*16 + 16*16 + 96)
ASMCONSTANTS_C_ASSERT(OFFSETOF__CONTEXT__VectorRegister
== offsetof(CONTEXT, VectorRegister[0]));

#define SIZEOF__FaultingExceptionFrame (0x20 + SIZEOF__CONTEXT)
ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame
== sizeof(FaultingExceptionFrame));
Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/vm/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@ namespace Loader
} LoadFlag;
}

#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
EXTERN_C void STDCALL ClrRestoreNonvolatileContext(PCONTEXT ContextRecord);
#elif !(defined(TARGET_WINDOWS) && defined(TARGET_X86)) // !(TARGET_WINDOWS && TARGET_AMD64) && !(TARGET_WINDOWS && TARGET_X86)
inline void ClrRestoreNonvolatileContext(PCONTEXT ContextRecord)
{
// Falling back to RtlRestoreContext() for now, though it should be possible to have simpler variants for these cases
RtlRestoreContext(ContextRecord, NULL);
}
#endif // TARGET_WINDOWS && TARGET_AMD64
#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE

// src/inc
#include "utilcode.h"
#include "log.h"
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/encee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ NOINLINE void EditAndContinueModule::FixContextAndResume(
#if defined(TARGET_AMD64)
// Since we made a copy of the incoming CONTEXT in context, clear any new flags we
// don't understand (like XSAVE), since we'll eventually be passing a CONTEXT based
// on this copy to RtlRestoreContext, and this copy doesn't have the extra info
// on this copy to ClrRestoreNonvolatileContext, and this copy doesn't have the extra info
// required by the XSAVE or other flags.
//
// FUTURE: No reason to ifdef this for amd64-only, except to make this late fix as
Expand Down Expand Up @@ -813,7 +813,7 @@ NOINLINE void EditAndContinueModule::FixContextAndResume(
#if defined(TARGET_X86)
ResumeAtJit(pContext, oldSP);
#else
RtlRestoreContext(pContext, NULL);
ClrRestoreNonvolatileContext(pContext);
#endif

// At this point we shouldn't have failed, so this is genuinely erroneous.
Expand Down
11 changes: 3 additions & 8 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,9 +1188,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord
RestoreSOToleranceState();
#endif

ExceptionTracker::ResumeExecution(pContextRecord,
NULL
);
ExceptionTracker::ResumeExecution(pContextRecord);
UNREACHABLE();
}
}
Expand Down Expand Up @@ -3936,10 +3934,7 @@ void ExceptionTracker::ResetLimitFrame()

//
// static
void ExceptionTracker::ResumeExecution(
CONTEXT* pContextRecord,
EXCEPTION_RECORD* pExceptionRecord
)
void ExceptionTracker::ResumeExecution(CONTEXT* pContextRecord)
{
//
// This method never returns, so it will leave its
Expand All @@ -3958,7 +3953,7 @@ void ExceptionTracker::ResumeExecution(
EH_LOG((LL_INFO100, "resuming execution at 0x%p\n", GetIP(pContextRecord)));
EH_LOG((LL_INFO100, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));

RtlRestoreContext(pContextRecord, pExceptionRecord);
ClrRestoreNonvolatileContext(pContextRecord);

UNREACHABLE();
//
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/vm/exceptionhandling.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,7 @@ class ExceptionTracker
StackTraceState* pSTState);

static void
ResumeExecution(T_CONTEXT* pContextRecord,
EXCEPTION_RECORD* pExceptionRecord
);
ResumeExecution(T_CONTEXT* pContextRecord);

void ResetLimitFrame();

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5222,7 +5222,7 @@ void JIT_Patchpoint(int* counter, int ilOffset)
SetIP(&frameContext, osrMethodCode);

// Transition!
RtlRestoreContext(&frameContext, NULL);
ClrRestoreNonvolatileContext(&frameContext);
}

#else
Expand Down

0 comments on commit c37257f

Please sign in to comment.