// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2016-20 Intel Corporation. */ #include <asm/mman.h> #include <asm/sgx.h> #include <linux/mman.h> #include <linux/delay.h> #include <linux/file.h> #include <linux/hashtable.h> #include <linux/highmem.h> #include <linux/ratelimit.h> #include <linux/sched/signal.h> #include <linux/shmem_fs.h> #include <linux/slab.h> #include <linux/suspend.h> #include "driver.h" #include "encl.h" #include "encls.h" struct sgx_va_page *sgx_encl_grow(struct sgx_encl *encl, bool reclaim) { … } void sgx_encl_shrink(struct sgx_encl *encl, struct sgx_va_page *va_page) { … } static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs) { … } /** * sgx_ioc_enclave_create() - handler for %SGX_IOC_ENCLAVE_CREATE * @encl: An enclave pointer. * @arg: The ioctl argument. * * Allocate kernel data structures for the enclave and invoke ECREATE. * * Return: * - 0: Success. * - -EIO: ECREATE failed. * - -errno: POSIX error. */ static long sgx_ioc_enclave_create(struct sgx_encl *encl, void __user *arg) { … } static int sgx_validate_secinfo(struct sgx_secinfo *secinfo) { … } static int __sgx_encl_add_page(struct sgx_encl *encl, struct sgx_encl_page *encl_page, struct sgx_epc_page *epc_page, struct sgx_secinfo *secinfo, unsigned long src) { … } /* * If the caller requires measurement of the page as a proof for the content, * use EEXTEND to add a measurement for 256 bytes of the page. Repeat this * operation until the entire page is measured." */ static int __sgx_encl_extend(struct sgx_encl *encl, struct sgx_epc_page *epc_page) { … } static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long src, unsigned long offset, struct sgx_secinfo *secinfo, unsigned long flags) { … } /* * Ensure user provided offset and length values are valid for * an enclave. */ static int sgx_validate_offset_length(struct sgx_encl *encl, unsigned long offset, unsigned long length) { … } /** * sgx_ioc_enclave_add_pages() - The handler for %SGX_IOC_ENCLAVE_ADD_PAGES * @encl: an enclave pointer * @arg: a user pointer to a struct sgx_enclave_add_pages instance * * Add one or more pages to an uninitialized enclave, and optionally extend the * measurement with the contents of the page. The SECINFO and measurement mask * are applied to all pages. * * A SECINFO for a TCS is required to always contain zero permissions because * CPU silently zeros them. Allowing anything else would cause a mismatch in * the measurement. * * mmap()'s protection bits are capped by the page permissions. For each page * address, the maximum protection bits are computed with the following * heuristics: * * 1. A regular page: PROT_R, PROT_W and PROT_X match the SECINFO permissions. * 2. A TCS page: PROT_R | PROT_W. * * mmap() is not allowed to surpass the minimum of the maximum protection bits * within the given address range. * * The function deinitializes kernel data structures for enclave and returns * -EIO in any of the following conditions: * * - Enclave Page Cache (EPC), the physical memory holding enclaves, has * been invalidated. This will cause EADD and EEXTEND to fail. * - If the source address is corrupted somehow when executing EADD. * * Return: * - 0: Success. * - -EACCES: The source page is located in a noexec partition. * - -ENOMEM: Out of EPC pages. * - -EINTR: The call was interrupted before data was processed. * - -EIO: Either EADD or EEXTEND failed because invalid source address * or power cycle. * - -errno: POSIX error. */ static long sgx_ioc_enclave_add_pages(struct sgx_encl *encl, void __user *arg) { … } static int __sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, void *hash) { … } static int sgx_get_key_hash(const void *modulus, void *hash) { … } static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, void *token) { … } /** * sgx_ioc_enclave_init() - handler for %SGX_IOC_ENCLAVE_INIT * @encl: an enclave pointer * @arg: userspace pointer to a struct sgx_enclave_init instance * * Flush any outstanding enqueued EADD operations and perform EINIT. The * Launch Enclave Public Key Hash MSRs are rewritten as necessary to match * the enclave's MRSIGNER, which is calculated from the provided sigstruct. * * Return: * - 0: Success. * - -EPERM: Invalid SIGSTRUCT. * - -EIO: EINIT failed because of a power cycle. * - -errno: POSIX error. */ static long sgx_ioc_enclave_init(struct sgx_encl *encl, void __user *arg) { … } /** * sgx_ioc_enclave_provision() - handler for %SGX_IOC_ENCLAVE_PROVISION * @encl: an enclave pointer * @arg: userspace pointer to a struct sgx_enclave_provision instance * * Allow ATTRIBUTE.PROVISION_KEY for an enclave by providing a file handle to * /dev/sgx_provision. * * Return: * - 0: Success. * - -errno: Otherwise. */ static long sgx_ioc_enclave_provision(struct sgx_encl *encl, void __user *arg) { … } /* * Ensure enclave is ready for SGX2 functions. Readiness is checked * by ensuring the hardware supports SGX2 and the enclave is initialized * and thus able to handle requests to modify pages within it. */ static int sgx_ioc_sgx2_ready(struct sgx_encl *encl) { … } /* * Some SGX functions require that no cached linear-to-physical address * mappings are present before they can succeed. Collaborate with * hardware via ENCLS[ETRACK] to ensure that all cached * linear-to-physical address mappings belonging to all threads of * the enclave are cleared. See sgx_encl_cpumask() for details. * * Must be called with enclave's mutex held from the time the * SGX function requiring that no cached linear-to-physical mappings * are present is executed until this ETRACK flow is complete. */ static int sgx_enclave_etrack(struct sgx_encl *encl) { … } /** * sgx_enclave_restrict_permissions() - Restrict EPCM permissions * @encl: Enclave to which the pages belong. * @modp: Checked parameters from user on which pages need modifying and * their new permissions. * * Return: * - 0: Success. * - -errno: Otherwise. */ static long sgx_enclave_restrict_permissions(struct sgx_encl *encl, struct sgx_enclave_restrict_permissions *modp) { … } /** * sgx_ioc_enclave_restrict_permissions() - handler for * %SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS * @encl: an enclave pointer * @arg: userspace pointer to a &struct sgx_enclave_restrict_permissions * instance * * SGX2 distinguishes between relaxing and restricting the enclave page * permissions maintained by the hardware (EPCM permissions) of pages * belonging to an initialized enclave (after SGX_IOC_ENCLAVE_INIT). * * EPCM permissions cannot be restricted from within the enclave, the enclave * requires the kernel to run the privileged level 0 instructions ENCLS[EMODPR] * and ENCLS[ETRACK]. An attempt to relax EPCM permissions with this call * will be ignored by the hardware. * * Return: * - 0: Success * - -errno: Otherwise */ static long sgx_ioc_enclave_restrict_permissions(struct sgx_encl *encl, void __user *arg) { … } /** * sgx_enclave_modify_types() - Modify type of SGX enclave pages * @encl: Enclave to which the pages belong. * @modt: Checked parameters from user about which pages need modifying * and their new page type. * * Return: * - 0: Success * - -errno: Otherwise */ static long sgx_enclave_modify_types(struct sgx_encl *encl, struct sgx_enclave_modify_types *modt) { … } /** * sgx_ioc_enclave_modify_types() - handler for %SGX_IOC_ENCLAVE_MODIFY_TYPES * @encl: an enclave pointer * @arg: userspace pointer to a &struct sgx_enclave_modify_types instance * * Ability to change the enclave page type supports the following use cases: * * * It is possible to add TCS pages to an enclave by changing the type of * regular pages (%SGX_PAGE_TYPE_REG) to TCS (%SGX_PAGE_TYPE_TCS) pages. * With this support the number of threads supported by an initialized * enclave can be increased dynamically. * * * Regular or TCS pages can dynamically be removed from an initialized * enclave by changing the page type to %SGX_PAGE_TYPE_TRIM. Changing the * page type to %SGX_PAGE_TYPE_TRIM marks the page for removal with actual * removal done by handler of %SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl() called * after ENCLU[EACCEPT] is run on %SGX_PAGE_TYPE_TRIM page from within the * enclave. * * Return: * - 0: Success * - -errno: Otherwise */ static long sgx_ioc_enclave_modify_types(struct sgx_encl *encl, void __user *arg) { … } /** * sgx_encl_remove_pages() - Remove trimmed pages from SGX enclave * @encl: Enclave to which the pages belong * @params: Checked parameters from user on which pages need to be removed * * Return: * - 0: Success. * - -errno: Otherwise. */ static long sgx_encl_remove_pages(struct sgx_encl *encl, struct sgx_enclave_remove_pages *params) { … } /** * sgx_ioc_enclave_remove_pages() - handler for %SGX_IOC_ENCLAVE_REMOVE_PAGES * @encl: an enclave pointer * @arg: userspace pointer to &struct sgx_enclave_remove_pages instance * * Final step of the flow removing pages from an initialized enclave. The * complete flow is: * * 1) User changes the type of the pages to be removed to %SGX_PAGE_TYPE_TRIM * using the %SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl(). * 2) User approves the page removal by running ENCLU[EACCEPT] from within * the enclave. * 3) User initiates actual page removal using the * %SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl() that is handled here. * * First remove any page table entries pointing to the page and then proceed * with the actual removal of the enclave page and data in support of it. * * VA pages are not affected by this removal. It is thus possible that the * enclave may end up with more VA pages than needed to support all its * pages. * * Return: * - 0: Success * - -errno: Otherwise */ static long sgx_ioc_enclave_remove_pages(struct sgx_encl *encl, void __user *arg) { … } long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { … }