From: Jethro Beekman <jethro@fortanix.com>
To: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>,
linux-kernel@vger.kernel.org, x86@kernel.org,
linux-sgx@vger.kernel.org
Cc: akpm@linux-foundation.org, dave.hansen@intel.com,
sean.j.christopherson@intel.com, nhorman@redhat.com,
npmccallum@redhat.com, haitao.huang@intel.com,
andriy.shevchenko@linux.intel.com, tglx@linutronix.de,
kai.svahn@intel.com, bp@alien8.de, josh@joshtriplett.org,
luto@kernel.org, kai.huang@intel.com, rientjes@google.com,
cedric.xing@intel.com, puiterwijk@redhat.com,
Andy Lutomirski <luto@amacapital.net>
Subject: Re: [PATCH v26 19/22] x86/vdso: Add __vdso_sgx_enter_enclave() to wrap SGX enclave transitions
Date: Thu, 13 Feb 2020 14:29:44 +0100 [thread overview]
Message-ID: <2b61b106-4dfd-ed47-3333-99280e33ca88@fortanix.com> (raw)
In-Reply-To: <20200209212609.7928-20-jarkko.sakkinen@linux.intel.com>
Tested-by: Jethro Beekman <jethro@fortanix.com>
--
Jethro Beekman | Fortanix
On 2020-02-09 22:26, Jarkko Sakkinen wrote:
> From: Sean Christopherson <sean.j.christopherson@intel.com>
>
> Intel Software Guard Extensions (SGX) introduces a new CPL3-only enclave
> mode that runs as a sort of black box shared object that is hosted by an
> untrusted normal CPL3 process.
>
> Skipping over a great deal of gory architecture details[1], SGX was
> designed in such a way that the host process can utilize a library to
> build, launch and run an enclave. This is roughly analogous to how
> e.g. libc implementations are used by most applications so that the
> application can focus on its business logic.
>
> The big gotcha is that because enclaves can generate *and* handle
> exceptions, any SGX library must be prepared to handle nearly any
> exception at any time (well, any time a thread is executing in an
> enclave). In Linux, this means the SGX library must register a
> signal handler in order to intercept relevant exceptions and forward
> them to the enclave (or in some cases, take action on behalf of the
> enclave). Unfortunately, Linux's signal mechanism doesn't mesh well
> with libraries, e.g. signal handlers are process wide, are difficult
> to chain, etc... This becomes particularly nasty when using multiple
> levels of libraries that register signal handlers, e.g. running an
> enclave via cgo inside of the Go runtime.
>
> In comes vDSO to save the day. Now that vDSO can fixup exceptions,
> add a function, __vdso_sgx_enter_enclave(), to wrap enclave transitions
> and intercept any exceptions that occur when running the enclave.
>
> __vdso_sgx_enter_enclave() does NOT adhere to the x86-64 ABI and instead
> uses a custom calling convention. The primary motivation is to avoid
> issues that arise due to asynchronous enclave exits. The x86-64 ABI
> requires that EFLAGS.DF, MXCSR and FCW be preserved by the callee, and
> unfortunately for the vDSO, the aformentioned registers/bits are not
> restored after an asynchronous exit, e.g. EFLAGS.DF is in an unknown
> state while MXCSR and FCW are reset to their init values. So the vDSO
> cannot simply pass the buck by requiring enclaves to adhere to the
> x86-64 ABI. That leaves three somewhat reasonable options:
>
> 1) Save/restore non-volatile GPRs, MXCSR and FCW, and clear EFLAGS.DF
>
> + 100% compliant with the x86-64 ABI
> + Callable from any code
> + Minimal documentation required
> - Restoring MXCSR/FCW is likely unnecessary 99% of the time
> - Slow
>
> 2) Save/restore non-volatile GPRs and clear EFLAGS.DF
>
> + Mostly compliant with the x86-64 ABI
> + Callable from any code that doesn't use SIMD registers
> - Need to document deviations from x86-64 ABI, i.e. MXCSR and FCW
>
> 3) Require the caller to save/restore everything.
>
> + Fast
> + Userspace can pass all GPRs to the enclave (minus EAX, RBX and RCX)
> - Custom ABI
> - For all intents and purposes must be called from an assembly wrapper
>
> __vdso_sgx_enter_enclave() implements option (3). The custom ABI is
> mostly a documentation issue, and even that is offset by the fact that
> being more similar to hardware's ENCLU[EENTER/ERESUME] ABI reduces the
> amount of documentation needed for the vDSO, e.g. options (2) and (3)
> would need to document which registers are marshalled to/from enclaves.
> Requiring an assembly wrapper imparts minimal pain on userspace as SGX
> libraries and/or applications need a healthy chunk of assembly, e.g. in
> the enclave, regardless of the vDSO's implementation.
>
> Note, the C-like pseudocode describing the assembly routine is wrapped
> in a non-existent macro instead of in a comment to trick kernel-doc into
> auto-parsing the documentation and function prototype. This is a double
> win as the pseudocode is intended to aid kernel developers, not userland
> enclave developers.
>
> [1] Documentation/x86/sgx/1.Architecture.rst
>
> Suggested-by: Andy Lutomirski <luto@amacapital.net>
> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> Co-developed-by: Cedric Xing <cedric.xing@intel.com>
> Signed-off-by: Cedric Xing <cedric.xing@intel.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
> arch/x86/entry/vdso/Makefile | 2 +
> arch/x86/entry/vdso/vdso.lds.S | 1 +
> arch/x86/entry/vdso/vsgx_enter_enclave.S | 187 +++++++++++++++++++++++
> arch/x86/include/uapi/asm/sgx.h | 37 +++++
> 4 files changed, 227 insertions(+)
> create mode 100644 arch/x86/entry/vdso/vsgx_enter_enclave.S
>
> diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
> index 629053b77e4a..d1d609d1626e 100644
> --- a/arch/x86/entry/vdso/Makefile
> +++ b/arch/x86/entry/vdso/Makefile
> @@ -24,6 +24,7 @@ VDSO32-$(CONFIG_IA32_EMULATION) := y
>
> # files to link into the vdso
> vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
> +vobjs-$(VDSO64-y) += vsgx_enter_enclave.o
>
> # files to link into kernel
> obj-y += vma.o extable.o
> @@ -90,6 +91,7 @@ $(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS
> CFLAGS_REMOVE_vclock_gettime.o = -pg
> CFLAGS_REMOVE_vdso32/vclock_gettime.o = -pg
> CFLAGS_REMOVE_vgetcpu.o = -pg
> +CFLAGS_REMOVE_vsgx_enter_enclave.o = -pg
>
> #
> # X32 processes use x32 vDSO to access 64bit kernel data.
> diff --git a/arch/x86/entry/vdso/vdso.lds.S b/arch/x86/entry/vdso/vdso.lds.S
> index 36b644e16272..4bf48462fca7 100644
> --- a/arch/x86/entry/vdso/vdso.lds.S
> +++ b/arch/x86/entry/vdso/vdso.lds.S
> @@ -27,6 +27,7 @@ VERSION {
> __vdso_time;
> clock_getres;
> __vdso_clock_getres;
> + __vdso_sgx_enter_enclave;
> local: *;
> };
> }
> diff --git a/arch/x86/entry/vdso/vsgx_enter_enclave.S b/arch/x86/entry/vdso/vsgx_enter_enclave.S
> new file mode 100644
> index 000000000000..94a8e5f99961
> --- /dev/null
> +++ b/arch/x86/entry/vdso/vsgx_enter_enclave.S
> @@ -0,0 +1,187 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#include <linux/linkage.h>
> +#include <asm/export.h>
> +#include <asm/errno.h>
> +
> +#include "extable.h"
> +
> +#define EX_LEAF 0*8
> +#define EX_TRAPNR 0*8+4
> +#define EX_ERROR_CODE 0*8+6
> +#define EX_ADDRESS 1*8
> +
> +.code64
> +.section .text, "ax"
> +
> +/**
> + * __vdso_sgx_enter_enclave() - Enter an SGX enclave
> + * @leaf: ENCLU leaf, must be EENTER or ERESUME
> + * @tcs: TCS, must be non-NULL
> + * @e: Optional struct sgx_enclave_exception instance
> + * @handler: Optional enclave exit handler
> + *
> + * **Important!** __vdso_sgx_enter_enclave() is **NOT** compliant with the
> + * x86-64 ABI, i.e. cannot be called from standard C code.
> + *
> + * Input ABI:
> + * @leaf %eax
> + * @tcs 8(%rsp)
> + * @e 0x10(%rsp)
> + * @handler 0x18(%rsp)
> + *
> + * Output ABI:
> + * @ret %eax
> + *
> + * All general purpose registers except RAX, RBX and RCX are passed as-is to
> + * the enclave. RAX, RBX and RCX are consumed by EENTER and ERESUME and are
> + * loaded with @leaf, asynchronous exit pointer, and @tcs respectively.
> + *
> + * RBP and the stack are used to anchor __vdso_sgx_enter_enclave() to the
> + * pre-enclave state, e.g. to retrieve @e and @handler after an enclave exit.
> + * All other registers are available for use by the enclave and its runtime,
> + * e.g. an enclave can push additional data onto the stack (and modify RSP) to
> + * pass information to the optional exit handler (see below).
> + *
> + * Most exceptions reported on ENCLU, including those that occur within the
> + * enclave, are fixed up and reported synchronously instead of being delivered
> + * via a standard signal. Debug Exceptions (#DB) and Breakpoints (#BP) are
> + * never fixed up and are always delivered via standard signals. On synchrously
> + * reported exceptions, -EFAULT is returned and details about the exception are
> + * recorded in @e, the optional sgx_enclave_exception struct.
> +
> + * If an exit handler is provided, the handler will be invoked on synchronous
> + * exits from the enclave and for all synchronously reported exceptions. In
> + * latter case, @e is filled prior to invoking the handler.
> + *
> + * The exit handler's return value is interpreted as follows:
> + * >0: continue, restart __vdso_sgx_enter_enclave() with @ret as @leaf
> + * 0: success, return @ret to the caller
> + * <0: error, return @ret to the caller
> + *
> + * The userspace exit handler is responsible for unwinding the stack, e.g. to
> + * pop @e, u_rsp and @tcs, prior to returning to __vdso_sgx_enter_enclave().
> + * The exit handler may also transfer control, e.g. via longjmp() or a C++
> + * exception, without returning to __vdso_sgx_enter_enclave().
> + *
> + * Return:
> + * 0 on success,
> + * -EINVAL if ENCLU leaf is not allowed,
> + * -EFAULT if an exception occurs on ENCLU or within the enclave
> + * -errno for all other negative values returned by the userspace exit handler
> + */
> +#ifdef SGX_KERNEL_DOC
> +/* C-style function prototype to coerce kernel-doc into parsing the comment. */
> +int __vdso_sgx_enter_enclave(int leaf, void *tcs,
> + struct sgx_enclave_exception *e,
> + sgx_enclave_exit_handler_t handler);
> +#endif
> +SYM_FUNC_START(__vdso_sgx_enter_enclave)
> + /* Prolog */
> + .cfi_startproc
> + push %rbp
> + .cfi_adjust_cfa_offset 8
> + .cfi_rel_offset %rbp, 0
> + mov %rsp, %rbp
> + .cfi_def_cfa_register %rbp
> +
> +.Lenter_enclave:
> + /* EENTER <= leaf <= ERESUME */
> + cmp $0x2, %eax
> + jb .Linvalid_leaf
> + cmp $0x3, %eax
> + ja .Linvalid_leaf
> +
> + /* Load TCS and AEP */
> + mov 0x10(%rbp), %rbx
> + lea .Lasync_exit_pointer(%rip), %rcx
> +
> + /* Single ENCLU serving as both EENTER and AEP (ERESUME) */
> +.Lasync_exit_pointer:
> +.Lenclu_eenter_eresume:
> + enclu
> +
> + /* EEXIT jumps here unless the enclave is doing something fancy. */
> + xor %eax, %eax
> +
> + /* Invoke userspace's exit handler if one was provided. */
> +.Lhandle_exit:
> + cmp $0, 0x20(%rbp)
> + jne .Linvoke_userspace_handler
> +
> +.Lout:
> + leave
> + .cfi_def_cfa %rsp, 8
> + ret
> +
> + /* The out-of-line code runs with the pre-leave stack frame. */
> + .cfi_def_cfa %rbp, 16
> +
> +.Linvalid_leaf:
> + mov $(-EINVAL), %eax
> + jmp .Lout
> +
> +.Lhandle_exception:
> + mov 0x18(%rbp), %rcx
> + test %rcx, %rcx
> + je .Lskip_exception_info
> +
> + /* Fill optional exception info. */
> + mov %eax, EX_LEAF(%rcx)
> + mov %di, EX_TRAPNR(%rcx)
> + mov %si, EX_ERROR_CODE(%rcx)
> + mov %rdx, EX_ADDRESS(%rcx)
> +.Lskip_exception_info:
> + mov $(-EFAULT), %eax
> + jmp .Lhandle_exit
> +
> +.Linvoke_userspace_handler:
> + /* Pass the untrusted RSP (at exit) to the callback via %rcx. */
> + mov %rsp, %rcx
> +
> + /* Save the untrusted RSP in %rbx (non-volatile register). */
> + mov %rsp, %rbx
> +
> + /*
> + * Align stack per x86_64 ABI. Note, %rsp needs to be 16-byte aligned
> + * _after_ pushing the parameters on the stack, hence the bonus push.
> + */
> + and $-0x10, %rsp
> + push %rax
> +
> + /* Push @e, the "return" value and @tcs as params to the callback. */
> + push 0x18(%rbp)
> + push %rax
> + push 0x10(%rbp)
> +
> + /* Clear RFLAGS.DF per x86_64 ABI */
> + cld
> +
> + /* Load the callback pointer to %rax and invoke it via retpoline. */
> + mov 0x20(%rbp), %rax
> + call .Lretpoline
> +
> + /* Restore %rsp to its post-exit value. */
> + mov %rbx, %rsp
> +
> + /*
> + * If the return from callback is zero or negative, return immediately,
> + * else re-execute ENCLU with the postive return value interpreted as
> + * the requested ENCLU leaf.
> + */
> + cmp $0, %eax
> + jle .Lout
> + jmp .Lenter_enclave
> +
> +.Lretpoline:
> + call 2f
> +1: pause
> + lfence
> + jmp 1b
> +2: mov %rax, (%rsp)
> + ret
> + .cfi_endproc
> +
> +_ASM_VDSO_EXTABLE_HANDLE(.Lenclu_eenter_eresume, .Lhandle_exception)
> +
> +SYM_FUNC_END(__vdso_sgx_enter_enclave)
> diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
> index 57d0d30c79b3..e196cfd44b70 100644
> --- a/arch/x86/include/uapi/asm/sgx.h
> +++ b/arch/x86/include/uapi/asm/sgx.h
> @@ -74,4 +74,41 @@ struct sgx_enclave_set_attribute {
> __u64 attribute_fd;
> };
>
> +/**
> + * struct sgx_enclave_exception - structure to report exceptions encountered in
> + * __vdso_sgx_enter_enclave()
> + *
> + * @leaf: ENCLU leaf from \%eax at time of exception
> + * @trapnr: exception trap number, a.k.a. fault vector
> + * @error_code: exception error code
> + * @address: exception address, e.g. CR2 on a #PF
> + * @reserved: reserved for future use
> + */
> +struct sgx_enclave_exception {
> + __u32 leaf;
> + __u16 trapnr;
> + __u16 error_code;
> + __u64 address;
> + __u64 reserved[2];
> +};
> +
> +/**
> + * typedef sgx_enclave_exit_handler_t - Exit handler function accepted by
> + * __vdso_sgx_enter_enclave()
> + *
> + * @rdi: RDI at the time of enclave exit
> + * @rsi: RSI at the time of enclave exit
> + * @rdx: RDX at the time of enclave exit
> + * @ursp: RSP at the time of enclave exit (untrusted stack)
> + * @r8: R8 at the time of enclave exit
> + * @r9: R9 at the time of enclave exit
> + * @tcs: Thread Control Structure used to enter enclave
> + * @ret: 0 on success (EEXIT), -EFAULT on an exception
> + * @e: Pointer to struct sgx_enclave_exception (as provided by caller)
> + */
> +typedef int (*sgx_enclave_exit_handler_t)(long rdi, long rsi, long rdx,
> + long ursp, long r8, long r9,
> + void *tcs, int ret,
> + struct sgx_enclave_exception *e);
> +
> #endif /* _UAPI_ASM_X86_SGX_H */
>
next prev parent reply other threads:[~2020-02-13 13:30 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-09 21:25 [PATCH v26 00/22] Intel SGX foundations Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 01/22] x86/cpufeatures: x86/msr: Add Intel SGX hardware bits Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 02/22] x86/cpufeatures: x86/msr: Intel SGX Launch Control " Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 03/22] x86/mm: x86/sgx: Signal SIGSEGV with PF_SGX Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 04/22] x86/sgx: Add SGX microarchitectural data structures Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 05/22] x86/sgx: Add wrappers for ENCLS leaf functions Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 06/22] x86/cpu/intel: Detect SGX supprt Jarkko Sakkinen
2020-02-12 16:57 ` Sean Christopherson
2020-02-13 18:04 ` Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 07/22] x86/sgx: Enumerate and track EPC sections Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 08/22] x86/sgx: Add functions to allocate and free EPC pages Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 09/22] mm: Introduce vm_ops->may_mprotect() Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 10/22] x86/sgx: Linux Enclave Driver Jarkko Sakkinen
2020-02-13 13:59 ` Jethro Beekman
2020-02-13 18:07 ` Sean Christopherson
2020-02-14 9:24 ` Jethro Beekman
2020-02-14 17:11 ` Sean Christopherson
2020-02-14 17:40 ` Andy Lutomirski
2020-02-14 17:52 ` Sean Christopherson
2020-02-15 16:56 ` Andy Lutomirski
2020-02-18 22:12 ` Sean Christopherson
2020-02-15 18:05 ` Dr. Greg
2020-02-15 7:32 ` Jarkko Sakkinen
2020-02-15 7:35 ` Jarkko Sakkinen
2020-02-19 3:26 ` Jordan Hand
2020-02-20 18:13 ` Sean Christopherson
2020-02-20 18:33 ` Jordan Hand
2020-02-20 18:48 ` Sean Christopherson
2020-02-20 22:16 ` Jarkko Sakkinen
2020-02-21 0:11 ` Jordan Hand
2020-02-21 12:53 ` Jarkko Sakkinen
2020-02-21 0:32 ` Andy Lutomirski
2020-02-21 13:01 ` Jarkko Sakkinen
2020-02-20 18:51 ` Andy Lutomirski
2020-02-20 19:15 ` Sean Christopherson
2020-02-20 22:10 ` Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 11/22] selftests/x86: Recurse into subdirectories Jarkko Sakkinen
2020-02-09 21:25 ` [PATCH v26 12/22] selftests/x86: Add a selftest for SGX Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 13/22] x86/sgx: Add provisioning Jarkko Sakkinen
2020-02-13 10:49 ` Jethro Beekman
2020-02-15 7:25 ` Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 14/22] x86/sgx: Add a page reclaimer Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 15/22] x86/sgx: ptrace() support for the SGX driver Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 16/22] x86/vdso: Add support for exception fixup in vDSO functions Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 17/22] x86/fault: Add helper function to sanitize error code Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 18/22] x86/traps: Attempt to fixup exceptions in vDSO before signaling Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 19/22] x86/vdso: Add __vdso_sgx_enter_enclave() to wrap SGX enclave transitions Jarkko Sakkinen
2020-02-13 13:29 ` Jethro Beekman [this message]
2020-02-15 7:26 ` Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 20/22] selftests/x86: Add vDSO selftest for SGX Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 21/22] x86/sgx: Update MAINTAINERS Jarkko Sakkinen
2020-02-09 21:26 ` [PATCH v26 22/22] docs: x86/sgx: Document SGX micro architecture and kernel internals Jarkko Sakkinen
2020-02-22 4:13 ` Randy Dunlap
2020-02-23 17:04 ` Jarkko Sakkinen
2020-02-23 17:05 ` Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2b61b106-4dfd-ed47-3333-99280e33ca88@fortanix.com \
--to=jethro@fortanix.com \
--cc=akpm@linux-foundation.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=bp@alien8.de \
--cc=cedric.xing@intel.com \
--cc=dave.hansen@intel.com \
--cc=haitao.huang@intel.com \
--cc=jarkko.sakkinen@linux.intel.com \
--cc=josh@joshtriplett.org \
--cc=kai.huang@intel.com \
--cc=kai.svahn@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sgx@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=luto@kernel.org \
--cc=nhorman@redhat.com \
--cc=npmccallum@redhat.com \
--cc=puiterwijk@redhat.com \
--cc=rientjes@google.com \
--cc=sean.j.christopherson@intel.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome