Re: [RFC PATCH 11/23] x86/sgx: Add helpers to expose ECREATE and EINIT to KVM

Dave Hansen
2021-01-06T20:13:51Z

On 1/5/21 5:56 PM, Kai Huang wrote:
> From: Sean Christopherson <sean.j.christopherson@intel.com>
>
> Provide wrappers around __ecreate() and __einit() to hide the ugliness
> of overloading the ENCLS return value to encode multiple error formats
> in a single int. KVM will trap-and-execute ECREATE and EINIT as part
> of SGX virtualization, and on an exception, KVM needs the trapnr so that
> it can inject the correct fault into the guest.

This is missing a bit of a step about how and why ECREATE needs to be
run in the host in the first place.

> diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h
> new file mode 100644
> index 000000000000..0d643b985085
> --- /dev/null
> +++ b/arch/x86/include/asm/sgx.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_SGX_H
> +#define _ASM_X86_SGX_H
> +
> +#include <linux/types.h>
> +
> +#ifdef CONFIG_X86_SGX_VIRTUALIZATION
> +struct sgx_pageinfo;
> +
> +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs,
> + int *trapnr);
> +int sgx_virt_einit(void __user *sigstruct, void __user *token,
> + void __user *secs, u64 *lepubkeyhash, int *trapnr);
> +#endif
> +
> +#endif /* _ASM_X86_SGX_H */
> diff --git a/arch/x86/kernel/cpu/sgx/virt.c b/arch/x86/kernel/cpu/sgx/virt.c
> index d625551ccf25..4e9810ba9259 100644
> --- a/arch/x86/kernel/cpu/sgx/virt.c
> +++ b/arch/x86/kernel/cpu/sgx/virt.c
> @@ -261,3 +261,58 @@ int __init sgx_virt_epc_init(void)
>
> return misc_register(&sgx_virt_epc_dev);
> }
> +
> +int sgx_virt_ecreate(struct sgx_pageinfo *pageinfo, void __user *secs,
> + int *trapnr)
> +{
> + int ret;
> +
> + __uaccess_begin();
> + ret = __ecreate(pageinfo, (void *)secs);
> + __uaccess_end();

The __uaccess_begin/end() worries me. There are *very* few of these in
the kernel and it seems like something we want to use as sparingly as
possible.

Why don't we just use the kernel mapping for 'secs' and not have to deal
with stac/clac?

I'm also just generally worried about casting away an __user without
doing any checking. How is that OK?

> + if (encls_faulted(ret)) {
> + *trapnr = ENCLS_TRAPNR(ret);
> + return -EFAULT;
> + }
> +
> + /* ECREATE doesn't return an error code, it faults or succeeds. */
> + WARN_ON_ONCE(ret);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(sgx_virt_ecreate);
> +
> +static int __sgx_virt_einit(void __user *sigstruct, void __user *token,
> + void __user *secs)
> +{
> + int ret;
> +
> + __uaccess_begin();
> + ret = __einit((void *)sigstruct, (void *)token, (void *)secs);
> + __uaccess_end();
> + return ret;
> +}

If casting away one __user wasn't good enough, we get three! :)

We need some more background in the changelog on why this is OK.

> +int sgx_virt_einit(void __user *sigstruct, void __user *token,
> + void __user *secs, u64 *lepubkeyhash, int *trapnr)
> +{
> + int ret;
> +
> + if (!boot_cpu_has(X86_FEATURE_SGX_LC)) {
> + ret = __sgx_virt_einit(sigstruct, token, secs);
> + } else {
> + preempt_disable();
> +
> + sgx_update_lepubkeyhash(lepubkeyhash);
> +
> + ret = __sgx_virt_einit(sigstruct, token, secs);
> + preempt_enable();
> + }
> +
> + if (encls_faulted(ret)) {
> + *trapnr = ENCLS_TRAPNR(ret);
> + return -EFAULT;
> + }
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(sgx_virt_einit);
>