arch/x86/include/uapi/asm/sgx.h | 2 + arch/x86/kernel/cpu/sgx/driver/Makefile | 1 + arch/x86/kernel/cpu/sgx/driver/driver.h | 7 + arch/x86/kernel/cpu/sgx/driver/ioctl.c | 88 ++++- arch/x86/kernel/cpu/sgx/driver/main.c | 5 + arch/x86/kernel/cpu/sgx/driver/policy.c | 584 ++++++++++++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/main.c | 27 +- arch/x86/kernel/cpu/sgx/sgx.h | 3 +- 8 files changed, 704 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h index 9ed690a38c70..694981e03c65 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -53,7 +53,9 @@ struct sgx_enclave_add_page { * @sigstruct: address for the SIGSTRUCT data */ struct sgx_enclave_init { + __u64 addr; __u64 sigstruct; + __u64 einittoken; }; /** diff --git a/arch/x86/kernel/cpu/sgx/driver/Makefile b/arch/x86/kernel/cpu/sgx/driver/Makefile index 01ebbbb06a47..ac7702201229 100644 --- a/arch/x86/kernel/cpu/sgx/driver/Makefile +++ b/arch/x86/kernel/cpu/sgx/driver/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_INTEL_SGX_DRIVER) += sgx.o sgx-$(CONFIG_INTEL_SGX_DRIVER) += ioctl.o sgx-$(CONFIG_INTEL_SGX_DRIVER) += main.o +sgx-$(CONFIG_INTEL_SGX_DRIVER) += policy.o diff --git a/arch/x86/kernel/cpu/sgx/driver/driver.h b/arch/x86/kernel/cpu/sgx/driver/driver.h index 153b4a48aa6f..d5994c4aa65d 100644 --- a/arch/x86/kernel/cpu/sgx/driver/driver.h +++ b/arch/x86/kernel/cpu/sgx/driver/driver.h @@ -33,6 +33,13 @@ extern u32 sgx_xsave_size_tbl[64]; extern const struct file_operations sgx_provision_fops; +uint8_t * sgx_get_launch_signer(uint8_t *signature); +int sgx_get_key_hash(const void *modulus, void *hash); +bool sgx_launch_control(uint8_t *modulus); +bool sgx_provisioning_control(uint8_t *modulus); +bool sgx_signing_control(uint8_t *modulus); +int sgx_policy_fs(void); +void sgx_policy_fs_remove(void); long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); #endif /* __ARCH_X86_INTEL_SGX_H__ */ diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c index 3a01c3dd579d..0d758f1498f7 100644 --- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c @@ -639,7 +639,17 @@ static int __sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, return crypto_shash_digest(shash, modulus, SGX_MODULUS_SIZE, hash); } -static int sgx_get_key_hash(const void *modulus, void *hash) +/** +* sgx_get_key_hash - Compute the hash of the enclave signer. +* +* @modulus: A pointer to the signature modulus. +* @hash: A pointer to the signature buffer. +* +* Return: +* 0 on success, +* Cryptographic subsystem error. +*/ +int sgx_get_key_hash(const void *modulus, void *hash) { struct crypto_shash *tfm; int ret; @@ -655,20 +665,26 @@ static int sgx_get_key_hash(const void *modulus, void *hash) } static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, - struct sgx_einittoken *token) + struct sgx_einittoken *token, bool use_lc) { u64 mrsigner[4]; int ret; int i; int j; + uint8_t *(*get_signer)(uint8_t *) = NULL; /* Check that the required attributes have been authorized. */ if (encl->secs_attributes & ~encl->allowed_attributes) return -EINVAL; - ret = sgx_get_key_hash(sigstruct->modulus, mrsigner); - if (ret) - return ret; + if (use_lc) + get_signer = sgx_get_launch_signer; + else { + pr_debug("%s: Using modulus signature.\n", __FILE__); + ret = sgx_get_key_hash(sigstruct->modulus, mrsigner); + if (ret) + return ret; + } flush_work(&encl->work); @@ -683,7 +699,7 @@ static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, for (i = 0; i < SGX_EINIT_SLEEP_COUNT; i++) { for (j = 0; j < SGX_EINIT_SPIN_COUNT; j++) { ret = sgx_einit(sigstruct, token, encl->secs.epc_page, - mrsigner); + mrsigner, get_signer); if (ret == SGX_UNMASKED_EVENT) continue; else @@ -737,6 +753,7 @@ static int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct, static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, unsigned long arg) { + bool use_sc, use_lc, use_pc; struct sgx_enclave_init *initp = (struct sgx_enclave_init *)arg; struct sgx_encl *encl = filep->private_data; struct sgx_einittoken *einittoken; @@ -744,6 +761,25 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, struct page *initp_page; int ret; + use_sc = sgx_signing_control(NULL); + pr_debug("%s: Signing control status: %s\n", __FILE__, + use_sc ? "active" : "disabled"); + + use_lc = sgx_launch_control(NULL); + pr_debug("%s: Launch control status: %s\n", __FILE__, + use_lc ? "active" : "disabled"); + + use_pc = sgx_provisioning_control(NULL); + pr_debug("%s: Provisioning control status: %s\n", __FILE__, + use_pc ? "active" : "disabled"); + + if (!use_sc) { + if (initp->einittoken != 0 && !use_lc) + return -EINVAL; + if (initp->einittoken == 0 && use_lc) + return -EINVAL; + } + initp_page = alloc_page(GFP_HIGHUSER); if (!initp_page) return -ENOMEM; @@ -751,7 +787,16 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, sigstruct = kmap(initp_page); einittoken = (struct sgx_einittoken *) ((unsigned long)sigstruct + PAGE_SIZE / 2); - memset(einittoken, 0, sizeof(*einittoken)); + if ( !initp->einittoken ) + memset(einittoken, 0, sizeof(*einittoken)); + else { + if (copy_from_user(einittoken, + (void __user *)initp->einittoken, + sizeof(*einittoken))) { + ret = -EFAULT; + goto out; + } + } if (copy_from_user(sigstruct, (void __user *)initp->sigstruct, sizeof(*sigstruct))) { @@ -759,8 +804,35 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd, goto out; } + if (!use_lc && (sigstruct->body.attributes & SGX_ATTR_EINITTOKENKEY)) { + ret = -EINVAL; + goto out; + } + + if ((sigstruct->body.attributes & SGX_ATTR_EINITTOKENKEY) && + sgx_launch_control(sigstruct->modulus)) + encl->allowed_attributes |= SGX_ATTR_EINITTOKENKEY; + + if (!use_pc) + encl->allowed_attributes |= SGX_ATTR_PROVISIONKEY; + else { + if ((sigstruct->body.attributes & SGX_ATTR_PROVISIONKEY) && + sgx_provisioning_control(sigstruct->modulus)) + encl->allowed_attributes |= SGX_ATTR_PROVISIONKEY; + } + + if (use_sc) { + use_sc = sgx_signing_control(sigstruct->modulus); + if (!use_sc && !use_lc) { + ret = -EINVAL; + goto out; + } + if (use_sc) + use_lc = false; + } + + ret = sgx_encl_init(encl, sigstruct, einittoken, use_lc); - ret = sgx_encl_init(encl, sigstruct, einittoken); out: kunmap(initp_page); diff --git a/arch/x86/kernel/cpu/sgx/driver/main.c b/arch/x86/kernel/cpu/sgx/driver/main.c index afe844aa81d6..503c2a9728ec 100644 --- a/arch/x86/kernel/cpu/sgx/driver/main.c +++ b/arch/x86/kernel/cpu/sgx/driver/main.c @@ -348,6 +348,10 @@ static int __init sgx_drv_init(void) { int ret; + ret = sgx_policy_fs(); + if (ret) + return ret; + ret = sgx_drv_subsys_init(); if (ret) return ret; @@ -362,6 +366,7 @@ module_init(sgx_drv_init); static void __exit sgx_drv_exit(void) { + sgx_policy_fs_remove(); platform_driver_unregister(&sgx_drv); sgx_drv_subsys_exit(); } diff --git a/arch/x86/kernel/cpu/sgx/driver/policy.c b/arch/x86/kernel/cpu/sgx/driver/policy.c new file mode 100644 index 000000000000..c72b1604c1fa --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/driver/policy.c @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) IDfusion, LLC + +#define KEY_SIZE 32 + +#include +#include +#include +#include +#include "driver.h" + +/* Variables for launch key management. */ +struct list_key { + struct list_head list; + uint8_t key[KEY_SIZE]; +}; + +static struct dentry *sgx_fs; +static struct dentry *launch_keys; +static atomic_t launch_keys_opencount = ATOMIC_INIT(1); +static unsigned int launch_keys_count; +static bool launch_keys_locked; +static DEFINE_MUTEX(launch_key_list_mutex); +static LIST_HEAD(launch_key_list); + +static struct dentry *provision_keys; +static atomic_t provision_keys_opencount = ATOMIC_INIT(1); +static unsigned int provision_keys_count; +static bool provision_keys_locked; +static DEFINE_MUTEX(provision_key_list_mutex); +static LIST_HEAD(provision_key_list); + +static struct dentry *signing_keys; +static atomic_t signing_keys_opencount = ATOMIC_INIT(1); +static unsigned int signing_keys_count; +static bool signing_keys_locked; +static DEFINE_MUTEX(signing_key_list_mutex); +static LIST_HEAD(signing_key_list); + +/** + * have_signer - Verify the presence presence of a key signer. + * + * @signature: Pointer to signature of signer. + * + * Return: + * 0 Signer signature was not found. + * 1 Signer signature was found. + */ +static bool have_signer(struct list_head *keylist, struct mutex *lock, + uint8_t *signature) +{ + bool retn = false; + struct list_key *kp; + + mutex_lock(lock); + list_for_each_entry(kp, keylist, list) { + pr_debug("%s: Checking signer=%*phN, ks=%*phN\n", __func__, + KEY_SIZE, signature, KEY_SIZE, kp->key); + if (memcmp(kp->key, signature, KEY_SIZE) == 0) { + retn = true; + goto done; + } + } + + done: + mutex_unlock(lock); + return retn; +} + +/** + * sgx_launch_control - Launch Control policy status + * + * Verifies whether or not launch control is active. + * + * Return: + * 0 No launch control is authorized. + * 1 Launch control is permitted. + */ +bool sgx_launch_control(uint8_t *modulus) +{ + bool retn = false; + uint8_t mrsigner[KEY_SIZE]; + + if (modulus == NULL) { + retn = launch_keys_count > 0; + goto done; + } + + pr_debug("%s: Verifying launch control modulus.\n", __func__); + if (sgx_get_key_hash(modulus, mrsigner)) + goto done; + retn = have_signer(&launch_key_list, &launch_key_list_mutex, mrsigner); + + done: + return retn; +} + +/** + * sgx_get_launch_signer - Iterate through list of enclave authorizers. + * + * @signer: The last returned enclave signer. + * + * This function iterates through the list of enclave signers from the + * last signature. Calling the function with a NULL signer value + * resets the iteration to the beginning of the list. + * + * Return: + * NULL indicates end of list + * non-NULL the next enclave signature on the list. + */ + +uint8_t * sgx_get_launch_signer(uint8_t *signature) +{ + bool seeking = false; + uint8_t *retn = NULL; + struct list_key *kp; + + if (!signature) { + kp = list_first_entry(&launch_key_list, struct list_key, list); + return kp->key; + } + + kp = list_last_entry(&launch_key_list, struct list_key, list); + if ( memcmp(kp->key, signature, sizeof(kp->key)) == 0 ) + return NULL; + + mutex_lock(&launch_key_list_mutex); + list_for_each_entry(kp, &launch_key_list, list) { + if (seeking) { + retn = kp->key; + goto done; + } + pr_debug("%s: Skipping: %*phN\n", __func__, KEY_SIZE, kp->key); + if (memcmp(kp->key, signature, KEY_SIZE) == 0) + seeking = true; + } + + done: + mutex_unlock(&launch_key_list_mutex); + return retn; +} + +/** + * sgx_provisioning_control - Provisioning control verification. + * + * This function returns a true value if provision control is active + * and the signature of the modulus of the signing key for an enclave + * with the PROVISION bit set is on the list of approved keys. + * + * Return: + * 0 No provisioning control is authorized. + * 1 Provisioning is authorized for the enclave. + */ +bool sgx_provisioning_control(uint8_t *modulus) +{ + bool retn = false; + uint8_t mrsigner[KEY_SIZE]; + + if (modulus == NULL) { + retn = provision_keys_count > 0; + goto done; + } + + pr_debug("Verifying provisioning control signature.\n"); + if (sgx_get_key_hash(modulus, mrsigner)) + goto done; + retn = have_signer(&provision_key_list, &provision_key_list_mutex, + mrsigner); + + done: + return retn; +} + +/** + * sgx_signing_control - Signing control verification. + * + * This function returns a true value if signing control is active + * and the signature of the modulus of the signing key for an enclave + * is on the list of approved keys. + * + * Return: + * 0 No signing control is authorized. + * 1 Signing is authorized for the enclave. + */ +bool sgx_signing_control(uint8_t *modulus) +{ + bool retn = false; + uint8_t mrsigner[KEY_SIZE]; + + if (modulus == NULL) { + retn = signing_keys_count > 0; + goto done; + } + + pr_debug("Verifying signing control signature.\n"); + if (sgx_get_key_hash(modulus, mrsigner)) + goto done; + retn = have_signer(&signing_key_list, &signing_key_list_mutex, + mrsigner); + + done: + return retn; +} + +static int process_write_key(const char __user *buf, size_t datalen, + unsigned int *keycnt, struct mutex *lock, + struct list_head *keylist) +{ + ssize_t retn; + + char *p, keybufr[KEY_SIZE*2 + 1], key[KEY_SIZE]; + + struct list_key *kp; + + if (datalen != sizeof(keybufr)) { + retn = -EINVAL; + goto done; + } + + memset(keybufr, '\0', sizeof(keybufr)); + if (copy_from_user(keybufr, buf, datalen)) { + retn = -EFAULT; + goto done; + } + + p = strchr(keybufr, '\n'); + if (!p) { + retn = -EINVAL; + goto done; + } + *p = '\0'; + if (hex2bin(key, keybufr, sizeof(key))) { + retn = -EINVAL; + goto done; + } + + kp = kzalloc(sizeof(*kp), GFP_KERNEL); + if (!kp) { + retn = -ENOMEM; + goto done; + } + memcpy(kp->key, key, sizeof(kp->key)); + + mutex_lock(lock); + list_add_tail(&kp->list, keylist); + ++*keycnt; + mutex_unlock(lock); + + retn = datalen; + pr_debug("%s: Added key: %*phN\n", __func__, KEY_SIZE, key); + + done: + return retn; +} + +static int process_lock(const char __user *buf, size_t datalen, bool *lockfile) +{ + char bufr[5]; + + if (datalen != strlen("lock") + 1) + return 0; + + memset(bufr, '\0', sizeof(bufr)); + if (copy_from_user(bufr, buf, datalen-1)) + return -EFAULT; + if ( strcmp(bufr, "lock") != 0 ) + return 0; + + *lockfile = true; + return datalen; +} + +static int process_clear(const char __user *buf, size_t datalen, char *type, + unsigned int *keycnt, struct mutex *lock, + struct list_head *keylist) +{ + char bufr[6]; + struct list_key *kp, *kp_tmp; + + if (datalen != strlen("clear") + 1) + return 0; + + memset(bufr, '\0', sizeof(bufr)); + if (copy_from_user(bufr, buf, datalen-1)) + return -EFAULT; + if ( strcmp(bufr, "clear") != 0 ) + return 0; + + mutex_lock(lock); + list_for_each_entry_safe(kp, kp_tmp, keylist, list) { + pr_debug("[%s]: Freeing signature: %*phN\n", __FILE__, + KEY_SIZE, kp->key); + list_del(&kp->list); + kfree(kp); + } + *keycnt = 0; + mutex_unlock(lock); + + pr_info("Cleared %s signatures.\n", type); + return datalen; +} + +static int process_dump(const char __user *buf, size_t datalen, char *type, + struct mutex *lock, struct list_head *keylist) +{ + char bufr[5]; + struct list_key *kp; + + if (datalen != strlen("dump") + 1) + return 0; + + memset(bufr, '\0', sizeof(bufr)); + if (copy_from_user(bufr, buf, datalen-1)) + return -EFAULT; + if ( strcmp(bufr, "dump") != 0 ) + return 0; + + pr_info("SGX %s keys:\n", type); + mutex_lock(lock); + list_for_each_entry(kp, keylist, list) { + pr_info("SGX %s: %*phN\n", type, KEY_SIZE, kp->key); + } + mutex_unlock(lock); + + return datalen; +} + +static int open_launch_keys(struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_WRONLY)) + return -EACCES; + if (atomic_dec_and_test(&launch_keys_opencount)) + return 0; + return -EBUSY; +} + +static ssize_t write_launch_keys(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + ssize_t retn; + + if (launch_keys_locked) { + retn = -EINVAL; + goto done; + } + + if (*ppos != 0) { + retn = -EINVAL; + goto done; + } + + retn = process_lock(buf, datalen, &launch_keys_locked); + if (retn != 0) + return retn; + + retn = process_clear(buf, datalen, "launch control", + &launch_keys_count, &launch_key_list_mutex, + &launch_key_list); + if (retn != 0) + return retn; + + retn = process_dump(buf, datalen, "lc", &launch_key_list_mutex, + &launch_key_list); + if (retn != 0) + return retn; + + retn = process_write_key(buf, datalen, &launch_keys_count, + &launch_key_list_mutex, &launch_key_list); + +done: + return retn; +} + +static int release_launch_keys(struct inode *inode, struct file *file) +{ + atomic_set(&launch_keys_opencount, 1); + return 0; +} + +static const struct file_operations launch_keys_ops = { + .open = open_launch_keys, + .write = write_launch_keys, + .release = release_launch_keys, + .llseek = generic_file_llseek, +}; + +/* Provisioning control. */ + +static int open_provision_keys(struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_WRONLY)) + return -EACCES; + if (atomic_dec_and_test(&provision_keys_opencount)) + return 0; + return -EBUSY; +} + +static ssize_t write_provision_keys(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + ssize_t retn; + + if (provision_keys_locked) { + retn = -EINVAL; + goto done; + } + + if (*ppos != 0) { + retn = -EINVAL; + goto done; + } + + retn = process_lock(buf, datalen, &provision_keys_locked); + if (retn != 0) + return retn; + + retn = process_clear(buf, datalen, "provisioning control", + &provision_keys_count, &provision_key_list_mutex, + &provision_key_list); + if (retn != 0) + return retn; + + retn = process_dump(buf, datalen, "pc", &provision_key_list_mutex, + &provision_key_list); + if (retn != 0) + return retn; + + retn = process_write_key(buf, datalen, &provision_keys_count, + &provision_key_list_mutex, + &provision_key_list); +done: + return retn; +} + +static int release_provision_keys(struct inode *inode, struct file *file) +{ + atomic_set(&provision_keys_opencount, 1); + return 0; +} + +static const struct file_operations provision_keys_ops = { + .open = open_provision_keys, + .write = write_provision_keys, + .release = release_provision_keys, + .llseek = generic_file_llseek, +}; + +/* + * Signing control. + */ + +static int open_signing_keys(struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_WRONLY)) + return -EACCES; + if (atomic_dec_and_test(&signing_keys_opencount)) + return 0; + return -EBUSY; +} + +static ssize_t write_signing_keys(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + ssize_t retn; + + if (signing_keys_locked) { + retn = -EINVAL; + goto done; + } + + if (*ppos != 0) { + retn = -EINVAL; + goto done; + } + + retn = process_lock(buf, datalen, &signing_keys_locked); + if (retn != 0) + return retn; + + retn = process_clear(buf, datalen, "signing control", + &signing_keys_count, &signing_key_list_mutex, + &signing_key_list); + if (retn != 0) + return retn; + + retn = process_dump(buf, datalen, "sc", &signing_key_list_mutex, + &signing_key_list); + if (retn != 0) + return retn; + + retn = process_write_key(buf, datalen, &signing_keys_count, + &signing_key_list_mutex, &signing_key_list); +done: + return retn; +} + +static int release_signing_keys(struct inode *inode, struct file *file) +{ + atomic_set(&signing_keys_opencount, 1); + return 0; +} + +static const struct file_operations signing_keys_ops = { + .open = open_signing_keys, + .write = write_signing_keys, + .release = release_signing_keys, + .llseek = generic_file_llseek, +}; + +int sgx_policy_fs(void) +{ + int retn = -1; + + sgx_fs = securityfs_create_dir("sgx", NULL); + if(IS_ERR(sgx_fs)) { + retn = PTR_ERR(sgx_fs); + goto err; + } + + launch_keys = securityfs_create_file("launch_keys", S_IWUSR | S_IRUSR, + sgx_fs, NULL, &launch_keys_ops); + if (IS_ERR(launch_keys)) { + retn = PTR_ERR(launch_keys); + goto err; + } + + provision_keys = securityfs_create_file("provisioning_keys", + S_IWUSR | S_IRUSR, + sgx_fs, NULL, + &provision_keys_ops); + if (IS_ERR(provision_keys)) { + retn = PTR_ERR(provision_keys); + goto err; + } + + signing_keys = securityfs_create_file("signing_keys", + S_IWUSR | S_IRUSR, + sgx_fs, NULL, + &signing_keys_ops); + if (IS_ERR(signing_keys)) { + retn = PTR_ERR(signing_keys); + goto err; + } + + return 0; + + err: + securityfs_remove(launch_keys); + securityfs_remove(provision_keys); + securityfs_remove(signing_keys); + securityfs_remove(sgx_fs); + return retn; +} + +void sgx_policy_fs_remove(void) +{ + struct list_key *kp, *kp_tmp; + + mutex_lock(&launch_key_list_mutex); + list_for_each_entry_safe(kp, kp_tmp, &launch_key_list, list) { + list_del(&kp->list); + kfree(kp); + } + mutex_unlock(&launch_key_list_mutex); + + mutex_lock(&provision_key_list_mutex); + list_for_each_entry_safe(kp, kp_tmp, &provision_key_list, list) { + list_del(&kp->list); + kfree(kp); + } + mutex_unlock(&provision_key_list_mutex); + + mutex_lock(&signing_key_list_mutex); + list_for_each_entry_safe(kp, kp_tmp, &signing_key_list, list) { + list_del(&kp->list); + kfree(kp); + } + mutex_unlock(&signing_key_list_mutex); + + securityfs_remove(launch_keys); + securityfs_remove(provision_keys); + securityfs_remove(signing_keys); + securityfs_remove(sgx_fs); +} diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 07adb35c260b..c5a9df27702c 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -189,6 +189,8 @@ static void sgx_update_lepubkeyhash_msrs(u64 *lepubkeyhash, bool enforce) * @token: a pointer an EINITTOKEN (optional) * @secs: a pointer a SECS * @lepubkeyhash: the desired value for IA32_SGXLEPUBKEYHASHx MSRs + * @launch_signer: a pointer to a function returning possible + * launch signers * * Execute ENCLS[EINIT], writing the IA32_SGXLEPUBKEYHASHx MSRs according * to @lepubkeyhash (if possible and necessary). @@ -198,13 +200,30 @@ static void sgx_update_lepubkeyhash_msrs(u64 *lepubkeyhash, bool enforce) * -errno or SGX error on failure */ int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, - struct sgx_epc_page *secs, u64 *lepubkeyhash) + struct sgx_epc_page *secs, u64 *lepubkeyhash, + uint8_t * (*launch_signer)(uint8_t *)) { int ret; + uint8_t *signer; + + if (launch_signer) { + signer = (*launch_signer)(NULL); + while (signer) { + pr_debug("%s: Trying signer: %*phN\n", __FILE__, 32, + signer); + preempt_disable(); + sgx_update_lepubkeyhash_msrs((u64 *) signer, true); + ret = __einit(sigstruct, token, sgx_epc_addr(secs)); + preempt_enable(); + if (!ret) + return ret; + signer = (*launch_signer)(signer); + } + return ret; + } - if (!boot_cpu_has(X86_FEATURE_SGX_LC)) - return __einit(sigstruct, token, sgx_epc_addr(secs)); - + pr_debug("%s: Setting LC register for EINIT to: %*phN.\n", __FILE__, + 32, lepubkeyhash); preempt_disable(); sgx_update_lepubkeyhash_msrs(lepubkeyhash, false); ret = __einit(sigstruct, token, sgx_epc_addr(secs)); diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h index 8a1dff1e5e8a..50fc9ee9d556 100644 --- a/arch/x86/kernel/cpu/sgx/sgx.h +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -85,6 +85,7 @@ struct sgx_epc_page *sgx_alloc_page(void *owner, bool reclaim); int __sgx_free_page(struct sgx_epc_page *page); void sgx_free_page(struct sgx_epc_page *page); int sgx_einit(struct sgx_sigstruct *sigstruct, struct sgx_einittoken *token, - struct sgx_epc_page *secs, u64 *lepubkeyhash); + struct sgx_epc_page *secs, u64 *lepubkeyhash, + uint8_t *(*get_signer)(uint8_t *)); #endif /* _X86_SGX_H */