Re: [PATCH v33 11/21] x86/sgx: Linux Enclave Driver
From: Sean Christopherson <hidden>
Date: 2020-06-26 14:16:31
Also in:
lkml
On Fri, Jun 26, 2020 at 11:14:19AM +0200, Borislav Petkov wrote:
On Thu, Jun 18, 2020 at 01:08:33AM +0300, Jarkko Sakkinen wrote:quoted
+static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) +{ + unsigned long encl_size = secs->size + PAGE_SIZE;Wait, you just copied @secs from user memory in sgx_ioc_enclave_create() and now use ->size unverified? You're kidding, right?
The size of the enclave is checked in sgx_validate_secs() before it is used to configure the shmem backing.
quoted
+ struct sgx_epc_page *secs_epc; + unsigned long ssaframesize; + struct sgx_pageinfo pginfo; + struct sgx_secinfo secinfo; + struct file *backing; + long ret; + + if (atomic_read(&encl->flags) & SGX_ENCL_CREATED) + return -EINVAL; + + ssaframesize = sgx_calc_ssaframesize(secs->miscselect, secs->xfrm);So this is using more un-validated user input to do further calculations. What can possibly go wrong?
ssaframesize is also validated below, and the computations on miscselect and xfm in sgx_calc_ssaframesize() are bounded such that bad input won't send the kernel into the weeds. That being said, I agree that it would be safer to move sgx_calc_ssaframesize() inside sgx_validate_secs() and only compute encl_size after the secs is validated.
I sure hope *I* am wrong and am missing something here. If not, please, for the next version, audit all your user input and validate it before using it. Srsly.quoted
+ if (sgx_validate_secs(secs, ssaframesize)) { + pr_debug("invalid SECS\n"); + return -EINVAL; + } + + backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5), + VM_NORESERVE); + if (IS_ERR(backing)) + return PTR_ERR(backing); + + encl->backing = backing; + + secs_epc = __sgx_alloc_epc_page(); + if (IS_ERR(secs_epc)) { + ret = PTR_ERR(secs_epc); + goto err_out_backing; + } + + encl->secs.epc_page = secs_epc; + + pginfo.addr = 0; + pginfo.contents = (unsigned long)secs; + pginfo.metadata = (unsigned long)&secinfo; + pginfo.secs = 0; + memset(&secinfo, 0, sizeof(secinfo)); + + ret = __ecreate((void *)&pginfo, sgx_get_epc_addr(secs_epc)); + if (ret) { + pr_debug("ECREATE returned %ld\n", ret); + goto err_out; + } + + if (secs->attributes & SGX_ATTR_DEBUG) + atomic_or(SGX_ENCL_DEBUG, &encl->flags); + + encl->secs.encl = encl; + encl->secs_attributes = secs->attributes; + encl->allowed_attributes |= SGX_ATTR_ALLOWED_MASK; + encl->base = secs->base; + encl->size = secs->size; + encl->ssaframesize = secs->ssa_frame_size; + + /* + * Set SGX_ENCL_CREATED only after the enclave is fully prepped. This + * allows setting and checking enclave creation without having to take + * encl->lock. + */ + atomic_or(SGX_ENCL_CREATED, &encl->flags); + + return 0; + +err_out: + sgx_free_epc_page(encl->secs.epc_page); + encl->secs.epc_page = NULL; + +err_out_backing: + fput(encl->backing); + encl->backing = NULL; + + return ret; +} + +/** + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE + * @filep: open file to /dev/sgxThat's @encl: enclave pointer or so.quoted
+ * @arg: userspace pointer to a struct sgx_enclave_create instance + * + * Allocate kernel data structures for a new enclave and execute ECREATE after + * verifying the correctness of the provided SECS. + * + * Note, enforcement of restricted and disallowed attributes is deferred until + * sgx_ioc_enclave_init(), only the architectural correctness of the SECS is + * checked by sgx_ioc_enclave_create().Well, I don't see that checking. Where is it?quoted
+ * + * Return: + * 0 on success, + * -errno otherwise + */ +static long sgx_ioc_enclave_create(struct sgx_encl *encl, void __user *arg) +{ + struct sgx_enclave_create ecreate; + struct page *secs_page; + struct sgx_secs *secs; + int ret; + + if (copy_from_user(&ecreate, arg, sizeof(ecreate))) + return -EFAULT; + + secs_page = alloc_page(GFP_KERNEL); + if (!secs_page) + return -ENOMEM; + + secs = kmap(secs_page); + if (copy_from_user(secs, (void __user *)ecreate.src, sizeof(*secs))) { + ret = -EFAULT; + goto out; + } + + ret = sgx_encl_create(encl, secs); + +out: + kunmap(secs_page); + __free_page(secs_page); + return ret; +}-- Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette